From e838776518a551c243facd2ef74f400aa858db04 Mon Sep 17 00:00:00 2001 From: Maksim Ivanov Date: Fri, 1 Mar 2024 19:18:43 +0300 Subject: [PATCH] refactor: fix ordering (#6930) --- package-lock.json | 2018 +++++++++-------- package.json | 5 +- .../arc-chart/arc-chart.component.ts | 10 +- .../components/axes/axes.component.ts | 10 +- .../bar-chart/bar-chart.component.ts | 12 +- .../line-chart/line-chart.component.ts | 18 +- .../line-days-chart.component.ts | 98 +- .../pie-chart/pie-chart.directive.ts | 10 +- .../input-card-grouped.component.ts | 114 +- .../input-card/abstract-input-card.ts | 24 +- .../input-card/input-card.component.ts | 10 +- .../input-cvc/input-cvc.component.ts | 22 +- .../input-expire/input-expire.component.ts | 10 +- .../components/demo/demo.component.ts | 24 +- ...umentation-property-connector.directive.ts | 12 +- .../documentation/documentation.component.ts | 4 +- .../components/example/example.component.ts | 14 +- .../language-switcher.component.ts | 12 +- .../components/page/page.component.ts | 2 +- .../scroll-into-view.directive.ts | 10 +- projects/addon-doc/services/theme.service.ts | 8 +- .../mobile-calendar.component.ts | 52 +- .../loader-android.component.ts | 26 +- .../pull-to-refresh.component.ts | 5 +- .../sheet-dialog/sheet-dialog.component.ts | 12 +- .../sheet/components/sheet/sheet.component.ts | 24 +- .../components/sheet/sheet.directive.ts | 10 +- .../directives/ripple/ripple.directive.ts | 3 +- .../directives/sidebar/sidebar.component.ts | 8 +- .../directives/sidebar/sidebar.directive.ts | 4 +- .../preview-pagination.component.ts | 12 +- .../components/reorder/reorder.component.ts | 22 +- .../table-pagination.component.ts | 37 +- .../table-pagination.template.html | 4 +- .../directives/direction-order.directive.ts | 10 +- .../table/directives/sort-by.directive.ts | 12 +- .../table/directives/sortable.directive.ts | 4 +- .../components/table/tbody/tbody.component.ts | 6 +- .../table-filters/table-filter.directive.ts | 4 +- projects/cdk/abstract/control.ts | 49 +- projects/cdk/abstract/interactive.ts | 8 +- projects/cdk/abstract/portals.ts | 16 +- projects/cdk/abstract/theme-switcher.ts | 8 +- .../active-zone/active-zone.directive.ts | 10 +- .../auto-focus/handlers/abstract.handler.ts | 4 +- .../directives/checked/checked.directive.ts | 6 +- .../focus-trap/focus-trap.directive.ts | 34 +- .../cdk/directives/media/media.directive.ts | 18 +- .../native-validator.directive.ts | 14 +- .../directives/obscured/obscured.directive.ts | 6 +- .../overscroll/overscroll.directive.ts | 8 +- .../v3/steps/migrate-textfield-controller.ts | 3 +- .../cdk/services/directive-styles.service.ts | 8 +- .../core/abstract/abstract-textfield-host.ts | 4 +- .../components/button/button.component.ts | 8 +- .../components/calendar/calendar.component.ts | 64 +- .../data-list/data-list.component.ts | 30 +- .../data-list/option/option.component.ts | 10 +- .../core/components/error/error.component.ts | 13 +- .../components/expand/expand.component.ts | 20 +- .../core/components/group/group.directive.ts | 3 +- .../hosted-dropdown.component.ts | 57 +- .../core/components/link/link.component.ts | 10 +- .../components/loader/loader.component.ts | 10 +- .../notification/notification.component.ts | 2 +- .../primitive-calendar.component.ts | 102 +- .../primitive-checkbox.component.ts | 10 +- .../primitive-spin-button.component.ts | 16 +- .../primitive-textfield.component.ts | 45 +- .../value-decoration.component.ts | 18 +- .../primitive-year-picker.component.ts | 98 +- .../scroll-controls/scrollbar.directive.ts | 6 +- .../scrollbar/scrollbar.component.ts | 4 +- projects/core/components/svg/svg.component.ts | 28 +- .../components/tooltip/tooltip.component.ts | 6 +- .../dropdown/dropdown-context.directive.ts | 11 +- .../dropdown/dropdown-open.directive.ts | 24 +- .../dropdown/dropdown-selection.directive.ts | 12 +- .../directives/dropdown/dropdown.directive.ts | 20 +- .../hint/hint-describe.directive.ts | 8 +- .../directives/hint/hint-options.directive.ts | 2 +- .../directives/hint/hint-pointer.directive.ts | 8 +- .../core/directives/hint/hint.component.ts | 2 +- .../core/directives/icons/icons.directive.ts | 4 +- .../number-format/number-format.directive.ts | 10 +- ...imitive-year-month-pagination.component.ts | 28 +- .../src/tests/mobile-calendar.cy.ts | 5 +- projects/demo-cypress/src/tests/range.cy.ts | 6 +- .../src/modules/app/classes/ts-file.parser.ts | 20 +- .../customization/customization.component.ts | 20 +- .../modules/app/landing/landing.component.ts | 8 +- .../components/checkbox/checkbox.component.ts | 20 +- .../combo-box/combo-box.component.ts | 16 +- .../hosted-dropdown/examples/4/index.ts | 8 +- .../input-card/input-card.component.ts | 26 +- .../input-copy/input-copy.component.ts | 12 +- .../input-date-multi.component.ts | 4 +- .../input-date-range.component.ts | 23 +- .../input-date-time.component.ts | 14 +- .../input-date/input-date.component.ts | 8 +- .../input-files/input-files.component.ts | 8 +- .../input-inline/input-inline.component.ts | 12 +- .../input-month-range.component.ts | 8 +- .../input-month/input-month.component.ts | 8 +- .../input-number/input-number.component.ts | 8 +- .../input-password.component.ts | 12 +- .../input-phone-international.component.ts | 9 +- .../input-phone/input-phone.component.ts | 8 +- .../input-range/input-range.component.ts | 12 +- .../input-slider/input-slider.component.ts | 26 +- .../input-tag/input-tag.component.ts | 36 +- .../input-time/input-time.component.ts | 8 +- .../input-year/input-year.component.ts | 8 +- .../components/input/input.component.ts | 29 +- .../multi-select/multi-select.component.ts | 38 +- .../primitive-textfield/examples/1/index.ts | 8 +- .../components/prompt/prompt.component.ts | 12 +- .../radio-list/radio-list.component.ts | 42 +- .../components/radio/radio.component.ts | 36 +- .../components/range/range.component.ts | 28 +- .../components/select/select.component.ts | 16 +- .../components/slider/slider.component.ts | 28 +- .../components/textarea/textarea.component.ts | 26 +- .../copy-processor/examples/1/index.ts | 10 +- .../dropdown-open/examples/4/index.ts | 8 +- .../directives/pan/examples/1/index.ts | 8 +- .../icons-group/icons-group.component.ts | 6 +- .../services/table-bar/table-bar.component.ts | 10 +- .../utils/pure/pure-getter.component.ts | 4 +- .../components/button/button.directive.ts | 3 +- .../components/chip/chip.directive.ts | 3 +- .../segmented/segmented.directive.ts | 18 +- .../components/textfield/select.directive.ts | 8 +- .../textfield/textfield.component.ts | 29 +- .../textfield/textfield.directive.ts | 5 +- .../components/toggle/toggle.component.ts | 8 +- .../components/tooltip/tooltip.component.ts | 6 +- .../directives/card/card.directive.ts | 4 +- .../directives/cell/cell.directive.ts | 4 +- .../progress-segmented.directive.ts | 4 +- .../sensitive/sensitive.directive.ts | 3 +- .../directives/surface/surface.directive.ts | 4 +- .../directives/title/title.directive.ts | 4 +- .../kit/abstract/abstract-native-select.ts | 2 +- .../accordion-item.component.ts | 10 +- .../kit/components/badge/badge.directive.ts | 3 +- .../kit/components/block/block.directive.ts | 4 +- .../breadcrumbs/breadcrumbs.component.ts | 8 +- .../breadcrumbs/breadcrumbs.template.html | 2 +- .../calendar-month.component.ts | 93 +- .../calendar-range.component.ts | 64 +- .../components/carousel/carousel.component.ts | 24 +- .../components/carousel/carousel.directive.ts | 8 +- .../combo-box/combo-box.component.ts | 90 +- .../data-list-wrapper/data-list-wrapper.ts | 6 +- .../components/files/files/files.component.ts | 8 +- .../input-files/input-files.directive.ts | 15 +- .../kit/components/filter/filter.component.ts | 16 +- .../input-copy/input-copy.component.ts | 28 +- .../input-date-multi.component.ts | 57 +- .../input-date-range.component.ts | 147 +- .../input-date-time.component.ts | 147 +- .../input-date/input-date.component.ts | 114 +- .../input-month-range.component.ts | 36 +- .../input-month/input-month.component.ts | 57 +- .../input-number/input-number.component.ts | 153 +- .../input-number/input-number.template.html | 4 +- .../input-password.component.ts | 18 +- .../input-phone-international.component.ts | 68 +- .../input-phone/input-phone.component.ts | 92 +- .../input-range/input-range.component.ts | 26 +- .../input-slider/input-slider.component.ts | 26 +- .../input-tag/input-tag.component.ts | 158 +- .../input-time/input-time.component.ts | 114 +- .../input-year/input-year.component.ts | 36 +- .../input-year/input-year.directive.ts | 8 +- .../kit/components/input/input.component.ts | 32 +- .../items-with-more.service.ts | 12 +- .../line-clamp/line-clamp.component.ts | 28 +- .../multi-select-group.component.ts | 24 +- .../multi-select/multi-select.component.ts | 71 +- .../multi-select/multi-select.directive.ts | 8 +- .../native-multi-select.ts | 6 +- .../pagination/pagination.component.ts | 16 +- .../components/push/push-alert.directive.ts | 10 +- .../radio-list/radio-list.component.ts | 14 +- .../kit/components/radio/radio.component.ts | 32 +- .../kit/components/range/range.component.ts | 52 +- .../kit/components/rating/rating.component.ts | 20 +- .../select-option/select-option.component.ts | 8 +- .../kit/components/select/select.component.ts | 50 +- .../helpers/slider-key-steps.directive.ts | 32 +- .../slider-thumb-label.component.ts | 18 +- .../kit/components/slider/slider.component.ts | 62 +- .../components/stepper/stepper.component.ts | 54 +- .../kit/components/tabs/tab/tab.component.ts | 10 +- .../tabs-with-more.component.ts | 65 +- .../kit/components/tabs/tabs.directive.ts | 28 +- .../components/tabs/tabs/tabs.component.ts | 14 +- .../tabs/underline/underline.component.ts | 10 +- .../components/textarea/textarea.component.ts | 38 +- .../kit/components/tiles/tile.component.ts | 42 +- .../kit/components/tiles/tiles.component.ts | 18 +- .../kit/components/toggle/toggle.component.ts | 30 +- .../tree-item-content.component.ts | 8 +- .../highlight/highlight.directive.ts | 8 +- .../lazy-loading/lazy-loading.directive.ts | 16 +- .../directives/present/present.directive.ts | 8 +- .../primitive-calendar-range.component.ts | 10 +- .../kit/pipes/field-error/field-error-pipe.ts | 30 +- 210 files changed, 3451 insertions(+), 3427 deletions(-) diff --git a/package-lock.json b/package-lock.json index f2ea904928e9..ada6e2b9ebb8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,7 +32,7 @@ "@taiga-ui/browserslist-config": "0.5.0", "@taiga-ui/commitlint-config": "0.5.6", "@taiga-ui/cspell-config": "0.34.0", - "@taiga-ui/eslint-plugin-experience": "0.60.0", + "@taiga-ui/eslint-plugin-experience": "0.62.0", "@taiga-ui/prettier-config": "0.8.4", "@taiga-ui/stylelint-config": "0.18.0", "@taiga-ui/tsconfig": "0.16.0", @@ -945,19 +945,6 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", - "dev": true, - "dependencies": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/@angular-devkit/build-webpack": { "version": "0.1502.10", "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1502.10.tgz", @@ -1633,30 +1620,6 @@ "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@angular/cdk/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "optional": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/@angular/cdk/node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "optional": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, "node_modules/@angular/cli": { "version": "15.2.10", "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-15.2.10.tgz", @@ -5509,6 +5472,35 @@ "node": ">= 6" } }, + "node_modules/@cypress/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/@cypress/request/node_modules/qs": { + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", + "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/@cypress/xvfb": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", @@ -6009,6 +6001,12 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -6034,6 +6032,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -6285,15 +6295,6 @@ "node": ">=8" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -6307,19 +6308,6 @@ "node": ">=8" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -9486,16 +9474,11 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@nx/workspace/node_modules/axios": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", - "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", - "dev": true, - "dependencies": { - "follow-redirects": "^1.15.4", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } + "node_modules/@nx/workspace/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/@nx/workspace/node_modules/chalk": { "version": "4.1.2", @@ -9531,20 +9514,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/@nx/workspace/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/@nx/workspace/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -9554,6 +9523,18 @@ "node": ">=8" } }, + "node_modules/@nx/workspace/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/@nx/workspace/node_modules/nx": { "version": "17.3.1", "resolved": "https://registry.npmjs.org/nx/-/nx-17.3.1.tgz", @@ -9647,12 +9628,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@nx/workspace/node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true - }, "node_modules/@nx/workspace/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -10239,9 +10214,9 @@ "link": true }, "node_modules/@taiga-ui/eslint-plugin-experience": { - "version": "0.60.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/eslint-plugin-experience/-/eslint-plugin-experience-0.60.0.tgz", - "integrity": "sha512-5mfdwlVSuhYTAYCVMi41wQ929zaIY/hZFkxqcGjU/yKdcJ7v0zBnHyHHQdc0JIl1YvmROrG7EGEDAmsyP2cHFw==", + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/eslint-plugin-experience/-/eslint-plugin-experience-0.62.0.tgz", + "integrity": "sha512-Asssx1NCl5YYekEZl60SA+DeVylLJnrTUSklb9cRZnGwv2sp/tRo3APoSXCgEgJUIvTbxwebKRAVm+PrLWV3iA==", "dev": true, "dependencies": { "@angular-eslint/eslint-plugin": "17.2.1", @@ -10787,30 +10762,6 @@ "parse5": "^7.0.0" } }, - "node_modules/@types/jsdom/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/@types/jsdom/node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dev": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -11899,6 +11850,12 @@ } } }, + "node_modules/@wessberg/ts-evaluator/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, "node_modules/@wessberg/ts-evaluator/node_modules/saxes": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", @@ -12052,28 +12009,6 @@ "node": ">=14.15.0" } }, - "node_modules/@yarnpkg/parsers/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@yarnpkg/parsers/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/@zkochan/js-yaml": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.6.tgz", @@ -12086,6 +12021,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/@zkochan/js-yaml/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -12392,9 +12333,13 @@ "dev": true }, "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } }, "node_modules/aria-query": { "version": "5.3.0", @@ -12765,12 +12710,14 @@ } }, "node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", + "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", "dev": true, "dependencies": { - "follow-redirects": "^1.14.0" + "follow-redirects": "^1.15.4", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, "node_modules/axobject-query": { @@ -13138,12 +13085,6 @@ "node": ">= 0.8" } }, - "node_modules/basic-auth/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -13421,6 +13362,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/browser-sync-ui/node_modules/connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, "node_modules/browser-sync-ui/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -13430,6 +13380,15 @@ "node": ">=8" } }, + "node_modules/browser-sync-ui/node_modules/immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/browser-sync-ui/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -13491,6 +13450,39 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/browser-sync/node_modules/connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/browser-sync/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/browser-sync/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/browser-sync/node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==", + "dev": true + }, "node_modules/browser-sync/node_modules/fs-extra": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", @@ -13511,6 +13503,36 @@ "node": ">=8" } }, + "node_modules/browser-sync/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/browser-sync/node_modules/immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/browser-sync/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, "node_modules/browser-sync/node_modules/jsonfile": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", @@ -13520,6 +13542,87 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/browser-sync/node_modules/mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true, + "bin": { + "mime": "cli.js" + } + }, + "node_modules/browser-sync/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/browser-sync/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/browser-sync/node_modules/send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/browser-sync/node_modules/serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/browser-sync/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/browser-sync/node_modules/statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/browser-sync/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -14025,21 +14128,71 @@ } }, "node_modules/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", "dev": true, "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/cli-width": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", @@ -14283,12 +14436,6 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/compression/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -14381,9 +14528,9 @@ } }, "node_modules/connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true, "engines": { "node": ">=0.8" @@ -14398,12 +14545,51 @@ "ms": "2.0.0" } }, + "node_modules/connect/node_modules/finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha512-ejnvM9ZXYzp6PUPUyQBMBf0Co5VX2gr5H2VQe2Ui2jWXNlxv+PYZo8wpAymJNJdLsG1R4p+M4aynF8KuoUEwRw==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.3.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/connect/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/connect/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha512-wuTCPGlJONk/a1kqZ4fQM2+908lC7fa7nPYpTC1EhnvqLX/IICbeP1OZGDtA374trpSq68YubKUMo8oRhN46yg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -14421,6 +14607,25 @@ "node": ">= 0.6" } }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/content-type": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", @@ -15645,6 +15850,26 @@ "typescript": ">=4" } }, + "node_modules/cosmiconfig/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "peer": true + }, + "node_modules/cosmiconfig/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/cp-file": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-10.0.0.tgz", @@ -15925,6 +16150,11 @@ "node": ">=8" } }, + "node_modules/critters/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, "node_modules/critters/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -16628,6 +16858,22 @@ "node": ">=8" } }, + "node_modules/cypress/node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cypress/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -16726,6 +16972,120 @@ "node": ">=8.12.0" } }, + "node_modules/cypress/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cypress/node_modules/listr2": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", + "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", + "dev": true, + "dependencies": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.1", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, + "node_modules/cypress/node_modules/log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cypress/node_modules/log-update/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/cypress/node_modules/log-update/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cypress/node_modules/proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", + "dev": true + }, + "node_modules/cypress/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/cypress/node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/cypress/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -19311,6 +19671,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -19477,6 +19843,18 @@ "node": ">=8" } }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -19771,23 +20149,6 @@ "ms": "2.0.0" } }, - "node_modules/express/node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/express/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -19807,47 +20168,24 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/express/node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/express/node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/extend": { "version": "3.0.2", @@ -20093,17 +20431,16 @@ } }, "node_modules/finalhandler": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", - "integrity": "sha512-ejnvM9ZXYzp6PUPUyQBMBf0Co5VX2gr5H2VQe2Ui2jWXNlxv+PYZo8wpAymJNJdLsG1R4p+M4aynF8KuoUEwRw==", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.1", + "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.3.1", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", "unpipe": "~1.0.0" }, "engines": { @@ -20114,7 +20451,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "dependencies": { "ms": "2.0.0" } @@ -20122,29 +20458,7 @@ "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/finalhandler/node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha512-wuTCPGlJONk/a1kqZ4fQM2+908lC7fa7nPYpTC1EhnvqLX/IICbeP1OZGDtA374trpSq68YubKUMo8oRhN46yg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/find-cache-dir": { "version": "3.3.2", @@ -20508,17 +20822,16 @@ } }, "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dependencies": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", + "combined-stream": "^1.0.8", "mime-types": "^2.1.12" }, "engines": { - "node": ">= 0.12" + "node": ">= 6" } }, "node_modules/forwarded": { @@ -20814,12 +21127,6 @@ "util-deprecate": "~1.0.1" } }, - "node_modules/get-pkg-repo/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, "node_modules/get-pkg-repo/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -21309,28 +21616,24 @@ } }, "node_modules/global-dirs": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", - "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==", "dev": true, + "peer": true, "dependencies": { - "ini": "2.0.0" + "ini": "^1.3.4" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, "node_modules/global-dirs/node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true, - "engines": { - "node": ">=10" - } + "peer": true }, "node_modules/global-modules": { "version": "2.0.0", @@ -21712,12 +22015,6 @@ "util-deprecate": "~1.0.1" } }, - "node_modules/hpack.js/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, "node_modules/hpack.js/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -21930,6 +22227,18 @@ } } }, + "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/http-server": { "version": "14.1.1", "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz", @@ -22176,13 +22485,10 @@ } }, "node_modules/immutable": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", - "integrity": "sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", + "dev": true }, "node_modules/import-fresh": { "version": "3.3.0", @@ -22455,11 +22761,12 @@ "dev": true }, "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "dev": true, "engines": { - "node": ">= 0.10" + "node": ">= 10" } }, "node_modules/is-array-buffer": { @@ -22655,11 +22962,15 @@ } }, "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-generator-fn": { @@ -22727,6 +23038,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-installed-globally/node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "dev": true, + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-installed-globally/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", @@ -22820,12 +23155,12 @@ } }, "node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -24111,32 +24446,6 @@ } } }, - "node_modules/jest-environment-jsdom/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/jest-environment-jsdom/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/jest-environment-jsdom/node_modules/jsdom": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", @@ -24182,18 +24491,6 @@ } } }, - "node_modules/jest-environment-jsdom/node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dev": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, "node_modules/jest-environment-node": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", @@ -25338,12 +25635,13 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "dependencies": { - "argparse": "^2.0.1" + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" @@ -25399,41 +25697,6 @@ } } }, - "node_modules/jsdom/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/jsdom/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/jsdom/node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -25865,45 +26128,6 @@ "url": "https://opencollective.com/lint-staged" } }, - "node_modules/lint-staged/node_modules/ansi-escapes": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", - "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", - "dev": true, - "dependencies": { - "type-fest": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/lint-staged/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/lint-staged/node_modules/chalk": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", @@ -25916,37 +26140,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/lint-staged/node_modules/cli-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", - "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", - "dev": true, - "dependencies": { - "restore-cursor": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/node_modules/cli-truncate": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", - "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", - "dev": true, - "dependencies": { - "slice-ansi": "^5.0.0", - "string-width": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/lint-staged/node_modules/commander": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", @@ -25956,18 +26149,6 @@ "node": ">=16" } }, - "node_modules/lint-staged/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", - "dev": true - }, - "node_modules/lint-staged/node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true - }, "node_modules/lint-staged/node_modules/execa": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", @@ -26012,18 +26193,6 @@ "node": ">=16.17.0" } }, - "node_modules/lint-staged/node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/lint-staged/node_modules/is-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", @@ -26045,73 +26214,6 @@ "node": ">=14" } }, - "node_modules/lint-staged/node_modules/listr2": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.0.1.tgz", - "integrity": "sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==", - "dev": true, - "dependencies": { - "cli-truncate": "^4.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^6.0.0", - "rfdc": "^1.3.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/lint-staged/node_modules/log-update": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", - "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", - "dev": true, - "dependencies": { - "ansi-escapes": "^6.2.0", - "cli-cursor": "^4.0.0", - "slice-ansi": "^7.0.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/node_modules/log-update/node_modules/is-fullwidth-code-point": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", - "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", - "dev": true, - "dependencies": { - "get-east-asian-width": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/node_modules/log-update/node_modules/slice-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", - "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, "node_modules/lint-staged/node_modules/mimic-fn": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", @@ -26166,81 +26268,93 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lint-staged/node_modules/restore-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "node_modules/lint-staged/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "engines": { + "node": ">=14" }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/lint-staged/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lint-staged/node_modules/restore-cursor/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "node_modules/lint-staged/node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", "dev": true, "engines": { - "node": ">=6" + "node": ">= 14" } }, - "node_modules/lint-staged/node_modules/restore-cursor/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/listr2": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.0.1.tgz", + "integrity": "sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==", "dev": true, "dependencies": { - "mimic-fn": "^2.1.0" + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.0.0", + "rfdc": "^1.3.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18.0.0" } }, - "node_modules/lint-staged/node_modules/restore-cursor/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/lint-staged/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, "engines": { - "node": ">=14" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/lint-staged/node_modules/slice-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", - "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "dependencies": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" - }, "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/lint-staged/node_modules/string-width": { + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + }, + "node_modules/listr2/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, + "node_modules/listr2/node_modules/string-width": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", @@ -26257,7 +26371,7 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lint-staged/node_modules/strip-ansi": { + "node_modules/listr2/node_modules/strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", @@ -26272,31 +26386,7 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/lint-staged/node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/node_modules/type-fest": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", - "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", - "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/node_modules/wrap-ansi": { + "node_modules/listr2/node_modules/wrap-ansi": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", @@ -26313,51 +26403,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/lint-staged/node_modules/yaml": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", - "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", - "dev": true, - "engines": { - "node": ">= 14" - } - }, - "node_modules/listr2": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", - "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", - "dev": true, - "dependencies": { - "cli-truncate": "^2.1.0", - "colorette": "^2.0.16", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rfdc": "^1.3.0", - "rxjs": "^7.5.1", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "enquirer": ">= 2.3.0 < 3" - }, - "peerDependenciesMeta": { - "enquirer": { - "optional": true - } - } - }, - "node_modules/listr2/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -26440,6 +26485,15 @@ "node": ">=8.3.0" } }, + "node_modules/localtunnel/node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, "node_modules/localtunnel/node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -26707,85 +26761,190 @@ } }, "node_modules/log-update": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", + "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", "dev": true, "dependencies": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" + "ansi-escapes": "^6.2.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^7.0.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", + "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "type-fest": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/log-update/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/log-update/node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "restore-cursor": "^4.0.0" }, "engines": { - "node": ">=7.0.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", "dev": true }, - "node_modules/log-update/node_modules/slice-ansi": { + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/restore-cursor": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" }, "funding": { "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/log-update/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/loose-envify": { @@ -27109,6 +27268,11 @@ "markdown-it": "bin/markdown-it.mjs" } }, + "node_modules/markdown-it/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, "node_modules/markdown-it/node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -28774,16 +28938,11 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/nx/node_modules/axios": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", - "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", - "dev": true, - "dependencies": { - "follow-redirects": "^1.15.4", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } + "node_modules/nx/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/nx/node_modules/brace-expansion": { "version": "1.1.11", @@ -28829,20 +28988,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/nx/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/nx/node_modules/glob": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", @@ -28869,6 +29014,18 @@ "node": ">=8" } }, + "node_modules/nx/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/nx/node_modules/minimatch": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", @@ -28881,12 +29038,6 @@ "node": "*" } }, - "node_modules/nx/node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true - }, "node_modules/nx/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -29538,9 +29689,15 @@ } }, "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } }, "node_modules/parse5-html-rewriting-stream": { "version": "7.0.0", @@ -29568,18 +29725,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/parse5-html-rewriting-stream/node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dev": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, "node_modules/parse5-htmlparser2-tree-adapter": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", @@ -29588,6 +29733,11 @@ "parse5": "^6.0.1" } }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, "node_modules/parse5-sax-parser": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", @@ -29600,11 +29750,10 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parse5-sax-parser/node_modules/entities": { + "node_modules/parse5/node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, "engines": { "node": ">=0.12" }, @@ -29612,18 +29761,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/parse5-sax-parser/node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dev": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -31125,10 +31262,18 @@ "node": ">= 0.10" } }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/proxy-from-env": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", - "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "dev": true }, "node_modules/prr": { @@ -31196,9 +31341,9 @@ } }, "node_modules/qs": { - "version": "6.10.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", - "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", "dev": true, "dependencies": { "side-channel": "^1.0.4" @@ -31817,26 +31962,6 @@ "node": ">=8" } }, - "node_modules/resolve-global/node_modules/global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==", - "dev": true, - "peer": true, - "dependencies": { - "ini": "^1.3.4" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-global/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true, - "peer": true - }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -32335,23 +32460,10 @@ } }, "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "node_modules/safe-regex-test": { "version": "1.0.3", @@ -32430,12 +32542,6 @@ } } }, - "node_modules/sass/node_modules/immutable": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", - "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", - "dev": true - }, "node_modules/sax": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", @@ -32543,24 +32649,23 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/send": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", - "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", - "dev": true, + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dependencies": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.4.1", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.4.0" + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" }, "engines": { "node": ">= 0.8.0" @@ -32570,88 +32675,19 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "dependencies": { "ms": "2.0.0" } }, - "node_modules/send/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/send/node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==", - "dev": true - }, - "node_modules/send/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", - "dev": true, - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/send/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true - }, - "node_modules/send/node_modules/mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", - "dev": true, - "bin": { - "mime": "cli.js" - } - }, - "node_modules/send/node_modules/ms": { + "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/send/node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/send/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/send/node_modules/statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", - "dev": true, - "engines": { - "node": ">= 0.6" - } + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/serialize-javascript": { "version": "6.0.2", @@ -32741,15 +32777,14 @@ } }, "node_modules/serve-static": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", - "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", - "dev": true, + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "parseurl": "~1.3.2", - "send": "0.16.2" + "parseurl": "~1.3.3", + "send": "0.18.0" }, "engines": { "node": ">= 0.8.0" @@ -32970,52 +33005,33 @@ } }, "node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -33229,18 +33245,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/sort-package-json/node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/sort-package-json/node_modules/slash": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", @@ -33613,6 +33617,26 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/string-argv": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", @@ -33669,11 +33693,28 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/string-width/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "node_modules/string-width/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, "node_modules/string.prototype.matchall": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", @@ -34041,6 +34082,12 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, + "node_modules/stylelint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/stylelint/node_modules/balanced-match": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", @@ -34089,6 +34136,18 @@ "node": ">=8.6.0" } }, + "node_modules/stylelint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/stylelint/node_modules/meow": { "version": "13.2.0", "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", @@ -34523,6 +34582,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/table/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/table/node_modules/slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", @@ -36001,37 +36069,6 @@ "node": ">=12.0.0" } }, - "node_modules/wait-on/node_modules/axios": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", - "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", - "dev": true, - "dependencies": { - "follow-redirects": "^1.15.4", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/wait-on/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/wait-on/node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true - }, "node_modules/wait-on/node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -36224,15 +36261,6 @@ "concat-map": "0.0.1" } }, - "node_modules/webpack-dev-server/node_modules/connect-history-api-fallback": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, "node_modules/webpack-dev-server/node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -36253,15 +36281,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/webpack-dev-server/node_modules/ipaddr.js": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", - "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, "node_modules/webpack-dev-server/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -36313,13 +36332,12 @@ } }, "node_modules/webpack-merge": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", - "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", "dev": true, "dependencies": { "clone-deep": "^4.0.1", - "flat": "^5.0.2", "wildcard": "^2.0.0" }, "engines": { @@ -37092,6 +37110,12 @@ "rxjs": ">=6.0.0" } }, + "projects/cdk/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "optional": true + }, "projects/core": { "name": "@taiga-ui/core", "version": "3.59.0", diff --git a/package.json b/package.json index e30d583d30b5..66c6579b2180 100644 --- a/package.json +++ b/package.json @@ -80,9 +80,6 @@ "plugin:@taiga-ui/experience/all", "plugin:@taiga-ui/experience/taiga-naming" ], - "rules": { - "@typescript-eslint/member-ordering": "off" - }, "root": true }, "stylelint": { @@ -119,7 +116,7 @@ "@taiga-ui/browserslist-config": "0.5.0", "@taiga-ui/commitlint-config": "0.5.6", "@taiga-ui/cspell-config": "0.34.0", - "@taiga-ui/eslint-plugin-experience": "0.60.0", + "@taiga-ui/eslint-plugin-experience": "0.62.0", "@taiga-ui/prettier-config": "0.8.4", "@taiga-ui/stylelint-config": "0.18.0", "@taiga-ui/tsconfig": "0.16.0", diff --git a/projects/addon-charts/components/arc-chart/arc-chart.component.ts b/projects/addon-charts/components/arc-chart/arc-chart.component.ts index b9ddd6754f69..8ea17da674fe 100644 --- a/projects/addon-charts/components/arc-chart/arc-chart.component.ts +++ b/projects/addon-charts/components/arc-chart/arc-chart.component.ts @@ -65,11 +65,6 @@ export class TuiArcChartComponent { private readonly sanitizer = inject(DomSanitizer); private readonly arcs$ = new ReplaySubject>>(1); - @ViewChildren('arc') - protected set arcs(arcs: QueryList>) { - this.arcs$.next(arcs); - } - @Input() public value: readonly number[] = []; @@ -115,6 +110,11 @@ export class TuiArcChartComponent { }); } + @ViewChildren('arc') + protected set arcs(arcs: QueryList>) { + this.arcs$.next(arcs); + } + @HostBinding('style.width.rem') @HostBinding('style.height.rem') protected get width(): number { diff --git a/projects/addon-charts/components/axes/axes.component.ts b/projects/addon-charts/components/axes/axes.component.ts index 9327a7563b9d..fd144183635b 100644 --- a/projects/addon-charts/components/axes/axes.component.ts +++ b/projects/addon-charts/components/axes/axes.component.ts @@ -60,11 +60,6 @@ export class TuiAxesComponent { @Input() public verticalLinesHandler: TuiLineHandler = TUI_ALWAYS_DASHED; - @HostBinding('class._centered') - protected get centeredXLabels(): boolean { - return this.axisY === 'none'; - } - protected readonly mode$ = inject(TUI_MODE); public get hasXLabels(): boolean { @@ -85,4 +80,9 @@ export class TuiAxesComponent { public fallback(label: string | null): string { return label || CHAR_NO_BREAK_SPACE; } + + @HostBinding('class._centered') + protected get centeredXLabels(): boolean { + return this.axisY === 'none'; + } } diff --git a/projects/addon-charts/components/bar-chart/bar-chart.component.ts b/projects/addon-charts/components/bar-chart/bar-chart.component.ts index c55e2926beb7..c5077464d235 100644 --- a/projects/addon-charts/components/bar-chart/bar-chart.component.ts +++ b/projects/addon-charts/components/bar-chart/bar-chart.component.ts @@ -35,9 +35,6 @@ export class TuiBarChartComponent { private readonly hintOptions = inject(TuiHintOptionsDirective, {optional: true}); private readonly autoIdString = inject(TuiIdService).generate(); - @ViewChildren(TuiHintHoverDirective) - protected readonly drivers: QueryList> = EMPTY_QUERY; - @Input() public value: ReadonlyArray = []; @@ -50,9 +47,8 @@ export class TuiBarChartComponent { @Input() public collapsed = false; - protected get hintContent(): PolymorpheusContent> { - return this.hintOptions?.content || ''; - } + @ViewChildren(TuiHintHoverDirective) + protected readonly drivers: QueryList> = EMPTY_QUERY; public get transposed(): ReadonlyArray { return this.transpose(this.value); @@ -68,6 +64,10 @@ export class TuiBarChartComponent { > = (set, collapsed, max) => (100 * (collapsed ? tuiSum(...set) : Math.max(...set))) / max; + protected get hintContent(): PolymorpheusContent> { + return this.hintOptions?.content || ''; + } + protected getHintId(index: number): string { return `${this.autoIdString}_${index}`; } diff --git a/projects/addon-charts/components/line-chart/line-chart.component.ts b/projects/addon-charts/components/line-chart/line-chart.component.ts index 55e3ec29534f..58799b43ce36 100644 --- a/projects/addon-charts/components/line-chart/line-chart.component.ts +++ b/projects/addon-charts/components/line-chart/line-chart.component.ts @@ -46,11 +46,6 @@ export class TuiLineChartComponent { @ViewChildren(TuiHintHoverDirective) public readonly drivers: QueryList> = EMPTY_QUERY; - @Input('value') - public set valueSetter(value: readonly TuiPoint[]) { - this.value = value.filter(item => !item.some(Number.isNaN)); - } - @Input() public x = 0; @@ -86,6 +81,15 @@ export class TuiLineChartComponent { protected readonly hintOptions = inject(TuiHintOptionsDirective, {optional: true}); + @Input('value') + public set valueSetter(value: readonly TuiPoint[]) { + this.value = value.filter(item => !item.some(Number.isNaN)); + } + + public onHovered(index: number): void { + this.hover$.next(index); + } + @tuiPure protected get hovered$(): Observable { return this.hover$.pipe(distinctUntilChanged(), tuiZoneOptimized(this.zone)); @@ -189,10 +193,6 @@ export class TuiLineChartComponent { } } - public onHovered(index: number): void { - this.hover$.next(index); - } - private get isSinglePoint(): boolean { return this.value.length === 1; } diff --git a/projects/addon-charts/components/line-days-chart/line-days-chart.component.ts b/projects/addon-charts/components/line-days-chart/line-days-chart.component.ts index d356df404ea1..107714fe03fa 100644 --- a/projects/addon-charts/components/line-days-chart/line-days-chart.component.ts +++ b/projects/addon-charts/components/line-days-chart/line-days-chart.component.ts @@ -63,27 +63,6 @@ export class TuiLineDaysChartComponent implements AfterViewInit { @ViewChildren(TuiLineChartComponent) public readonly charts: QueryList = EMPTY_QUERY; - @Input('value') - public set valueSetter(value: ReadonlyArray<[TuiDay, number]>) { - if (!value.length) { - this.value = []; - - return; - } - - const start = value[0][0]; - const mutable = [...value]; - const length = TuiDay.lengthBetween(start, value[value.length - 1][0]) + 1; - - this.value = Array.from({length}, (_, day) => { - const currentDay = start.append({day}); - const shifted = currentDay.daySame(mutable[0][0]) ? mutable.shift() : null; - const currentValue = shifted ? shifted[1] : NaN; - - return [currentDay, currentValue] as [TuiDay, number]; - }); - } - @Input() public y = 0; @@ -110,26 +89,25 @@ export class TuiLineDaysChartComponent implements AfterViewInit { public value: ReadonlyArray<[TuiDay, number]> = []; - protected get months(): ReadonlyArray { - return this.value.length ? this.breakMonths(this.value) : EMPTY_ARRAY; - } + @Input('value') + public set valueSetter(value: ReadonlyArray<[TuiDay, number]>) { + if (!value.length) { + this.value = []; - protected get firstWidth(): number { - return this.months.length * this.value[0][0].daysCount; - } + return; + } - protected get hint(): - | PolymorpheusContent> - | PolymorpheusContent> { - return this.hintDirective?.hint ?? this.hintContent; - } + const start = value[0][0]; + const mutable = [...value]; + const length = TuiDay.lengthBetween(start, value[value.length - 1][0]) + 1; - @tuiPure - protected getHintContext( - x: number, - value: ReadonlyArray<[TuiDay, number]>, - ): [TuiDay, number] { - return value[x - value[0][0].day + 1]; + this.value = Array.from({length}, (_, day) => { + const currentDay = start.append({day}); + const shifted = currentDay.daySame(mutable[0][0]) ? mutable.shift() : null; + const currentValue = shifted ? shifted[1] : NaN; + + return [currentDay, currentValue] as [TuiDay, number]; + }); } public ngAfterViewInit(): void { @@ -144,17 +122,6 @@ export class TuiLineDaysChartComponent implements AfterViewInit { }); } - protected readonly daysStringify: TuiStringHandler = index => - this.xStringify ? this.xStringify(this.getDay(index)) : ''; - - protected getX(index: number): number { - const current = this.getDay(index); - const months = TuiMonth.lengthBetween(this.value[0][0], current); - const offset = months * current.daysCount; - - return index - offset; - } - public onHovered(day: TuiDay | number): void { if (tuiIsNumber(day)) { this.charts.forEach(chart => chart.onHovered(NaN)); @@ -175,6 +142,39 @@ export class TuiLineDaysChartComponent implements AfterViewInit { }); } + protected get months(): ReadonlyArray { + return this.value.length ? this.breakMonths(this.value) : EMPTY_ARRAY; + } + + protected get firstWidth(): number { + return this.months.length * this.value[0][0].daysCount; + } + + protected get hint(): + | PolymorpheusContent> + | PolymorpheusContent> { + return this.hintDirective?.hint ?? this.hintContent; + } + + @tuiPure + protected getHintContext( + x: number, + value: ReadonlyArray<[TuiDay, number]>, + ): [TuiDay, number] { + return value[x - value[0][0].day + 1]; + } + + protected readonly daysStringify: TuiStringHandler = index => + this.xStringify ? this.xStringify(this.getDay(index)) : ''; + + protected getX(index: number): number { + const current = this.getDay(index); + const months = TuiMonth.lengthBetween(this.value[0][0], current); + const offset = months * current.daysCount; + + return index - offset; + } + protected raise(index: number, {value}: TuiLineChartComponent): void { const x = value[index][0]; const month = this.getDay(x); diff --git a/projects/addon-charts/components/pie-chart/pie-chart.directive.ts b/projects/addon-charts/components/pie-chart/pie-chart.directive.ts index fe110c32b1f7..0e3f8c287fc4 100644 --- a/projects/addon-charts/components/pie-chart/pie-chart.directive.ts +++ b/projects/addon-charts/components/pie-chart/pie-chart.directive.ts @@ -12,11 +12,6 @@ import {BehaviorSubject, map, pairwise, switchMap, takeUntil, takeWhile} from 'r export class TuiPieChartDirective { private readonly sector$ = new BehaviorSubject([0, 0]); - @Input() - public set tuiPieChart(sector: readonly [number, number]) { - this.sector$.next(sector); - } - constructor() { const el: SVGPathElement = inject(ElementRef).nativeElement; const performance = inject(PERFORMANCE); @@ -51,4 +46,9 @@ export class TuiPieChartDirective { el.setAttribute('d', tuiDescribeSector(start, end)), ); } + + @Input() + public set tuiPieChart(sector: readonly [number, number]) { + this.sector$.next(sector); + } } diff --git a/projects/addon-commerce/components/input-card-grouped/input-card-grouped.component.ts b/projects/addon-commerce/components/input-card-grouped/input-card-grouped.component.ts index b3b6dde20eca..e0e9034f4dcf 100644 --- a/projects/addon-commerce/components/input-card-grouped/input-card-grouped.component.ts +++ b/projects/addon-commerce/components/input-card-grouped/input-card-grouped.component.ts @@ -101,17 +101,11 @@ export class TuiInputCardGroupedComponent @Input() public cardValidator = this.options.cardValidator; - @Input() - public set codeLength(length: TuiCodeCVCLength) { - this.exampleTextCVC = '0'.repeat(length); - this.maskCVC = { - mask: new Array(length).fill(TUI_DIGIT_REGEXP), - }; - } - @Output() public readonly autofilledChange = new EventEmitter(); + public open = false; + @ContentChild(TuiDataListDirective, {read: TemplateRef}) protected readonly dropdown: PolymorpheusContent; @@ -133,8 +127,6 @@ export class TuiInputCardGroupedComponent separator: '/', }); - public open = false; - protected readonly mode$ = inject(TUI_MODE); protected readonly cardGroupedTexts$ = inject(TUI_INPUT_CARD_GROUPED_TEXTS); protected readonly controller = inject(TUI_TEXTFIELD_WATCHED_CONTROLLER); @@ -145,6 +137,14 @@ export class TuiInputCardGroupedComponent super(inject(TUI_INPUT_CARD_GROUPED_OPTIONS)); } + @Input() + public set codeLength(length: TuiCodeCVCLength) { + this.exampleTextCVC = '0'.repeat(length); + this.maskCVC = { + mask: new Array(length).fill(TUI_DIGIT_REGEXP), + }; + } + public get nativeFocusableElement(): HTMLInputElement | null { return this.inputCard?.nativeElement ?? null; } @@ -153,14 +153,55 @@ export class TuiInputCardGroupedComponent return this.open || tuiIsNativeFocusedIn(this.el); } - protected get appearance(): string { - return this.controller.appearance; - } - public get card(): string { return this.value?.card || ''; } + public override writeValue(value: TuiCard | null): void { + const {bin} = this; + + super.writeValue(value); + this.updateBin(bin); + this.expireInert = !!this.expire && this.cardPrefilled; + } + + /** Public API for manual focus management */ + public focusCard(): void { + this.cardNumberAutofocusRef?.focus(); + } + + public focusExpire(): void { + this.expireCardAutofocusRef?.focus(); + } + + public focusCVC(): void { + this.cvcCardAutofocusRef?.focus(); + } + + public handleOption(option: Partial): void { + const {card = '', expire = '', cvc = ''} = option; + const {bin} = this; + const element = + (!expire && this.inputExpire?.nativeElement) || this.inputCVC?.nativeElement; + + this.value = {card, expire, cvc}; + this.updateBin(bin); + this.open = false; + this.expireInert = !!expire; + + element?.focus(); + } + + public clear(): void { + this.expireInert = false; + this.value = null; + this.focusCard(); + } + + protected get appearance(): string { + return this.controller.appearance; + } + protected get expire(): string { return this.value?.expire || ''; } @@ -242,10 +283,6 @@ export class TuiInputCardGroupedComponent return this.cardPrefilled ? `*${this.card.slice(-4)}` : '*'; } - private get expireSelectionStart(): number { - return this.inputExpire?.nativeElement.selectionStart || 0; - } - @HostListener('keydown.esc') protected onEsc(): void { this.open = false; @@ -259,20 +296,6 @@ export class TuiInputCardGroupedComponent this.datalist?.onKeyDownArrow(element, step); } - public handleOption(option: Partial): void { - const {card = '', expire = '', cvc = ''} = option; - const {bin} = this; - const element = - (!expire && this.inputExpire?.nativeElement) || this.inputCVC?.nativeElement; - - this.value = {card, expire, cvc}; - this.updateBin(bin); - this.open = false; - this.expireInert = !!expire; - - element?.focus(); - } - protected onCardChange(card: string): void { const {value, bin} = this; const parsed = card.split(' ').join(''); @@ -328,35 +351,12 @@ export class TuiInputCardGroupedComponent } } - public clear(): void { - this.expireInert = false; - this.value = null; - this.focusCard(); - } - protected toggle(): void { this.open = !this.open; } - public override writeValue(value: TuiCard | null): void { - const {bin} = this; - - super.writeValue(value); - this.updateBin(bin); - this.expireInert = !!this.expire && this.cardPrefilled; - } - - /** Public API for manual focus management */ - public focusCard(): void { - this.cardNumberAutofocusRef?.focus(); - } - - public focusExpire(): void { - this.expireCardAutofocusRef?.focus(); - } - - public focusCVC(): void { - this.cvcCardAutofocusRef?.focus(); + private get expireSelectionStart(): number { + return this.inputExpire?.nativeElement.selectionStart || 0; } private get cardFocused(): boolean { diff --git a/projects/addon-commerce/components/input-card/abstract-input-card.ts b/projects/addon-commerce/components/input-card/abstract-input-card.ts index 52687b723fb1..854c7ad7a143 100644 --- a/projects/addon-commerce/components/input-card/abstract-input-card.ts +++ b/projects/addon-commerce/components/input-card/abstract-input-card.ts @@ -36,6 +36,18 @@ export abstract class AbstractTuiInputCard< public abstract get nativeFocusableElement(): TuiNativeFocusableElement | null; + /** + * @deprecated: drop in v4.0 + * use {@link autocomplete} + */ + public get autocompleteCard(): TuiAutofillFieldName { + return this.autocomplete; + } + + public get bin(): string | null { + return this.card.length < 6 ? null : this.card.slice(0, 6); + } + public get defaultIcon(): string | null { const paymentSystem = this.getPaymentSystem(this.card); @@ -55,18 +67,6 @@ export abstract class AbstractTuiInputCard< return this.autocompleteEnabled ? 'cc-number' : 'off'; } - /** - * @deprecated: drop in v4.0 - * use {@link autocomplete} - */ - public get autocompleteCard(): TuiAutofillFieldName { - return this.autocomplete; - } - - public get bin(): string | null { - return this.card.length < 6 ? null : this.card.slice(0, 6); - } - @tuiPure protected getPaymentSystem(cardNumber?: string | null): TuiPaymentSystem | null { return this.options.paymentSystemHandler(cardNumber); diff --git a/projects/addon-commerce/components/input-card/input-card.component.ts b/projects/addon-commerce/components/input-card/input-card.component.ts index dbc79674c03e..fd0d2f662cd0 100644 --- a/projects/addon-commerce/components/input-card/input-card.component.ts +++ b/projects/addon-commerce/components/input-card/input-card.component.ts @@ -42,11 +42,6 @@ export class TuiInputCardComponent extends AbstractTuiInputCard { super(inject(TUI_INPUT_CARD_OPTIONS)); } - @HostBinding('attr.data-size') - protected get size(): TuiSizeL | TuiSizeS { - return this.textfieldSize.size; - } - public get card(): string { return this.value ?? ''; } @@ -88,6 +83,11 @@ export class TuiInputCardComponent extends AbstractTuiInputCard { } } + @HostBinding('attr.data-size') + protected get size(): TuiSizeL | TuiSizeS { + return this.textfieldSize.size; + } + protected override getFallbackValue(): string { return ''; } diff --git a/projects/addon-commerce/components/input-cvc/input-cvc.component.ts b/projects/addon-commerce/components/input-cvc/input-cvc.component.ts index f8c4abd87ebc..c0b2a2724ffa 100644 --- a/projects/addon-commerce/components/input-cvc/input-cvc.component.ts +++ b/projects/addon-commerce/components/input-cvc/input-cvc.component.ts @@ -48,23 +48,18 @@ export class TuiInputCVCComponent @Input() public autocompleteEnabled = false; - @Input() - public set length(length: TuiCodeCVCLength) { - this.exampleText = '0'.repeat(length); - this.maskOptions = { - mask: new Array(length).fill(TUI_DIGIT_REGEXP), - }; - } - public exampleText = '000'; public maskOptions: MaskitoOptions = { mask: new Array(3).fill(TUI_DIGIT_REGEXP), }; - @HostBinding('attr.data-size') - protected get size(): TuiSizeL | TuiSizeS { - return this.textfieldSize.size; + @Input() + public set length(length: TuiCodeCVCLength) { + this.exampleText = '0'.repeat(length); + this.maskOptions = { + mask: new Array(length).fill(TUI_DIGIT_REGEXP), + }; } public get nativeFocusableElement(): TuiNativeFocusableElement | null { @@ -75,6 +70,11 @@ export class TuiInputCVCComponent return !!this.input && this.input.focused; } + @HostBinding('attr.data-size') + protected get size(): TuiSizeL | TuiSizeS { + return this.textfieldSize.size; + } + protected get autocomplete(): TuiAutofillFieldName { return this.autocompleteEnabled ? 'cc-csc' : 'off'; } diff --git a/projects/addon-commerce/components/input-expire/input-expire.component.ts b/projects/addon-commerce/components/input-expire/input-expire.component.ts index 3e32271494b5..91601390d043 100644 --- a/projects/addon-commerce/components/input-expire/input-expire.component.ts +++ b/projects/addon-commerce/components/input-expire/input-expire.component.ts @@ -48,11 +48,6 @@ export class TuiInputExpireComponent separator: '/', }); - @HostBinding('attr.data-size') - protected get size(): TuiSizeL | TuiSizeS { - return this.textfieldSize.size; - } - public get nativeFocusableElement(): HTMLInputElement | null { return this.input?.nativeFocusableElement ?? null; } @@ -61,6 +56,11 @@ export class TuiInputExpireComponent return !!this.input && this.input.focused; } + @HostBinding('attr.data-size') + protected get size(): TuiSizeL | TuiSizeS { + return this.textfieldSize.size; + } + protected get autocomplete(): TuiAutofillFieldName { return this.autocompleteEnabled ? 'cc-exp' : 'off'; } diff --git a/projects/addon-doc/components/demo/demo.component.ts b/projects/addon-doc/components/demo/demo.component.ts index 642a0c430248..3b4bd167ba1f 100644 --- a/projects/addon-doc/components/demo/demo.component.ts +++ b/projects/addon-doc/components/demo/demo.component.ts @@ -69,6 +69,9 @@ export class TuiDocDemoComponent implements OnInit { @HostBinding('class._sticky') public sticky = true; + public mode: TuiBrightness | null = this.params.tuiMode || null; + public readonly change$ = new Subject(); + @ContentChild(TemplateRef) protected readonly template: TemplateRef> | null = null; @@ -81,15 +84,17 @@ export class TuiDocDemoComponent implements OnInit { protected opaque = tuiCoerceValueIsTrue(this.params.sandboxOpaque ?? true); protected expanded = tuiCoerceValueIsTrue(this.params.sandboxExpanded ?? false); - public mode: TuiBrightness | null = this.params.tuiMode || null; protected sandboxWidth = tuiToInteger(this.params.sandboxWidth); - - public readonly change$ = new Subject(); protected readonly items: readonly TuiBrightness[] = ['onLight', 'onDark']; protected readonly options = inject(TUI_ARROW_OPTIONS); protected readonly isMobile = inject(TUI_IS_MOBILE); protected readonly texts = inject(TUI_DOC_DEMO_TEXTS); + public ngOnInit(): void { + this.createForm(); + this.updateWidth(this.sandboxWidth + this.delta); + } + @HostListener('window:resize') protected onResize(): void { this.updateWidth(); @@ -101,11 +106,6 @@ export class TuiDocDemoComponent implements OnInit { this.updateUrl({sandboxWidth: this.sandboxWidth}); } - public ngOnInit(): void { - this.createForm(); - this.updateWidth(this.sandboxWidth + this.delta); - } - protected onModeChange(mode: TuiBrightness | null): void { this.mode = mode; this.updateUrl({sandboxWidth: this.sandboxWidth}); @@ -150,6 +150,10 @@ export class TuiDocDemoComponent implements OnInit { : 0; } + private get params(): Params | TuiDemoParams { + return this.getUrlTree().queryParams; + } + @tuiPure private updateUrl(params: TuiDemoParams): void { const tree = this.getUrlTree(); @@ -177,8 +181,4 @@ export class TuiDocDemoComponent implements OnInit { private getUrlTree(): UrlTree { return this.urlSerializer.parse(this.locationRef.path()); } - - private get params(): Params | TuiDemoParams { - return this.getUrlTree().queryParams; - } } diff --git a/projects/addon-doc/components/documentation/documentation-property-connector.directive.ts b/projects/addon-doc/components/documentation/documentation-property-connector.directive.ts index 04947801bd13..be3c4a51ea2b 100644 --- a/projects/addon-doc/components/documentation/documentation-property-connector.directive.ts +++ b/projects/addon-doc/components/documentation/documentation-property-connector.directive.ts @@ -61,10 +61,6 @@ export class TuiDocDocumentationPropertyConnectorDirective public readonly template = inject(TemplateRef); - public ngOnInit(): void { - this.parseParams(this.activatedRoute.snapshot.queryParams); - } - public get attrName(): string { switch (this.documentationPropertyMode) { case 'input': @@ -78,12 +74,16 @@ export class TuiDocDocumentationPropertyConnectorDirective } } + public get shouldShowValues(): boolean { + return this.documentationPropertyMode !== 'output'; + } + public get hasItems(): boolean { return !!this.documentationPropertyValues; } - public get shouldShowValues(): boolean { - return this.documentationPropertyMode !== 'output'; + public ngOnInit(): void { + this.parseParams(this.activatedRoute.snapshot.queryParams); } public ngOnChanges(): void { diff --git a/projects/addon-doc/components/documentation/documentation.component.ts b/projects/addon-doc/components/documentation/documentation.component.ts index b5e58f52a6e5..3363dd98d337 100644 --- a/projects/addon-doc/components/documentation/documentation.component.ts +++ b/projects/addon-doc/components/documentation/documentation.component.ts @@ -46,8 +46,6 @@ export class TuiDocDocumentationComponent implements AfterContentInit { private readonly destroy$ = inject(TuiDestroyService, {self: true}); private readonly getColor = inject(TuiGetColorPipe); private readonly getOpacity = inject(TuiGetOpacityPipe); - protected readonly texts = inject(TUI_DOC_DOCUMENTATION_TEXTS); - protected readonly excludedProperties = inject(TUI_DOC_EXCLUDED_PROPERTIES); @Input() public heading = ''; @@ -63,6 +61,8 @@ export class TuiDocDocumentationComponent implements AfterContentInit { TuiDocDocumentationPropertyConnectorDirective > = EMPTY_QUERY; + protected readonly texts = inject(TUI_DOC_DOCUMENTATION_TEXTS); + protected readonly excludedProperties = inject(TUI_DOC_EXCLUDED_PROPERTIES); protected activeItemIndex = 0; public ngAfterContentInit(): void { diff --git a/projects/addon-doc/components/example/example.component.ts b/projects/addon-doc/components/example/example.component.ts index 88acbbdf2a77..3600a357e30c 100644 --- a/projects/addon-doc/components/example/example.component.ts +++ b/projects/addon-doc/components/example/example.component.ts @@ -36,7 +36,6 @@ export class TuiDocExampleComponent { private readonly copyTexts$ = inject(TUI_COPY_TEXTS); private readonly processContent = inject(TUI_DOC_EXAMPLE_CONTENT_PROCESSOR); private readonly rawLoader$$ = new BehaviorSubject({}); - protected readonly options = inject(TUI_DOC_EXAMPLE_OPTIONS); @Input() public id: string | null = null; @@ -47,18 +46,14 @@ export class TuiDocExampleComponent { @Input() public description: PolymorpheusContent; - @Input() - public set content(content: TuiDocExample) { - this.rawLoader$$.next(content); - } - @Input() @HostBinding('class._fullsize') - public fullsize = this.options.fullsize; + public fullsize = inject(TUI_DOC_EXAMPLE_OPTIONS).fullsize; @Input() public componentName: string = this.location.pathname.slice(1); + protected readonly options = inject(TUI_DOC_EXAMPLE_OPTIONS); protected readonly texts = inject(TUI_DOC_EXAMPLE_TEXTS); protected readonly codeEditor = inject(TUI_DOC_CODE_EDITOR, {optional: true}); protected readonly isE2E = inject(TUI_IS_E2E); @@ -83,6 +78,11 @@ export class TuiDocExampleComponent { protected readonly loading$ = new Subject(); + @Input() + public set content(content: TuiDocExample) { + this.rawLoader$$.next(content); + } + protected readonly visible = (files: Record): boolean => Boolean(this.codeEditor && this.options.codeEditorVisibilityHandler(files)); diff --git a/projects/addon-doc/components/language-switcher/language-switcher.component.ts b/projects/addon-doc/components/language-switcher/language-switcher.component.ts index 05d219821d4a..8d60a3ca9491 100644 --- a/projects/addon-doc/components/language-switcher/language-switcher.component.ts +++ b/projects/addon-doc/components/language-switcher/language-switcher.component.ts @@ -32,12 +32,6 @@ import {TuiSelectModule} from '@taiga-ui/kit'; export class TuiLanguageSwitcherComponent { private readonly flagPipe = inject(TuiFlagPipe); - protected readonly switcher = inject(TuiLanguageSwitcher); - - protected readonly language = new FormControl( - tuiCapitalizeFirstLetter(this.switcher.language), - ); - public readonly flags = new Map([ ['belarusian', TuiCountryIsoCode.BY], ['chinese', TuiCountryIsoCode.CN], @@ -57,6 +51,12 @@ export class TuiLanguageSwitcherComponent { ['vietnamese', TuiCountryIsoCode.VN], ]); + protected readonly switcher = inject(TuiLanguageSwitcher); + + protected readonly language = new FormControl( + tuiCapitalizeFirstLetter(this.switcher.language), + ); + protected readonly names: TuiLanguageName[] = Array.from(this.flags.keys()); /** diff --git a/projects/addon-doc/components/page/page.component.ts b/projects/addon-doc/components/page/page.component.ts index 3ca3746e4243..1a299896e72e 100644 --- a/projects/addon-doc/components/page/page.component.ts +++ b/projects/addon-doc/components/page/page.component.ts @@ -40,12 +40,12 @@ export class TuiDocPageComponent { EMPTY_QUERY; public activeItemIndex = 0; + public readonly seeAlso = inject(PAGE_SEE_ALSO); protected readonly from = / /g; protected readonly to = '_'; protected readonly defaultTabs = inject(TUI_DOC_DEFAULT_TABS); - public readonly seeAlso = inject(PAGE_SEE_ALSO); public get showSeeAlso(): boolean { return !!this.seeAlso.length && this.activeItemIndex === 0; diff --git a/projects/addon-doc/directives/scroll-into-view/scroll-into-view.directive.ts b/projects/addon-doc/directives/scroll-into-view/scroll-into-view.directive.ts index 7f5bdb95be54..7095a7935e88 100644 --- a/projects/addon-doc/directives/scroll-into-view/scroll-into-view.directive.ts +++ b/projects/addon-doc/directives/scroll-into-view/scroll-into-view.directive.ts @@ -10,11 +10,6 @@ import {debounceTime, filter, ReplaySubject, switchMap, takeUntil} from 'rxjs'; export class TuiScrollIntoViewLinkDirective { private readonly scroll$ = new ReplaySubject(1); - @Input() - public set tuiScrollIntoViewLink(shallWe: boolean) { - this.scroll$.next(shallWe); - } - constructor() { const el: HTMLElement = inject(ElementRef).nativeElement; @@ -28,4 +23,9 @@ export class TuiScrollIntoViewLinkDirective { ) .subscribe(() => el.scrollIntoView()); } + + @Input() + public set tuiScrollIntoViewLink(shallWe: boolean) { + this.scroll$.next(shallWe); + } } diff --git a/projects/addon-doc/services/theme.service.ts b/projects/addon-doc/services/theme.service.ts index fe39923f9c36..bb37b8d7cff5 100644 --- a/projects/addon-doc/services/theme.service.ts +++ b/projects/addon-doc/services/theme.service.ts @@ -21,12 +21,12 @@ export class TuiThemeService extends BehaviorSubject { super(storage.getItem(key) || initialTheme); } + public get isDefaultTheme(): boolean { + return this.value === TUI_THEME_DEFAULT_NAME; + } + public override next(theme: string): void { this.storage.setItem(this.key, theme); super.next(theme); } - - public get isDefaultTheme(): boolean { - return this.value === TUI_THEME_DEFAULT_NAME; - } } diff --git a/projects/addon-mobile/components/mobile-calendar/mobile-calendar.component.ts b/projects/addon-mobile/components/mobile-calendar/mobile-calendar.component.ts index 994902eb6651..fb4a40164f43 100644 --- a/projects/addon-mobile/components/mobile-calendar/mobile-calendar.component.ts +++ b/projects/addon-mobile/components/mobile-calendar/mobile-calendar.component.ts @@ -146,10 +146,6 @@ export class TuiMobileCalendarComponent implements AfterViewInit { }); } - protected get yearWidth(): number { - return this.doc.documentElement.clientWidth / YEARS_IN_ROW; - } - public ngAfterViewInit(): void { this.activeYear = this.initialYear; this.activeMonth = this.initialMonth; @@ -158,6 +154,24 @@ export class TuiMobileCalendarComponent implements AfterViewInit { this.waitScrolledChange(); } + public setYear(year: number): void { + if (this.activeYear === year) { + return; + } + + this.activeMonth += this.getMonthOffset(year); + this.activeYear = year; + this.scrollToActiveYear('smooth'); + + timer(0) + .pipe(tuiZonefree(this.ngZone), takeUntil(this.destroy$)) + .subscribe(() => this.scrollToActiveMonth()); + } + + protected get yearWidth(): number { + return this.doc.documentElement.clientWidth / YEARS_IN_ROW; + } + protected onClose(): void { this.cancel.emit(); } @@ -214,20 +228,6 @@ export class TuiMobileCalendarComponent implements AfterViewInit { this.scrollToActiveYear(); } - public setYear(year: number): void { - if (this.activeYear === year) { - return; - } - - this.activeMonth += this.getMonthOffset(year); - this.activeYear = year; - this.scrollToActiveYear('smooth'); - - timer(0) - .pipe(tuiZonefree(this.ngZone), takeUntil(this.destroy$)) - .subscribe(() => this.scrollToActiveMonth()); - } - protected readonly disabledItemHandlerMapper: TuiTypedMapper< [TuiBooleanHandler, TuiDay, TuiDay], TuiBooleanHandler @@ -236,14 +236,6 @@ export class TuiMobileCalendarComponent implements AfterViewInit { (max !== null && item.dayAfter(max)) || disabledItemHandler(item); - private isMultiValue(day: any): day is readonly TuiDay[] | undefined { - return !(day instanceof TuiDay) && !(day instanceof TuiDayRange) && this.multi; - } - - private isSingleValue(day: any): day is TuiDay { - return day instanceof TuiDay || (day instanceof TuiDayRange && !day.isSingleDay); - } - private get initialYear(): number { if (!this.value) { return this.today.year; @@ -283,6 +275,14 @@ export class TuiMobileCalendarComponent implements AfterViewInit { ); } + private isMultiValue(day: any): day is readonly TuiDay[] | undefined { + return !(day instanceof TuiDay) && !(day instanceof TuiDayRange) && this.multi; + } + + private isSingleValue(day: any): day is TuiDay { + return day instanceof TuiDay || (day instanceof TuiDayRange && !day.isSingleDay); + } + private getYearsViewportSize(): number { return this.yearsScrollRef?.getViewportSize() || 0; } diff --git a/projects/addon-mobile/components/pull-to-refresh/loader-android/loader-android.component.ts b/projects/addon-mobile/components/pull-to-refresh/loader-android/loader-android.component.ts index 235024930217..f9dc2a980c75 100644 --- a/projects/addon-mobile/components/pull-to-refresh/loader-android/loader-android.component.ts +++ b/projects/addon-mobile/components/pull-to-refresh/loader-android/loader-android.component.ts @@ -23,24 +23,11 @@ export class TuiMobileLoaderAndroidComponent { private readonly context = inject>(POLYMORPHEUS_CONTEXT); private readonly threshold = inject(TUI_PULL_TO_REFRESH_THRESHOLD); - protected get transform(): string { - const rotateX = Math.min( - ROTATE_X_DEFAULT + this.percent * ROTATE_X_MULTIPLIER, - ROTATE_X_MAX, - ); - - return `rotate(${rotateX} 0 0)`; - } - @HostBinding('class._visible') protected get percent(): number { return (this.context.$implicit * 100) / this.threshold; } - protected get opacity(): number { - return this.context.$implicit / (this.threshold * 1.5); - } - @HostBinding('class._dropped') protected get dropped(): boolean { return ( @@ -53,6 +40,19 @@ export class TuiMobileLoaderAndroidComponent { protected get hostTransform(): string { return `translateY(${Math.min(this.context.$implicit, this.threshold * 1.5)}px)`; } + + protected get opacity(): number { + return this.context.$implicit / (this.threshold * 1.5); + } + + protected get transform(): string { + const rotateX = Math.min( + ROTATE_X_DEFAULT + this.percent * ROTATE_X_MULTIPLIER, + ROTATE_X_MAX, + ); + + return `rotate(${rotateX} 0 0)`; + } } export const TUI_ANDROID_LOADER = new PolymorpheusComponent( diff --git a/projects/addon-mobile/components/pull-to-refresh/pull-to-refresh.component.ts b/projects/addon-mobile/components/pull-to-refresh/pull-to-refresh.component.ts index fa6b3b04da9d..68478572c5f6 100644 --- a/projects/addon-mobile/components/pull-to-refresh/pull-to-refresh.component.ts +++ b/projects/addon-mobile/components/pull-to-refresh/pull-to-refresh.component.ts @@ -35,7 +35,6 @@ import {MICRO_OFFSET, TuiPullToRefreshService} from './pull-to-refresh.service'; export class TuiPullToRefreshComponent { private readonly isIOS = inject(TUI_IS_IOS); private readonly threshold = inject(TUI_PULL_TO_REFRESH_THRESHOLD); - protected readonly pulling$ = inject(TuiPullToRefreshService); @Input() public styleHandler: TuiHandler | null> = this.isIOS @@ -43,10 +42,12 @@ export class TuiPullToRefreshComponent { : () => null; @Output() - public readonly pulled: Observable = this.pulling$.pipe( + public readonly pulled: Observable = inject(TuiPullToRefreshService).pipe( filter(distance => distance === this.threshold), ); + protected readonly pulling$ = inject(TuiPullToRefreshService); + protected readonly component = inject>>( TUI_PULL_TO_REFRESH_COMPONENT, ); diff --git a/projects/addon-mobile/components/sheet-dialog/sheet-dialog.component.ts b/projects/addon-mobile/components/sheet-dialog/sheet-dialog.component.ts index add7307afa13..b4f00385b08e 100644 --- a/projects/addon-mobile/components/sheet-dialog/sheet-dialog.component.ts +++ b/projects/addon-mobile/components/sheet-dialog/sheet-dialog.component.ts @@ -68,6 +68,12 @@ export class TuiSheetDialogComponent implements AfterViewInit { protected readonly context = inject, any>>(POLYMORPHEUS_CONTEXT); + public ngAfterViewInit(): void { + this.el.scrollTop = [...this.getStops(this.stopsRefs), this.sheetTop][ + this.context.initial + ]; + } + @HostBinding('style.top.px') protected get offset(): number { return this.context.offset; @@ -107,12 +113,6 @@ export class TuiSheetDialogComponent implements AfterViewInit { this.context.$implicit.complete(); } - public ngAfterViewInit(): void { - this.el.scrollTop = [...this.getStops(this.stopsRefs), this.sheetTop][ - this.context.initial - ]; - } - private get sheetTop(): number { return this.sheet?.nativeElement.offsetTop ?? Infinity; } diff --git a/projects/addon-mobile/components/sheet/components/sheet/sheet.component.ts b/projects/addon-mobile/components/sheet/components/sheet/sheet.component.ts index 301cb1493b2e..d7dd63545384 100644 --- a/projects/addon-mobile/components/sheet/components/sheet/sheet.component.ts +++ b/projects/addon-mobile/components/sheet/components/sheet/sheet.component.ts @@ -70,6 +70,14 @@ export class TuiSheetComponent implements TuiSheetRequiredProps, AfterView map(y => Math.floor(y) > this.contentTop), ); + @tuiPure + public get context(): TuiSheet { + return { + ...this.item, + scroll$: this.scroll$.pipe(tuiZonefull(this.zone)), + }; + } + public get stops(): readonly number[] { return this.getStops(this.stopsRefs); } @@ -82,12 +90,10 @@ export class TuiSheetComponent implements TuiSheetRequiredProps, AfterView return this.contentTop - this.sheetTop; } - @tuiPure - public get context(): TuiSheet { - return { - ...this.item, - scroll$: this.scroll$.pipe(tuiZonefull(this.zone)), - }; + public ngAfterViewInit(): void { + this.el.scrollTop = [...this.stops, this.sheetTop, this.contentTop][ + this.item.initial + ]; } @HostListener(TUI_SHEET_ID, ['$event.detail']) @@ -95,12 +101,6 @@ export class TuiSheetComponent implements TuiSheetRequiredProps, AfterView this.id = id; } - public ngAfterViewInit(): void { - this.el.scrollTop = [...this.stops, this.sheetTop, this.contentTop][ - this.item.initial - ]; - } - protected scrollTo(top: number = this.sheetTop): void { if (this.isIos) { const offset = top - this.el.scrollTop - 16; diff --git a/projects/addon-mobile/components/sheet/sheet.directive.ts b/projects/addon-mobile/components/sheet/sheet.directive.ts index 4f2fd9ce9a04..58cf4ebf8c8b 100644 --- a/projects/addon-mobile/components/sheet/sheet.directive.ts +++ b/projects/addon-mobile/components/sheet/sheet.directive.ts @@ -21,11 +21,6 @@ export class TuiSheetDirective extends PolymorpheusTemplate> { @Input('tuiSheetOptions') public options: Partial = {}; - @Input() - public set tuiSheet(open: boolean) { - this.open$.next(open); - } - @Output() public readonly tuiSheetChange = this.open$.pipe( tuiIfMap(() => @@ -33,4 +28,9 @@ export class TuiSheetDirective extends PolymorpheusTemplate> { ), share(), ); + + @Input() + public set tuiSheet(open: boolean) { + this.open$.next(open); + } } diff --git a/projects/addon-mobile/directives/ripple/ripple.directive.ts b/projects/addon-mobile/directives/ripple/ripple.directive.ts index b0ed87396ad0..ed4fcae0448a 100644 --- a/projects/addon-mobile/directives/ripple/ripple.directive.ts +++ b/projects/addon-mobile/directives/ripple/ripple.directive.ts @@ -28,11 +28,12 @@ export class TuiRippleDirective { private readonly destroy$ = inject(TuiDestroyService, {self: true}); private readonly start$ = inject(TUI_RIPPLE_START); private readonly end$ = inject(TUI_RIPPLE_END); - protected readonly nothing = tuiWithStyles(TuiRippleStylesComponent); @Input() public tuiRipple?: string | ''; + protected readonly nothing = tuiWithStyles(TuiRippleStylesComponent); + constructor() { const touchEnd$ = tuiTypedFromEvent(this.el, 'touchend'); const touchMove$ = tuiTypedFromEvent(this.el, 'touchmove'); diff --git a/projects/addon-mobile/directives/sidebar/sidebar.component.ts b/projects/addon-mobile/directives/sidebar/sidebar.component.ts index 920a64acb1bf..2e92b3371b53 100644 --- a/projects/addon-mobile/directives/sidebar/sidebar.component.ts +++ b/projects/addon-mobile/directives/sidebar/sidebar.component.ts @@ -29,6 +29,10 @@ export class TuiSidebarComponent implements DoCheck { private readonly left = {...this.options, value: 'left'}; private readonly right = {...this.options, value: 'right'}; + public ngDoCheck(): void { + this.directive.check(); + } + @HostBinding('@tuiSlideIn') protected get animation(): AnimationOptions { return this.direction === 'left' ? this.left : this.right; @@ -50,8 +54,4 @@ export class TuiSidebarComponent implements DoCheck { protected get autoWidth(): boolean { return this.directive.autoWidth; } - - public ngDoCheck(): void { - this.directive.check(); - } } diff --git a/projects/addon-mobile/directives/sidebar/sidebar.directive.ts b/projects/addon-mobile/directives/sidebar/sidebar.directive.ts index 6bfd3273d6fe..7dab11334df4 100644 --- a/projects/addon-mobile/directives/sidebar/sidebar.directive.ts +++ b/projects/addon-mobile/directives/sidebar/sidebar.directive.ts @@ -35,6 +35,8 @@ export class TuiSidebarDirective> @Input('tuiSidebarAutoWidth') public autoWidth = false; + public readonly content = inject(TemplateRef); + @Input() public set tuiSidebar(open: boolean) { if (open) { @@ -44,8 +46,6 @@ export class TuiSidebarDirective> } } - public readonly content = inject(TemplateRef); - public ngOnDestroy(): void { this.hide(); } diff --git a/projects/addon-preview/components/preview/pagination/preview-pagination.component.ts b/projects/addon-preview/components/preview/pagination/preview-pagination.component.ts index 07fd560ebf32..45e68a381631 100644 --- a/projects/addon-preview/components/preview/pagination/preview-pagination.component.ts +++ b/projects/addon-preview/components/preview/pagination/preview-pagination.component.ts @@ -30,6 +30,12 @@ export class TuiPreviewPaginationComponent { protected readonly icons = inject(TUI_PREVIEW_ICONS); protected readonly texts$ = inject(TUI_PAGINATION_TEXTS); + @HostListener('document:keydown.arrowRight.prevent', ['1']) + @HostListener('document:keydown.arrowLeft.prevent', ['-1']) + public onArrowClick(step: number): void { + this.updateIndex(tuiClamp(this.index + step, 0, this.length - 1)); + } + protected get leftButtonDisabled(): boolean { return this.index === 0; } @@ -38,12 +44,6 @@ export class TuiPreviewPaginationComponent { return this.index === this.length - 1; } - @HostListener('document:keydown.arrowRight.prevent', ['1']) - @HostListener('document:keydown.arrowLeft.prevent', ['-1']) - public onArrowClick(step: number): void { - this.updateIndex(tuiClamp(this.index + step, 0, this.length - 1)); - } - private updateIndex(index: number): void { if (this.index === index) { return; diff --git a/projects/addon-table/components/reorder/reorder.component.ts b/projects/addon-table/components/reorder/reorder.component.ts index af1e8b9f66a8..8e08d6144fa2 100644 --- a/projects/addon-table/components/reorder/reorder.component.ts +++ b/projects/addon-table/components/reorder/reorder.component.ts @@ -20,16 +20,6 @@ import {TUI_REORDER_OPTIONS} from './reorder.options'; export class TuiReorderComponent { private dragging = false; - @Input() - public set items(items: readonly T[]) { - if ( - items.length !== this.unsortedItems.length || - !items.every(item => this.unsortedItems.includes(item)) - ) { - this.unsortedItems = items; - } - } - @Input() public enabled: readonly T[] = []; @@ -40,12 +30,20 @@ export class TuiReorderComponent { public readonly enabledChange = new EventEmitter(); protected order = new Map(); - protected unsortedItems: readonly T[] = []; - protected readonly options = inject(TUI_REORDER_OPTIONS); protected readonly showHideText$ = inject(TUI_TABLE_SHOW_HIDE_MESSAGE); + @Input() + public set items(items: readonly T[]) { + if ( + items.length !== this.unsortedItems.length || + !items.every(item => this.unsortedItems.includes(item)) + ) { + this.unsortedItems = items; + } + } + @HostListener('focusout.stop') protected noop(): void {} diff --git a/projects/addon-table/components/table-pagination/table-pagination.component.ts b/projects/addon-table/components/table-pagination/table-pagination.component.ts index 402fcb77efe8..3c0ea29f5c75 100644 --- a/projects/addon-table/components/table-pagination/table-pagination.component.ts +++ b/projects/addon-table/components/table-pagination/table-pagination.component.ts @@ -9,7 +9,10 @@ import { import {TUI_TABLE_PAGINATION_TEXTS} from '@taiga-ui/addon-table/tokens'; import {TUI_COMMON_ICONS, TUI_SPIN_ICONS, TUI_SPIN_TEXTS} from '@taiga-ui/core'; -import {TUI_TABLE_PAGINATION_OPTIONS} from './table-pagination.options'; +import { + TUI_TABLE_PAGINATION_OPTIONS, + TuiTablePaginationOptions, +} from './table-pagination.options'; export interface TuiTablePagination { readonly page: number; @@ -23,7 +26,7 @@ export interface TuiTablePagination { changeDetection: ChangeDetectionStrategy.OnPush, }) export class TuiTablePaginationComponent { - protected readonly options = inject(TUI_TABLE_PAGINATION_OPTIONS); + private readonly options = inject(TUI_TABLE_PAGINATION_OPTIONS); @Input() public items: readonly number[] = this.options.items; @@ -61,10 +64,29 @@ export class TuiTablePaginationComponent { protected readonly texts$ = inject(TUI_TABLE_PAGINATION_TEXTS); protected readonly commonIcons = inject(TUI_COMMON_ICONS); + public onItem(size: number): void { + const {start} = this; + + this.size = size; + this.sizeChange.emit(size); + this.open = false; + this.page = Math.floor(start / this.size); + this.pageChange.emit(this.page); + this.paginationChange.emit(this.pagination); + } + protected get pages(): number { return Math.ceil(this.total / this.size); } + protected get showPages(): boolean { + return this.options.showPages; + } + + protected get sizeOptionContent(): TuiTablePaginationOptions['sizeOptionContent'] { + return this.options.sizeOptionContent; + } + protected get start(): number { return this.page * this.size; } @@ -88,17 +110,6 @@ export class TuiTablePaginationComponent { }; } - public onItem(size: number): void { - const {start} = this; - - this.size = size; - this.sizeChange.emit(size); - this.open = false; - this.page = Math.floor(start / this.size); - this.pageChange.emit(this.page); - this.paginationChange.emit(this.pagination); - } - protected back(): void { this.page--; this.pageChange.emit(this.page); diff --git a/projects/addon-table/components/table-pagination/table-pagination.template.html b/projects/addon-table/components/table-pagination/table-pagination.template.html index bc7ed1e9bed5..2be5dbf4133a 100644 --- a/projects/addon-table/components/table-pagination/table-pagination.template.html +++ b/projects/addon-table/components/table-pagination/table-pagination.template.html @@ -1,6 +1,6 @@ - + {{ texts.pages }} {{ pages }} @@ -27,7 +27,7 @@ > diff --git a/projects/addon-table/components/table/directives/direction-order.directive.ts b/projects/addon-table/components/table/directives/direction-order.directive.ts index eeaff7fa8629..0507b63d3b05 100644 --- a/projects/addon-table/components/table/directives/direction-order.directive.ts +++ b/projects/addon-table/components/table/directives/direction-order.directive.ts @@ -9,13 +9,13 @@ import {TuiTableDirective} from './table.directive'; export class TuiDirectionOrderDirective { private readonly table = inject(TuiTableDirective); - @Input() - public set directionOrder(order: 'asc' | 'desc') { - this.table.direction = order === 'asc' ? 1 : -1; - } - @Output() public readonly directionOrderChange = this.table.directionChange.pipe( map(dir => (dir === 1 ? 'asc' : 'desc')), ); + + @Input() + public set directionOrder(order: 'asc' | 'desc') { + this.table.direction = order === 'asc' ? 1 : -1; + } } diff --git a/projects/addon-table/components/table/directives/sort-by.directive.ts b/projects/addon-table/components/table/directives/sort-by.directive.ts index 54766e12136a..621acb6759d3 100644 --- a/projects/addon-table/components/table/directives/sort-by.directive.ts +++ b/projects/addon-table/components/table/directives/sort-by.directive.ts @@ -22,12 +22,6 @@ export class TuiSortByDirective>> { private readonly table = inject(TuiTableDirective); - @Input('tuiSortBy') - public set sortBy(sortBy: string | keyof T | null) { - this.tuiSortBy = sortBy; - this.checkSortables(); - } - @Output() public readonly tuiSortByChange = this.table.sorterChange.pipe( // delay is for getting actual ContentChildren (sortables) https://github.com/angular/angular/issues/38976 @@ -38,6 +32,12 @@ export class TuiSortByDirective>> { public tuiSortBy: string | keyof T | null = null; + @Input('tuiSortBy') + public set sortBy(sortBy: string | keyof T | null) { + this.tuiSortBy = sortBy; + this.checkSortables(); + } + protected checkSortables(): void { this.sortables.forEach(s => s.check()); } diff --git a/projects/addon-table/components/table/directives/sortable.directive.ts b/projects/addon-table/components/table/directives/sortable.directive.ts index ee64de711695..4e52a302e84d 100644 --- a/projects/addon-table/components/table/directives/sortable.directive.ts +++ b/projects/addon-table/components/table/directives/sortable.directive.ts @@ -17,12 +17,12 @@ export class TuiSortableDirective>> forwardRef(() => TuiSortByDirective), ); - public sorter: TuiComparator = (): number => 0; - public get key(): keyof T { return this.th.key; } + public sorter: TuiComparator = (): number => 0; + public ngOnInit(): void { this.sorter = this.match ? this.table.sorter : this.sorter; this.th.sorter = this.sorter; diff --git a/projects/addon-table/components/table/tbody/tbody.component.ts b/projects/addon-table/components/table/tbody/tbody.component.ts index 433638efc1ae..24b7be934f15 100644 --- a/projects/addon-table/components/table/tbody/tbody.component.ts +++ b/projects/addon-table/components/table/tbody/tbody.component.ts @@ -32,6 +32,9 @@ export class TuiTbodyComponent>> { private readonly pipe = inject(TuiTableSortPipe); private readonly options = inject(TUI_TABLE_OPTIONS); + @ContentChildren(forwardRef(() => TuiTrComponent)) + public readonly rows: QueryList> = EMPTY_QUERY; + @Input() public data: readonly T[] = []; @@ -47,9 +50,6 @@ export class TuiTbodyComponent>> { @ContentChild(forwardRef(() => TuiRowDirective)) protected readonly row?: TuiRowDirective; - @ContentChildren(forwardRef(() => TuiTrComponent)) - public readonly rows: QueryList> = EMPTY_QUERY; - protected readonly arrowOptions = inject(TUI_ARROW_OPTIONS); protected readonly table = inject>( forwardRef(() => TuiTableDirective), diff --git a/projects/addon-table/directives/table-filters/table-filter.directive.ts b/projects/addon-table/directives/table-filters/table-filter.directive.ts index 39fc70cb0b4e..c21b85cb4e9b 100644 --- a/projects/addon-table/directives/table-filters/table-filter.directive.ts +++ b/projects/addon-table/directives/table-filters/table-filter.directive.ts @@ -19,8 +19,6 @@ export class TuiTableFilterDirective implements OnInit, OnDestroy, TuiTableFi @Input() public tuiTableFilter?: keyof T; - protected readonly filters = inject(TuiTableFiltersDirective); - public readonly refresh$ = defer(() => merge( this.control.valueChanges || EMPTY, @@ -28,6 +26,8 @@ export class TuiTableFilterDirective implements OnInit, OnDestroy, TuiTableFi ), ); + protected readonly filters = inject(TuiTableFiltersDirective); + public ngOnInit(): void { this.filters.register(this); } diff --git a/projects/cdk/abstract/control.ts b/projects/cdk/abstract/control.ts index 9038649ceb11..59a4289748ca 100644 --- a/projects/cdk/abstract/control.ts +++ b/projects/cdk/abstract/control.ts @@ -41,15 +41,6 @@ export abstract class AbstractTuiControl private readonly ngControl = inject(NgControl, {optional: true}); private previousInternalValue?: T | null; private readonly refresh$ = new Subject(); - private onTouched = EMPTY_FUNCTION; - private onChange = EMPTY_FUNCTION; - protected readonly fallbackValue = this.getFallbackValue(); - protected readonly destroy$ = new Subject(); - protected readonly cdr = inject(ChangeDetectorRef); - protected readonly valueTransformer = inject>( - AbstractTuiValueTransformer, - {optional: true}, - ); @Input() @HostBinding('class._readonly') @@ -58,6 +49,16 @@ export abstract class AbstractTuiControl @Input() public pseudoInvalid: boolean | null = null; + protected onTouched = EMPTY_FUNCTION; + protected onChange = EMPTY_FUNCTION; + protected readonly fallbackValue = this.getFallbackValue(); + protected readonly destroy$ = new Subject(); + protected readonly cdr = inject(ChangeDetectorRef); + protected readonly valueTransformer = inject>( + AbstractTuiValueTransformer, + {optional: true}, + ); + constructor() { super(); @@ -133,21 +134,6 @@ export abstract class AbstractTuiControl return this.ngControl?.name?.toString() ?? null; } - private get rawValue(): T | undefined { - const {ngControl} = this; - - if (ngControl === null) { - return undefined; - } - - const controlValue = - ngControl instanceof NgModel && this.previousInternalValue === undefined - ? ngControl.viewModel - : ngControl.value; - - return this.fromControlValue(controlValue); - } - public ngOnInit(): void { this.refresh$ .pipe( @@ -222,6 +208,21 @@ export abstract class AbstractTuiControl return oldValue === newValue; } + private get rawValue(): T | undefined { + const {ngControl} = this; + + if (ngControl === null) { + return undefined; + } + + const controlValue = + ngControl instanceof NgModel && this.previousInternalValue === undefined + ? ngControl.viewModel + : ngControl.value; + + return this.fromControlValue(controlValue); + } + private safeNgControlData( extractor: (ngControl: NgControl) => T | null | undefined, defaultFieldValue: T, diff --git a/projects/cdk/abstract/interactive.ts b/projects/cdk/abstract/interactive.ts index e46ca958ee6f..95ada228c015 100644 --- a/projects/cdk/abstract/interactive.ts +++ b/projects/cdk/abstract/interactive.ts @@ -54,10 +54,6 @@ export abstract class AbstractTuiInteractive { return this.disabled; } - public get computedFocusable(): boolean { - return !this.computedDisabled && (this.focusable || this.focused); - } - @HostBinding('class._focused') public get computedFocused(): boolean { return !this.computedDisabled && (this.pseudoFocus ?? this.focused); @@ -68,6 +64,10 @@ export abstract class AbstractTuiInteractive { return !this.computedDisabled && (this.pseudoFocus ?? this.focusVisible); } + public get computedFocusable(): boolean { + return !this.computedDisabled && (this.focusable || this.focused); + } + // TODO: 3.0 Consider removing since native input is exposed public get id(): string { return this.nativeId || this.autoIdString; diff --git a/projects/cdk/abstract/portals.ts b/projects/cdk/abstract/portals.ts index 5bb717b16416..f0fe10ddc9b9 100644 --- a/projects/cdk/abstract/portals.ts +++ b/projects/cdk/abstract/portals.ts @@ -49,14 +49,6 @@ export abstract class TuiPortalsComponent { export abstract class TuiPortalService { protected host?: TuiPortalsComponent; - protected get safeHost(): TuiPortalsComponent { - if (!this.host) { - throw new TuiNoHostException(); - } - - return this.host; - } - public attach(host: TuiPortalsComponent): void { this.host = host; } @@ -80,6 +72,14 @@ export abstract class TuiPortalService { viewRef.destroy(); } } + + protected get safeHost(): TuiPortalsComponent { + if (!this.host) { + throw new TuiNoHostException(); + } + + return this.host; + } } export function tuiAsPortal(useExisting: typeof TuiPortalService): Provider { diff --git a/projects/cdk/abstract/theme-switcher.ts b/projects/cdk/abstract/theme-switcher.ts index 9cd5577deed5..e7bc9fab0b81 100644 --- a/projects/cdk/abstract/theme-switcher.ts +++ b/projects/cdk/abstract/theme-switcher.ts @@ -26,14 +26,14 @@ export abstract class AbstractTuiThemeSwitcher implements OnDestroy { styles[styles.length - 1]; } - protected get style(): HTMLStyleElement | null { - return (this.constructor as typeof AbstractTuiThemeSwitcher).style; - } - public ngOnDestroy(): void { this.removeTheme(); } + protected get style(): HTMLStyleElement | null { + return (this.constructor as typeof AbstractTuiThemeSwitcher).style; + } + private addTheme(): void { if (this.style) { this.doc.head.appendChild(this.style); diff --git a/projects/cdk/directives/active-zone/active-zone.directive.ts b/projects/cdk/directives/active-zone/active-zone.directive.ts index 998288ed907e..367c236fda85 100644 --- a/projects/cdk/directives/active-zone/active-zone.directive.ts +++ b/projects/cdk/directives/active-zone/active-zone.directive.ts @@ -30,11 +30,6 @@ export class TuiActiveZoneDirective implements OnDestroy { optional: true, }); - @Input('tuiActiveZoneParent') - public set tuiActiveZoneParentSetter(zone: TuiActiveZoneDirective | null) { - this.setZone(zone); - } - @Output() public readonly tuiActiveZoneChange = this.active$.pipe( map(element => !!element && this.contains(element)), @@ -48,6 +43,11 @@ export class TuiActiveZoneDirective implements OnDestroy { this.directParentActiveZone?.addSubActiveZone(this); } + @Input('tuiActiveZoneParent') + public set tuiActiveZoneParentSetter(zone: TuiActiveZoneDirective | null) { + this.setZone(zone); + } + public ngOnDestroy(): void { this.directParentActiveZone?.removeSubActiveZone(this); this.tuiActiveZoneParent?.removeSubActiveZone(this); diff --git a/projects/cdk/directives/auto-focus/handlers/abstract.handler.ts b/projects/cdk/directives/auto-focus/handlers/abstract.handler.ts index cfd5fd0f679b..32e50b4afa40 100644 --- a/projects/cdk/directives/auto-focus/handlers/abstract.handler.ts +++ b/projects/cdk/directives/auto-focus/handlers/abstract.handler.ts @@ -12,6 +12,8 @@ export abstract class AbstractTuiAutofocusHandler implements TuiAutofocusHandler protected readonly el: ElementRef, ) {} + public abstract setFocus(): void; + protected get element(): TuiNativeFocusableElement { return this.focusable?.nativeFocusableElement || this.el.nativeElement; } @@ -19,6 +21,4 @@ export abstract class AbstractTuiAutofocusHandler implements TuiAutofocusHandler protected get isTextFieldElement(): boolean { return this.element.matches('input, textarea, [contenteditable]'); } - - public abstract setFocus(): void; } diff --git a/projects/cdk/directives/checked/checked.directive.ts b/projects/cdk/directives/checked/checked.directive.ts index 7fb866fdbe76..76e1642823f7 100644 --- a/projects/cdk/directives/checked/checked.directive.ts +++ b/projects/cdk/directives/checked/checked.directive.ts @@ -14,6 +14,9 @@ export class TuiCheckedDirective { private indeterminate = false; private checked = false; + @Output() + public readonly tuiCheckedChange = new EventEmitter(); + @HostBinding('checked') public get isChecked(): boolean { return this.checked; @@ -30,9 +33,6 @@ export class TuiCheckedDirective { this.indeterminate = checked === null; } - @Output() - public readonly tuiCheckedChange = new EventEmitter(); - @HostListener('change', ['$event.target']) public onChange({checked}: HTMLInputElement): void { this.checked = checked; diff --git a/projects/cdk/directives/focus-trap/focus-trap.directive.ts b/projects/cdk/directives/focus-trap/focus-trap.directive.ts index dc9f202ebb11..7e2cb8102ee7 100644 --- a/projects/cdk/directives/focus-trap/focus-trap.directive.ts +++ b/projects/cdk/directives/focus-trap/focus-trap.directive.ts @@ -35,6 +35,23 @@ export class TuiFocusTrapDirective implements OnDestroy { void Promise.resolve().then(() => this.el.focus()); } + public ngOnDestroy(): void { + tuiBlurNativeFocused(this.doc); + + /** + * HostListeners are triggered even after ngOnDestroy + * {@link https://github.com/angular/angular/issues/38100} + * so we need to delay it but stay in the same sync cycle, + * therefore using Promise instead of setTimeout + */ + // eslint-disable-next-line + Promise.resolve().then(() => { + if (tuiIsHTMLElement(this.activeElement)) { + this.activeElement.focus(); + } + }); + } + @HostListener('blur') protected onBlur(): void { this.renderer.removeAttribute(this.el, 'tabIndex'); @@ -55,21 +72,4 @@ export class TuiFocusTrapDirective implements OnDestroy { focusable.focus(); } } - - public ngOnDestroy(): void { - tuiBlurNativeFocused(this.doc); - - /** - * HostListeners are triggered even after ngOnDestroy - * {@link https://github.com/angular/angular/issues/38100} - * so we need to delay it but stay in the same sync cycle, - * therefore using Promise instead of setTimeout - */ - // eslint-disable-next-line - Promise.resolve().then(() => { - if (tuiIsHTMLElement(this.activeElement)) { - this.activeElement.focus(); - } - }); - } } diff --git a/projects/cdk/directives/media/media.directive.ts b/projects/cdk/directives/media/media.directive.ts index 5056a90d5a1e..93d1eaf7cd76 100644 --- a/projects/cdk/directives/media/media.directive.ts +++ b/projects/cdk/directives/media/media.directive.ts @@ -23,11 +23,6 @@ export class TuiMediaDirective { @HostBinding('volume') public volume = 1; - @Input('playbackRate') - public set playbackRateSetter(playbackRate: number) { - this.updatePlaybackRate(playbackRate); - } - @Output() public readonly currentTimeChange = new EventEmitter(); @@ -37,6 +32,11 @@ export class TuiMediaDirective { @Output() public readonly volumeChange = new EventEmitter(); + @Input('playbackRate') + public set playbackRateSetter(playbackRate: number) { + this.updatePlaybackRate(playbackRate); + } + @Input() public set currentTime(currentTime: number) { if (Math.abs(currentTime - this.currentTime) > 0.05) { @@ -44,10 +44,6 @@ export class TuiMediaDirective { } } - public get currentTime(): number { - return this.el.currentTime; - } - @Input() public set paused(paused: boolean) { if (paused) { @@ -58,6 +54,10 @@ export class TuiMediaDirective { } } + public get currentTime(): number { + return this.el.currentTime; + } + public get paused(): boolean { return this.el.paused; } diff --git a/projects/cdk/directives/native-validator/native-validator.directive.ts b/projects/cdk/directives/native-validator/native-validator.directive.ts index 21829c0fa67c..70a264e174b6 100644 --- a/projects/cdk/directives/native-validator/native-validator.directive.ts +++ b/projects/cdk/directives/native-validator/native-validator.directive.ts @@ -25,13 +25,6 @@ export class TuiNativeValidatorDirective implements Validator { @Input() public tuiNativeValidator = 'Invalid'; - @HostListener('blur') - protected handleValidation(): void { - this.el.setCustomValidity( - this.control?.touched && this.control?.invalid ? this.tuiNativeValidator : '', - ); - } - public validate(control: AbstractControl): null { this.control = control; @@ -42,6 +35,13 @@ export class TuiNativeValidatorDirective implements Validator { return null; } + @HostListener('blur') + protected handleValidation(): void { + this.el.setCustomValidity( + this.control?.touched && this.control?.invalid ? this.tuiNativeValidator : '', + ); + } + private get el(): HTMLInputElement { return this.host.querySelector('input,textarea,select') || this.host; } diff --git a/projects/cdk/directives/obscured/obscured.directive.ts b/projects/cdk/directives/obscured/obscured.directive.ts index 77e9bff27a58..8bdee11fd30d 100644 --- a/projects/cdk/directives/obscured/obscured.directive.ts +++ b/projects/cdk/directives/obscured/obscured.directive.ts @@ -19,11 +19,11 @@ export class TuiObscuredDirective { map(by => !!by?.every(el => !this.activeZone?.contains(el))), ); + @Output() + public readonly tuiObscured = this.enabled$.pipe(tuiIfMap(() => this.obscured$)); + @Input() public set tuiObscuredEnabled(enabled: boolean) { this.enabled$.next(enabled); } - - @Output() - public readonly tuiObscured = this.enabled$.pipe(tuiIfMap(() => this.obscured$)); } diff --git a/projects/cdk/directives/overscroll/overscroll.directive.ts b/projects/cdk/directives/overscroll/overscroll.directive.ts index fb04613f0382..97cf8ffeb602 100644 --- a/projects/cdk/directives/overscroll/overscroll.directive.ts +++ b/projects/cdk/directives/overscroll/overscroll.directive.ts @@ -74,15 +74,15 @@ export class TuiOverscrollDirective { .subscribe(); } - protected get enabled(): boolean { - return this.mode !== 'none'; - } - @HostBinding('style.overscrollBehavior') protected get overscrollBehavior(): 'contain' | null { return this.enabled ? 'contain' : null; } + protected get enabled(): boolean { + return this.mode !== 'none'; + } + private processEvent( event: TuiEventWith, vertical: boolean, diff --git a/projects/cdk/schematics/ng-update/v3/steps/migrate-textfield-controller.ts b/projects/cdk/schematics/ng-update/v3/steps/migrate-textfield-controller.ts index bbbae8ef9474..138cf3cdcdb6 100644 --- a/projects/cdk/schematics/ng-update/v3/steps/migrate-textfield-controller.ts +++ b/projects/cdk/schematics/ng-update/v3/steps/migrate-textfield-controller.ts @@ -86,8 +86,7 @@ function addAttrToExistingInput({ templateOffset: number; }): void { attrs.forEach(attr => { - const insertTo = - existingInput.sourceCodeLocation?.attrs?.['tuitextfield']?.endOffset; + const insertTo = existingInput.sourceCodeLocation?.attrs?.tuitextfield?.endOffset; if (insertTo) { recorder.insertLeft( diff --git a/projects/cdk/services/directive-styles.service.ts b/projects/cdk/services/directive-styles.service.ts index b965b975f0d2..d6a6d71ea010 100644 --- a/projects/cdk/services/directive-styles.service.ts +++ b/projects/cdk/services/directive-styles.service.ts @@ -31,6 +31,10 @@ export class TuiDirectiveStylesService implements OnDestroy { public readonly map = new Map(); + public ngOnDestroy(): void { + this.map.forEach(component => component.destroy()); + } + protected addComponent(component: Type): void { if (!this.map.has(component)) { this.map.set( @@ -39,8 +43,4 @@ export class TuiDirectiveStylesService implements OnDestroy { ); } } - - public ngOnDestroy(): void { - this.map.forEach(component => component.destroy()); - } } diff --git a/projects/core/abstract/abstract-textfield-host.ts b/projects/core/abstract/abstract-textfield-host.ts index 46342b95c457..0971f8bb9f24 100644 --- a/projects/core/abstract/abstract-textfield-host.ts +++ b/projects/core/abstract/abstract-textfield-host.ts @@ -8,6 +8,8 @@ export abstract class AbstractTuiTextfieldHost { protected readonly host: T = inject(AbstractTuiControl, {optional: true}); + public abstract onValueChange(value: string): void; + public get readOnly(): boolean { return this.host.readOnly; } @@ -32,7 +34,5 @@ export abstract class AbstractTuiTextfieldHost return this.host.value?.toString() || ''; } - public abstract onValueChange(value: string): void; - public process(_input: HTMLInputElement): void {} } diff --git a/projects/core/components/button/button.component.ts b/projects/core/components/button/button.component.ts index 6f38b9b0a36a..a2ecb4e912a3 100644 --- a/projects/core/components/button/button.component.ts +++ b/projects/core/components/button/button.component.ts @@ -75,10 +75,6 @@ export class TuiButtonComponent return !this.showLoader && tuiIsNativeFocused(this.el); } - protected get loaderSize(): TuiSizeS { - return this.size === 'l' || this.size === 'xl' ? 'm' : 's'; - } - @HostBinding('attr.data-appearance') protected get computedAppearance(): string { return this.appearance ?? (this.options.appearance || ''); @@ -94,6 +90,10 @@ export class TuiButtonComponent return this.focusable ? 0 : -1; } + protected get loaderSize(): TuiSizeS { + return this.size === 'l' || this.size === 'xl' ? 'm' : 's'; + } + @HostListener('focusin', ['true']) @HostListener('focusout', ['false']) protected onFocused(focused: boolean): void { diff --git a/projects/core/components/calendar/calendar.component.ts b/projects/core/components/calendar/calendar.component.ts index 022dbc54992b..db1380749249 100644 --- a/projects/core/components/calendar/calendar.component.ts +++ b/projects/core/components/calendar/calendar.component.ts @@ -32,11 +32,6 @@ export class TuiCalendarComponent implements TuiWithOptionalMinMax { private view: TuiCalendarView = 'month'; - @Input() - public set initialView(view: TuiCalendarView) { - this.view = view; - } - @Input() public month: TuiMonth = TuiMonth.currentLocal(); @@ -64,6 +59,15 @@ export class TuiCalendarComponent implements TuiWithOptionalMinMax { @Input() public markerHandler: TuiMarkerHandler = TUI_DEFAULT_MARKER_HANDLER; + @Output() + public readonly dayClick = new EventEmitter(); + + @Output() + public readonly monthChange = new EventEmitter(); + + @Output() + public readonly hoveredItemChange = new EventEmitter(); + @Input() public set value(value: TuiDay | TuiDayRange | readonly TuiDay[] | null) { this.day = value; @@ -73,28 +77,26 @@ export class TuiCalendarComponent implements TuiWithOptionalMinMax { } } + @Input() + public set initialView(view: TuiCalendarView) { + this.view = view; + } + public get value(): TuiDay | TuiDayRange | readonly TuiDay[] | null { return this.day; } - @Output() - public readonly dayClick = new EventEmitter(); - - @Output() - public readonly monthChange = new EventEmitter(); - - @Output() - public readonly hoveredItemChange = new EventEmitter(); + public onPaginationValueChange(month: TuiMonth): void { + this.updateViewedMonth(month); + } - protected get isInYearView(): boolean { - return this.view === 'year'; + public onDayClick(day: TuiDay): void { + this.dayClick.emit(day); } - protected readonly disabledItemHandlerMapper: TuiTypedMapper< - [TuiBooleanHandler, TuiDay, TuiDay], - TuiBooleanHandler - > = (disabledItemHandler, min, max) => item => - item.dayBefore(min) || item.dayAfter(max) || disabledItemHandler(item); + public onHoveredItemChange(day: TuiDay | null): void { + this.updateHoveredDay(day); + } protected get computedMin(): TuiDay { return this.min ?? TUI_FIRST_DAY; @@ -118,6 +120,16 @@ export class TuiCalendarComponent implements TuiWithOptionalMinMax { return maxViewed.monthSameOrBefore(max) ? maxViewed : max; } + protected get isInYearView(): boolean { + return this.view === 'year'; + } + + protected readonly disabledItemHandlerMapper: TuiTypedMapper< + [TuiBooleanHandler, TuiDay, TuiDay], + TuiBooleanHandler + > = (disabledItemHandler, min, max) => item => + item.dayBefore(min) || item.dayAfter(max) || disabledItemHandler(item); + protected onPaginationYearClick(): void { this.view = 'year'; } @@ -127,18 +139,6 @@ export class TuiCalendarComponent implements TuiWithOptionalMinMax { this.updateViewedMonth(new TuiMonth(year, this.month.month)); } - public onPaginationValueChange(month: TuiMonth): void { - this.updateViewedMonth(month); - } - - public onDayClick(day: TuiDay): void { - this.dayClick.emit(day); - } - - public onHoveredItemChange(day: TuiDay | null): void { - this.updateHoveredDay(day); - } - private updateViewedMonth(month: TuiMonth): void { if (this.month.monthSame(month)) { return; diff --git a/projects/core/components/data-list/data-list.component.ts b/projects/core/components/data-list/data-list.component.ts index 535e63435a59..dd0a7529e8e5 100644 --- a/projects/core/components/data-list/data-list.component.ts +++ b/projects/core/components/data-list/data-list.component.ts @@ -68,21 +68,6 @@ export class TuiDataListComponent implements TuiDataListAccessor { protected readonly defaultEmptyContent$ = inject(TUI_NOTHING_FOUND_MESSAGE); - @tuiPure - protected get empty$(): Observable { - return tuiQueryListChanges(this.options).pipe(map(({length}) => !length)); - } - - @HostListener('focusin', ['$event.relatedTarget', '$event.currentTarget']) - protected onFocusIn(relatedTarget: HTMLElement, currentTarget: HTMLElement): void { - if (!currentTarget.contains(relatedTarget) && !this.origin) { - this.origin = relatedTarget; - } - } - - @HostListener('mousedown.prevent') - protected noop(): void {} - @HostListener('keydown.arrowDown.prevent', ['$event.target', '1']) @HostListener('keydown.arrowUp.prevent', ['$event.target', '-1']) public onKeyDownArrow(current: HTMLElement, step: number): void { @@ -118,6 +103,21 @@ export class TuiDataListComponent implements TuiDataListAccessor { this.handleFocusLossIfNecessary(target); } + @tuiPure + protected get empty$(): Observable { + return tuiQueryListChanges(this.options).pipe(map(({length}) => !length)); + } + + @HostListener('focusin', ['$event.relatedTarget', '$event.currentTarget']) + protected onFocusIn(relatedTarget: HTMLElement, currentTarget: HTMLElement): void { + if (!currentTarget.contains(relatedTarget) && !this.origin) { + this.origin = relatedTarget; + } + } + + @HostListener('mousedown.prevent') + protected noop(): void {} + private get elements(): readonly HTMLElement[] { return Array.from(this.el.querySelectorAll('[tuiOption]')); } diff --git a/projects/core/components/data-list/option/option.component.ts b/projects/core/components/data-list/option/option.component.ts index 779057d57692..896e745e8992 100644 --- a/projects/core/components/data-list/option/option.component.ts +++ b/projects/core/components/data-list/option/option.component.ts @@ -72,6 +72,11 @@ export class TuiOptionComponent implements OnDestroy { protected readonly icons = inject(TUI_COMMON_ICONS); + // Preventing focus loss upon focused option removal + public ngOnDestroy(): void { + this.dataList?.handleFocusLossIfNecessary(this.el); + } + @HostBinding('class._with-dropdown') protected get active(): boolean { return !!this.dropdown && !!this.dropdown.dropdownBoxRef; @@ -90,9 +95,4 @@ export class TuiOptionComponent implements OnDestroy { protected onMouseMove({currentTarget}: TuiEventWith): void { currentTarget.focus({preventScroll: true}); } - - // Preventing focus loss upon focused option removal - public ngOnDestroy(): void { - this.dataList?.handleFocusLossIfNecessary(this.el); - } } diff --git a/projects/core/components/error/error.component.ts b/projects/core/components/error/error.component.ts index d36fdd40afb2..566c66102c0d 100644 --- a/projects/core/components/error/error.component.ts +++ b/projects/core/components/error/error.component.ts @@ -26,20 +26,17 @@ import {Observable} from 'rxjs'; animations: [tuiHeightCollapse, tuiFadeIn], }) export class TuiErrorComponent { - @Input('error') - public set errorSetter(error: TuiValidationError | string | null) { - this.error = tuiIsString(error) ? new TuiValidationError(error) : error; - } - protected readonly options = tuiToAnimationOptions(inject(TUI_ANIMATIONS_SPEED)); - protected error: TuiValidationError | null = null; - protected visible = true; - protected readonly mode$ = inject>(TUI_MODE); protected readonly defaultErrorMessage$ = inject(TUI_DEFAULT_ERROR_MESSAGE); + @Input('error') + public set errorSetter(error: TuiValidationError | string | null) { + this.error = tuiIsString(error) ? new TuiValidationError(error) : error; + } + @HostListener('animationcancel.self', ['false']) @HostListener('animationstart.self', ['true']) protected onAnimation(visible: boolean): void { diff --git a/projects/core/components/expand/expand.component.ts b/projects/core/components/expand/expand.component.ts index 99742310336b..cf2c4c1727d9 100644 --- a/projects/core/components/expand/expand.component.ts +++ b/projects/core/components/expand/expand.component.ts @@ -47,6 +47,13 @@ export class TuiExpandComponent { @Input() public async = false; + @ContentChild(TuiExpandContentDirective, {read: TemplateRef}) + protected content: TemplateRef> | null = null; + + @HostBinding('class._expanded') + @HostBinding('attr.aria-expanded') + protected expanded: boolean | null = null; + @Input('expanded') public set expandedSetter(expanded: boolean | null) { if (this.expanded === null) { @@ -66,12 +73,9 @@ export class TuiExpandComponent { this.retrigger(this.async && expanded ? State.Loading : State.Animated); } - @ContentChild(TuiExpandContentDirective, {read: TemplateRef}) - protected content: TemplateRef> | null = null; - - @HostBinding('class._expanded') - @HostBinding('attr.aria-expanded') - protected expanded: boolean | null = null; + public get contentVisible(): boolean { + return this.expanded || this.state !== State.Idle; + } @HostBinding('class._overflow') protected get overflow(): boolean { @@ -109,10 +113,6 @@ export class TuiExpandComponent { return null; } - public get contentVisible(): boolean { - return this.expanded || this.state !== State.Idle; - } - @HostListener('transitionend.self', ['$event']) protected onTransitionEnd({propertyName}: TransitionEvent): void { if (propertyName === 'opacity' && this.state === State.Animated) { diff --git a/projects/core/components/group/group.directive.ts b/projects/core/components/group/group.directive.ts index 1654b88bd7d8..222cfbbe6587 100644 --- a/projects/core/components/group/group.directive.ts +++ b/projects/core/components/group/group.directive.ts @@ -18,7 +18,6 @@ import {TUI_GROUP_OPTIONS} from './group.options'; }) export class TuiGroupDirective { private readonly options = inject(TUI_GROUP_OPTIONS); - protected readonly nothing = tuiWithStyles(TuiGroupComponent); @Input() public orientation: TuiOrientation = this.options.orientation; @@ -33,4 +32,6 @@ export class TuiGroupDirective { @Input() public size: TuiSizeL = this.options.size; + + protected readonly nothing = tuiWithStyles(TuiGroupComponent); } diff --git a/projects/core/components/hosted-dropdown/hosted-dropdown.component.ts b/projects/core/components/hosted-dropdown/hosted-dropdown.component.ts index 6ea707b242a0..28f8e531c69a 100644 --- a/projects/core/components/hosted-dropdown/hosted-dropdown.component.ts +++ b/projects/core/components/hosted-dropdown/hosted-dropdown.component.ts @@ -129,9 +129,6 @@ export class TuiHostedDropdownComponent implements TuiFocusableElementAccessor { ) .pipe(map(([visible, hovered]) => visible && hovered)); - @ViewChild(TuiActiveZoneDirective) - protected readonly activeZone!: TuiActiveZoneDirective; - @Input() public content: PolymorpheusContent; @@ -152,11 +149,13 @@ export class TuiHostedDropdownComponent implements TuiFocusableElementAccessor { @Output() public readonly focusedChange = new EventEmitter(); - protected readonly focus$ = new BehaviorSubject(false); - /** TODO: rename in 4.0 */ public readonly openChange = this.openChange$; + @ViewChild(TuiActiveZoneDirective) + protected readonly activeZone!: TuiActiveZoneDirective; + + protected readonly focus$ = new BehaviorSubject(false); protected readonly context!: TuiContext; @Input() @@ -168,22 +167,6 @@ export class TuiHostedDropdownComponent implements TuiFocusableElementAccessor { return this.openChange.value; } - protected get host(): HTMLElement { - return this.dropdownHost?.nativeElement || this.el; - } - - protected get computedHost(): HTMLElement { - return ( - this.dropdownHost?.nativeElement || - (this.nativeFocusableElement as HTMLElement) || - this.el - ); - } - - protected get dropdown(): HTMLElement | undefined { - return this.dropdownDirective?.dropdownBoxRef?.location.nativeElement; - } - public get nativeFocusableElement(): TuiNativeFocusableElement | null { return tuiIsNativeKeyboardFocusable(this.host) ? this.host @@ -202,6 +185,30 @@ export class TuiHostedDropdownComponent implements TuiFocusableElementAccessor { ); } + public updateOpen(open: boolean): void { + if (!open || this.canOpen) { + this.open = open; + } + } + + public readonly close = (): void => this.updateOpen(false); + + protected get host(): HTMLElement { + return this.dropdownHost?.nativeElement || this.el; + } + + protected get computedHost(): HTMLElement { + return ( + this.dropdownHost?.nativeElement || + (this.nativeFocusableElement as HTMLElement) || + this.el + ); + } + + protected get dropdown(): HTMLElement | undefined { + return this.dropdownDirective?.dropdownBoxRef?.location.nativeElement; + } + @HostListener('focusin.capture.silent') @HostListener('focusout.capture.silent') protected onFocusInOut(): void { @@ -265,14 +272,6 @@ export class TuiHostedDropdownComponent implements TuiFocusableElementAccessor { } } - public updateOpen(open: boolean): void { - if (!open || this.canOpen) { - this.open = open; - } - } - - public readonly close = (): void => this.updateOpen(false); - private get hostEditable(): boolean { return tuiIsElementEditable(this.computedHost); } diff --git a/projects/core/components/link/link.component.ts b/projects/core/components/link/link.component.ts index 854ec06f0a66..e34f8bdc285f 100644 --- a/projects/core/components/link/link.component.ts +++ b/projects/core/components/link/link.component.ts @@ -60,16 +60,16 @@ export class TuiLinkComponent implements TuiFocusableElementAccessor { @HostBinding('attr.data-host-mode') public mode: 'negative' | 'positive' | null = null; - @HostBinding('class._focus-visible') - protected focusVisible = false; - - protected readonly mode$ = inject(TUI_MODE); - public readonly focusedChange = merge( tuiTypedFromEvent(this.el, 'focusin').pipe(map(ALWAYS_TRUE_HANDLER)), tuiTypedFromEvent(this.el, 'focusout').pipe(map(ALWAYS_FALSE_HANDLER)), ); + @HostBinding('class._focus-visible') + protected focusVisible = false; + + protected readonly mode$ = inject(TUI_MODE); + constructor() { inject(TuiFocusVisibleService).subscribe(visible => { this.focusVisible = visible; diff --git a/projects/core/components/loader/loader.component.ts b/projects/core/components/loader/loader.component.ts index d165b44dc3fb..6e28bcd0924c 100644 --- a/projects/core/components/loader/loader.component.ts +++ b/projects/core/components/loader/loader.component.ts @@ -43,6 +43,11 @@ export class TuiLoaderComponent { @Input() public textContent: PolymorpheusContent; + @HostBinding('class._loading') + protected loading = true; + + protected readonly isApple = tuiIsSafari(this.el) || this.isIOS; + @Input() public set showLoader(value: boolean) { // @bad TODO: https://github.com/angular/angular/issues/32083 think of a better way @@ -53,11 +58,6 @@ export class TuiLoaderComponent { this.loading = value; } - @HostBinding('class._loading') - protected loading = true; - - protected readonly isApple = tuiIsSafari(this.el) || this.isIOS; - protected get hasOverlay(): boolean { return this.overlay && this.loading; } diff --git a/projects/core/components/notification/notification.component.ts b/projects/core/components/notification/notification.component.ts index d371fe440234..4ea36aaa8405 100644 --- a/projects/core/components/notification/notification.component.ts +++ b/projects/core/components/notification/notification.component.ts @@ -19,7 +19,7 @@ import {TUI_NOTIFICATION_OPTIONS} from './notification.options'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class TuiNotificationComponent { - protected readonly options = inject(TUI_NOTIFICATION_OPTIONS); + private readonly options = inject(TUI_NOTIFICATION_OPTIONS); @Input() public icon = this.options.icon; diff --git a/projects/core/components/primitive-calendar/primitive-calendar.component.ts b/projects/core/components/primitive-calendar/primitive-calendar.component.ts index 7abe65dc059c..7f8fde980ab6 100644 --- a/projects/core/components/primitive-calendar/primitive-calendar.component.ts +++ b/projects/core/components/primitive-calendar/primitive-calendar.component.ts @@ -57,33 +57,6 @@ export class TuiPrimitiveCalendarComponent { protected readonly unorderedWeekDays$ = inject(TUI_SHORT_WEEK_DAYS); protected readonly dayTypeHandler = inject(TUI_DAY_TYPE_HANDLER); - @HostBinding('class._single') - protected get isSingleDayRange(): boolean { - return this.value instanceof TuiDayRange && this.value.isSingleDay; - } - - /** - * @deprecated: use {@link this.isSingleDayRange} - */ - protected get isSingle(): boolean { - return this.isSingleDayRange; - } - - protected readonly toMarkers = ( - day: TuiDay, - today: boolean, - inRange: boolean, - markerHandler: TuiMarkerHandler, - ): [string, string] | [string] | null => { - if (today || inRange) { - return null; - } - - const markers = markerHandler(day); - - return markers.length === 0 ? null : markers; - }; - public getItemState(item: TuiDay): TuiInteractiveState | null { const {disabledItemHandler, pressedItem, hoveredItem} = this; @@ -102,6 +75,34 @@ export class TuiPrimitiveCalendarComponent { return null; } + public itemIsInterval(day: TuiDay): boolean { + const {value, hoveredItem} = this; + + if (!(value instanceof TuiDayRange)) { + return false; + } + + if (!value.isSingleDay) { + return value.from.daySameOrBefore(day) && value.to.dayAfter(day); + } + + if (hoveredItem === null) { + return false; + } + + const range = TuiDayRange.sort(value.from, hoveredItem); + + return range.from.daySameOrBefore(day) && range.to.dayAfter(day); + } + + public onItemHovered(item: TuiDay | false): void { + this.updateHoveredItem(item || null); + } + + public onItemPressed(item: TuiDay | false): void { + this.pressedItem = item || null; + } + public getItemRange(item: TuiDay): TuiRangeState | null { const {value, hoveredItem} = this; @@ -144,40 +145,39 @@ export class TuiPrimitiveCalendarComponent { return value.isSingleDay && value.from.daySame(item) ? 'single' : null; } - protected itemIsToday(item: TuiDay): boolean { - return this.today.daySame(item); + @HostBinding('class._single') + protected get isSingleDayRange(): boolean { + return this.value instanceof TuiDayRange && this.value.isSingleDay; } - protected itemIsUnavailable(item: TuiDay): boolean { - return !this.month.monthSame(item); + /** + * @deprecated: use {@link this.isSingleDayRange} + */ + protected get isSingle(): boolean { + return this.isSingleDayRange; } - public itemIsInterval(day: TuiDay): boolean { - const {value, hoveredItem} = this; - - if (!(value instanceof TuiDayRange)) { - return false; - } - - if (!value.isSingleDay) { - return value.from.daySameOrBefore(day) && value.to.dayAfter(day); - } - - if (hoveredItem === null) { - return false; + protected readonly toMarkers = ( + day: TuiDay, + today: boolean, + inRange: boolean, + markerHandler: TuiMarkerHandler, + ): [string, string] | [string] | null => { + if (today || inRange) { + return null; } - const range = TuiDayRange.sort(value.from, hoveredItem); + const markers = markerHandler(day); - return range.from.daySameOrBefore(day) && range.to.dayAfter(day); - } + return markers.length === 0 ? null : markers; + }; - public onItemHovered(item: TuiDay | false): void { - this.updateHoveredItem(item || null); + protected itemIsToday(item: TuiDay): boolean { + return this.today.daySame(item); } - public onItemPressed(item: TuiDay | false): void { - this.pressedItem = item || null; + protected itemIsUnavailable(item: TuiDay): boolean { + return !this.month.monthSame(item); } protected onItemClick(item: TuiDay): void { diff --git a/projects/core/components/primitive-checkbox/primitive-checkbox.component.ts b/projects/core/components/primitive-checkbox/primitive-checkbox.component.ts index cd1141646dc6..48f8091eb66f 100644 --- a/projects/core/components/primitive-checkbox/primitive-checkbox.component.ts +++ b/projects/core/components/primitive-checkbox/primitive-checkbox.component.ts @@ -39,6 +39,11 @@ export class TuiPrimitiveCheckboxComponent { @Input() public invalid = false; + protected icon: PolymorpheusContent> = + this.options.icons.checked; + + protected value: boolean | null = false; + @Input('value') public set valueSetter(value: boolean | null) { if (value !== false) { @@ -48,11 +53,6 @@ export class TuiPrimitiveCheckboxComponent { this.value = value; } - protected icon: PolymorpheusContent> = - this.options.icons.checked; - - protected value: boolean | null = false; - protected get appearance(): string { switch (this.value) { case false: diff --git a/projects/core/components/primitive-spin-button/primitive-spin-button.component.ts b/projects/core/components/primitive-spin-button/primitive-spin-button.component.ts index b2705cd81dc6..591e2c791e70 100644 --- a/projects/core/components/primitive-spin-button/primitive-spin-button.component.ts +++ b/projects/core/components/primitive-spin-button/primitive-spin-button.component.ts @@ -45,14 +45,6 @@ export class TuiPrimitiveSpinButtonComponent extends AbstractTuiInteractive { return tuiIsNativeFocusedIn(this.el); } - protected get leftComputedDisabled(): boolean { - return this.computedDisabled || this.leftDisabled; - } - - protected get rightComputedDisabled(): boolean { - return this.computedDisabled || this.rightDisabled; - } - @HostListener('keydown.arrowLeft.prevent') public onLeftClick(): void { if (!this.leftComputedDisabled) { @@ -73,6 +65,14 @@ export class TuiPrimitiveSpinButtonComponent extends AbstractTuiInteractive { this.updateFocused(focused); } + protected get leftComputedDisabled(): boolean { + return this.computedDisabled || this.leftDisabled; + } + + protected get rightComputedDisabled(): boolean { + return this.computedDisabled || this.rightDisabled; + } + protected onFocusVisible(focusVisible: boolean): void { this.updateFocusVisible(focusVisible); } diff --git a/projects/core/components/primitive-textfield/primitive-textfield.component.ts b/projects/core/components/primitive-textfield/primitive-textfield.component.ts index cf010ce8a9fa..e4bed852cb27 100644 --- a/projects/core/components/primitive-textfield/primitive-textfield.component.ts +++ b/projects/core/components/primitive-textfield/primitive-textfield.component.ts @@ -60,11 +60,9 @@ export class TuiPrimitiveTextfieldComponent @ViewChild('focusableElement') private readonly focusableElement?: ElementRef; + private readonly options = inject(TUI_TEXTFIELD_OPTIONS); private readonly el: HTMLElement = inject(ElementRef).nativeElement; - protected readonly hintOptions = inject(TuiHintOptionsDirective, {optional: true}); - protected readonly options = inject(TUI_TEXTFIELD_OPTIONS); - @Input() public editable = true; @@ -94,6 +92,7 @@ export class TuiPrimitiveTextfieldComponent @ContentChildren(PolymorpheusOutletDirective, {descendants: true}) protected readonly content?: QueryList; + protected readonly hintOptions = inject(TuiHintOptionsDirective, {optional: true}); protected autofilled = false; protected readonly controller = inject(TUI_TEXTFIELD_WATCHED_CONTROLLER); @@ -129,6 +128,10 @@ export class TuiPrimitiveTextfieldComponent return this.controller.appearance; } + public onModelChange(value: string): void { + this.updateValue(value); + } + @HostBinding('attr.data-size') protected get size(): TuiSizeL | TuiSizeS { return this.controller.size; @@ -144,6 +147,22 @@ export class TuiPrimitiveTextfieldComponent return !!this.content?.length; } + @HostBinding('style.--border-start.rem') + protected get borderStart(): number { + return this.iconLeftContent ? this.iconPaddingLeft : 0; + } + + @HostBinding('style.--border-end.rem') + protected get borderEnd(): number { + return tuiGetBorder( + !!this.iconContent, + this.hasCleaner, + this.hasTooltip, + this.hasCustomContent, + this.size, + ); + } + protected get hasValue(): boolean { return !!this.value; } @@ -187,22 +206,6 @@ export class TuiPrimitiveTextfieldComponent ); } - @HostBinding('style.--border-start.rem') - protected get borderStart(): number { - return this.iconLeftContent ? this.iconPaddingLeft : 0; - } - - @HostBinding('style.--border-end.rem') - protected get borderEnd(): number { - return tuiGetBorder( - !!this.iconContent, - this.hasCleaner, - this.hasTooltip, - this.hasCustomContent, - this.size, - ); - } - protected get iconContent(): PolymorpheusContent> { return this.controller.icon; } @@ -263,10 +266,6 @@ export class TuiPrimitiveTextfieldComponent nativeFocusableElement.focus(); } - public onModelChange(value: string): void { - this.updateValue(value); - } - protected onAutofilled(autofilled: boolean): void { this.updateAutofilled(autofilled); } diff --git a/projects/core/components/primitive-textfield/value-decoration/value-decoration.component.ts b/projects/core/components/primitive-textfield/value-decoration/value-decoration.component.ts index 46fea40e31ba..53fcbcb77eb7 100644 --- a/projects/core/components/primitive-textfield/value-decoration/value-decoration.component.ts +++ b/projects/core/components/primitive-textfield/value-decoration/value-decoration.component.ts @@ -41,15 +41,16 @@ export class TuiValueDecorationComponent implements DoCheck { distinctUntilChanged(), ); + @HostListener('animationstart') + public ngDoCheck(): void { + this.prefix$.next(this.prefix); + } + @HostBinding('class._table') protected get isContextTable(): boolean { return this.textfield.appearance === TuiAppearance.Table; } - protected get value(): string { - return this.textfield.value; - } - @HostBinding('class._filler') protected get filler(): string { const {focused, placeholder, exampleText, value, textfield} = this; @@ -61,6 +62,10 @@ export class TuiValueDecorationComponent implements DoCheck { return focused ? exampleText || textfield.filler.slice(value.length) : ''; } + protected get value(): string { + return this.textfield.value; + } + protected get prefix(): string { return this.decorationsVisible ? this.textfield.prefix : ''; } @@ -69,11 +74,6 @@ export class TuiValueDecorationComponent implements DoCheck { return this.decorationsVisible ? this.computedPostfix : ''; } - @HostListener('animationstart') - public ngDoCheck(): void { - this.prefix$.next(this.prefix); - } - private get placeholder(): string { return this.textfield.nativeFocusableElement?.placeholder || ''; } diff --git a/projects/core/components/primitive-year-picker/primitive-year-picker.component.ts b/projects/core/components/primitive-year-picker/primitive-year-picker.component.ts index d95cbb7ecbc2..6a4f72c83da3 100644 --- a/projects/core/components/primitive-year-picker/primitive-year-picker.component.ts +++ b/projects/core/components/primitive-year-picker/primitive-year-picker.component.ts @@ -52,51 +52,6 @@ export class TuiPrimitiveYearPickerComponent { @Output() public readonly yearClick = new EventEmitter(); - protected get computedMin(): TuiYear { - return this.min ?? TUI_FIRST_DAY; - } - - protected get computedMax(): TuiYear { - return this.max ?? TUI_LAST_DAY; - } - - @HostBinding('class._single') - protected get isSingle(): boolean { - return this.isRange(this.value) && this.value.from.yearSame(this.value.to); - } - - protected get rows(): number { - return Math.ceil((this.calculatedMax - this.calculatedMin) / ITEMS_IN_ROW); - } - - protected get calculatedMin(): number { - const initial = this.initialItem.year - LIMIT; - const min = this.computedMin; - - return min.year > initial ? min.year : initial; - } - - protected get calculatedMax(): number { - const initial = this.initialItem.year + LIMIT; - const max = this.computedMax; - - return max.year < initial ? max.year + 1 : initial; - } - - protected isRange( - item: TuiMonthRange | TuiYear | readonly TuiDay[] | null, - ): item is TuiMonthRange { - return item instanceof TuiMonthRange; - } - - protected scrollItemIntoView(item: number): boolean { - return this.initialItem.year === item; - } - - protected getItem(rowIndex: number, colIndex: number): number { - return rowIndex * ITEMS_IN_ROW + colIndex + this.calculatedMin; - } - public getItemState(item: number): TuiInteractiveState | null { const {disabledItemHandler, pressedItem, hoveredItem} = this; const max = this.computedMax; @@ -167,10 +122,6 @@ export class TuiPrimitiveYearPickerComponent { : null; } - protected itemIsToday(item: number): boolean { - return this.currentYear === item; - } - public itemIsInterval(item: number): boolean { const {value, hoveredItem} = this; @@ -205,6 +156,55 @@ export class TuiPrimitiveYearPickerComponent { this.yearClick.emit(new TuiYear(item)); } + @HostBinding('class._single') + protected get isSingle(): boolean { + return this.isRange(this.value) && this.value.from.yearSame(this.value.to); + } + + protected get computedMin(): TuiYear { + return this.min ?? TUI_FIRST_DAY; + } + + protected get computedMax(): TuiYear { + return this.max ?? TUI_LAST_DAY; + } + + protected get rows(): number { + return Math.ceil((this.calculatedMax - this.calculatedMin) / ITEMS_IN_ROW); + } + + protected get calculatedMin(): number { + const initial = this.initialItem.year - LIMIT; + const min = this.computedMin; + + return min.year > initial ? min.year : initial; + } + + protected get calculatedMax(): number { + const initial = this.initialItem.year + LIMIT; + const max = this.computedMax; + + return max.year < initial ? max.year + 1 : initial; + } + + protected isRange( + item: TuiMonthRange | TuiYear | readonly TuiDay[] | null, + ): item is TuiMonthRange { + return item instanceof TuiMonthRange; + } + + protected scrollItemIntoView(item: number): boolean { + return this.initialItem.year === item; + } + + protected getItem(rowIndex: number, colIndex: number): number { + return rowIndex * ITEMS_IN_ROW + colIndex + this.calculatedMin; + } + + protected itemIsToday(item: number): boolean { + return this.currentYear === item; + } + private updateHoveredItem(hovered: boolean, item: number): void { this.hoveredItem = hovered ? item : null; } diff --git a/projects/core/components/scroll-controls/scrollbar.directive.ts b/projects/core/components/scroll-controls/scrollbar.directive.ts index 675ae94c6d5e..12427f41e1ff 100644 --- a/projects/core/components/scroll-controls/scrollbar.directive.ts +++ b/projects/core/components/scroll-controls/scrollbar.directive.ts @@ -17,6 +17,9 @@ export class TuiScrollbarDirective { private readonly el: HTMLElement = inject(TUI_SCROLL_REF).nativeElement; private readonly style: CSSStyleDeclaration = inject(ElementRef).nativeElement.style; + @Input() + public tuiScrollbar: 'horizontal' | 'vertical' = 'vertical'; + protected readonly scrollSub = inject(TuiScrollbarService) .pipe(takeUntil(inject(TuiDestroyService))) .subscribe(([top, left]) => { @@ -40,9 +43,6 @@ export class TuiScrollbarDirective { } }); - @Input() - public tuiScrollbar: 'horizontal' | 'vertical' = 'vertical'; - private get scrolled(): number { const { scrollTop, diff --git a/projects/core/components/scrollbar/scrollbar.component.ts b/projects/core/components/scrollbar/scrollbar.component.ts index 3e74f9348e13..28be99833a0a 100644 --- a/projects/core/components/scrollbar/scrollbar.component.ts +++ b/projects/core/components/scrollbar/scrollbar.component.ts @@ -30,11 +30,11 @@ import {TUI_SCROLL_REF} from '@taiga-ui/core/tokens'; export class TuiScrollbarComponent { private readonly el: HTMLElement = inject(ElementRef).nativeElement; - protected readonly isIOS = inject(TUI_IS_IOS); - @Input() public hidden = false; + protected readonly isIOS = inject(TUI_IS_IOS); + protected readonly browserScrollRef = new ElementRef(this.el); protected get delegated(): boolean { diff --git a/projects/core/components/svg/svg.component.ts b/projects/core/components/svg/svg.component.ts index b3bcce073f2c..11d43eb1f373 100644 --- a/projects/core/components/svg/svg.component.ts +++ b/projects/core/components/svg/svg.component.ts @@ -115,6 +115,20 @@ export class TuiSvgComponent { ); } + protected onError(message: string = MISSING_EXTERNAL_ICON): void { + const {icon} = this; + const event = new CustomEvent(TUI_ICON_ERROR, { + bubbles: true, + detail: { + message, + icon: icon as string, + }, + }); + + ngDevMode && tuiAssert.assert(false, message, icon); + this.el.dispatchEvent(event); + } + private get isShadowDOM(): boolean { return tuiGetDocumentOrShadowRoot(this.el) !== this.doc; } @@ -150,20 +164,6 @@ export class TuiSvgComponent { ); } - protected onError(message: string = MISSING_EXTERNAL_ICON): void { - const {icon} = this; - const event = new CustomEvent(TUI_ICON_ERROR, { - bubbles: true, - detail: { - message, - icon: icon as string, - }, - }); - - ngDevMode && tuiAssert.assert(false, message, icon); - this.el.dispatchEvent(event); - } - @tuiPure private resolveName(name: string, iconsPath: TuiSvgOptions['path']): string { return iconsPath(name, this.baseHref); diff --git a/projects/core/components/tooltip/tooltip.component.ts b/projects/core/components/tooltip/tooltip.component.ts index 55f2a7392750..b4467d5f156d 100644 --- a/projects/core/components/tooltip/tooltip.component.ts +++ b/projects/core/components/tooltip/tooltip.component.ts @@ -26,15 +26,15 @@ export class TuiTooltipComponent extends TuiHintOptionsDirective { private readonly isMobile = inject(TUI_IS_MOBILE); private mode: TuiBrightness | null = null; - @ViewChild(TuiHintHoverDirective) - protected readonly driver$?: TuiHintHoverDirective; - @Input() public describeId = ''; @Input() public context?: C; + @ViewChild(TuiHintHoverDirective) + protected readonly driver$?: TuiHintHoverDirective; + constructor() { super(); diff --git a/projects/core/directives/dropdown/dropdown-context.directive.ts b/projects/core/directives/dropdown/dropdown-context.directive.ts index fdd59d6799d9..e41b0f876fc9 100644 --- a/projects/core/directives/dropdown/dropdown-context.directive.ts +++ b/projects/core/directives/dropdown/dropdown-context.directive.ts @@ -27,9 +27,14 @@ export class TuiDropdownContextDirective extends TuiRectAccessor { private readonly driver = inject(TuiDropdownDriver); private currentRect = EMPTY_CLIENT_RECT; - protected readonly activeZone = inject(TuiActiveZoneDirective); public readonly type = 'dropdown'; + protected readonly activeZone = inject(TuiActiveZoneDirective); + + public getClientRect(): DOMRect { + return this.currentRect; + } + @HostListener('contextmenu.prevent.stop', ['$event.clientX', '$event.clientY']) protected onContextMenu(x: number, y: number): void { this.currentRect = tuiPointToClientRect(x, y); @@ -43,8 +48,4 @@ export class TuiDropdownContextDirective extends TuiRectAccessor { protected closeDropdown(): void { this.driver.next(false); } - - public getClientRect(): DOMRect { - return this.currentRect; - } } diff --git a/projects/core/directives/dropdown/dropdown-open.directive.ts b/projects/core/directives/dropdown/dropdown-open.directive.ts index 88d8d518d23b..96dc77a7ab28 100644 --- a/projects/core/directives/dropdown/dropdown-open.directive.ts +++ b/projects/core/directives/dropdown/dropdown-open.directive.ts @@ -98,6 +98,18 @@ export class TuiDropdownOpenDirective implements OnChanges { return this.directive?.dropdownBoxRef?.location.nativeElement; } + public ngOnChanges(): void { + this.drive(); + } + + public toggle(open: boolean): void { + if (this.focused && !open) { + this.host.focus({preventScroll: true}); + } + + this.update(open); + } + @HostListener('click', ['$event.target', '$event.defaultPrevented']) protected onClick(target: HTMLElement, prevented: boolean): void { if (!this.editable && !prevented && this.host.contains(target)) { @@ -140,18 +152,6 @@ export class TuiDropdownOpenDirective implements OnChanges { this.host.focus({preventScroll: true}); } - public ngOnChanges(): void { - this.drive(); - } - - public toggle(open: boolean): void { - if (this.focused && !open) { - this.host.focus({preventScroll: true}); - } - - this.update(open); - } - private get host(): HTMLElement { const initial = this.dropdownHost?.nativeElement || this.el; const focusable = tuiIsNativeKeyboardFocusable(initial) diff --git a/projects/core/directives/dropdown/dropdown-selection.directive.ts b/projects/core/directives/dropdown/dropdown-selection.directive.ts index 40aa0e9c6d00..055cc1d201f2 100644 --- a/projects/core/directives/dropdown/dropdown-selection.directive.ts +++ b/projects/core/directives/dropdown/dropdown-selection.directive.ts @@ -80,6 +80,12 @@ export class TuiDropdownSelectionDirective @Input('tuiDropdownSelectionPosition') public position: 'selection' | 'tag' | 'word' = 'selection'; + public readonly type = 'dropdown'; + + constructor() { + super(subscriber => this.stream$.subscribe(subscriber)); + } + @Input() public set tuiDropdownSelection(visible: TuiBooleanHandler | string) { if (!tuiIsString(visible)) { @@ -87,12 +93,6 @@ export class TuiDropdownSelectionDirective } } - public readonly type = 'dropdown'; - - constructor() { - super(subscriber => this.stream$.subscribe(subscriber)); - } - public getClientRect(): DOMRect { switch (this.position) { case 'tag': { diff --git a/projects/core/directives/dropdown/dropdown.directive.ts b/projects/core/directives/dropdown/dropdown.directive.ts index f04f88069c18..eb6ecf2983aa 100644 --- a/projects/core/directives/dropdown/dropdown.directive.ts +++ b/projects/core/directives/dropdown/dropdown.directive.ts @@ -61,16 +61,6 @@ export class TuiDropdownDirective private readonly service = inject(TuiDropdownService); private readonly cdr = inject(ChangeDetectorRef); - @Input() - public set tuiDropdown( - content: PolymorpheusContent>, - ) { - this.content = - content instanceof TemplateRef - ? new PolymorpheusTemplate(content, this.cdr) - : content; - } - public readonly el: HTMLElement = inject(ElementRef).nativeElement; public readonly type = 'dropdown'; public readonly component = new PolymorpheusComponent( @@ -88,6 +78,16 @@ export class TuiDropdownDirective this.dropdownBoxRef?.changeDetectorRef.markForCheck(); }); + @Input() + public set tuiDropdown( + content: PolymorpheusContent>, + ) { + this.content = + content instanceof TemplateRef + ? new PolymorpheusTemplate(content, this.cdr) + : content; + } + @tuiPure public get position(): 'absolute' | 'fixed' { return tuiCheckFixedPosition(this.el) ? 'fixed' : 'absolute'; diff --git a/projects/core/directives/hint/hint-describe.directive.ts b/projects/core/directives/hint/hint-describe.directive.ts index 06361735e2e4..af594f3e965d 100644 --- a/projects/core/directives/hint/hint-describe.directive.ts +++ b/projects/core/directives/hint/hint-describe.directive.ts @@ -62,12 +62,12 @@ export class TuiHintDescribeDirective extends TuiDriver implements OnChanges { this.id$.next(this.tuiHintDescribe); } - private get focused(): boolean { - return tuiIsNativeFocused(this.element); - } - @tuiPure private get element(): HTMLElement { return this.doc.getElementById(this.tuiHintDescribe || '') || this.el; } + + private get focused(): boolean { + return tuiIsNativeFocused(this.element); + } } diff --git a/projects/core/directives/hint/hint-options.directive.ts b/projects/core/directives/hint/hint-options.directive.ts index 7055fa86105d..e667a51049d8 100644 --- a/projects/core/directives/hint/hint-options.directive.ts +++ b/projects/core/directives/hint/hint-options.directive.ts @@ -58,7 +58,7 @@ export class TuiHintOptionsDirective extends AbstractTuiController implements TuiHintOptions { - protected readonly options = inject(TUI_HINT_OPTIONS, {skipSelf: true}); + private readonly options = inject(TUI_HINT_OPTIONS, {skipSelf: true}); @Input('tuiHintContent') public content: PolymorpheusContent; diff --git a/projects/core/directives/hint/hint-pointer.directive.ts b/projects/core/directives/hint/hint-pointer.directive.ts index 4be9ead1acdb..595af9d55062 100644 --- a/projects/core/directives/hint/hint-pointer.directive.ts +++ b/projects/core/directives/hint/hint-pointer.directive.ts @@ -17,12 +17,12 @@ export class TuiHintPointerDirective { private currentRect = EMPTY_CLIENT_RECT; + public getClientRect(): ClientRect { + return this.currentRect; + } + @HostListener('mousemove.silent', ['$event']) protected onMove({clientX, clientY}: MouseEvent): void { this.currentRect = tuiPointToClientRect(clientX, clientY); } - - public getClientRect(): ClientRect { - return this.currentRect; - } } diff --git a/projects/core/directives/hint/hint.component.ts b/projects/core/directives/hint/hint.component.ts index 1c5f424faeba..4b3c6c6be47f 100644 --- a/projects/core/directives/hint/hint.component.ts +++ b/projects/core/directives/hint/hint.component.ts @@ -71,7 +71,6 @@ export class TuiHintComponent { private readonly mode = inject(TuiModeDirective, {optional: true}); private readonly visualViewportService = inject(TuiVisualViewportService); private readonly viewport = inject(TUI_VIEWPORT); - protected readonly accessor = inject(TuiRectAccessor); @HostBinding('attr.data-appearance') protected readonly appearance = @@ -79,6 +78,7 @@ export class TuiHintComponent { protected readonly options = tuiToAnimationOptions(inject(TUI_ANIMATIONS_SPEED)); protected readonly pointer = inject(TuiHintPointerDirective, {optional: true}); + protected readonly accessor = inject(TuiRectAccessor); constructor() { inject(TuiPositionService) diff --git a/projects/core/directives/icons/icons.directive.ts b/projects/core/directives/icons/icons.directive.ts index f573f6c6d358..ddf0df86216c 100644 --- a/projects/core/directives/icons/icons.directive.ts +++ b/projects/core/directives/icons/icons.directive.ts @@ -16,13 +16,13 @@ import {TuiIconsComponent} from './icons.component'; }, }) export class TuiIconsDirective { - protected readonly nothing = tuiWithStyles(TuiIconsComponent); - @Input() public iconLeft = ''; @Input() public iconRight = ''; + protected readonly nothing = tuiWithStyles(TuiIconsComponent); + protected readonly resolver = inject>(TUI_ICON_RESOLVER); } diff --git a/projects/core/directives/number-format/number-format.directive.ts b/projects/core/directives/number-format/number-format.directive.ts index 9a18c2e1957c..b38976d3a9d8 100644 --- a/projects/core/directives/number-format/number-format.directive.ts +++ b/projects/core/directives/number-format/number-format.directive.ts @@ -16,11 +16,6 @@ export class TuiNumberFormatDirective extends Observable>(1); private readonly parent = inject(TUI_NUMBER_FORMAT, {skipSelf: true}); - @Input() - public set tuiNumberFormat(format: Partial) { - this.settings.next(format); - } - constructor() { super(subscriber => combineLatest([this.parent, this.settings]) @@ -28,4 +23,9 @@ export class TuiNumberFormatDirective extends Observable) { + this.settings.next(format); + } } diff --git a/projects/core/internal/primitive-year-month-pagination/primitive-year-month-pagination.component.ts b/projects/core/internal/primitive-year-month-pagination/primitive-year-month-pagination.component.ts index 19101bcc956a..fbd897615ad2 100644 --- a/projects/core/internal/primitive-year-month-pagination/primitive-year-month-pagination.component.ts +++ b/projects/core/internal/primitive-year-month-pagination/primitive-year-month-pagination.component.ts @@ -38,14 +38,6 @@ export class TuiPrimitiveYearMonthPaginationComponent @Output() public readonly yearClick = new EventEmitter(); - protected get computedMin(): TuiMonth { - return this.min ?? TUI_FIRST_DAY; - } - - protected get computedMax(): TuiMonth { - return this.max ?? TUI_LAST_DAY; - } - public get prevMonthDisabled(): boolean { return this.value.monthSameOrBefore(this.computedMin); } @@ -54,12 +46,6 @@ export class TuiPrimitiveYearMonthPaginationComponent return this.value.monthSameOrAfter(this.computedMax); } - protected get oneYear(): boolean { - const {computedMin, computedMax} = this; - - return computedMin.year === computedMax.year; - } - public onYearClick(): void { this.yearClick.next(this.value); } @@ -72,6 +58,20 @@ export class TuiPrimitiveYearMonthPaginationComponent this.appendValueWithLimit({month: 1}); } + protected get computedMin(): TuiMonth { + return this.min ?? TUI_FIRST_DAY; + } + + protected get computedMax(): TuiMonth { + return this.max ?? TUI_LAST_DAY; + } + + protected get oneYear(): boolean { + const {computedMin, computedMax} = this; + + return computedMin.year === computedMax.year; + } + private appendValueWithLimit(date: TuiMonthLike): void { const newMonth: TuiMonth = this.value.append(date); const {computedMin, computedMax} = this; diff --git a/projects/demo-cypress/src/tests/mobile-calendar.cy.ts b/projects/demo-cypress/src/tests/mobile-calendar.cy.ts index 9da475069e5c..e8bbee3b7d51 100644 --- a/projects/demo-cypress/src/tests/mobile-calendar.cy.ts +++ b/projects/demo-cypress/src/tests/mobile-calendar.cy.ts @@ -45,11 +45,12 @@ describe('Mobile calendar', () => { public calendar!: TuiMobileCalendarComponent; public single = true; + public onCancel = new EventEmitter(); + public onConfirm = new EventEmitter(); + protected min = TUI_FIRST_DAY; protected max = TUI_LAST_DAY; protected disabledItemHandler = ALWAYS_FALSE_HANDLER; - public onCancel = new EventEmitter(); - public onConfirm = new EventEmitter(); } it('the back button emits a cancel event', () => { diff --git a/projects/demo-cypress/src/tests/range.cy.ts b/projects/demo-cypress/src/tests/range.cy.ts index ef0a3eb63373..c14c44a72aff 100644 --- a/projects/demo-cypress/src/tests/range.cy.ts +++ b/projects/demo-cypress/src/tests/range.cy.ts @@ -23,9 +23,6 @@ describe('TuiRange', () => { `, }) class TestComponent { - @ViewChild(TuiRangeComponent, {static: true}) - protected component!: TuiRangeComponent; - @ViewChild(TuiRangeComponent, {static: true, read: ElementRef}) public el!: ElementRef; @@ -35,6 +32,9 @@ describe('TuiRange', () => { public segments = 10; public step = 1; public keySteps: TuiKeySteps | null = null; + + @ViewChild(TuiRangeComponent, {static: true}) + protected component!: TuiRangeComponent; } beforeEach(() => { diff --git a/projects/demo/src/modules/app/classes/ts-file.parser.ts b/projects/demo/src/modules/app/classes/ts-file.parser.ts index 3c554c375886..1adf3cebf877 100644 --- a/projects/demo/src/modules/app/classes/ts-file.parser.ts +++ b/projects/demo/src/modules/app/classes/ts-file.parser.ts @@ -1,6 +1,16 @@ import {TuiTsParserException} from '@taiga-ui/cdk'; export class TsFileParser { + constructor(protected rawFileContent: string) { + const classesInside = rawFileContent.match(/export class/gi) || []; + + if (classesInside.length > 1) { + throw new TuiTsParserException(); + } + + this.replaceMetaAssets(); + } + public get className(): string { const [, className] = this.rawFileContent.match(/(?:export class\s)(\w*)/i) || []; @@ -22,16 +32,6 @@ export class TsFileParser { return this.rawFileContent.includes('@Component'); } - constructor(protected rawFileContent: string) { - const classesInside = rawFileContent.match(/export class/gi) || []; - - if (classesInside.length > 1) { - throw new TuiTsParserException(); - } - - this.replaceMetaAssets(); - } - public addImport(entity: string, packageOrPath: string): void { const fromName = packageOrPath.replace('.ts', ''); diff --git a/projects/demo/src/modules/app/customization/customization.component.ts b/projects/demo/src/modules/app/customization/customization.component.ts index e188d5794685..4352dbf68481 100644 --- a/projects/demo/src/modules/app/customization/customization.component.ts +++ b/projects/demo/src/modules/app/customization/customization.component.ts @@ -28,6 +28,16 @@ export class TuiCustomizationComponent implements AfterViewInit { protected readonly change$ = new Subject(); + public ngAfterViewInit(): void { + if (!this.demo) { + return; + } + + this.demo.change$ + .pipe(takeUntil(this.destroy$)) + .subscribe(() => this.change$.next()); + } + protected get style(): SafeStyle { return this.getStyle(this.sanitizer, this.stringify(this.variables)); } @@ -52,16 +62,6 @@ export class TuiCustomizationComponent implements AfterViewInit { return this.demo?.mode || null; } - public ngAfterViewInit(): void { - if (!this.demo) { - return; - } - - this.demo.change$.pipe(takeUntil(this.destroy$)).subscribe(() => { - this.change$.next(); - }); - } - protected isLight(key: string): boolean { return key.includes('onDark'); } diff --git a/projects/demo/src/modules/app/landing/landing.component.ts b/projects/demo/src/modules/app/landing/landing.component.ts index 8a6243eea281..84f04e8f0833 100644 --- a/projects/demo/src/modules/app/landing/landing.component.ts +++ b/projects/demo/src/modules/app/landing/landing.component.ts @@ -60,15 +60,15 @@ export default class LandingComponent implements OnInit { await this.clearQueryParams(); } - protected get hidden(): boolean { - return !!this.storage.getItem('env'); - } - @HostBinding('style.background') protected get background(): string { return this.current ? '#5f6ed0' : '#3dc67c'; } + protected get hidden(): boolean { + return !!this.storage.getItem('env'); + } + protected onIntersection( [{isIntersecting, target}]: IntersectionObserverEntry[], index: number, diff --git a/projects/demo/src/modules/components/checkbox/checkbox.component.ts b/projects/demo/src/modules/components/checkbox/checkbox.component.ts index 55a23adf7381..cc1212a9425f 100644 --- a/projects/demo/src/modules/components/checkbox/checkbox.component.ts +++ b/projects/demo/src/modules/components/checkbox/checkbox.component.ts @@ -19,6 +19,16 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr ], }) export class ExampleTuiCheckboxComponent extends AbstractExampleTuiControl { + public override readonly sizeVariants: readonly TuiSizeL[] = ['m', 'l']; + + public override size: TuiSizeL = this.sizeVariants[0]; + + public readonly control = new FormGroup({ + testValue1: new FormControl(false), + testValue2: new FormControl(null), + testValue3: new FormControl(true), + }); + protected readonly exampleForm = import('./examples/import/declare-form.md?raw'); protected readonly exampleOptions = import('./examples/import/define-options.md?raw'); protected readonly exampleModule = import('./examples/import/import-module.md?raw'); @@ -33,14 +43,4 @@ export class ExampleTuiCheckboxComponent extends AbstractExampleTuiControl { TypeScript: import('./examples/2/index.ts?raw'), HTML: import('./examples/2/index.html?raw'), }; - - public override readonly sizeVariants: readonly TuiSizeL[] = ['m', 'l']; - - public override size: TuiSizeL = this.sizeVariants[0]; - - public readonly control = new FormGroup({ - testValue1: new FormControl(false), - testValue2: new FormControl(null), - testValue3: new FormControl(true), - }); } diff --git a/projects/demo/src/modules/components/combo-box/combo-box.component.ts b/projects/demo/src/modules/components/combo-box/combo-box.component.ts index 276ecc109735..84f9b6205b9d 100644 --- a/projects/demo/src/modules/components/combo-box/combo-box.component.ts +++ b/projects/demo/src/modules/components/combo-box/combo-box.component.ts @@ -47,6 +47,12 @@ export class ExampleTuiComboBoxComponent extends AbstractExampleTuiControl { TuiValueContentContext >; + public readonly control = new FormControl(null, Validators.required); + + public readonly iconVariants = ['', 'tuiIconPieChartLarge', 'tuiIconCreditCardLarge']; + + public override iconLeft = this.iconVariants[0]; + protected readonly exampleForm = import('./examples/import/declare-form.md?raw'); protected readonly exampleModule = import('./examples/import/import-module.md?raw'); @@ -114,14 +120,6 @@ export class ExampleTuiComboBoxComponent extends AbstractExampleTuiControl { protected selectedValueTemplate = ''; - protected readonly iconVariants = [ - '', - 'tuiIconPieChartLarge', - 'tuiIconCreditCardLarge', - ]; - - public override iconLeft = this.iconVariants[0]; - protected readonly stringifyVariants: Array> = [ TUI_DEFAULT_STRINGIFY, item => String(String(item).match(/\d+/)), @@ -147,8 +145,6 @@ export class ExampleTuiComboBoxComponent extends AbstractExampleTuiControl { protected identityMatcher = this.identityMatcherVariants[0]; - public readonly control = new FormControl(null, Validators.required); - protected get valueContent(): PolymorpheusContent> { return this.valueTemplateRef && this.selectedValueTemplate ? this.valueTemplateRef diff --git a/projects/demo/src/modules/components/hosted-dropdown/examples/4/index.ts b/projects/demo/src/modules/components/hosted-dropdown/examples/4/index.ts index beb04e002843..9cedcf0457b1 100644 --- a/projects/demo/src/modules/components/hosted-dropdown/examples/4/index.ts +++ b/projects/demo/src/modules/components/hosted-dropdown/examples/4/index.ts @@ -21,10 +21,6 @@ export class TuiHostedDropdownExample4 { protected readonly arrow = TUI_ARROW; - private get value(): readonly string[] { - return this.form.get('control')?.value || []; - } - protected get appearance(): string { return this.length ? 'whiteblock-active' : 'whiteblock'; } @@ -43,4 +39,8 @@ export class TuiHostedDropdownExample4 { return `${this.length} selected`; } } + + private get value(): readonly string[] { + return this.form.get('control')?.value || []; + } } diff --git a/projects/demo/src/modules/components/input-card/input-card.component.ts b/projects/demo/src/modules/components/input-card/input-card.component.ts index 40c69e24a1cd..7b383ed310b6 100644 --- a/projects/demo/src/modules/components/input-card/input-card.component.ts +++ b/projects/demo/src/modules/components/input-card/input-card.component.ts @@ -24,6 +24,19 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr ], }) export class ExampleTuiInputCardComponent extends AbstractExampleTuiControl { + public control = new FormGroup({ + card: new FormControl('', [ + Validators.required, + tuiCreateLuhnValidator('Invalid card number'), + ]), + expire: new FormControl('', Validators.required), + cvc: new FormControl('', Validators.required), + }); + + public override cleaner = false; + + public override exampleText = '0000 0000 0000 0000'; + @ViewChild('documentationPropertyBinChange', { read: TuiDocDocumentationPropertyConnectorDirective, }) @@ -43,10 +56,6 @@ export class ExampleTuiInputCardComponent extends AbstractExampleTuiControl { protected length = this.lengthVariants[0]; - public override cleaner = false; - - public override exampleText = '0000 0000 0000 0000'; - protected hintContentCVC = null; protected hintDirectionCVC: TuiHintOptions['direction'] = 'bottom-left'; @@ -72,15 +81,6 @@ export class ExampleTuiInputCardComponent extends AbstractExampleTuiControl { protected autocompleteEnabledExpire = false; - public control = new FormGroup({ - card: new FormControl('', [ - Validators.required, - tuiCreateLuhnValidator('Invalid card number'), - ]), - expire: new FormControl('', Validators.required), - cvc: new FormControl('', Validators.required), - }); - protected get cardSrc(): string | null { return this.cardSrcSelected === null ? null : this.cards[this.cardSrcSelected]; } diff --git a/projects/demo/src/modules/components/input-copy/input-copy.component.ts b/projects/demo/src/modules/components/input-copy/input-copy.component.ts index 55632bbc5dc8..5885317a5345 100644 --- a/projects/demo/src/modules/components/input-copy/input-copy.component.ts +++ b/projects/demo/src/modules/components/input-copy/input-copy.component.ts @@ -20,6 +20,12 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr ], }) export class ExampleTuiInputCopyComponent extends AbstractExampleTuiControl { + public readonly control = new FormControl('', Validators.required); + + public override readonly maxLengthVariants: readonly number[] = [10]; + + public override readonly maxLength = null; + @ViewChild('customTemplate') protected customTemplate: PolymorpheusContent; @@ -32,12 +38,6 @@ export class ExampleTuiInputCopyComponent extends AbstractExampleTuiControl { protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); protected readonly exampleForm = import('./examples/import/declare-form.md?raw'); - public readonly control = new FormControl('', Validators.required); - - public override readonly maxLengthVariants: readonly number[] = [10]; - - public override readonly maxLength = null; - protected readonly successMessageVariants = ['Copied', 'Template']; protected successMessage = this.successMessageVariants[0]; diff --git a/projects/demo/src/modules/components/input-date-multi/input-date-multi.component.ts b/projects/demo/src/modules/components/input-date-multi/input-date-multi.component.ts index ea0837411988..2c653bff2a69 100644 --- a/projects/demo/src/modules/components/input-date-multi/input-date-multi.component.ts +++ b/projects/demo/src/modules/components/input-date-multi/input-date-multi.component.ts @@ -26,6 +26,8 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr ], }) export class ExampleTuiInputDateMultiComponent extends AbstractExampleTuiControl { + public control = new FormControl([], Validators.required); + protected readonly exampleForm = import('./examples/import/declare-form.md?raw'); protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); @@ -72,6 +74,4 @@ export class ExampleTuiInputDateMultiComponent extends AbstractExampleTuiControl ]; protected markerHandler: TuiMarkerHandler = this.markerHandlerVariants[0]; - - public control = new FormControl([], Validators.required); } diff --git a/projects/demo/src/modules/components/input-date-range/input-date-range.component.ts b/projects/demo/src/modules/components/input-date-range/input-date-range.component.ts index dffc307bc550..6f1164568bb5 100644 --- a/projects/demo/src/modules/components/input-date-range/input-date-range.component.ts +++ b/projects/demo/src/modules/components/input-date-range/input-date-range.component.ts @@ -33,6 +33,17 @@ const ONE_DOT: [string] = ['var(--tui-success-fill)']; ], }) export class ExampleTuiInputDateRangeComponent extends AbstractExampleTuiControl { + public override cleaner = false; + public control = new FormControl(null, Validators.required); + + public override readonly maxLengthVariants: readonly TuiDayLike[] = [ + {day: 5}, + {month: 1}, + {year: 1}, + ]; + + public override maxLength: TuiDayLike | null = null; + protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); protected readonly exampleForm = import('./examples/import/declare-form.md?raw'); @@ -79,14 +90,6 @@ export class ExampleTuiInputDateRangeComponent extends AbstractExampleTuiControl protected minLength: TuiDayLike | null = null; - public override readonly maxLengthVariants: readonly TuiDayLike[] = [ - {day: 5}, - {month: 1}, - {year: 1}, - ]; - - public override maxLength: TuiDayLike | null = null; - protected max = this.dayVariants[this.dayVariants.length - 1]; protected readonly markerHandlerVariants: readonly TuiMarkerHandler[] = [ @@ -96,16 +99,12 @@ export class ExampleTuiInputDateRangeComponent extends AbstractExampleTuiControl protected markerHandler: TuiMarkerHandler = this.markerHandlerVariants[0]; - public override cleaner = false; - protected readonly disabledItemHandlerVariants: ReadonlyArray< TuiBooleanHandler > = [ALWAYS_FALSE_HANDLER, ({day}) => day % 3 === 0]; protected disabledItemHandler = this.disabledItemHandlerVariants[0]; - public control = new FormControl(null, Validators.required); - protected readonly itemsVariants: ReadonlyArray = [ [], tuiCreateDefaultDayRangePeriods(), diff --git a/projects/demo/src/modules/components/input-date-time/input-date-time.component.ts b/projects/demo/src/modules/components/input-date-time/input-date-time.component.ts index 582eef9c057d..da38cb0a7f10 100644 --- a/projects/demo/src/modules/components/input-date-time/input-date-time.component.ts +++ b/projects/demo/src/modules/components/input-date-time/input-date-time.component.ts @@ -31,6 +31,13 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr export class ExampleTuiInputDateTimeComponent extends AbstractExampleTuiControl { private readonly today = TuiDay.currentLocal(); + public override cleaner = false; + + public readonly control = new FormControl<[TuiDay | null, TuiTime | null] | null>( + null, + Validators.required, + ); + protected readonly exampleForm = import('./examples/import/declare-form.md?raw'); protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); @@ -102,13 +109,6 @@ export class ExampleTuiInputDateTimeComponent extends AbstractExampleTuiControl protected items = this.itemsVariants[0]; - public override cleaner = false; - - public readonly control = new FormControl<[TuiDay | null, TuiTime | null] | null>( - null, - Validators.required, - ); - protected readonly modeVariants: readonly TuiTimeMode[] = [ 'HH:MM', 'HH:MM:SS', diff --git a/projects/demo/src/modules/components/input-date/input-date.component.ts b/projects/demo/src/modules/components/input-date/input-date.component.ts index cb43702bd6bc..13ef5cf17533 100644 --- a/projects/demo/src/modules/components/input-date/input-date.component.ts +++ b/projects/demo/src/modules/components/input-date/input-date.component.ts @@ -30,6 +30,10 @@ const ONE_DOT: [string] = ['var(--tui-success-fill)']; ], }) export class ExampleTuiInputDateComponent extends AbstractExampleTuiControl { + public override cleaner = false; + + public control = new FormControl(null, Validators.required); + protected readonly exampleForm = import('./examples/import/declare-form.md?raw'); protected readonly exampleModule = import('./examples/import/import-module.md?raw'); @@ -106,8 +110,4 @@ export class ExampleTuiInputDateComponent extends AbstractExampleTuiControl { protected markerHandler: TuiMarkerHandler = this.markerHandlerVariants[0]; protected items = this.itemsVariants[0]; - - public override cleaner = false; - - public control = new FormControl(null, Validators.required); } diff --git a/projects/demo/src/modules/components/input-files/input-files.component.ts b/projects/demo/src/modules/components/input-files/input-files.component.ts index ff43ee599a05..1664d6b667fe 100644 --- a/projects/demo/src/modules/components/input-files/input-files.component.ts +++ b/projects/demo/src/modules/components/input-files/input-files.component.ts @@ -21,6 +21,10 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr ], }) export class ExampleTuiInputFilesComponent extends AbstractExampleTuiControl { + public override readonly sizeVariants: readonly TuiSizeL[] = ['m', 'l']; + public override size = this.sizeVariants[0]; + public readonly control = new FormControl(null); + protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); @@ -60,7 +64,6 @@ export class ExampleTuiInputFilesComponent extends AbstractExampleTuiControl { HTML: import('./examples/7/index.html?raw'), }; - public readonly control = new FormControl(null); protected readonly files$ = this.control.valueChanges.pipe( map(() => tuiFilesAccepted(this.control)), ); @@ -86,9 +89,6 @@ export class ExampleTuiInputFilesComponent extends AbstractExampleTuiControl { 2.2 * 1000 * 1000, ]; - public override readonly sizeVariants: readonly TuiSizeL[] = ['m', 'l']; - - public override size = this.sizeVariants[0]; protected rejected: readonly File[] = []; protected maxFileSize = this.maxFileSizeVariants[2]; diff --git a/projects/demo/src/modules/components/input-inline/input-inline.component.ts b/projects/demo/src/modules/components/input-inline/input-inline.component.ts index 98f4dda3a9e2..9594133ed935 100644 --- a/projects/demo/src/modules/components/input-inline/input-inline.component.ts +++ b/projects/demo/src/modules/components/input-inline/input-inline.component.ts @@ -11,6 +11,12 @@ import {AbstractExampleTuiControl} from '../abstract/control'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class ExampleTuiInputInlineComponent extends AbstractExampleTuiControl { + public control = new FormControl('111', Validators.required); + + public override readonly maxLengthVariants: readonly number[] = [10]; + + public override maxLength: number | null = null; + protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); @@ -32,10 +38,4 @@ export class ExampleTuiInputInlineComponent extends AbstractExampleTuiControl { HTML: import('./examples/3/template.html?raw'), LESS: import('./examples/3/style.less?raw'), }; - - public control = new FormControl('111', Validators.required); - - public override readonly maxLengthVariants: readonly number[] = [10]; - - public override maxLength: number | null = null; } diff --git a/projects/demo/src/modules/components/input-month-range/input-month-range.component.ts b/projects/demo/src/modules/components/input-month-range/input-month-range.component.ts index bbca18ffd89b..c8f63ef22a0b 100644 --- a/projects/demo/src/modules/components/input-month-range/input-month-range.component.ts +++ b/projects/demo/src/modules/components/input-month-range/input-month-range.component.ts @@ -27,6 +27,10 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr ], }) export class ExampleTuiInputMonthRangeComponent extends AbstractExampleTuiControl { + public override cleaner = false; + + public control = new FormControl(null, Validators.required); + protected readonly exampleForm = import('./examples/import/declare-form.md?raw'); protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); @@ -68,8 +72,4 @@ export class ExampleTuiInputMonthRangeComponent extends AbstractExampleTuiContro > = [ALWAYS_FALSE_HANDLER, ({month}) => month % 3 === 0]; protected disabledItemHandler = this.disabledItemHandlerVariants[0]; - - public override cleaner = false; - - public control = new FormControl(null, Validators.required); } diff --git a/projects/demo/src/modules/components/input-month/input-month.component.ts b/projects/demo/src/modules/components/input-month/input-month.component.ts index cef8284dd23b..183139043c0a 100644 --- a/projects/demo/src/modules/components/input-month/input-month.component.ts +++ b/projects/demo/src/modules/components/input-month/input-month.component.ts @@ -26,6 +26,10 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr ], }) export class ExampleInputMonthComponent extends AbstractExampleTuiControl { + public override cleaner = false; + + public control = new FormControl(null, Validators.required); + protected readonly example1: TuiDocExample = { TypeScript: import('./examples/1/index.ts?raw'), HTML: import('./examples/1/index.html?raw'), @@ -67,8 +71,4 @@ export class ExampleInputMonthComponent extends AbstractExampleTuiControl { > = [ALWAYS_FALSE_HANDLER, ({month}) => month % 3 === 0]; protected disabledItemHandler = this.disabledItemHandlerVariants[0]; - - public override cleaner = false; - - public control = new FormControl(null, Validators.required); } diff --git a/projects/demo/src/modules/components/input-number/input-number.component.ts b/projects/demo/src/modules/components/input-number/input-number.component.ts index 349c35337107..1ad6c6f595c1 100644 --- a/projects/demo/src/modules/components/input-number/input-number.component.ts +++ b/projects/demo/src/modules/components/input-number/input-number.component.ts @@ -19,6 +19,10 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr ], }) export class ExampleTuiInputNumberComponent extends AbstractExampleTuiControl { + public override cleaner = false; + + public readonly control = new FormControl(6432, Validators.required); + protected readonly exampleForm = import('./examples/import/declare-form.md?raw'); protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); @@ -77,13 +81,9 @@ export class ExampleTuiInputNumberComponent extends AbstractExampleTuiControl { protected decimal = this.decimalVariants[0]; - public override cleaner = false; - protected readonly precisionVariants: readonly number[] = [2, 3, 4, Infinity]; protected precision = this.precisionVariants[0]; - public readonly control = new FormControl(6432, Validators.required); - protected step = 0; } diff --git a/projects/demo/src/modules/components/input-password/input-password.component.ts b/projects/demo/src/modules/components/input-password/input-password.component.ts index e6b398303c9a..c417d16a4cc2 100644 --- a/projects/demo/src/modules/components/input-password/input-password.component.ts +++ b/projects/demo/src/modules/components/input-password/input-password.component.ts @@ -18,6 +18,12 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr ], }) export class ExampleTuiInputPasswordComponent extends AbstractExampleTuiControl { + public override readonly maxLengthVariants: readonly number[] = [10]; + + public override maxLength = null; + + public control = new FormControl('', Validators.required); + protected readonly exampleForm = import('./examples/import/declare-form.md?raw'); protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); @@ -32,10 +38,4 @@ export class ExampleTuiInputPasswordComponent extends AbstractExampleTuiControl TypeScript: import('./examples/2/index.ts?raw'), HTML: import('./examples/2/index.html?raw'), }; - - public override readonly maxLengthVariants: readonly number[] = [10]; - - public override maxLength = null; - - public control = new FormControl('', Validators.required); } diff --git a/projects/demo/src/modules/components/input-phone-international/input-phone-international.component.ts b/projects/demo/src/modules/components/input-phone-international/input-phone-international.component.ts index 1bbdad11ce6f..ea24c4056996 100644 --- a/projects/demo/src/modules/components/input-phone-international/input-phone-international.component.ts +++ b/projects/demo/src/modules/components/input-phone-international/input-phone-international.component.ts @@ -19,6 +19,10 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr ], }) export class ExampleTuiInputPhoneInternationalComponent extends AbstractExampleTuiControl { + public override cleaner = false; + public override labelOutside = true; + public control = new FormControl('', [Validators.required, Validators.minLength(9)]); + protected readonly exampleForm = import('./examples/import/declare-form.md?raw'); protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); @@ -35,10 +39,6 @@ export class ExampleTuiInputPhoneInternationalComponent extends AbstractExampleT LESS: import('./examples/2/index.less?raw'), }; - public override cleaner = false; - - public control = new FormControl('', [Validators.required, Validators.minLength(9)]); - protected readonly countriesVariants: ReadonlyArray = [ [ TuiCountryIsoCode.RU, @@ -59,5 +59,4 @@ export class ExampleTuiInputPhoneInternationalComponent extends AbstractExampleT ]; protected countryIsoCode = this.countryIsoCodeVariants[0]; - public override labelOutside = true; } diff --git a/projects/demo/src/modules/components/input-phone/input-phone.component.ts b/projects/demo/src/modules/components/input-phone/input-phone.component.ts index 8d738cf9682f..94e7bb9c620d 100644 --- a/projects/demo/src/modules/components/input-phone/input-phone.component.ts +++ b/projects/demo/src/modules/components/input-phone/input-phone.component.ts @@ -19,6 +19,10 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr ], }) export class ExampleTuiInputPhoneComponent extends AbstractExampleTuiControl { + public override cleaner = false; + + public control = new FormControl('', [Validators.required, Validators.minLength(12)]); + protected readonly exampleForm = import('./examples/import/declare-form.md?raw'); protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); @@ -39,10 +43,6 @@ export class ExampleTuiInputPhoneComponent extends AbstractExampleTuiControl { LESS: import('./examples/3/index.less?raw'), }; - public override cleaner = false; - - public control = new FormControl('', [Validators.required, Validators.minLength(12)]); - protected countryCodes = ['+7', '+850', '+1', '+52']; protected countryCode = this.countryCodes[0]; diff --git a/projects/demo/src/modules/components/input-range/input-range.component.ts b/projects/demo/src/modules/components/input-range/input-range.component.ts index d9cf26b7987a..1d026245ee0a 100644 --- a/projects/demo/src/modules/components/input-range/input-range.component.ts +++ b/projects/demo/src/modules/components/input-range/input-range.component.ts @@ -21,6 +21,12 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr ], }) export class ExampleTuiInputRangeComponent extends AbstractExampleTuiControl { + public control = new FormControl([0, 10]); + + public override sizeVariants: readonly TuiSizeL[] = ['m', 'l']; + + public override size = this.sizeVariants[1]; + protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); @@ -57,8 +63,6 @@ export class ExampleTuiInputRangeComponent extends AbstractExampleTuiControl { 'transformer.ts': import('./examples/6/transformer.ts?raw'), }; - public control = new FormControl([0, 10]); - protected minVariants: readonly number[] = [0, 5, 7.77, -10]; protected min = this.minVariants[0]; @@ -75,10 +79,6 @@ export class ExampleTuiInputRangeComponent extends AbstractExampleTuiControl { protected quantum = this.quantumVariants[0]; - public override sizeVariants: readonly TuiSizeL[] = ['m', 'l']; - - public override size = this.sizeVariants[1]; - protected readonly pluralizeVariants: ReadonlyArray> = [ {one: 'thing', few: 'things', many: 'things', other: 'things'}, { diff --git a/projects/demo/src/modules/components/input-slider/input-slider.component.ts b/projects/demo/src/modules/components/input-slider/input-slider.component.ts index 897c5ada0b52..29fddfcc017c 100644 --- a/projects/demo/src/modules/components/input-slider/input-slider.component.ts +++ b/projects/demo/src/modules/components/input-slider/input-slider.component.ts @@ -21,6 +21,18 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr ], }) export class ExampleTuiInputSliderComponent extends AbstractExampleTuiControl { + public override readonly sizeVariants: readonly TuiSizeL[] = ['m', 'l']; + public override size = this.sizeVariants[1]; + public readonly control = new FormControl(0); + + public override readonly customContentVariants: string[] = [ + '', + 'tuiIconVisaMono', + 'tuiIconMastercardMono', + ]; + + public override customContentSelected = this.customContentVariants[0]; + protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); @@ -53,8 +65,6 @@ export class ExampleTuiInputSliderComponent extends AbstractExampleTuiControl { LESS: import('./examples/5/index.less?raw'), }; - public readonly control = new FormControl(0); - protected readonly minVariants: readonly number[] = [0, 1, 5, 7.77, -10]; protected min = this.minVariants[0]; @@ -73,10 +83,6 @@ export class ExampleTuiInputSliderComponent extends AbstractExampleTuiControl { protected quantum = this.quantumVariants[0]; - public override readonly sizeVariants: readonly TuiSizeL[] = ['m', 'l']; - - public override size = this.sizeVariants[1]; - protected readonly valueContentVariants = [ '', 'TOP SECRET', @@ -96,12 +102,4 @@ export class ExampleTuiInputSliderComponent extends AbstractExampleTuiControl { ]; protected keySteps: TuiKeySteps | null = null; - - public override readonly customContentVariants: string[] = [ - '', - 'tuiIconVisaMono', - 'tuiIconMastercardMono', - ]; - - public override customContentSelected = this.customContentVariants[0]; } diff --git a/projects/demo/src/modules/components/input-tag/input-tag.component.ts b/projects/demo/src/modules/components/input-tag/input-tag.component.ts index 630ba65e7864..b1fcd77ecc38 100644 --- a/projects/demo/src/modules/components/input-tag/input-tag.component.ts +++ b/projects/demo/src/modules/components/input-tag/input-tag.component.ts @@ -30,6 +30,24 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr ], }) export class ExampleTuiInputTagComponent extends AbstractExampleTuiControl { + public override readonly sizeVariants: ReadonlyArray = [ + 's', + 'm', + 'l', + ]; + + public override size: TuiSizeL | TuiSizeS = + this.sizeVariants[this.sizeVariants.length - 1]; + + public readonly control = new FormControl( + ['John Cleese', 'Eric Idle', 'Michael Palin'], + Validators.required, + ); + + public override maxLengthVariants: number[] = [10, 20]; + + public override maxLength: number | null = null; + protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); @@ -81,11 +99,6 @@ export class ExampleTuiInputTagComponent extends AbstractExampleTuiControl { HTML: import('./examples/9/index.html?raw'), }; - public readonly control = new FormControl( - ['John Cleese', 'Eric Idle', 'Michael Palin'], - Validators.required, - ); - protected editable = true; protected uniqueTags = true; @@ -98,23 +111,10 @@ export class ExampleTuiInputTagComponent extends AbstractExampleTuiControl { protected icon = ''; - public override maxLengthVariants: number[] = [10, 20]; - - public override maxLength: number | null = null; - protected search = ''; protected rows = 100; - public override readonly sizeVariants: ReadonlyArray = [ - 's', - 'm', - 'l', - ]; - - public override size: TuiSizeL | TuiSizeS = - this.sizeVariants[this.sizeVariants.length - 1]; - protected tagValidatorVariants: ReadonlyArray> = [ ALWAYS_TRUE_HANDLER, item => item === 'test', diff --git a/projects/demo/src/modules/components/input-time/input-time.component.ts b/projects/demo/src/modules/components/input-time/input-time.component.ts index 471203bbde57..1d98e4982138 100644 --- a/projects/demo/src/modules/components/input-time/input-time.component.ts +++ b/projects/demo/src/modules/components/input-time/input-time.component.ts @@ -27,6 +27,10 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr ], }) export class ExampleTuiInputTimeComponent extends AbstractExampleTuiControl { + public override cleaner = false; + + public control = new FormControl(TuiTime.currentLocal(), Validators.required); + protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); @@ -65,10 +69,6 @@ export class ExampleTuiInputTimeComponent extends AbstractExampleTuiControl { HTML: import('./examples/6/index.html?raw'), }; - public override cleaner = false; - - public control = new FormControl(TuiTime.currentLocal(), Validators.required); - protected readonly disabledItemHandlerVariants: ReadonlyArray< TuiBooleanHandler > = [ diff --git a/projects/demo/src/modules/components/input-year/input-year.component.ts b/projects/demo/src/modules/components/input-year/input-year.component.ts index 997c90abb756..9c78015e36c5 100644 --- a/projects/demo/src/modules/components/input-year/input-year.component.ts +++ b/projects/demo/src/modules/components/input-year/input-year.component.ts @@ -24,6 +24,10 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr ], }) export class ExampleInputYearComponent extends AbstractExampleTuiControl { + public override cleaner = false; + + public control = new FormControl(null, Validators.required); + protected readonly example1: TuiDocExample = { TypeScript: import('./examples/1/index.ts?raw'), HTML: import('./examples/1/index.html?raw'), @@ -49,8 +53,4 @@ export class ExampleInputYearComponent extends AbstractExampleTuiControl { > = [ALWAYS_FALSE_HANDLER, year => year % 3 === 0]; protected disabledItemHandler = this.disabledItemHandlerVariants[0]; - - public override cleaner = false; - - public control = new FormControl(null, Validators.required); } diff --git a/projects/demo/src/modules/components/input/input.component.ts b/projects/demo/src/modules/components/input/input.component.ts index ace2603542d0..56a0aaf14d40 100644 --- a/projects/demo/src/modules/components/input/input.component.ts +++ b/projects/demo/src/modules/components/input/input.component.ts @@ -25,6 +25,21 @@ export class ExampleTuiInputComponent extends AbstractExampleTuiControl { @ViewChild('justLongText', {static: true}) private readonly longTextRef!: TemplateRef; + public readonly iconVariants = ['', 'tuiIconSearchLarge', 'tuiIconCalendarLarge']; + + public override iconLeft = this.iconVariants[0]; + + public readonly control = new FormControl('111', Validators.required); + + public override readonly customContentVariants = [ + '', + 'tuiIconSearchLarge', + 'tuiIconCalendarLarge', + 'tuiIconVisaMono', + 'tuiIconMastercardMono', + LONG_TEXT_TEMPLATE, + ]; + protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); @@ -87,24 +102,10 @@ export class ExampleTuiInputComponent extends AbstractExampleTuiControl { HTML: import('./examples/10/index.html?raw'), }; - protected readonly iconVariants = ['', 'tuiIconSearchLarge', 'tuiIconCalendarLarge']; - protected icon = this.iconVariants[0]; - public override iconLeft = this.iconVariants[0]; - - public readonly control = new FormControl('111', Validators.required); protected placeholder = 'Field placeholder'; - public override readonly customContentVariants = [ - '', - 'tuiIconSearchLarge', - 'tuiIconCalendarLarge', - 'tuiIconVisaMono', - 'tuiIconMastercardMono', - LONG_TEXT_TEMPLATE, - ]; - public override get customContent(): PolymorpheusContent { return this.customContentSelected === LONG_TEXT_TEMPLATE ? this.longTextRef diff --git a/projects/demo/src/modules/components/multi-select/multi-select.component.ts b/projects/demo/src/modules/components/multi-select/multi-select.component.ts index 0b24b8fe6d4e..6a3d67a02fdf 100644 --- a/projects/demo/src/modules/components/multi-select/multi-select.component.ts +++ b/projects/demo/src/modules/components/multi-select/multi-select.component.ts @@ -47,6 +47,25 @@ class Account { ], }) export class ExampleTuiMultiSelectComponent extends AbstractExampleTuiControl { + public control = new FormControl(null); + + public override iconLeft = ''; + + public override readonly sizeVariants: ReadonlyArray = [ + 's', + 'm', + 'l', + ]; + + public override size: TuiSizeL | TuiSizeS = + this.sizeVariants[this.sizeVariants.length - 1]; + + public override readonly maxLengthVariants: readonly number[] = [10]; + + public override maxLength = null; + + public override labelOutside = true; + protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); protected readonly exampleForm = import('./examples/import/declare-form.md?raw'); @@ -109,8 +128,6 @@ export class ExampleTuiMultiSelectComponent extends AbstractExampleTuiControl { HTML: import('./examples/11/index.html?raw'), }; - public override labelOutside = true; - protected readonly items = [ new Account('Ruble', 500), new Account('Dollar', 500), @@ -125,12 +142,6 @@ export class ExampleTuiMultiSelectComponent extends AbstractExampleTuiControl { protected search: string | null = ''; - public override readonly sizeVariants: ReadonlyArray = [ - 's', - 'm', - 'l', - ]; - protected readonly iconVariants = [ '', 'tuiIconSearchLarge', @@ -138,11 +149,6 @@ export class ExampleTuiMultiSelectComponent extends AbstractExampleTuiControl { 'tuiIconCreditCardLarge', ]; - public override iconLeft = ''; - - public override size: TuiSizeL | TuiSizeS = - this.sizeVariants[this.sizeVariants.length - 1]; - protected stringifyVariants: Array> = [ TUI_DEFAULT_STRINGIFY, item => String(String(item).match(/\d+/)), @@ -165,18 +171,12 @@ export class ExampleTuiMultiSelectComponent extends AbstractExampleTuiControl { protected tagValidator = this.tagValidatorVariants[0]; - public override readonly maxLengthVariants: readonly number[] = [10]; - - public override maxLength = null; - protected readonly valueContentVariants: ReadonlyArray< PolymorpheusContent> > = ['', ({$implicit: {length}}) => `Selected: ${length}`]; protected valueContent = this.valueContentVariants[0]; - public control = new FormControl(null); - protected readonly disabledItemHandlerVariants: ReadonlyArray< TuiBooleanHandler > = [ALWAYS_FALSE_HANDLER, (item: Account) => item.balance < 300]; diff --git a/projects/demo/src/modules/components/primitive-textfield/examples/1/index.ts b/projects/demo/src/modules/components/primitive-textfield/examples/1/index.ts index 65033a60d0e5..4f364470aaa0 100644 --- a/projects/demo/src/modules/components/primitive-textfield/examples/1/index.ts +++ b/projects/demo/src/modules/components/primitive-textfield/examples/1/index.ts @@ -17,16 +17,16 @@ export class TuiPrimitiveTextfieldExample1 extends AbstractTuiControl { private isPasswordHidden = true; + public get focused(): boolean { + return !!this.textfield?.focused; + } + protected get nativeFocusableElement(): TuiNativeFocusableElement | null { return this.computedDisabled || !this.textfield ? null : this.textfield.nativeFocusableElement; } - public get focused(): boolean { - return !!this.textfield?.focused; - } - protected get icon(): string { return this.isPasswordHidden ? 'tuiIconEyeLarge' : 'tuiIconEyeOffLarge'; } diff --git a/projects/demo/src/modules/components/prompt/prompt.component.ts b/projects/demo/src/modules/components/prompt/prompt.component.ts index e7e67a11a33d..6ee900d3c01f 100644 --- a/projects/demo/src/modules/components/prompt/prompt.component.ts +++ b/projects/demo/src/modules/components/prompt/prompt.component.ts @@ -14,6 +14,12 @@ export class ExampleTuiPromptComponent implements TuiPromptData { private readonly dialogs = inject(TuiDialogService); private readonly alerts = inject(TuiAlertService); + public no = 'No'; + public yes = 'Yes'; + + public readonly content = + 'This is PolymorpheusContent, so it can be anything you like!'; + protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleService = import('./examples/import/service.md?raw'); @@ -22,12 +28,6 @@ export class ExampleTuiPromptComponent implements TuiPromptData { HTML: import('./examples/1/index.html?raw'), }; - public readonly content = - 'This is PolymorpheusContent, so it can be anything you like!'; - - public no = 'No'; - public yes = 'Yes'; - protected onClick(): void { this.dialogs .open(TUI_PROMPT, { diff --git a/projects/demo/src/modules/components/radio-list/radio-list.component.ts b/projects/demo/src/modules/components/radio-list/radio-list.component.ts index a3ea61cdf10c..cbf898b7e39d 100644 --- a/projects/demo/src/modules/components/radio-list/radio-list.component.ts +++ b/projects/demo/src/modules/components/radio-list/radio-list.component.ts @@ -30,6 +30,27 @@ interface ItemRadio { ], }) export class ExampleTuiRadioListComponent extends AbstractExampleTuiControl { + public override readonly sizeVariants: readonly TuiSizeL[] = ['m', 'l']; + + public override size: TuiSizeL = this.sizeVariants[0]; + + public readonly items: readonly ItemRadio[] = [ + { + name: 'Simple', + description: 'It is simple', + }, + { + name: 'Advanced', + description: 'For better clients', + }, + { + name: 'PRO', + description: 'For pro and cool clients', + }, + ]; + + public control = new FormControl(this.items[0]); + protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); protected readonly exampleForm = import('./examples/import/declare-form.md?raw'); @@ -53,29 +74,8 @@ export class ExampleTuiRadioListComponent extends AbstractExampleTuiControl { protected orientation: TuiOrientation = this.orientationVariants[0]; - protected readonly items: readonly ItemRadio[] = [ - { - name: 'Simple', - description: 'It is simple', - }, - { - name: 'Advanced', - description: 'For better clients', - }, - { - name: 'PRO', - description: 'For pro and cool clients', - }, - ]; - - public override readonly sizeVariants: readonly TuiSizeL[] = ['m', 'l']; - - public override size: TuiSizeL = this.sizeVariants[0]; - protected readonly disabledItemHandlerVariants: Array> = [ALWAYS_FALSE_HANDLER, ALWAYS_TRUE_HANDLER, item => item.name === 'Advanced']; protected disabledItemHandler = this.disabledItemHandlerVariants[0]; - - public control = new FormControl(this.items[0]); } diff --git a/projects/demo/src/modules/components/radio/radio.component.ts b/projects/demo/src/modules/components/radio/radio.component.ts index d96c41013ddc..719ad4406c14 100644 --- a/projects/demo/src/modules/components/radio/radio.component.ts +++ b/projects/demo/src/modules/components/radio/radio.component.ts @@ -20,22 +20,7 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr ], }) export class ExampleTuiRadioComponent extends AbstractExampleTuiControl { - protected readonly exampleModule = import('./examples/import/import-module.md?raw'); - protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); - protected readonly exampleForm = import('./examples/import/declare-form.md?raw'); - protected readonly exampleOptions = import('./examples/import/define-options.md?raw'); - - protected readonly example1: TuiDocExample = { - TypeScript: import('./examples/1/index.ts?raw'), - HTML: import('./examples/1/index.html?raw'), - }; - - protected readonly example2: TuiDocExample = { - TypeScript: import('./examples/2/index.ts?raw'), - HTML: import('./examples/2/index.html?raw'), - }; - - protected items = [ + public items = [ { id: 0, value: 'One', @@ -54,6 +39,23 @@ export class ExampleTuiRadioComponent extends AbstractExampleTuiControl { public override size: TuiSizeL = this.sizeVariants[0]; + public control = new FormControl(this.items[1]); + + protected readonly exampleModule = import('./examples/import/import-module.md?raw'); + protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); + protected readonly exampleForm = import('./examples/import/declare-form.md?raw'); + protected readonly exampleOptions = import('./examples/import/define-options.md?raw'); + + protected readonly example1: TuiDocExample = { + TypeScript: import('./examples/1/index.ts?raw'), + HTML: import('./examples/1/index.html?raw'), + }; + + protected readonly example2: TuiDocExample = { + TypeScript: import('./examples/2/index.ts?raw'), + HTML: import('./examples/2/index.html?raw'), + }; + protected pseudoDisabled = false; protected identityMatcherVariants: ReadonlyArray< @@ -62,8 +64,6 @@ export class ExampleTuiRadioComponent extends AbstractExampleTuiControl { protected identityMatcher = this.identityMatcherVariants[0]; - public control = new FormControl(this.items[1]); - protected onClick(): void { this.control.setValue({id: 0, value: 'One'}); } diff --git a/projects/demo/src/modules/components/range/range.component.ts b/projects/demo/src/modules/components/range/range.component.ts index 0288fe134c81..3e4debe68593 100644 --- a/projects/demo/src/modules/components/range/range.component.ts +++ b/projects/demo/src/modules/components/range/range.component.ts @@ -40,20 +40,6 @@ export class ExampleTuiRangeComponent { protected readonly control = new FormControl([0, 0]); - protected get disabled(): boolean { - return this.control.disabled; - } - - protected set disabled(value: boolean) { - if (value) { - this.control.disable(); - - return; - } - - this.control.enable(); - } - protected readonly sizeVariants: readonly TuiSizeS[] = ['s', 'm']; protected size: TuiSizeS = this.sizeVariants[1]; @@ -75,4 +61,18 @@ export class ExampleTuiRangeComponent { ]; protected keySteps: TuiKeySteps | null = null; + + protected get disabled(): boolean { + return this.control.disabled; + } + + protected set disabled(value: boolean) { + if (value) { + this.control.disable(); + + return; + } + + this.control.enable(); + } } diff --git a/projects/demo/src/modules/components/select/select.component.ts b/projects/demo/src/modules/components/select/select.component.ts index efc5ac6d7175..68f699ed8f2c 100644 --- a/projects/demo/src/modules/components/select/select.component.ts +++ b/projects/demo/src/modules/components/select/select.component.ts @@ -39,6 +39,12 @@ export class ExampleTuiSelectComponent extends AbstractExampleTuiControl { TuiValueContentContext >; + public readonly iconVariants = ['', 'tuiIconPieChartLarge', 'tuiIconCreditCardLarge']; + + public override iconLeft = this.iconVariants[0]; + + public control = new FormControl(null, Validators.required); + protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); protected readonly exampleForm = import('./examples/import/declare-form.md?raw'); @@ -119,14 +125,6 @@ export class ExampleTuiSelectComponent extends AbstractExampleTuiControl { protected readonly valueTemplateVariants = ['', 'Template']; - protected readonly iconVariants = [ - '', - 'tuiIconPieChartLarge', - 'tuiIconCreditCardLarge', - ]; - - public override iconLeft = this.iconVariants[0]; - protected selectedValueTemplate = this.valueTemplateVariants[0]; protected readonly identityMatcherVariants: ReadonlyArray< @@ -138,8 +136,6 @@ export class ExampleTuiSelectComponent extends AbstractExampleTuiControl { protected identityMatcher = this.identityMatcherVariants[0]; - public control = new FormControl(null, Validators.required); - protected readonly disabledItemHandlerVariants: ReadonlyArray< TuiBooleanHandler > = [ALWAYS_FALSE_HANDLER, (item: Account) => item.balance < 300]; diff --git a/projects/demo/src/modules/components/slider/slider.component.ts b/projects/demo/src/modules/components/slider/slider.component.ts index 2fded20da399..648cbdc9ca29 100644 --- a/projects/demo/src/modules/components/slider/slider.component.ts +++ b/projects/demo/src/modules/components/slider/slider.component.ts @@ -18,20 +18,6 @@ export class ExampleTuiSliderComponent { protected size: TuiSizeS = this.sizeVariants[1]; protected segments = this.max; - protected get disabled(): boolean { - return this.control.disabled; - } - - protected set disabled(value: boolean) { - if (value) { - this.control.disable(); - - return; - } - - this.control.enable(); - } - protected readonly exampleImportModule = import( './examples/import/import-module.md?raw' ); @@ -77,4 +63,18 @@ export class ExampleTuiSliderComponent { LESS: import('./examples/6/index.less?raw'), TypeScript: import('./examples/6/index.ts?raw'), }; + + protected get disabled(): boolean { + return this.control.disabled; + } + + protected set disabled(value: boolean) { + if (value) { + this.control.disable(); + + return; + } + + this.control.enable(); + } } diff --git a/projects/demo/src/modules/components/textarea/textarea.component.ts b/projects/demo/src/modules/components/textarea/textarea.component.ts index 912135e3ac3c..ce99df081bcb 100644 --- a/projects/demo/src/modules/components/textarea/textarea.component.ts +++ b/projects/demo/src/modules/components/textarea/textarea.component.ts @@ -24,6 +24,19 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr ], }) export class ExampleTuiTextareaComponent extends AbstractExampleTuiControl { + public control = new FormControl(''); + + public override readonly maxLengthVariants: readonly number[] = [50, 100, 500]; + + public override maxLength: number | null = null; + + public override readonly sizeVariants: ReadonlyArray = [ + 'm', + 'l', + ]; + + public override size: TuiSizeL | TuiSizeM = this.sizeVariants[1]; + protected readonly example1: TuiDocExample = { TypeScript: import('./examples/1/index.ts?raw'), HTML: import('./examples/1/index.html?raw'), @@ -61,10 +74,6 @@ export class ExampleTuiTextareaComponent extends AbstractExampleTuiControl { protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); protected readonly exampleForm = import('./examples/import/declare-form.md?raw'); - public override readonly maxLengthVariants: readonly number[] = [50, 100, 500]; - - public override maxLength: number | null = null; - protected readonly iconVariants = ['', 'tuiIconSearchLarge', 'tuiIconCalendarLarge']; protected icon = this.iconVariants[0]; @@ -75,14 +84,5 @@ export class ExampleTuiTextareaComponent extends AbstractExampleTuiControl { protected expandable = false; - public control = new FormControl(''); - - public override readonly sizeVariants: ReadonlyArray = [ - 'm', - 'l', - ]; - - public override size: TuiSizeL | TuiSizeM = this.sizeVariants[1]; - protected placeholder = 'Placeholder'; } diff --git a/projects/demo/src/modules/directives/copy-processor/examples/1/index.ts b/projects/demo/src/modules/directives/copy-processor/examples/1/index.ts index be73d2e30109..8f514ddd3196 100644 --- a/projects/demo/src/modules/directives/copy-processor/examples/1/index.ts +++ b/projects/demo/src/modules/directives/copy-processor/examples/1/index.ts @@ -18,11 +18,6 @@ export class TuiCopyProcessorExample1 { protected value = 12345.67; - @HostListener('copy', ['$event']) - protected onCopy(event: ClipboardEvent): void { - this.alerts.open(event.clipboardData?.getData('text/plain') ?? '').subscribe(); - } - protected numberProcessor$ = this.format.pipe( map( format => (text: string) => @@ -32,6 +27,11 @@ export class TuiCopyProcessorExample1 { ), ); + @HostListener('copy', ['$event']) + protected onCopy(event: ClipboardEvent): void { + this.alerts.open(event.clipboardData?.getData('text/plain') ?? '').subscribe(); + } + protected readonly textProcessor: TuiStringHandler = text => text.toUpperCase(); } diff --git a/projects/demo/src/modules/directives/dropdown-open/examples/4/index.ts b/projects/demo/src/modules/directives/dropdown-open/examples/4/index.ts index 1d8dedac387a..fc2bd9477fc1 100644 --- a/projects/demo/src/modules/directives/dropdown-open/examples/4/index.ts +++ b/projects/demo/src/modules/directives/dropdown-open/examples/4/index.ts @@ -21,10 +21,6 @@ export class TuiDropdownOpenExample4 { protected readonly arrow = TUI_ARROW; - private get value(): readonly string[] { - return this.form.get('control')?.value || []; - } - protected get appearance(): string { return this.length ? 'whiteblock-active' : 'whiteblock'; } @@ -43,4 +39,8 @@ export class TuiDropdownOpenExample4 { return `${this.length} selected`; } } + + private get value(): readonly string[] { + return this.form.get('control')?.value || []; + } } diff --git a/projects/demo/src/modules/directives/pan/examples/1/index.ts b/projects/demo/src/modules/directives/pan/examples/1/index.ts index 96fa15ae2464..984c25f18431 100644 --- a/projects/demo/src/modules/directives/pan/examples/1/index.ts +++ b/projects/demo/src/modules/directives/pan/examples/1/index.ts @@ -24,14 +24,14 @@ export class TuiPanExample1 { ), ); + protected get currentCoords(): number[] { + return this.coordinates$.value; + } + protected onPan(delta: readonly [number, number]): void { this.coordinates$.next([ this.currentCoords[0] + delta[0], this.currentCoords[1] + delta[1], ]); } - - protected get currentCoords(): number[] { - return this.coordinates$.value; - } } diff --git a/projects/demo/src/modules/icons/icons-group/icons-group.component.ts b/projects/demo/src/modules/icons/icons-group/icons-group.component.ts index d145174fa5c9..2e18896f506b 100644 --- a/projects/demo/src/modules/icons/icons-group/icons-group.component.ts +++ b/projects/demo/src/modules/icons/icons-group/icons-group.component.ts @@ -30,15 +30,15 @@ export class IconsGroupComponent implements OnInit { private readonly router = inject(Router); private readonly destroy$ = inject(TuiDestroyService, {self: true}); - @ContentChild(IconsGroupDirective) - protected readonly iconGroup?: IconsGroupDirective; - @Input() public icons: Record = {}; @Input() public color: string | null = null; + @ContentChild(IconsGroupDirective) + protected readonly iconGroup?: IconsGroupDirective; + protected matcher = TUI_DEFAULT_MATCHER; protected control = new FormControl(''); diff --git a/projects/demo/src/modules/services/table-bar/table-bar.component.ts b/projects/demo/src/modules/services/table-bar/table-bar.component.ts index c503eafd9383..39c56dec810b 100644 --- a/projects/demo/src/modules/services/table-bar/table-bar.component.ts +++ b/projects/demo/src/modules/services/table-bar/table-bar.component.ts @@ -48,6 +48,11 @@ export class ExampleTuiTableBarComponent implements OnDestroy { protected subscription = new Subscription(); + public ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + protected showTableBar(): void { this.subscription.unsubscribe(); @@ -64,9 +69,4 @@ export class ExampleTuiTableBarComponent implements OnDestroy { protected destroy(): void { this.destroy$.next(); } - - public ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } } diff --git a/projects/demo/src/modules/utils/pure/pure-getter.component.ts b/projects/demo/src/modules/utils/pure/pure-getter.component.ts index 0578609b8a43..fe889231dbfb 100644 --- a/projects/demo/src/modules/utils/pure/pure-getter.component.ts +++ b/projects/demo/src/modules/utils/pure/pure-getter.component.ts @@ -8,13 +8,13 @@ import {tuiPure} from '@taiga-ui/cdk'; changeDetection, }) export class ExampleTuiPureGetterComponent { + protected show = false; + @tuiPure protected get fibonacci42(): number { return this.fibonacci(42); } - protected show = false; - private fibonacci(num: number): number { return num <= 1 ? num : this.fibonacci(num - 1) + this.fibonacci(num - 2); } diff --git a/projects/experimental/components/button/button.directive.ts b/projects/experimental/components/button/button.directive.ts index 1b03b9a2808b..563d626a98d1 100644 --- a/projects/experimental/components/button/button.directive.ts +++ b/projects/experimental/components/button/button.directive.ts @@ -53,10 +53,11 @@ export class TuiButtonStylesComponent {} }) export class TuiButtonDirective { private readonly options = inject(TUI_BUTTON_OPTIONS); - protected readonly nothing = tuiWithStyles(TuiButtonStylesComponent); @Input() public size = this.options.size; + protected readonly nothing = tuiWithStyles(TuiButtonStylesComponent); + protected readonly mode$ = inject(TUI_MODE); } diff --git a/projects/experimental/components/chip/chip.directive.ts b/projects/experimental/components/chip/chip.directive.ts index 5bf5e1a1bd9a..e82405d0b2db 100644 --- a/projects/experimental/components/chip/chip.directive.ts +++ b/projects/experimental/components/chip/chip.directive.ts @@ -44,8 +44,9 @@ import {TUI_CHIP_OPTIONS} from './chip.options'; }) export class TuiChipDirective { private readonly options = inject(TUI_CHIP_OPTIONS); - protected readonly nothing = tuiWithStyles(TuiChipComponent); @Input() public size: TuiSizeXXS = this.options.size; + + protected readonly nothing = tuiWithStyles(TuiChipComponent); } diff --git a/projects/experimental/components/segmented/segmented.directive.ts b/projects/experimental/components/segmented/segmented.directive.ts index 85bcacb27422..0fe204455e68 100644 --- a/projects/experimental/components/segmented/segmented.directive.ts +++ b/projects/experimental/components/segmented/segmented.directive.ts @@ -33,15 +33,6 @@ export class TuiSegmentedDirective implements AfterContentChecked, AfterContentI private readonly component = inject(TuiSegmentedComponent); private readonly el: HTMLElement = inject(ElementRef).nativeElement; - @HostListener('click', ['$event.target']) - protected update(target: Element | null): void { - const index = this.getIndex(target); - - if (index >= 0) { - this.component.update(index); - } - } - public ngAfterContentInit(): void { tuiQueryListChanges(this.controls) .pipe( @@ -59,6 +50,15 @@ export class TuiSegmentedDirective implements AfterContentChecked, AfterContentI } } + @HostListener('click', ['$event.target']) + protected update(target: Element | null): void { + const index = this.getIndex(target); + + if (index >= 0) { + this.component.update(index); + } + } + private get linkIndex(): number { return this.links.toArray().findIndex(link => link.isActive); } diff --git a/projects/experimental/components/textfield/select.directive.ts b/projects/experimental/components/textfield/select.directive.ts index 495ff009e2aa..72fa34279dd7 100644 --- a/projects/experimental/components/textfield/select.directive.ts +++ b/projects/experimental/components/textfield/select.directive.ts @@ -38,6 +38,10 @@ export class TuiSelectDirective extends TuiTextfieldDirective { @Input() public placeholder = ''; + public override setValue(value: string): void { + this.control.control?.setValue(value); + } + protected get value(): string { return this.textfield.stringify(this.control.value); } @@ -45,8 +49,4 @@ export class TuiSelectDirective extends TuiTextfieldDirective { protected async onCopy(): Promise { await this.nav.clipboard.writeText(this.el.value); } - - public override setValue(value: string): void { - this.control.control?.setValue(value); - } } diff --git a/projects/experimental/components/textfield/textfield.component.ts b/projects/experimental/components/textfield/textfield.component.ts index b5659479faa2..59d1380fd9ec 100644 --- a/projects/experimental/components/textfield/textfield.component.ts +++ b/projects/experimental/components/textfield/textfield.component.ts @@ -81,12 +81,6 @@ export class TuiTextfieldComponent self: true, }); - @ContentChild(TuiTextfieldDirective) - protected readonly directive?: TuiTextfieldDirective; - - @ContentChild(TuiLabelDirective) - protected readonly label?: unknown; - @Input() public filler = ''; @@ -96,17 +90,22 @@ export class TuiTextfieldComponent @Input() public content: PolymorpheusContent>; - protected side = 0; + // TODO: Refactor + public readonly focusedChange = EMPTY; + + @ContentChild(TuiTextfieldDirective) + protected readonly directive?: TuiTextfieldDirective; + + @ContentChild(TuiLabelDirective) + protected readonly label?: unknown; + protected side = 0; protected readonly change$ = inject(TuiTextfieldOptionsDirective, {optional: true}) ?.change$; protected readonly options = inject(TUI_TEXTFIELD_OPTIONS); protected readonly control = inject(NgControl, {optional: true}); - // TODO: Refactor - public readonly focusedChange = EMPTY; - public get nativeFocusableElement(): HTMLInputElement { return this.input; } @@ -120,6 +119,11 @@ export class TuiTextfieldComponent return !!this.dropdown?.dropdown || tuiIsNativeFocused(this.el?.nativeElement); } + public handleOption(option: T): void { + this.directive?.setValue(this.stringify(option)); + this.dropdown?.toggle(false); + } + protected get input(): HTMLInputElement { if (!this.el) { throw new Error('[tuiTextfield] component is required'); @@ -142,9 +146,4 @@ export class TuiTextfieldComponent (!!this.input.value || !this.input.placeholder) ); } - - public handleOption(option: T): void { - this.directive?.setValue(this.stringify(option)); - this.dropdown?.toggle(false); - } } diff --git a/projects/experimental/components/textfield/textfield.directive.ts b/projects/experimental/components/textfield/textfield.directive.ts index 14e25e9ffeb4..65cf300e2d23 100644 --- a/projects/experimental/components/textfield/textfield.directive.ts +++ b/projects/experimental/components/textfield/textfield.directive.ts @@ -24,9 +24,6 @@ export class TuiTextfieldDirective implements DoCheck { private readonly appearance = inject(TuiAppearanceDirective); private readonly options = inject(TUI_TEXTFIELD_OPTIONS); - protected readonly textfield = inject(TuiTextfieldComponent); - protected readonly id = inject(TuiIdService).generate(); - @Input() public readOnly = false; @@ -39,6 +36,8 @@ export class TuiTextfieldDirective implements DoCheck { @Input() public state: TuiInteractiveStateT | null = null; + protected readonly textfield = inject(TuiTextfieldComponent); + protected readonly id = inject(TuiIdService).generate(); protected readonly el: HTMLInputElement = inject(ElementRef).nativeElement; public ngDoCheck(): void { diff --git a/projects/experimental/components/toggle/toggle.component.ts b/projects/experimental/components/toggle/toggle.component.ts index 3ad96fb663e3..79f106ccd157 100644 --- a/projects/experimental/components/toggle/toggle.component.ts +++ b/projects/experimental/components/toggle/toggle.component.ts @@ -50,6 +50,10 @@ export class TuiToggleComponent implements DoCheck { protected readonly control = inject(NgControl, {optional: true}); + public ngDoCheck(): void { + this.appearance.tuiAppearance = this.options.appearance(this.el); + } + @HostBinding('style.--t-mask') protected get icon(): string { const {options, resolver, size} = this; @@ -57,8 +61,4 @@ export class TuiToggleComponent implements DoCheck { return `url(${resolver(icon)})`; } - - public ngDoCheck(): void { - this.appearance.tuiAppearance = this.options.appearance(this.el); - } } diff --git a/projects/experimental/components/tooltip/tooltip.component.ts b/projects/experimental/components/tooltip/tooltip.component.ts index 098e0bccb798..044489368364 100644 --- a/projects/experimental/components/tooltip/tooltip.component.ts +++ b/projects/experimental/components/tooltip/tooltip.component.ts @@ -35,15 +35,15 @@ export class TuiTooltipComponent extends TuiHintOptionsDirective { private readonly platform = inject(TUI_PLATFORM); private mode: TuiBrightness | null = null; - @ViewChild(TuiHintHoverDirective) - protected readonly driver$?: TuiHintHoverDirective; - @Input() public describeId = ''; @Input() public context?: C; + @ViewChild(TuiHintHoverDirective) + protected readonly driver$?: TuiHintHoverDirective; + protected readonly tooltipOptions = inject(TUI_TOOLTIP_OPTIONS); protected readonly iconAppearance = inject(TuiAppearanceDirective, {optional: true}); diff --git a/projects/experimental/directives/card/card.directive.ts b/projects/experimental/directives/card/card.directive.ts index 79025fab611e..c68cc8661f6a 100644 --- a/projects/experimental/directives/card/card.directive.ts +++ b/projects/experimental/directives/card/card.directive.ts @@ -21,8 +21,8 @@ export class TuiCardMediumDirective { }, }) export class TuiCardLargeDirective { - protected readonly nothing = tuiWithStyles(TuiCardComponent); - @Input('tuiCardLarge') public space: '' | 'compact' | 'normal' = 'normal'; + + protected readonly nothing = tuiWithStyles(TuiCardComponent); } diff --git a/projects/experimental/directives/cell/cell.directive.ts b/projects/experimental/directives/cell/cell.directive.ts index c1149c3de45b..1077c8a1937b 100644 --- a/projects/experimental/directives/cell/cell.directive.ts +++ b/projects/experimental/directives/cell/cell.directive.ts @@ -18,8 +18,8 @@ import {TuiCellComponent} from './cell.component'; }, }) export class TuiCellDirective { - protected readonly nothing = tuiWithStyles(TuiCellComponent); - @Input('tuiCell') public size: TuiSizeL | TuiSizeS | '' = 'l'; + + protected readonly nothing = tuiWithStyles(TuiCellComponent); } diff --git a/projects/experimental/directives/progress-segmented/progress-segmented.directive.ts b/projects/experimental/directives/progress-segmented/progress-segmented.directive.ts index 862c9213f351..1e458b710c22 100644 --- a/projects/experimental/directives/progress-segmented/progress-segmented.directive.ts +++ b/projects/experimental/directives/progress-segmented/progress-segmented.directive.ts @@ -12,8 +12,8 @@ import {TuiProgressSegmentedComponent} from './progress-segmented.component'; }, }) export class TuiProgressSegmentedDirective { - protected readonly nothing = tuiWithStyles(TuiProgressSegmentedComponent); - @Input() public segments = 1; + + protected readonly nothing = tuiWithStyles(TuiProgressSegmentedComponent); } diff --git a/projects/experimental/directives/sensitive/sensitive.directive.ts b/projects/experimental/directives/sensitive/sensitive.directive.ts index b4cd50822ce1..baad200e3ccc 100644 --- a/projects/experimental/directives/sensitive/sensitive.directive.ts +++ b/projects/experimental/directives/sensitive/sensitive.directive.ts @@ -18,11 +18,10 @@ const rowsInSvg = 3; }, }) export class TuiSensitiveDirective { - protected readonly nothing = tuiWithStyles(TuiSensitiveComponent); - @Input() public tuiSensitive: boolean | null = false; + protected readonly nothing = tuiWithStyles(TuiSensitiveComponent); protected readonly offset = Math.round(Math.random() * 10) * 10; protected readonly height$ = inject(ResizeObserverService).pipe( map(([{contentRect}]) => [ diff --git a/projects/experimental/directives/surface/surface.directive.ts b/projects/experimental/directives/surface/surface.directive.ts index 7cd3b832cd33..9629ae52182a 100644 --- a/projects/experimental/directives/surface/surface.directive.ts +++ b/projects/experimental/directives/surface/surface.directive.ts @@ -11,8 +11,8 @@ import {TuiSurfaceComponent} from './surface.component'; }, }) export class TuiSurfaceDirective { - protected readonly nothing = tuiWithStyles(TuiSurfaceComponent); - @Input() public tuiSurface = ''; + + protected readonly nothing = tuiWithStyles(TuiSurfaceComponent); } diff --git a/projects/experimental/directives/title/title.directive.ts b/projects/experimental/directives/title/title.directive.ts index ab4fc3548b10..d813f94a0e9a 100644 --- a/projects/experimental/directives/title/title.directive.ts +++ b/projects/experimental/directives/title/title.directive.ts @@ -12,8 +12,8 @@ import {TuiTitleComponent} from './title.component'; }, }) export class TuiTitleDirective { - protected readonly nothing = tuiWithStyles(TuiTitleComponent); - @Input('tuiTitle') public size: TuiSizeL | TuiSizeS | '' = ''; + + protected readonly nothing = tuiWithStyles(TuiTitleComponent); } diff --git a/projects/kit/abstract/abstract-native-select.ts b/projects/kit/abstract/abstract-native-select.ts index 004dbb84b35c..d0c6e63104b0 100644 --- a/projects/kit/abstract/abstract-native-select.ts +++ b/projects/kit/abstract/abstract-native-select.ts @@ -14,7 +14,6 @@ import {TUI_ITEMS_HANDLERS} from '@taiga-ui/kit/tokens'; @Directive() export abstract class AbstractTuiNativeSelect { private readonly idService = inject(TuiIdService); - protected readonly el: HTMLSelectElement = inject(ElementRef).nativeElement; @Input() public disabledItemHandler: TuiBooleanHandler | null = null; @@ -22,6 +21,7 @@ export abstract class AbstractTuiNativeSelect @ViewChild(TuiDataListDirective, {read: TemplateRef, static: true}) protected readonly datalist: TemplateRef | null = null; + protected readonly el: HTMLSelectElement = inject(ElementRef).nativeElement; protected readonly host = inject(TUI_TEXTFIELD_HOST); protected readonly control = inject(AbstractTuiControl); protected readonly itemsHandlers = inject(TUI_ITEMS_HANDLERS); diff --git a/projects/kit/components/accordion/accordion-item/accordion-item.component.ts b/projects/kit/components/accordion/accordion-item/accordion-item.component.ts index e1971b80b8f9..c0154d3ab1c4 100644 --- a/projects/kit/components/accordion/accordion-item/accordion-item.component.ts +++ b/projects/kit/components/accordion/accordion-item/accordion-item.component.ts @@ -94,6 +94,11 @@ export class TuiAccordionItemComponent return tuiIsNativeFocused(this.nativeFocusableElement); } + public close(): void { + this.updateOpen(false); + this.cdr.markForCheck(); + } + protected onFocused(focused: boolean): void { this.updateFocused(focused); } @@ -117,11 +122,6 @@ export class TuiAccordionItemComponent this.updateOpen(false); } - public close(): void { - this.updateOpen(false); - this.cdr.markForCheck(); - } - private updateOpen(open: boolean): void { if (this.open === open) { return; diff --git a/projects/kit/components/badge/badge.directive.ts b/projects/kit/components/badge/badge.directive.ts index 377b3727e9a1..39f1a80e8a3e 100644 --- a/projects/kit/components/badge/badge.directive.ts +++ b/projects/kit/components/badge/badge.directive.ts @@ -34,11 +34,12 @@ import {TUI_BADGE_OPTIONS} from './badge.options'; }) export class TuiBadgeDirective { private readonly options = inject(TUI_BADGE_OPTIONS); - protected readonly nothing = tuiWithStyles(TuiBadgeComponent); @Input() public size = this.options.size; @Input() public dot = this.options.dot; + + protected readonly nothing = tuiWithStyles(TuiBadgeComponent); } diff --git a/projects/kit/components/block/block.directive.ts b/projects/kit/components/block/block.directive.ts index 888ca625759d..3aa93074aa1a 100644 --- a/projects/kit/components/block/block.directive.ts +++ b/projects/kit/components/block/block.directive.ts @@ -42,11 +42,11 @@ export class TuiBlockDirective { private readonly options = inject(TUI_BLOCK_OPTIONS); - protected readonly nothing = tuiWithStyles(TuiBlockComponent); - @Input('tuiBlock') public size: TuiSizeL | TuiSizeXS | '' = this.options.size; + protected readonly nothing = tuiWithStyles(TuiBlockComponent); + protected get disabled(): boolean { return !!this.control?.disabled; } diff --git a/projects/kit/components/breadcrumbs/breadcrumbs.component.ts b/projects/kit/components/breadcrumbs/breadcrumbs.component.ts index aaa0938a5e66..a30c39c9ecc2 100644 --- a/projects/kit/components/breadcrumbs/breadcrumbs.component.ts +++ b/projects/kit/components/breadcrumbs/breadcrumbs.component.ts @@ -27,15 +27,19 @@ import {TUI_BREADCRUMBS_OPTIONS} from './breadcrumbs.options'; ], }) export class TuiBreadcrumbsComponent extends TuiModeDirective { - protected readonly options = inject(TUI_BREADCRUMBS_OPTIONS); + private readonly options = inject(TUI_BREADCRUMBS_OPTIONS); @Input() @HostBinding('attr.data-size') public size = this.options.size; + public override readonly mode = this.options.mode; + @ContentChildren(TuiItemDirective, {read: TemplateRef}) protected readonly items: QueryList>> = EMPTY_QUERY; - public override readonly mode = this.options.mode; + public get icon(): string { + return this.options.icon; + } } diff --git a/projects/kit/components/breadcrumbs/breadcrumbs.template.html b/projects/kit/components/breadcrumbs/breadcrumbs.template.html index c9cef6a738ac..a9f508e0f4b7 100644 --- a/projects/kit/components/breadcrumbs/breadcrumbs.template.html +++ b/projects/kit/components/breadcrumbs/breadcrumbs.template.html @@ -4,6 +4,6 @@ diff --git a/projects/kit/components/calendar-month/calendar-month.component.ts b/projects/kit/components/calendar-month/calendar-month.component.ts index 3a7333c6e6f9..1fc4d973b09a 100644 --- a/projects/kit/components/calendar-month/calendar-month.component.ts +++ b/projects/kit/components/calendar-month/calendar-month.component.ts @@ -58,11 +58,10 @@ export class TuiCalendarMonthComponent implements TuiWithOptionalMinMax(); - protected isYearPickerShown = false; - public hoveredItem: TuiMonth | null = null; public pressedItem: TuiMonth | null = null; + protected isYearPickerShown = false; protected readonly months$ = inject(TUI_CALENDAR_MONTHS); @HostBinding('class._single') @@ -73,20 +72,32 @@ export class TuiCalendarMonthComponent implements TuiWithOptionalMinMax { + return this.calculateDisabledItemHandlerWithMinMax( + this.disabledItemHandler, + this.value, + this.computedMin, + this.computedMax, + ); + } + @tuiPure private calculateDisabledItemHandlerWithMinMax( disabledItemHandler: TuiBooleanHandlerWithContext, @@ -228,15 +236,6 @@ export class TuiCalendarMonthComponent implements TuiWithOptionalMinMax { - return this.calculateDisabledItemHandlerWithMinMax( - this.disabledItemHandler, - this.value, - this.computedMin, - this.computedMax, - ); - } - private updateHoveredItem(month: TuiMonth | null): void { if (tuiNullableSame(this.hoveredItem, month, (a, b) => a.monthSame(b))) { return; diff --git a/projects/kit/components/calendar-range/calendar-range.component.ts b/projects/kit/components/calendar-range/calendar-range.component.ts index 8425af0ab598..39abaffc872a 100644 --- a/projects/kit/components/calendar-range/calendar-range.component.ts +++ b/projects/kit/components/calendar-range/calendar-range.component.ts @@ -84,14 +84,6 @@ export class TuiCalendarRangeComponent implements TuiWithOptionalMinMax protected readonly maxLengthMapper = MAX_DAY_RANGE_LENGTH_MAPPER; - protected get computedMin(): TuiDay { - return this.min ?? TUI_FIRST_DAY; - } - - protected get computedMax(): TuiDay { - return this.max ?? TUI_LAST_DAY; - } - constructor() { this.valueChanges ?.pipe( @@ -103,6 +95,38 @@ export class TuiCalendarRangeComponent implements TuiWithOptionalMinMax }); } + public onItemSelect(item: TuiDayRangePeriod | string): void { + if (typeof item !== 'string') { + this.updateValue(item.range.dayLimit(this.min, this.max)); + + return; + } + + if (this.activePeriod !== null) { + this.updateValue(null); + } + } + + protected get computedMin(): TuiDay { + return this.min ?? TUI_FIRST_DAY; + } + + protected get computedMax(): TuiDay { + return this.max ?? TUI_LAST_DAY; + } + + protected get calculatedDisabledItemHandler(): TuiBooleanHandler { + return this.calculateDisabledItemHandler( + this.disabledItemHandler, + this.value, + this.minLength, + ); + } + + protected get computedMonth(): TuiMonth { + return this.value ? this.value.to : this.defaultViewedMonth; + } + @HostListener('document:keydown.capture', ['$event']) protected onEsc(event: KeyboardEvent): void { if (event.key !== 'Escape' || !this.value?.isSingleDay) { @@ -133,18 +157,6 @@ export class TuiCalendarRangeComponent implements TuiWithOptionalMinMax otherDateText, ]; - protected get calculatedDisabledItemHandler(): TuiBooleanHandler { - return this.calculateDisabledItemHandler( - this.disabledItemHandler, - this.value, - this.minLength, - ); - } - - protected get computedMonth(): TuiMonth { - return this.value ? this.value.to : this.defaultViewedMonth; - } - protected isItemActive(item: TuiDayRangePeriod | string): boolean { const {activePeriod} = this; @@ -170,18 +182,6 @@ export class TuiCalendarRangeComponent implements TuiWithOptionalMinMax this.updateValue(TuiDayRange.sort(value.from, day)); } - public onItemSelect(item: TuiDayRangePeriod | string): void { - if (typeof item !== 'string') { - this.updateValue(item.range.dayLimit(this.min, this.max)); - - return; - } - - if (this.activePeriod !== null) { - this.updateValue(null); - } - } - protected updateValue(value: TuiDayRange | null): void { this.value = value; this.valueChange.emit(value); diff --git a/projects/kit/components/carousel/carousel.component.ts b/projects/kit/components/carousel/carousel.component.ts index 50b7bcbae4b0..23d53514c76d 100644 --- a/projects/kit/components/carousel/carousel.component.ts +++ b/projects/kit/components/carousel/carousel.component.ts @@ -54,6 +54,18 @@ export class TuiCarouselComponent { @HostBinding('class._transitioned') protected transitioned = true; + public next(): void { + if (this.items && this.index === this.items.length - this.itemsCount) { + return; + } + + this.updateIndex(this.index + 1); + } + + public prev(): void { + this.updateIndex(this.index - 1); + } + protected get transform(): string { const x = this.transitioned ? this.computedTranslate : this.translate; @@ -83,18 +95,6 @@ export class TuiCarouselComponent { }; } - public next(): void { - if (this.items && this.index === this.items.length - this.itemsCount) { - return; - } - - this.updateIndex(this.index + 1); - } - - public prev(): void { - this.updateIndex(this.index - 1); - } - protected isDisabled(index: number): boolean { return index < this.index || index > this.index + this.itemsCount; } diff --git a/projects/kit/components/carousel/carousel.directive.ts b/projects/kit/components/carousel/carousel.directive.ts index 259bf0393893..484129dda2eb 100644 --- a/projects/kit/components/carousel/carousel.directive.ts +++ b/projects/kit/components/carousel/carousel.directive.ts @@ -30,6 +30,10 @@ export class TuiCarouselDirective extends Observable { ), ); + constructor() { + super(subscriber => this.output$.subscribe(subscriber)); + } + @Input() public set duration(duration: number) { this.duration$.next(duration); @@ -39,8 +43,4 @@ export class TuiCarouselDirective extends Observable { public set index(_: number) { this.duration$.next(this.duration$.value); } - - constructor() { - super(subscriber => this.output$.subscribe(subscriber)); - } } diff --git a/projects/kit/components/combo-box/combo-box.component.ts b/projects/kit/components/combo-box/combo-box.component.ts index 112deb76fe16..e7ae5f8e81d5 100644 --- a/projects/kit/components/combo-box/combo-box.component.ts +++ b/projects/kit/components/combo-box/combo-box.component.ts @@ -95,21 +95,10 @@ export class TuiComboBoxComponent @Output() public readonly searchChange = new EventEmitter(); - @ContentChild(TuiDataListDirective, {read: TemplateRef}) - protected readonly datalist: PolymorpheusContent>; - public open = false; - @HostBinding('attr.data-size') - protected get size(): TuiSizeL | TuiSizeS { - return this.textfieldSize.size; - } - - protected get arrow(): PolymorpheusContent< - TuiContext - > { - return !this.interactive ? this.arrowMode.disabled : this.arrowMode.interactive; - } + @ContentChild(TuiDataListDirective, {read: TemplateRef}) + protected readonly datalist: PolymorpheusContent>; public get nativeFocusableElement(): HTMLInputElement | null { return this.textfield?.nativeFocusableElement ?? null; @@ -126,18 +115,6 @@ export class TuiComboBoxComponent return this.value === null ? this.search || '' : this.stringify(this.value); } - protected get showValueTemplate(): boolean { - return tuiIsPresent(this.value) && !this.focused; - } - - protected get computedContent(): PolymorpheusContent> { - return this.valueContent || this.nativeValue; - } - - protected onActiveZone(active: boolean): void { - this.updateFocused(active); - } - public checkOption(option: T): void { if (!this.isStrictMatch(option)) { return; @@ -158,22 +135,6 @@ export class TuiComboBoxComponent } } - protected onFieldKeyDownEnter(event: Event): void { - if (this.open) { - event.preventDefault(); - } - - const options = this.accessor?.getOptions() || []; - - if (options.length !== 1) { - return; - } - - this.value = options[0]; - this.updateSearch(null); - this.close(); - } - public onValueChange(value: string): void { this.updateSearch(value); @@ -196,15 +157,54 @@ export class TuiComboBoxComponent } } + public toggle(): void { + this.hostedDropdown?.updateOpen(!this.open); + } + + @HostBinding('attr.data-size') + protected get size(): TuiSizeL | TuiSizeS { + return this.textfieldSize.size; + } + + protected get arrow(): PolymorpheusContent< + TuiContext + > { + return !this.interactive ? this.arrowMode.disabled : this.arrowMode.interactive; + } + + protected get showValueTemplate(): boolean { + return tuiIsPresent(this.value) && !this.focused; + } + + protected get computedContent(): PolymorpheusContent> { + return this.valueContent || this.nativeValue; + } + + protected onActiveZone(active: boolean): void { + this.updateFocused(active); + } + + protected onFieldKeyDownEnter(event: Event): void { + if (this.open) { + event.preventDefault(); + } + + const options = this.accessor?.getOptions() || []; + + if (options.length !== 1) { + return; + } + + this.value = options[0]; + this.updateSearch(null); + this.close(); + } + /** @deprecated use 'value' setter */ protected override updateValue(value: T | null): void { super.updateValue(value); } - public toggle(): void { - this.hostedDropdown?.updateOpen(!this.open); - } - private isStrictMatch(item: T): boolean { return !!this.search && !!this.strictMatcher?.(item, this.search, this.stringify); } diff --git a/projects/kit/components/data-list-wrapper/data-list-wrapper.ts b/projects/kit/components/data-list-wrapper/data-list-wrapper.ts index db985871d30d..aaa3ecf903ce 100644 --- a/projects/kit/components/data-list-wrapper/data-list-wrapper.ts +++ b/projects/kit/components/data-list-wrapper/data-list-wrapper.ts @@ -20,9 +20,6 @@ import {PolymorpheusContent} from '@tinkoff/ng-polymorpheus'; @Directive() export abstract class AbstractTuiDataListWrapper { - @ViewChildren(forwardRef(() => TuiOptionComponent)) - protected readonly optionsQuery: QueryList> = EMPTY_QUERY; - @Input() public disabledItemHandler: TuiItemsHandlers['disabledItemHandler'] = this.itemsHandlers.disabledItemHandler; @@ -36,6 +33,9 @@ export abstract class AbstractTuiDataListWrapper { @Output() public readonly itemClick = new EventEmitter(); + @ViewChildren(forwardRef(() => TuiOptionComponent)) + protected readonly optionsQuery: QueryList> = EMPTY_QUERY; + protected constructor( public readonly itemsHandlers: TuiItemsHandlers, public readonly defaultSize: TuiSizeL | TuiSizeXS, diff --git a/projects/kit/components/files/files/files.component.ts b/projects/kit/components/files/files/files.component.ts index adb84561f985..94379e601284 100644 --- a/projects/kit/components/files/files/files.component.ts +++ b/projects/kit/components/files/files/files.component.ts @@ -32,10 +32,6 @@ import {TUI_HIDE_TEXT, TUI_SHOW_ALL_TEXT} from '@taiga-ui/kit/tokens'; hostDirectives: [TuiGroupDirective], }) export class TuiFilesComponent { - @ContentChildren(TuiItemDirective, {read: TemplateRef}) - protected readonly items: QueryList>> = - EMPTY_QUERY; - @Input() public max = 0; @@ -45,6 +41,10 @@ export class TuiFilesComponent { @Output() public readonly expandedChange = new EventEmitter(); + @ContentChildren(TuiItemDirective, {read: TemplateRef}) + protected readonly items: QueryList>> = + EMPTY_QUERY; + protected readonly hideText$ = inject(TUI_HIDE_TEXT); protected readonly showAllText$ = inject(TUI_SHOW_ALL_TEXT); diff --git a/projects/kit/components/files/input-files/input-files.directive.ts b/projects/kit/components/files/input-files/input-files.directive.ts index 91a4db00258c..77cb77cda9bd 100644 --- a/projects/kit/components/files/input-files/input-files.directive.ts +++ b/projects/kit/components/files/input-files/input-files.directive.ts @@ -54,24 +54,25 @@ export class TuiInputFilesDirective ); public readonly appearance = 'file'; - protected readonly host = inject(forwardRef(() => TuiInputFilesComponent)); public readonly input: HTMLInputElement = inject(ElementRef).nativeElement; + protected readonly host = inject(forwardRef(() => TuiInputFilesComponent)); + public get focused(): boolean { return tuiIsNativeFocused(this.input); } - protected onClick(event: MouseEvent): void { - if (this.input.readOnly) { - event.preventDefault(); - } - } - public process(files: FileList): void { this.value = this.input.multiple ? [...toArray(this.value), ...Array.from(files)] : files[0] || null; } + + protected onClick(event: MouseEvent): void { + if (this.input.readOnly) { + event.preventDefault(); + } + } } function toArray(value: TuiFileLike | readonly TuiFileLike[] | null): TuiFileLike[] { diff --git a/projects/kit/components/filter/filter.component.ts b/projects/kit/components/filter/filter.component.ts index 40c81e15ec8c..b94c90e0cdfc 100644 --- a/projects/kit/components/filter/filter.component.ts +++ b/projects/kit/components/filter/filter.component.ts @@ -55,6 +55,10 @@ export class TuiFilterComponent extends AbstractTuiMultipleControl { @Output() public readonly toggledItem = new EventEmitter(); + public get focused(): boolean { + return tuiIsNativeFocusedIn(this.el); + } + @Input() public content: PolymorpheusContent = ({$implicit}: TuiContext) => TUI_DEFAULT_STRINGIFY($implicit); @@ -62,14 +66,6 @@ export class TuiFilterComponent extends AbstractTuiMultipleControl { @Input() public badgeHandler: TuiHandler = item => Number(item); - public get focused(): boolean { - return tuiIsNativeFocusedIn(this.el); - } - - protected get badgeSize(): TuiSizeS | TuiSizeXL { - return badgeSizeMap[this.size]; - } - public onCheckbox(value: boolean, item: T): void { this.toggledItem.emit(item); this.value = value @@ -77,6 +73,10 @@ export class TuiFilterComponent extends AbstractTuiMultipleControl { : this.value.filter(arrItem => !this.identityMatcher(arrItem, item)); } + protected get badgeSize(): TuiSizeS | TuiSizeXL { + return badgeSizeMap[this.size]; + } + protected isCheckboxEnabled(item: T): boolean { return this.value.some(arrItem => this.identityMatcher(arrItem, item)); } diff --git a/projects/kit/components/input-copy/input-copy.component.ts b/projects/kit/components/input-copy/input-copy.component.ts index 6e2c91f5c52f..e4f83f40c748 100644 --- a/projects/kit/components/input-copy/input-copy.component.ts +++ b/projects/kit/components/input-copy/input-copy.component.ts @@ -61,6 +61,20 @@ export class TuiInputCopyComponent @Input() public messageAppearance = this.options.messageAppearance; + public get nativeFocusableElement(): TuiNativeFocusableElement | null { + return this.computedDisabled || !this.textfield + ? null + : this.textfield.nativeFocusableElement; + } + + public get focused(): boolean { + return !!this.textfield?.focused; + } + + public onValueChange(value: string): void { + this.value = value; + } + @HostBinding('attr.data-size') protected get size(): TuiSizeL | TuiSizeS { return this.textfieldSize.size; @@ -83,24 +97,10 @@ export class TuiInputCopyComponent ); } - public get nativeFocusableElement(): TuiNativeFocusableElement | null { - return this.computedDisabled || !this.textfield - ? null - : this.textfield.nativeFocusableElement; - } - - public get focused(): boolean { - return !!this.textfield?.focused; - } - protected get icon(): TuiInputCopyOptions['icon'] { return this.options.icon; } - public onValueChange(value: string): void { - this.value = value; - } - protected onFocused(focused: boolean): void { this.updateFocused(focused); } diff --git a/projects/kit/components/input-date-multi/input-date-multi.component.ts b/projects/kit/components/input-date-multi/input-date-multi.component.ts index 0ef6cdec1d0e..cc788f3ebe0b 100644 --- a/projects/kit/components/input-date-multi/input-date-multi.component.ts +++ b/projects/kit/components/input-date-multi/input-date-multi.component.ts @@ -80,10 +80,6 @@ export class TuiInputDateMultiComponent private readonly mobileCalendar = inject(TUI_MOBILE_CALENDAR, {optional: true}); private readonly options = inject(TUI_INPUT_DATE_OPTIONS); private readonly textfieldSize = inject(TUI_TEXTFIELD_SIZE); - protected readonly dateTexts$ = inject(TUI_DATE_TEXTS); - protected override readonly valueTransformer = inject< - AbstractTuiValueTransformer - >(TUI_DATE_VALUE_TRANSFORMER, {optional: true}); @Input() public min: TuiDay | null = this.options.min; @@ -116,6 +112,11 @@ export class TuiInputDateMultiComponent @Input() public rows = 1; + protected readonly dateTexts$ = inject(TUI_DATE_TEXTS); + protected override readonly valueTransformer = inject< + AbstractTuiValueTransformer + >(TUI_DATE_VALUE_TRANSFORMER, {optional: true}); + protected maskitoOptions: MaskitoOptions = maskitoDateOptionsGenerator({ mode: 'dd/mm/yyyy', separator: '.', @@ -135,6 +136,14 @@ export class TuiInputDateMultiComponent ), ); + public get nativeFocusableElement(): HTMLInputElement | null { + return this.textfield?.nativeFocusableElement || null; + } + + public get focused(): boolean { + return !!this.textfield?.focused; + } + @Input() public tagValidator: TuiBooleanHandler = (tag: TuiDay | string) => { const {year, month, day} = tuiIsString(tag) @@ -150,19 +159,11 @@ export class TuiInputDateMultiComponent ); }; - @HostListener('click') - protected onClick(): void { - if (!this.isMobile) { - this.open = !this.open; - } + public override setDisabledState(): void { + super.setDisabledState(); + this.open = false; } - protected readonly disabledItemHandlerWrapper: TuiMapper< - TuiBooleanHandler | TuiBooleanHandler, - TuiBooleanHandler | string> - > = handler => stringifiable => - tuiIsString(stringifiable) || handler(stringifiable.item); - @HostBinding('attr.data-size') protected get size(): TuiSizeL | TuiSizeS { return this.textfieldSize.size; @@ -180,14 +181,6 @@ export class TuiInputDateMultiComponent return this.max ?? this.options.max; } - public get nativeFocusableElement(): HTMLInputElement | null { - return this.textfield?.nativeFocusableElement || null; - } - - public get focused(): boolean { - return !!this.textfield?.focused; - } - protected get computedMobile(): boolean { return this.isMobile && !!this.mobileCalendar; } @@ -208,6 +201,13 @@ export class TuiInputDateMultiComponent return this.interactive && !this.computedMobile; } + @HostListener('click') + protected onClick(): void { + if (!this.isMobile) { + this.open = !this.open; + } + } + protected onIconClick(): void { if (!this.computedMobile || !this.mobileCalendar) { return; @@ -233,6 +233,12 @@ export class TuiInputDateMultiComponent }); } + protected readonly disabledItemHandlerWrapper: TuiMapper< + TuiBooleanHandler | TuiBooleanHandler, + TuiBooleanHandler | string> + > = handler => stringifiable => + tuiIsString(stringifiable) || handler(stringifiable.item); + protected onEnter(search: string): void { if (!this.tagValidator(search)) { return; @@ -279,9 +285,4 @@ export class TuiInputDateMultiComponent protected onFocused(focused: boolean): void { this.updateFocused(focused); } - - public override setDisabledState(): void { - super.setDisabledState(); - this.open = false; - } } diff --git a/projects/kit/components/input-date-range/input-date-range.component.ts b/projects/kit/components/input-date-range/input-date-range.component.ts index 3b70763f8e6f..fc19f306d928 100644 --- a/projects/kit/components/input-date-range/input-date-range.component.ts +++ b/projects/kit/components/input-date-range/input-date-range.component.ts @@ -86,11 +86,6 @@ export class TuiInputDateRangeComponent private readonly mobileCalendar = inject(TUI_MOBILE_CALENDAR, {optional: true}); private readonly options = inject(TUI_INPUT_DATE_OPTIONS); private readonly textfieldSize = inject(TUI_TEXTFIELD_SIZE); - protected readonly dateTexts$ = inject(TUI_DATE_TEXTS); - protected override readonly valueTransformer = inject( - TUI_DATE_RANGE_VALUE_TRANSFORMER, - {optional: true}, - ); @Input() public disabledItemHandler: TuiBooleanHandler = ALWAYS_FALSE_HANDLER; @@ -118,6 +113,12 @@ export class TuiInputDateRangeComponent public open = false; + protected readonly dateTexts$ = inject(TUI_DATE_TEXTS); + protected override readonly valueTransformer = inject( + TUI_DATE_RANGE_VALUE_TRANSFORMER, + {optional: true}, + ); + protected readonly maxLengthMapper: TuiTypedMapper< [TuiDay, TuiDayRange | null, TuiDayLike | null, boolean], TuiDay @@ -132,6 +133,70 @@ export class TuiInputDateRangeComponent protected readonly dateFormat = inject(TUI_DATE_FORMAT); protected readonly dateSeparator = inject(TUI_DATE_SEPARATOR); + public get nativeFocusableElement(): HTMLInputElement | null { + return this.textfield?.nativeFocusableElement ?? null; + } + + public get focused(): boolean { + return !!this.textfield?.focused; + } + + public get computedExampleText(): string { + return this.items.length + ? this.textfield?.nativeFocusableElement?.placeholder || '' + : ''; + } + + public get computedValue(): string { + const {value, nativeValue, activePeriod} = this; + + if (activePeriod) { + return String(activePeriod); + } + + return value + ? value.getFormattedDayRange(this.dateFormat, this.dateSeparator) + : nativeValue; + } + + @HostListener('click') + public onClick(): void { + if (!this.isMobile) { + this.toggle(); + } + } + + public onValueChange(value: string): void { + if (this.control) { + this.control.updateValueAndValidity({emitEvent: false}); + } + + if (!value) { + this.onOpenChange(true); + } + + this.value = + value.length === DATE_RANGE_FILLER_LENGTH + ? TuiDayRange.normalizeParse(value, this.dateFormat) + : null; + } + + public onRangeChange(range: TuiDayRange | null): void { + this.toggle(); + this.focusInput(); + + if (!range) { + this.nativeValue = ''; + } + + this.value = range; + } + + public override writeValue(value: TuiDayRange | null): void { + super.writeValue(value); + this.nativeValue = value ? this.computedValue : ''; + } + @HostBinding('attr.data-size') protected get size(): TuiSizeL | TuiSizeS { return this.textfieldSize.size; @@ -145,14 +210,6 @@ export class TuiInputDateRangeComponent return this.max ?? TUI_LAST_DAY; } - public get nativeFocusableElement(): HTMLInputElement | null { - return this.textfield?.nativeFocusableElement ?? null; - } - - public get focused(): boolean { - return !!this.textfield?.focused; - } - protected get computedMobile(): boolean { return this.isMobile && !!this.mobileCalendar; } @@ -165,12 +222,6 @@ export class TuiInputDateRangeComponent return this.interactive && !this.computedMobile; } - public get computedExampleText(): string { - return this.items.length - ? this.textfield?.nativeFocusableElement?.placeholder || '' - : ''; - } - protected get computedMask(): MaskitoOptions { return this.activePeriod ? MASKITO_DEFAULT_OPTIONS @@ -198,18 +249,6 @@ export class TuiInputDateRangeComponent ); } - public get computedValue(): string { - const {value, nativeValue, activePeriod} = this; - - if (activePeriod) { - return String(activePeriod); - } - - return value - ? value.getFormattedDayRange(this.dateFormat, this.dateSeparator) - : nativeValue; - } - protected get showValueTemplate(): boolean { return tuiIsPresent(this.value) && !this.focused; } @@ -240,13 +279,6 @@ export class TuiInputDateRangeComponent } } - @HostListener('click') - public onClick(): void { - if (!this.isMobile) { - this.toggle(); - } - } - protected getComputedRangeFiller(dateFiller: string): string { return this.activePeriod ? '' : this.getDateRangeFiller(dateFiller); } @@ -289,32 +321,6 @@ export class TuiInputDateRangeComponent this.open = open; } - public onValueChange(value: string): void { - if (this.control) { - this.control.updateValueAndValidity({emitEvent: false}); - } - - if (!value) { - this.onOpenChange(true); - } - - this.value = - value.length === DATE_RANGE_FILLER_LENGTH - ? TuiDayRange.normalizeParse(value, this.dateFormat) - : null; - } - - public onRangeChange(range: TuiDayRange | null): void { - this.toggle(); - this.focusInput(); - - if (!range) { - this.nativeValue = ''; - } - - this.value = range; - } - // TODO: investigate if it is used anywhere and (if not) delete it in v4.0 protected onItemSelect(item: TuiDayRangePeriod | string): void { this.toggle(); @@ -348,11 +354,6 @@ export class TuiInputDateRangeComponent } } - public override writeValue(value: TuiDayRange | null): void { - super.writeValue(value); - this.nativeValue = value ? this.computedValue : ''; - } - protected override valueIdenticalComparator( oldValue: TuiDayRange | null, newValue: TuiDayRange | null, @@ -360,6 +361,10 @@ export class TuiInputDateRangeComponent return tuiNullableSame(oldValue, newValue, (a, b) => a.daySame(b)); } + private get itemSelected(): boolean { + return this.items.findIndex(item => String(item) === this.nativeValue) !== -1; + } + @tuiPure private calculateMask( dateFormat: TuiDateMode, @@ -379,10 +384,6 @@ export class TuiInputDateRangeComponent }); } - private get itemSelected(): boolean { - return this.items.findIndex(item => String(item) === this.nativeValue) !== -1; - } - private toggle(): void { this.open = !this.open; } diff --git a/projects/kit/components/input-date-time/input-date-time.component.ts b/projects/kit/components/input-date-time/input-date-time.component.ts index e351414b974b..f182e6a6330d 100644 --- a/projects/kit/components/input-date-time/input-date-time.component.ts +++ b/projects/kit/components/input-date-time/input-date-time.component.ts @@ -79,12 +79,6 @@ export class TuiInputDateTimeComponent private readonly textfieldSize = inject(TUI_TEXTFIELD_SIZE); private month: TuiMonth | null = null; private readonly timeMode$ = new BehaviorSubject('HH:MM'); - protected readonly timeTexts$ = inject(TUI_TIME_TEXTS); - protected readonly dateTexts$ = inject(TUI_DATE_TEXTS); - protected override readonly valueTransformer = inject( - TUI_DATE_TIME_VALUE_TRANSFORMER, - {optional: true}, - ); @Input() public min: TuiDay | [TuiDay | null, TuiTime | null] | null = this.options.min; @@ -98,17 +92,15 @@ export class TuiInputDateTimeComponent @Input() public defaultActiveYearMonth = TuiMonth.currentLocal(); - @Input() - public set timeMode(value: TuiTimeMode) { - this.timeMode$.next(value); - } - - public get timeMode(): TuiTimeMode { - return this.timeMode$.value; - } - public open = false; + protected readonly timeTexts$ = inject(TUI_TIME_TEXTS); + protected readonly dateTexts$ = inject(TUI_DATE_TEXTS); + protected override readonly valueTransformer = inject( + TUI_DATE_TIME_VALUE_TRANSFORMER, + {optional: true}, + ); + protected readonly type!: TuiContext; protected readonly filler$: Observable = combineLatest([ @@ -130,6 +122,69 @@ export class TuiInputDateTimeComponent protected readonly isMobile = inject(TUI_IS_MOBILE); protected readonly isIos = inject(TUI_IS_IOS); + @Input() + public set timeMode(value: TuiTimeMode) { + this.timeMode$.next(value); + } + + public get timeMode(): TuiTimeMode { + return this.timeMode$.value; + } + + public get nativeFocusableElement(): HTMLInputElement | null { + return this.textfield?.nativeFocusableElement ?? null; + } + + public get focused(): boolean { + return !!this.textfield?.focused; + } + + public get computedValue(): string { + const {value, nativeValue, timeMode} = this; + const [date, time] = value; + const hasTimeInputChars = nativeValue.length > DATE_FILLER_LENGTH; + + if (!date || (!time && hasTimeInputChars)) { + return nativeValue; + } + + return this.getDateTimeString(date, time, timeMode); + } + + public override setDisabledState(): void { + super.setDisabledState(); + this.open = false; + } + + public override writeValue(value: [TuiDay | null, TuiTime | null] | null): void { + super.writeValue(value); + + this.nativeValue = + this.value && (this.value[0] || this.value[1]) ? this.computedValue : ''; + } + + public onValueChange(value: string): void { + if (!value) { + this.onOpenChange(true); + } + + if (value.length < DATE_FILLER_LENGTH) { + this.value = [null, null]; + + return; + } + + const [date, time] = value.split(DATE_TIME_SEPARATOR); + const parsedDate = TuiDay.normalizeParse(date, this.dateFormat); + const parsedTime = + time && time.length === this.timeMode.length + ? TuiTime.fromString(time) + : null; + + this.open = false; + this.value = [parsedDate, parsedTime]; + } + @HostBinding('attr.data-size') protected get size(): TuiSizeL | TuiSizeS { return this.textfieldSize.size; @@ -157,38 +212,14 @@ export class TuiInputDateTimeComponent ); } - public get nativeFocusableElement(): HTMLInputElement | null { - return this.textfield?.nativeFocusableElement ?? null; - } - - public get focused(): boolean { - return !!this.textfield?.focused; - } - protected get calendarIcon(): TuiInputDateOptions['icon'] { return this.options.icon; } - private get nativePicker(): boolean { - return this.options.nativePicker && this.isMobile; - } - protected get showNativePicker(): boolean { return this.nativePicker && this.timeMode === 'HH:MM'; } - public get computedValue(): string { - const {value, nativeValue, timeMode} = this; - const [date, time] = value; - const hasTimeInputChars = nativeValue.length > DATE_FILLER_LENGTH; - - if (!date || (!time && hasTimeInputChars)) { - return nativeValue; - } - - return this.getDateTimeString(date, time, timeMode); - } - protected get calendarValue(): TuiDay | null { return this.value[0]; } @@ -236,28 +267,6 @@ export class TuiInputDateTimeComponent this.open = !this.open; } - public onValueChange(value: string): void { - if (!value) { - this.onOpenChange(true); - } - - if (value.length < DATE_FILLER_LENGTH) { - this.value = [null, null]; - - return; - } - - const [date, time] = value.split(DATE_TIME_SEPARATOR); - const parsedDate = TuiDay.normalizeParse(date, this.dateFormat); - const parsedTime = - time && time.length === this.timeMode.length - ? TuiTime.fromString(time) - : null; - - this.open = false; - this.value = [parsedDate, parsedTime]; - } - protected onDayClick(day: TuiDay): void { const modifiedTime = this.value[1] && this.clampTime(this.value[1], day); const newCaretIndex = DATE_FILLER_LENGTH + DATE_TIME_SEPARATOR.length; @@ -309,18 +318,6 @@ export class TuiInputDateTimeComponent this.value = [this.value[0], parsedTime]; } - public override setDisabledState(): void { - super.setDisabledState(); - this.open = false; - } - - public override writeValue(value: [TuiDay | null, TuiTime | null] | null): void { - super.writeValue(value); - - this.nativeValue = - this.value && (this.value[0] || this.value[1]) ? this.computedValue : ''; - } - protected getFallbackValue(): [TuiDay | null, TuiTime | null] { return [null, null]; } @@ -335,6 +332,10 @@ export class TuiInputDateTimeComponent ); } + private get nativePicker(): boolean { + return this.options.nativePicker && this.isMobile; + } + @tuiPure private calculateMask( min: TuiDay | [TuiDay, TuiTime], diff --git a/projects/kit/components/input-date/input-date.component.ts b/projects/kit/components/input-date/input-date.component.ts index b5d12ffa221d..e27a87354ad1 100644 --- a/projects/kit/components/input-date/input-date.component.ts +++ b/projects/kit/components/input-date/input-date.component.ts @@ -78,10 +78,6 @@ export class TuiInputDateComponent private readonly dialogs = inject(TuiDialogService); private readonly mobileCalendar = inject(TUI_MOBILE_CALENDAR, {optional: true}); private month: TuiMonth | null = null; - protected readonly dateTexts$ = inject(TUI_DATE_TEXTS); - protected override readonly valueTransformer = inject(TUI_DATE_VALUE_TRANSFORMER, { - optional: true, - }); @Input() public min: TuiDay | null = this.options.min; @@ -102,24 +98,21 @@ export class TuiInputDateComponent public defaultActiveYearMonth = TuiMonth.currentLocal(); protected open = false; + protected readonly dateTexts$ = inject(TUI_DATE_TEXTS); + protected override readonly valueTransformer = inject(TUI_DATE_VALUE_TRANSFORMER, { + optional: true, + }); + protected readonly isMobile = inject(TUI_IS_MOBILE); + protected readonly dateFormat = inject(TUI_DATE_FORMAT); + protected readonly dateSeparator = inject(TUI_DATE_SEPARATOR); protected readonly type!: TuiContext; - protected readonly filler$: Observable = this.dateTexts$.pipe( map(dateTexts => changeDateSeparator(dateTexts[this.dateFormat], this.dateSeparator), ), ); - protected readonly isMobile = inject(TUI_IS_MOBILE); - protected readonly dateFormat = inject(TUI_DATE_FORMAT); - protected readonly dateSeparator = inject(TUI_DATE_SEPARATOR); - - @HostBinding('attr.data-size') - protected get size(): TuiSizeL | TuiSizeS { - return this.textfieldSize.size; - } - public get computedMin(): TuiDay { return this.min ?? this.options.min; } @@ -136,16 +129,16 @@ export class TuiInputDateComponent return !!this.textfield?.focused; } - protected get computedMobile(): boolean { - return this.isMobile && (!!this.mobileCalendar || this.nativePicker); + public get nativeValue(): string { + return this.nativeFocusableElement?.value || ''; } - protected get nativePicker(): boolean { - return this.options.nativePicker; - } + public set nativeValue(value: string) { + if (!this.nativeFocusableElement) { + return; + } - protected get calendarIcon(): TuiInputDateOptions['icon'] { - return this.options.icon; + this.nativeFocusableElement.value = value; } public get computedValue(): string { @@ -158,6 +151,48 @@ export class TuiInputDateComponent return value ? value.toString(this.dateFormat, this.dateSeparator) : nativeValue; } + public onValueChange(value: string): void { + if (this.control) { + this.control.updateValueAndValidity({emitEvent: false}); + } + + if (!value) { + this.onOpenChange(true); + } + + this.value = + value.length !== DATE_FILLER_LENGTH + ? null + : TuiDay.normalizeParse(value, this.dateFormat); + } + + public override setDisabledState(): void { + super.setDisabledState(); + this.open = false; + } + + public override writeValue(value: TuiDay | null): void { + super.writeValue(value); + this.nativeValue = value ? this.computedValue : ''; + } + + @HostBinding('attr.data-size') + protected get size(): TuiSizeL | TuiSizeS { + return this.textfieldSize.size; + } + + protected get computedMobile(): boolean { + return this.isMobile && (!!this.mobileCalendar || this.nativePicker); + } + + protected get nativePicker(): boolean { + return this.options.nativePicker; + } + + protected get calendarIcon(): TuiInputDateOptions['icon'] { + return this.options.icon; + } + protected get computedActiveYearMonth(): TuiMonth { if (this.items[0] && this.value && this.value.daySame(this.items[0].day)) { return this.items[0].displayDay; @@ -170,18 +205,6 @@ export class TuiInputDateComponent ); } - public get nativeValue(): string { - return this.nativeFocusableElement?.value || ''; - } - - public set nativeValue(value: string) { - if (!this.nativeFocusableElement) { - return; - } - - this.nativeFocusableElement.value = value; - } - protected get canOpen(): boolean { return this.interactive && !this.computedMobile; } @@ -245,21 +268,6 @@ export class TuiInputDateComponent }); } - public onValueChange(value: string): void { - if (this.control) { - this.control.updateValueAndValidity({emitEvent: false}); - } - - if (!value) { - this.onOpenChange(true); - } - - this.value = - value.length !== DATE_FILLER_LENGTH - ? null - : TuiDay.normalizeParse(value, this.dateFormat); - } - protected onDayClick(value: TuiDay): void { this.value = value; this.open = false; @@ -277,16 +285,6 @@ export class TuiInputDateComponent this.updateFocused(focused); } - public override setDisabledState(): void { - super.setDisabledState(); - this.open = false; - } - - public override writeValue(value: TuiDay | null): void { - super.writeValue(value); - this.nativeValue = value ? this.computedValue : ''; - } - protected override valueIdenticalComparator( oldValue: TuiDay | null, newValue: TuiDay | null, diff --git a/projects/kit/components/input-month-range/input-month-range.component.ts b/projects/kit/components/input-month-range/input-month-range.component.ts index 89f248565037..81b1f4dd36c4 100644 --- a/projects/kit/components/input-month-range/input-month-range.component.ts +++ b/projects/kit/components/input-month-range/input-month-range.component.ts @@ -75,27 +75,17 @@ export class TuiInputMonthRangeComponent protected readonly formatter = inject(TUI_MONTH_FORMATTER); - @HostBinding('attr.data-size') - protected get size(): TuiSizeL | TuiSizeS { - return this.textfieldSize.size; - } - public get nativeFocusableElement(): HTMLInputElement | null { return this.textfield?.nativeFocusableElement ?? null; } - protected get computedDefaultActiveYear(): TuiYear { - return ( - this.value?.from || tuiDateClamp(this.defaultActiveYear, this.min, this.max) - ); - } - public get focused(): boolean { return !!this.textfield?.focused; } - protected get calendarIcon(): TuiInputDateOptions['icon'] { - return this.options.icon; + public override setDisabledState(): void { + super.setDisabledState(); + this.close(); } public computeValue(from: string | null, to: string | null): string { @@ -124,6 +114,21 @@ export class TuiInputMonthRangeComponent this.close(); } + @HostBinding('attr.data-size') + protected get size(): TuiSizeL | TuiSizeS { + return this.textfieldSize.size; + } + + protected get computedDefaultActiveYear(): TuiYear { + return ( + this.value?.from || tuiDateClamp(this.defaultActiveYear, this.min, this.max) + ); + } + + protected get calendarIcon(): TuiInputDateOptions['icon'] { + return this.options.icon; + } + protected onOpenChange(open: boolean): void { this.open = open; } @@ -140,11 +145,6 @@ export class TuiInputMonthRangeComponent } } - public override setDisabledState(): void { - super.setDisabledState(); - this.close(); - } - private close(): void { this.open = false; } diff --git a/projects/kit/components/input-month/input-month.component.ts b/projects/kit/components/input-month/input-month.component.ts index 0985ef3dc8c7..c530187b4001 100644 --- a/projects/kit/components/input-month/input-month.component.ts +++ b/projects/kit/components/input-month/input-month.component.ts @@ -69,11 +69,37 @@ export class TuiInputMonthComponent @Input() public defaultActiveYear: TuiYear = TuiDay.currentLocal(); - protected activeYear?: TuiYear; - public open = false; protected readonly formatter = inject(TUI_MONTH_FORMATTER); + protected activeYear?: TuiYear; + + public get nativeFocusableElement(): HTMLInputElement | null { + return this.textfield?.nativeFocusableElement || null; + } + + public get focused(): boolean { + return !!this.textfield?.focused; + } + + public onValueChange(value: string): void { + if (value) { + return; + } + + this.value = null; + this.onOpenChange(!this.nativePicker); + } + + public onMonthClick(month: TuiMonth): void { + this.value = month; + this.close(); + } + + public override setDisabledState(): void { + super.setDisabledState(); + this.close(); + } @HostBinding('attr.data-size') protected get size(): TuiSizeL | TuiSizeS { @@ -88,10 +114,6 @@ export class TuiInputMonthComponent return this.max ?? this.options.max; } - public get nativeFocusableElement(): HTMLInputElement | null { - return this.textfield?.nativeFocusableElement || null; - } - protected get computedDefaultActiveYear(): TuiYear { return ( this.activeYear || @@ -100,10 +122,6 @@ export class TuiInputMonthComponent ); } - public get focused(): boolean { - return !!this.textfield?.focused; - } - protected get calendarIcon(): TuiInputDateOptions['icon'] { return this.options.icon; } @@ -136,20 +154,6 @@ export class TuiInputMonthComponent : null; } - public onValueChange(value: string): void { - if (value) { - return; - } - - this.value = null; - this.onOpenChange(!this.nativePicker); - } - - public onMonthClick(month: TuiMonth): void { - this.value = month; - this.close(); - } - protected onFocused(focused: boolean): void { this.updateFocused(focused); } @@ -162,11 +166,6 @@ export class TuiInputMonthComponent this.open = open; } - public override setDisabledState(): void { - super.setDisabledState(); - this.close(); - } - private close(): void { this.open = false; } diff --git a/projects/kit/components/input-number/input-number.component.ts b/projects/kit/components/input-number/input-number.component.ts index fae47e3c973b..230411ee24db 100644 --- a/projects/kit/components/input-number/input-number.component.ts +++ b/projects/kit/components/input-number/input-number.component.ts @@ -47,7 +47,7 @@ import { import {PolymorpheusOutletDirective} from '@tinkoff/ng-polymorpheus'; import {takeUntil} from 'rxjs'; -import {TUI_INPUT_NUMBER_OPTIONS} from './input-number.options'; +import {TUI_INPUT_NUMBER_OPTIONS, TuiInputNumberOptions} from './input-number.options'; const DEFAULT_MAX_LENGTH = 18; @@ -75,17 +75,9 @@ export class TuiInputNumberComponent private readonly isIOS = inject(TUI_IS_IOS); private readonly textfieldSize = inject(TUI_TEXTFIELD_SIZE); - + private readonly options = inject(TUI_INPUT_NUMBER_OPTIONS); private unfinishedValue: string | null = ''; - protected override readonly valueTransformer = inject< - AbstractTuiValueTransformer - >(TUI_NUMBER_VALUE_TRANSFORMER, {optional: true}); - - protected readonly options = inject(TUI_INPUT_NUMBER_OPTIONS); - - protected numberFormat = TUI_DEFAULT_NUMBER_FORMAT; - @Input() public min: number | null = this.options.min; @@ -104,6 +96,11 @@ export class TuiInputNumberComponent @ContentChildren(PolymorpheusOutletDirective, {descendants: true}) protected readonly polymorpheusValueContent: QueryList = EMPTY_QUERY; + protected override readonly valueTransformer = inject< + AbstractTuiValueTransformer + >(TUI_NUMBER_VALUE_TRANSFORMER, {optional: true}); + + protected numberFormat = TUI_DEFAULT_NUMBER_FORMAT; protected readonly controller = inject(TUI_TEXTFIELD_WATCHED_CONTROLLER); protected readonly numberFormat$ = inject(TUI_NUMBER_FORMAT) .pipe(tuiWatch(this.cdr), takeUntil(this.destroy$)) @@ -111,19 +108,6 @@ export class TuiInputNumberComponent this.numberFormat = format; }); - @HostBinding('attr.data-size') - protected get size(): TuiSizeL | TuiSizeS { - return this.textfieldSize.size; - } - - protected get computedMin(): number { - return this.computeMin(this.min, this.max); - } - - protected get computedMax(): number { - return this.computeMax(this.min, this.max); - } - public get nativeFocusableElement(): HTMLInputElement | null { return !this.textfield || this.computedDisabled ? null @@ -134,10 +118,6 @@ export class TuiInputNumberComponent return !!this.textfield?.focused; } - protected get isNegativeAllowed(): boolean { - return this.computedMin < 0; - } - public get inputMode(): TuiInputMode { if (this.isIOS && this.isNegativeAllowed) { // iPhone does not have minus sign if inputMode is equal to 'numeric' / 'decimal' @@ -157,14 +137,67 @@ export class TuiInputNumberComponent return DEFAULT_MAX_LENGTH + precision + takeThousand; } - protected get formattedValue(): string { - return this.value !== null ? this.getFormattedValue(this.value || 0) : ''; - } - public get computedValue(): string { return this.focused ? this.nativeValue : this.formattedValue; } + public onValueChange(nativeValue: string): void { + const parsedValue = maskitoParseNumber( + nativeValue, + this.numberFormat.decimalSeparator, + ); + + this.unfinishedValue = null; + + if (Number.isNaN(parsedValue)) { + this.value = null; + + return; + } + + if (this.isNativeValueNotFinished) { + this.unfinishedValue = nativeValue; + + return; + } + + if (parsedValue < this.computedMin || parsedValue > this.computedMax) { + return; + } + + this.value = parsedValue; + } + + public override writeValue(value: number | null): void { + super.writeValue(value); + this.nativeValue = this.formattedValue; + } + + @HostBinding('attr.data-size') + protected get size(): TuiSizeL | TuiSizeS { + return this.textfieldSize.size; + } + + protected get icons(): TuiInputNumberOptions['icons'] { + return this.options.icons; + } + + protected get computedMin(): number { + return this.computeMin(this.min, this.max); + } + + protected get computedMax(): number { + return this.computeMax(this.min, this.max); + } + + protected get isNegativeAllowed(): boolean { + return this.computedMin < 0; + } + + protected get formattedValue(): string { + return this.value !== null ? this.getFormattedValue(this.value || 0) : ''; + } + protected get canDecrement(): boolean { return this.interactive && (this.value || 0) > this.computedMin; } @@ -196,6 +229,19 @@ export class TuiInputNumberComponent ); } + protected get nativeValue(): string { + return this.nativeFocusableElement?.value || ''; + } + + protected set nativeValue(value: string) { + if (!this.textfield || !this.nativeFocusableElement) { + return; + } + + this.textfield.value = value; + this.nativeFocusableElement.value = value; + } + @HostListener('keydown.arrowDown', ['-step']) @HostListener('keydown.arrowUp', ['step']) protected onArrow(step: number | null): void { @@ -211,33 +257,6 @@ export class TuiInputNumberComponent this.nativeValue = this.formattedValue; } - public onValueChange(nativeValue: string): void { - const parsedValue = maskitoParseNumber( - nativeValue, - this.numberFormat.decimalSeparator, - ); - - this.unfinishedValue = null; - - if (Number.isNaN(parsedValue)) { - this.value = null; - - return; - } - - if (this.isNativeValueNotFinished) { - this.unfinishedValue = nativeValue; - - return; - } - - if (parsedValue < this.computedMin || parsedValue > this.computedMax) { - return; - } - - this.value = parsedValue; - } - protected onFocused(focused: boolean): void { this.updateFocused(focused); @@ -294,24 +313,6 @@ export class TuiInputNumberComponent : nativeNumberValue < this.computedMin; } - protected get nativeValue(): string { - return this.nativeFocusableElement?.value || ''; - } - - protected set nativeValue(value: string) { - if (!this.textfield || !this.nativeFocusableElement) { - return; - } - - this.textfield.value = value; - this.nativeFocusableElement.value = value; - } - - public override writeValue(value: number | null): void { - super.writeValue(value); - this.nativeValue = this.formattedValue; - } - private get nativeNumberValue(): number { return maskitoParseNumber(this.nativeValue, this.numberFormat.decimalSeparator); } diff --git a/projects/kit/components/input-number/input-number.template.html b/projects/kit/components/input-number/input-number.template.html index 2cb130e97f71..67f9d8a11853 100644 --- a/projects/kit/components/input-number/input-number.template.html +++ b/projects/kit/components/input-number/input-number.template.html @@ -44,7 +44,7 @@ [appearance]="textfield.appearance" [disabled]="!canIncrement" [focusable]="false" - [icon]="options.icons.up" + [icon]="icons.up" (click.prevent)="onArrow(step)" (mousedown.prevent)="nativeFocusableElement?.focus()" > @@ -58,7 +58,7 @@ [appearance]="textfield.appearance" [disabled]="!canDecrement" [focusable]="false" - [icon]="options.icons.down" + [icon]="icons.down" (click.prevent)="onArrow(-step)" (mousedown.prevent)="nativeFocusableElement?.focus()" > diff --git a/projects/kit/components/input-password/input-password.component.ts b/projects/kit/components/input-password/input-password.component.ts index 5f91be6831db..6a27e7d61695 100644 --- a/projects/kit/components/input-password/input-password.component.ts +++ b/projects/kit/components/input-password/input-password.component.ts @@ -69,11 +69,6 @@ export class TuiInputPasswordComponent protected readonly options = inject(TUI_INPUT_PASSWORD_OPTIONS); protected readonly type!: TuiContext; - @HostBinding('attr.data-size') - protected get size(): TuiSizeL | TuiSizeS { - return this.textfieldSize.size; - } - public get nativeFocusableElement(): TuiNativeFocusableElement | null { return this.computedDisabled || !this.textfield ? null @@ -84,10 +79,6 @@ export class TuiInputPasswordComponent return !!this.textfield?.focused; } - protected get icon(): PolymorpheusContent> { - return this.isPasswordHidden ? this.options.icons.show : this.options.icons.hide; - } - public get inputType(): TuiInputType { return this.isPasswordHidden || !this.interactive ? 'password' : 'text'; } @@ -96,6 +87,15 @@ export class TuiInputPasswordComponent this.value = textValue; } + @HostBinding('attr.data-size') + protected get size(): TuiSizeL | TuiSizeS { + return this.textfieldSize.size; + } + + protected get icon(): PolymorpheusContent> { + return this.isPasswordHidden ? this.options.icons.show : this.options.icons.hide; + } + protected onFocused(focused: boolean): void { this.updateFocused(focused); } diff --git a/projects/kit/components/input-phone-international/input-phone-international.component.ts b/projects/kit/components/input-phone-international/input-phone-international.component.ts index a402e4325129..dd54d0a3d818 100644 --- a/projects/kit/components/input-phone-international/input-phone-international.component.ts +++ b/projects/kit/components/input-phone-international/input-phone-international.component.ts @@ -70,16 +70,6 @@ export class TuiInputPhoneInternationalComponent private readonly extractCountryCodePipe = inject(TuiToCountryCodePipe); private readonly textfieldSize = inject(TUI_TEXTFIELD_SIZE); - @Input('countryIsoCode') - public set isoCode(code: TuiCountryIsoCode) { - if (this.countryIsoCode === code) { - return; - } - - this.inputPhoneComponent?.writeValue(this.value); - this.countryIsoCode = code; - } - @Input() public countries = this.options.countries; @@ -96,9 +86,14 @@ export class TuiInputPhoneInternationalComponent TuiContext > = TUI_ARROW; - @HostBinding('attr.data-size') - protected get size(): TuiSizeL | TuiSizeS { - return this.textfieldSize.size; + @Input('countryIsoCode') + public set isoCode(code: TuiCountryIsoCode) { + if (this.countryIsoCode === code) { + return; + } + + this.inputPhoneComponent?.writeValue(this.value); + this.countryIsoCode = code; } public get nativeFocusableElement(): HTMLElement | null { @@ -127,14 +122,6 @@ export class TuiInputPhoneInternationalComponent ); } - /** - * @deprecated use `` - * TODO drop in v4.0 - */ - protected get countryFlagPath(): string { - return this.getFlagPath(this.countryIsoCode); - } - @HostListener('paste.capture.prevent.stop', ['$event']) @HostListener('drop.capture.prevent.stop', ['$event']) public onPaste(event: ClipboardEvent | DragEvent): void { @@ -163,19 +150,6 @@ export class TuiInputPhoneInternationalComponent this.value = `${CHAR_PLUS}${value}`; } - protected readonly isoToCountryCodeMapper: TuiTypedMapper< - [TuiCountryIsoCode], - string - > = item => tuiIsoToCountryCode(this.countriesMasks, item); - - /** - * @deprecated use `` - * TODO drop in v4.0 - */ - protected getFlagPath(code: TuiCountryIsoCode): string { - return this.flagPipe.transform(code); - } - public onItemClick(isoCode: TuiCountryIsoCode): void { this.open = false; this.updateCountryIsoCode(isoCode); @@ -206,6 +180,32 @@ export class TuiInputPhoneInternationalComponent return tuiIsoToCountryCode(this.countriesMasks, isoCode); } + @HostBinding('attr.data-size') + protected get size(): TuiSizeL | TuiSizeS { + return this.textfieldSize.size; + } + + /** + * @deprecated use `` + * TODO drop in v4.0 + */ + protected get countryFlagPath(): string { + return this.getFlagPath(this.countryIsoCode); + } + + protected readonly isoToCountryCodeMapper: TuiTypedMapper< + [TuiCountryIsoCode], + string + > = item => tuiIsoToCountryCode(this.countriesMasks, item); + + /** + * @deprecated use `` + * TODO drop in v4.0 + */ + protected getFlagPath(code: TuiCountryIsoCode): string { + return this.flagPipe.transform(code); + } + /** @deprecated use 'value' setter */ protected onModelChange(value: string): void { this.value = value; diff --git a/projects/kit/components/input-phone/input-phone.component.ts b/projects/kit/components/input-phone/input-phone.component.ts index 7af3189a92d3..94f13ea34ecc 100644 --- a/projects/kit/components/input-phone/input-phone.component.ts +++ b/projects/kit/components/input-phone/input-phone.component.ts @@ -73,14 +73,6 @@ export class TuiInputPhoneComponent private readonly options = inject(TUI_INPUT_PHONE_OPTIONS); private readonly textfieldSize = inject(TUI_TEXTFIELD_SIZE); - @Input('countryCode') - public set countryCodeSetter(newCountryCode: string) { - const prevCountryCode = this.countryCode; - - this.countryCode = newCountryCode; - this.updateValueWithNewCountryCode(prevCountryCode, newCountryCode); - } - @Input() public phoneMaskAfterCountryCode = this.options.phoneMaskAfterCountryCode; @@ -93,16 +85,19 @@ export class TuiInputPhoneComponent @Output() public readonly searchChange = new EventEmitter(); + public countryCode = this.options.countryCode; + @ContentChild(TuiDataListDirective, {read: TemplateRef}) protected readonly datalist?: TemplateRef>; - public countryCode = this.options.countryCode; - protected open = false; - @HostBinding('attr.data-size') - protected get size(): TuiSizeL | TuiSizeS { - return this.textfieldSize.size; + @Input('countryCode') + public set countryCodeSetter(newCountryCode: string) { + const prevCountryCode = this.countryCode; + + this.countryCode = newCountryCode; + this.updateValueWithNewCountryCode(prevCountryCode, newCountryCode); } public get nativeFocusableElement(): HTMLInputElement | null { @@ -135,6 +130,44 @@ export class TuiInputPhoneComponent return this.allowText ? 'text' : 'numeric'; } + public onValueChange(value: string): void { + const parsed = isText(value) + ? value + : value.replace(TUI_MASK_SYMBOLS_REGEXP, '').slice(0, this.maxPhoneLength); + + this.updateSearch(parsed); + this.value = parsed === this.countryCode || isText(parsed) ? '' : parsed; + this.open = true; + + if (!this.value && !this.allowText) { + this.nativeValue = this.nonRemovablePrefix; + } + } + + public handleOption(item: string): void { + this.focusInput(); + this.value = item; + this.nativeValue = maskitoTransform(this.value, this.maskOptions); + this.updateSearch(''); + this.open = false; + } + + public override setDisabledState(): void { + super.setDisabledState(); + this.open = false; + } + + public override writeValue(value: string | null): void { + super.writeValue(value); + this.nativeValue = maskitoTransform(value || '', this.maskOptions); + this.updateSearch(''); + } + + @HostBinding('attr.data-size') + protected get size(): TuiSizeL | TuiSizeS { + return this.textfieldSize.size; + } + protected get canOpen(): boolean { return this.interactive && !!this.datalist; } @@ -176,39 +209,6 @@ export class TuiInputPhoneComponent } } - public onValueChange(value: string): void { - const parsed = isText(value) - ? value - : value.replace(TUI_MASK_SYMBOLS_REGEXP, '').slice(0, this.maxPhoneLength); - - this.updateSearch(parsed); - this.value = parsed === this.countryCode || isText(parsed) ? '' : parsed; - this.open = true; - - if (!this.value && !this.allowText) { - this.nativeValue = this.nonRemovablePrefix; - } - } - - public handleOption(item: string): void { - this.focusInput(); - this.value = item; - this.nativeValue = maskitoTransform(this.value, this.maskOptions); - this.updateSearch(''); - this.open = false; - } - - public override setDisabledState(): void { - super.setDisabledState(); - this.open = false; - } - - public override writeValue(value: string | null): void { - super.writeValue(value); - this.nativeValue = maskitoTransform(value || '', this.maskOptions); - this.updateSearch(''); - } - protected getFallbackValue(): string { return ''; } diff --git a/projects/kit/components/input-range/input-range.component.ts b/projects/kit/components/input-range/input-range.component.ts index 07b599e141aa..9249deb77063 100644 --- a/projects/kit/components/input-range/input-range.component.ts +++ b/projects/kit/components/input-range/input-range.component.ts @@ -97,14 +97,6 @@ export class TuiInputRangeComponent protected readonly controller = inject(TUI_TEXTFIELD_WATCHED_CONTROLLER); - protected get leftFocusableElement(): HTMLInputElement | null { - return this.inputNumberRefs.first?.nativeFocusableElement || null; - } - - protected get rightFocusableElement(): HTMLInputElement | null { - return this.inputNumberRefs.last?.nativeFocusableElement || null; - } - public get nativeFocusableElement(): TuiNativeFocusableElement | null { return this.disabled ? null @@ -115,6 +107,19 @@ export class TuiInputRangeComponent return tuiIsNativeFocusedIn(this.el); } + public override writeValue(value: [number, number]): void { + super.writeValue(value); + this.updateTextfieldValues(this.value); + } + + protected get leftFocusableElement(): HTMLInputElement | null { + return this.inputNumberRefs.first?.nativeFocusableElement || null; + } + + protected get rightFocusableElement(): HTMLInputElement | null { + return this.inputNumberRefs.last?.nativeFocusableElement || null; + } + protected get appearance(): string { return this.controller.appearance; } @@ -223,11 +228,6 @@ export class TuiInputRangeComponent this.lastActiveSide = activeThumb; } - public override writeValue(value: [number, number]): void { - super.writeValue(value); - this.updateTextfieldValues(this.value); - } - protected getFallbackValue(): [number, number] { return [0, 0]; } diff --git a/projects/kit/components/input-slider/input-slider.component.ts b/projects/kit/components/input-slider/input-slider.component.ts index e58a753d1d11..c00358e1d51d 100644 --- a/projects/kit/components/input-slider/input-slider.component.ts +++ b/projects/kit/components/input-slider/input-slider.component.ts @@ -85,14 +85,6 @@ export class TuiInputSliderComponent protected readonly controller = inject(TUI_TEXTFIELD_WATCHED_CONTROLLER); - protected get prefix(): string { - return this.controller.prefix; - } - - protected get postfix(): string { - return this.controller.postfix; - } - public get nativeFocusableElement(): TuiNativeFocusableElement | null { return !this.inputNumberRef?.nativeFocusableElement || this.computedDisabled ? null @@ -106,6 +98,19 @@ export class TuiInputSliderComponent ); } + public override writeValue(value: number | null): void { + super.writeValue(value); + this.textfieldValue = this.value; + } + + protected get prefix(): string { + return this.controller.prefix; + } + + protected get postfix(): string { + return this.controller.postfix; + } + protected get computedSteps(): number { return this.steps || (this.max - this.min) / this.quantum; } @@ -180,11 +185,6 @@ export class TuiInputSliderComponent this.updateFocused(focused); } - public override writeValue(value: number | null): void { - super.writeValue(value); - this.textfieldValue = this.value; - } - protected getFallbackValue(): number { return 0; } diff --git a/projects/kit/components/input-tag/input-tag.component.ts b/projects/kit/components/input-tag/input-tag.component.ts index 98055d7486a2..18e7d430b3bd 100644 --- a/projects/kit/components/input-tag/input-tag.component.ts +++ b/projects/kit/components/input-tag/input-tag.component.ts @@ -146,15 +146,6 @@ export class TuiInputTagComponent public disabledItemHandler: TuiBooleanHandler | string> = ALWAYS_FALSE_HANDLER; - @Input('pseudoFocused') - public set pseudoFocusedSetter(value: boolean | null) { - if (!value && !this.focused) { - this.scrollTo(0); - } - - this.pseudoFocus = value; - } - @Output() public readonly searchChange = new EventEmitter(); @@ -167,27 +158,85 @@ export class TuiInputTagComponent protected readonly hintOptions = inject(TuiHintOptionsDirective, {optional: true}); protected readonly controller = inject(TUI_TEXTFIELD_WATCHED_CONTROLLER); protected readonly icons = inject(TUI_COMMON_ICONS); - protected status$: Observable = this.mode$.pipe(map(() => this.status)); - protected open = false; + @Input('pseudoFocused') + public set pseudoFocusedSetter(value: boolean | null) { + if (!value && !this.focused) { + this.scrollTo(0); + } + + this.pseudoFocus = value; + } + + @HostBinding('class._label-outside') + public get labelOutside(): boolean { + const {size, labelOutside} = this.controller; + + return size === 's' || labelOutside; + } + public get nativeFocusableElement(): HTMLInputElement | null { return !this.focusableElement || this.computedDisabled ? null : this.focusableElement.nativeElement; } + public get hasValue(): boolean { + return !!this.value.length || this.hasNativeValue; + } + + public get hasExampleText(): boolean { + return ( + !!this.nativeFocusableElement?.placeholder && + this.computedFocused && + !this.hasValue && + !this.readOnly + ); + } + + public get hasPlaceholder(): boolean { + return ( + !this.labelOutside || + (!this.hasValue && (!this.hasExampleText || this.inputHidden)) + ); + } + public get focused(): boolean { return tuiIsNativeFocusedIn(this.el) || !!this.hostedDropdown?.focused; } - protected get appearance(): string { - return this.controller.appearance; + public onTagEdited(value: string, index: number): void { + this.focusInput(value === ''); + this.value = this.filterValue( + this.value + .map((tag, tagIndex) => + tagIndex !== index + ? tag + : value + .split(this.separator) + .map(tag => tag.trim()) + .filter(Boolean), + ) + .reduce( + (result, item: string[] | string) => result.concat(item), + [], + ), + ); } - protected get expandable(): boolean { - return this.rows > 1; + public handleOption(item: string): void { + this.focusInput(); + this.updateSearch(''); + this.value = this.filterValue(this.value.concat(item)); + this.open = false; + this.scrollTo(); + } + + public override setDisabledState(): void { + super.setDisabledState(); + this.open = false; } @HostBinding('attr.data-size') @@ -195,18 +244,19 @@ export class TuiInputTagComponent return this.controller.size; } - @HostBinding('class._label-outside') - public get labelOutside(): boolean { - const {size, labelOutside} = this.controller; - - return size === 's' || labelOutside; - } - @HostBinding('class._icon-left') protected get iconLeft(): PolymorpheusContent> { return this.controller.iconLeft; } + protected get appearance(): string { + return this.controller.appearance; + } + + protected get expandable(): boolean { + return this.rows > 1; + } + protected get icon(): PolymorpheusContent> { return this.controller.icon; } @@ -223,17 +273,6 @@ export class TuiInputTagComponent return !!this.search; } - public get hasValue(): boolean { - return !!this.value.length || this.hasNativeValue; - } - - public get hasPlaceholder(): boolean { - return ( - !this.labelOutside || - (!this.hasValue && (!this.hasExampleText || this.inputHidden)) - ); - } - protected get placeholderRaised(): boolean { return ( !this.labelOutside && @@ -241,15 +280,6 @@ export class TuiInputTagComponent ); } - public get hasExampleText(): boolean { - return ( - !!this.nativeFocusableElement?.placeholder && - this.computedFocused && - !this.hasValue && - !this.readOnly - ); - } - protected get hasRightIcons(): boolean { return ( this.hasCleaner || @@ -366,33 +396,6 @@ export class TuiInputTagComponent } } - public onTagEdited(value: string, index: number): void { - this.focusInput(value === ''); - this.value = this.filterValue( - this.value - .map((tag, tagIndex) => - tagIndex !== index - ? tag - : value - .split(this.separator) - .map(tag => tag.trim()) - .filter(Boolean), - ) - .reduce( - (result, item: string[] | string) => result.concat(item), - [], - ), - ); - } - - public handleOption(item: string): void { - this.focusInput(); - this.updateSearch(''); - this.value = this.filterValue(this.value.concat(item)); - this.open = false; - this.scrollTo(); - } - protected onInput(value: string): void { const array = value.split(this.separator); const tags = array @@ -422,16 +425,17 @@ export class TuiInputTagComponent } } - public override setDisabledState(): void { - super.setDisabledState(); - this.open = false; - } - protected trackByFn(_: number, tag: string): string { // Actually tag has TuiStringifiableItem type not string return tag.toString(); } + private get lineHeight(): number { + return this.labelOutside + ? TAG_SIZE_REM[this.controller.size] + 2 * TAG_VERTICAL_SPACE_REM + : LINE_HEIGHT_REM[this.controller.size]; + } + private scrollTo(scrollLeft = this.scrollBar?.nativeElement.scrollWidth): void { // Allow change detection to run and add new tag to DOM timer(0) @@ -511,10 +515,4 @@ export class TuiInputTagComponent private clippedValue(value: string): string { return value.slice(0, this.maxLength || value.length); } - - private get lineHeight(): number { - return this.labelOutside - ? TAG_SIZE_REM[this.controller.size] + 2 * TAG_VERTICAL_SPACE_REM - : LINE_HEIGHT_REM[this.controller.size]; - } } diff --git a/projects/kit/components/input-time/input-time.component.ts b/projects/kit/components/input-time/input-time.component.ts index c7f983fe9b13..b1c5bc3af88e 100644 --- a/projects/kit/components/input-time/input-time.component.ts +++ b/projects/kit/components/input-time/input-time.component.ts @@ -86,11 +86,6 @@ export class TuiInputTimeComponent protected open = false; - @HostBinding('attr.data-size') - protected get size(): TuiSizeL | TuiSizeS { - return this.textfieldSize.size; - } - public get nativeFocusableElement(): HTMLInputElement | null { return this.textfield?.nativeFocusableElement ?? null; } @@ -99,6 +94,63 @@ export class TuiInputTimeComponent return tuiIsNativeFocused(this.nativeFocusableElement); } + public get computedValue(): string { + return this.value ? this.value.toString(this.mode) : this.nativeValue; + } + + public get nativeValue(): string { + return this.nativeFocusableElement?.value || ''; + } + + public set nativeValue(value: string) { + if (!this.nativeFocusableElement) { + return; + } + + this.nativeFocusableElement.value = value; + } + + public handleOption(item: TuiTime): void { + this.focusInput(); + this.value = item; + } + + public override writeValue(value: TuiTime | null): void { + super.writeValue(value); + this.nativeValue = value ? this.computedValue : ''; + } + + public onValueChange(value: string): void { + this.open = !!this.items.length; + + if (this.control) { + this.control.updateValueAndValidity({emitEvent: false}); + } + + const match = this.getMatch(value); + + if (match !== undefined) { + this.value = match; + + return; + } + + if (value.length !== this.mode.length) { + this.value = null; + + return; + } + + const time = TuiTime.fromString(value); + + this.value = this.strict ? this.findNearestTimeFromItems(time) : time; + } + + @HostBinding('attr.data-size') + protected get size(): TuiSizeL | TuiSizeS { + return this.textfieldSize.size; + } + protected get canOpen(): boolean { return this.interactive && !!this.filtered.length; } @@ -122,10 +174,6 @@ export class TuiInputTimeComponent return this.calculateMask(this.mode); } - public get computedValue(): string { - return this.value ? this.value.toString(this.mode) : this.nativeValue; - } - protected get computedSearch(): string { return this.computedValue.length !== this.mode.length ? this.computedValue : ''; } @@ -146,18 +194,6 @@ export class TuiInputTimeComponent return this.options.icon; } - public get nativeValue(): string { - return this.nativeFocusableElement?.value || ''; - } - - public set nativeValue(value: string) { - if (!this.nativeFocusableElement) { - return; - } - - this.nativeFocusableElement.value = value; - } - @tuiPure protected getFiller$(mode: TuiTimeMode): Observable { return this.timeTexts$.pipe(map(texts => texts[mode])); @@ -168,32 +204,6 @@ export class TuiInputTimeComponent this.open = !this.open; } - public onValueChange(value: string): void { - this.open = !!this.items.length; - - if (this.control) { - this.control.updateValueAndValidity({emitEvent: false}); - } - - const match = this.getMatch(value); - - if (match !== undefined) { - this.value = match; - - return; - } - - if (value.length !== this.mode.length) { - this.value = null; - - return; - } - - const time = TuiTime.fromString(value); - - this.value = this.strict ? this.findNearestTimeFromItems(time) : time; - } - protected onFocused(focused: boolean): void { this.updateFocused(focused); @@ -233,20 +243,10 @@ export class TuiInputTimeComponent this.processArrow(event, -1); } - public handleOption(item: TuiTime): void { - this.focusInput(); - this.value = item; - } - protected onOpen(open: boolean): void { this.open = open; } - public override writeValue(value: TuiTime | null): void { - super.writeValue(value); - this.nativeValue = value ? this.computedValue : ''; - } - private get nativePicker(): boolean { return !!this.options.nativePicker && this.isMobile; } diff --git a/projects/kit/components/input-year/input-year.component.ts b/projects/kit/components/input-year/input-year.component.ts index 1fbe6bb94846..1e64fbf5e009 100644 --- a/projects/kit/components/input-year/input-year.component.ts +++ b/projects/kit/components/input-year/input-year.component.ts @@ -58,11 +58,28 @@ export class TuiInputYearComponent @Input() public disabledItemHandler: TuiBooleanHandler = ALWAYS_FALSE_HANDLER; - protected open = false; public nativeValue = ''; + protected open = false; protected readonly initialItem = new Date().getFullYear(); + public get nativeFocusableElement(): HTMLInputElement | null { + return this.textfield?.nativeFocusableElement || null; + } + + public get focused(): boolean { + return !!this.textfield?.focused; + } + + public onValueChange(value: string): void { + this.value = value ? Number(value) : null; + } + + public override writeValue(value: number | null): void { + super.writeValue(value); + this.updateNativeValue(value); + } + @HostBinding('attr.data-size') protected get size(): TuiSizeL | TuiSizeS { return this.textfieldSize.size; @@ -76,14 +93,6 @@ export class TuiInputYearComponent return this.max ?? this.options.max.year; } - public get nativeFocusableElement(): HTMLInputElement | null { - return this.textfield?.nativeFocusableElement || null; - } - - public get focused(): boolean { - return !!this.textfield?.focused; - } - protected get calendarIcon(): TuiInputDateOptions['icon'] { return this.options.icon; } @@ -100,10 +109,6 @@ export class TuiInputYearComponent }; } - public onValueChange(value: string): void { - this.value = value ? Number(value) : null; - } - protected onYearClick({year}: TuiYear): void { this.value = year; this.updateNativeValue(year); @@ -122,11 +127,6 @@ export class TuiInputYearComponent this.open = !this.open; } - public override writeValue(value: number | null): void { - super.writeValue(value); - this.updateNativeValue(value); - } - private updateNativeValue(value: number | null): void { this.nativeValue = value?.toString() || ''; } diff --git a/projects/kit/components/input-year/input-year.directive.ts b/projects/kit/components/input-year/input-year.directive.ts index d9e5970e3c27..d80f140c0f8f 100644 --- a/projects/kit/components/input-year/input-year.directive.ts +++ b/projects/kit/components/input-year/input-year.directive.ts @@ -8,15 +8,15 @@ import {TuiInputYearComponent} from './input-year.component'; providers: [tuiAsTextfieldHost(TuiInputYearDirective)], }) export class TuiInputYearDirective extends AbstractTuiTextfieldHost { + public override get value(): string { + return this.host.nativeValue; + } + public onValueChange(value: string): void { this.host.onValueChange(value); this.host.nativeValue = value; } - public override get value(): string { - return this.host.nativeValue; - } - public override process(input: HTMLInputElement): void { input.inputMode = 'numeric'; } diff --git a/projects/kit/components/input/input.component.ts b/projects/kit/components/input/input.component.ts index b9bed1bf831b..fb40205078ac 100644 --- a/projects/kit/components/input/input.component.ts +++ b/projects/kit/components/input/input.component.ts @@ -57,15 +57,10 @@ export class TuiInputComponent private readonly textfieldSize = inject(TUI_TEXTFIELD_SIZE); - @ContentChild(TuiDataListDirective, {read: TemplateRef}) - protected readonly datalist: PolymorpheusContent>; - public open = false; - @HostBinding('attr.data-size') - protected get size(): TuiSizeL | TuiSizeS { - return this.textfieldSize.size; - } + @ContentChild(TuiDataListDirective, {read: TemplateRef}) + protected readonly datalist: PolymorpheusContent>; public get nativeFocusableElement(): HTMLInputElement | null { return this.computedDisabled || !this.textfield @@ -80,8 +75,11 @@ export class TuiInputComponent ); } - protected get canOpen(): boolean { - return this.interactive && !!this.datalist; + public handleOption(item: unknown): void { + this.setNativeValue(String(item)); + this.focusInput(); + this.value = String(item); + this.open = false; } public onValueChange(value: string): void { @@ -89,15 +87,17 @@ export class TuiInputComponent this.open = true; } - protected onActiveZone(active: boolean): void { - this.updateFocused(active); + @HostBinding('attr.data-size') + protected get size(): TuiSizeL | TuiSizeS { + return this.textfieldSize.size; } - public handleOption(item: unknown): void { - this.setNativeValue(String(item)); - this.focusInput(); - this.value = String(item); - this.open = false; + protected get canOpen(): boolean { + return this.interactive && !!this.datalist; + } + + protected onActiveZone(active: boolean): void { + this.updateFocused(active); } protected getFallbackValue(): string { diff --git a/projects/kit/components/items-with-more/items-with-more.service.ts b/projects/kit/components/items-with-more/items-with-more.service.ts index ae9640a0a01e..f5214cb0410a 100644 --- a/projects/kit/components/items-with-more/items-with-more.service.ts +++ b/projects/kit/components/items-with-more/items-with-more.service.ts @@ -27,6 +27,12 @@ export class TuiItemsWithMoreService extends Observable { super(subscriber => this.stream$.subscribe(subscriber)); } + private get maxItems(): number { + return this.directive.itemsLimit > this.directive.required + ? this.directive.itemsLimit - 1 + : this.directive.itemsLimit - 2; + } + private getOverflowIndex(): number { const {clientWidth, children} = this.el; const items = Array.from(children, ({clientWidth}) => clientWidth); @@ -56,10 +62,4 @@ export class TuiItemsWithMoreService extends Observable { return -1; } - - private get maxItems(): number { - return this.directive.itemsLimit > this.directive.required - ? this.directive.itemsLimit - 1 - : this.directive.itemsLimit - 2; - } } diff --git a/projects/kit/components/line-clamp/line-clamp.component.ts b/projects/kit/components/line-clamp/line-clamp.component.ts index cf8a522efcd1..db92e397bd3b 100644 --- a/projects/kit/components/line-clamp/line-clamp.component.ts +++ b/projects/kit/components/line-clamp/line-clamp.component.ts @@ -58,11 +58,6 @@ export class TuiLineClampComponent implements DoCheck, AfterViewInit { private readonly isOverflown$ = new Subject(); private initialized = false; - @Input() - public set linesLimit(linesLimit: number) { - this.linesLimit$.next(linesLimit); - } - @Input() public lineHeight = 24; @@ -90,6 +85,20 @@ export class TuiLineClampComponent implements DoCheck, AfterViewInit { this.skipInitialTransition(); } + @Input() + public set linesLimit(linesLimit: number) { + this.linesLimit$.next(linesLimit); + } + + public ngDoCheck(): void { + this.update(); + this.isOverflown$.next(this.overflown); + } + + public ngAfterViewInit(): void { + this.initialized = true; + } + protected get overflown(): boolean { if (!this.outlet) { return false; @@ -111,15 +120,6 @@ export class TuiLineClampComponent implements DoCheck, AfterViewInit { this.cd.detectChanges(); } - public ngDoCheck(): void { - this.update(); - this.isOverflown$.next(this.overflown); - } - - public ngAfterViewInit(): void { - this.initialized = true; - } - private skipInitialTransition(): void { timer(0) .pipe(tuiZonefree(this.zone)) diff --git a/projects/kit/components/multi-select/multi-select-group/multi-select-group.component.ts b/projects/kit/components/multi-select/multi-select-group/multi-select-group.component.ts index 021263c43e08..e970dcb747f8 100644 --- a/projects/kit/components/multi-select/multi-select-group/multi-select-group.component.ts +++ b/projects/kit/components/multi-select/multi-select-group/multi-select-group.component.ts @@ -47,10 +47,6 @@ export class TuiMultiSelectGroupComponent { protected readonly multiSelectTexts$ = inject(TUI_MULTI_SELECT_TEXTS); - protected get size(): TuiSizeL | TuiSizeXS { - return this.options.first?.size || 'm'; - } - @tuiPure protected get empty$(): Observable { return tuiQueryListChanges(this.options).pipe(map(({length}) => !length)); @@ -86,6 +82,10 @@ export class TuiMultiSelectGroupComponent { ); } + protected get size(): TuiSizeL | TuiSizeXS { + return this.options.first?.size || 'm'; + } + protected onClick(checked: boolean | null): void { if (!this.control.control) { return; @@ -100,14 +100,6 @@ export class TuiMultiSelectGroupComponent { this.control.control.setValue(checked ? filtered : [...filtered, ...values]); } - private get values(): readonly T[] { - return this.filter(tuiGetOriginalArrayFromQueryList(this.options)); - } - - private get matcher(): TuiIdentityMatcher { - return this.host.identityMatcher || TUI_DEFAULT_IDENTITY_MATCHER; - } - @tuiPure private get items$(): Observable { return tuiQueryListChanges(this.options).pipe( @@ -122,6 +114,14 @@ export class TuiMultiSelectGroupComponent { ); } + private get values(): readonly T[] { + return this.filter(tuiGetOriginalArrayFromQueryList(this.options)); + } + + private get matcher(): TuiIdentityMatcher { + return this.host.identityMatcher || TUI_DEFAULT_IDENTITY_MATCHER; + } + @tuiPure private filter(items: ReadonlyArray>): readonly T[] { return items.map(({value}) => value).filter(tuiIsPresent); diff --git a/projects/kit/components/multi-select/multi-select.component.ts b/projects/kit/components/multi-select/multi-select.component.ts index aac6bb7b11c9..662f222e3e04 100644 --- a/projects/kit/components/multi-select/multi-select.component.ts +++ b/projects/kit/components/multi-select/multi-select.component.ts @@ -123,10 +123,44 @@ export class TuiMultiSelectComponent protected readonly datalist: PolymorpheusContent>; protected open = false; - protected readonly controller = inject(TUI_TEXTFIELD_WATCHED_CONTROLLER); protected readonly isMobile: boolean = inject(TUI_IS_MOBILE); + public get nativeFocusableElement(): HTMLInputElement | null { + return this.input?.nativeFocusableElement ?? null; + } + + public get focused(): boolean { + return !!this.input?.focused || !!this.hostedDropdown?.focused; + } + + public onValueChange(value: readonly T[]): void { + this.value = value; + } + + public onSearch(search: string | null): void { + // Clearing sets the empty value, the dropdown should not be opened on clear. + if (search !== '') { + this.hostedDropdown?.updateOpen(true); + } + + this.updateSearch(search); + } + + public override setDisabledState(): void { + super.setDisabledState(); + this.hostedDropdown?.updateOpen(false); + } + + public handleOption(option: T): void { + const {value, identityMatcher} = this; + const index = value.findIndex(item => identityMatcher(item, option)); + + this.value = + index === -1 ? [...value, option] : value.filter((_, i) => i !== index); + this.updateSearch(null); + } + @HostBinding('attr.data-size') protected get size(): TuiSizeL | TuiSizeS { return this.controller.size; @@ -138,14 +172,6 @@ export class TuiMultiSelectComponent return this.interactive ? this.arrowMode.interactive : this.arrowMode.disabled; } - public get nativeFocusableElement(): HTMLInputElement | null { - return this.input?.nativeFocusableElement ?? null; - } - - public get focused(): boolean { - return !!this.input?.focused || !!this.hostedDropdown?.focused; - } - protected get nativeDropdownMode(): boolean { return !!this.nativeSelect && this.isMobile && !this.editable; } @@ -202,15 +228,6 @@ export class TuiMultiSelectComponent } } - public handleOption(option: T): void { - const {value, identityMatcher} = this; - const index = value.findIndex(item => identityMatcher(item, option)); - - this.value = - index === -1 ? [...value, option] : value.filter((_, i) => i !== index); - this.updateSearch(null); - } - protected onEnter(event: Event): void { const {value} = this; const options = this.accessor ? this.accessor.getOptions() : []; @@ -238,28 +255,10 @@ export class TuiMultiSelectComponent this.value = value.map(({item}) => item); } - public onValueChange(value: readonly T[]): void { - this.value = value; - } - - public onSearch(search: string | null): void { - // Clearing sets the empty value, the dropdown should not be opened on clear. - if (search !== '') { - this.hostedDropdown?.updateOpen(true); - } - - this.updateSearch(search); - } - protected onActiveZone(active: boolean): void { this.updateFocused(active); } - public override setDisabledState(): void { - super.setDisabledState(); - this.hostedDropdown?.updateOpen(false); - } - private updateSearch(search: string | null): void { if (this.search === search) { return; diff --git a/projects/kit/components/multi-select/multi-select.directive.ts b/projects/kit/components/multi-select/multi-select.directive.ts index 7d5cf3b266af..14277b0ffba1 100644 --- a/projects/kit/components/multi-select/multi-select.directive.ts +++ b/projects/kit/components/multi-select/multi-select.directive.ts @@ -16,15 +16,15 @@ export class TuiMultiSelectDirective extends AbstractTuiTextfieldHos return true; } + public get stringify(): TuiItemsHandlers['stringify'] { + return this.host.stringify; + } + public disableItemHandler: TuiBooleanHandler = item => this.host.disabledItemHandler(item); public onValueChange(): void {} - public get stringify(): TuiItemsHandlers['stringify'] { - return this.host.stringify; - } - public onSelectionChange(value: T[]): void { this.host.onValueChange(value); } diff --git a/projects/kit/components/multi-select/native-multi-select/native-multi-select.ts b/projects/kit/components/multi-select/native-multi-select/native-multi-select.ts index bf62c62de933..aa4ec5f2d516 100644 --- a/projects/kit/components/multi-select/native-multi-select/native-multi-select.ts +++ b/projects/kit/components/multi-select/native-multi-select/native-multi-select.ts @@ -10,10 +10,10 @@ export abstract class AbstractTuiNativeMultiSelect extends AbstractTuiNativeS TuiMultiSelectDirective, T > { - protected selectedMapper: TuiTypedMapper<[T, ...any[]], boolean> = (option, value) => - value.includes(option); - protected get stringify(): TuiItemsHandlers['stringify'] { return this.host.stringify; } + + protected selectedMapper: TuiTypedMapper<[T, ...any[]], boolean> = (option, value) => + value.includes(option); } diff --git a/projects/kit/components/pagination/pagination.component.ts b/projects/kit/components/pagination/pagination.component.ts index 9b47f549a149..49b7d782cc09 100644 --- a/projects/kit/components/pagination/pagination.component.ts +++ b/projects/kit/components/pagination/pagination.component.ts @@ -129,6 +129,14 @@ export class TuiPaginationComponent return tuiIsNativeFocusedIn(this.el); } + public get arrowIsDisabledLeft(): boolean { + return this.index === 0; + } + + public get arrowIsDisabledRight(): boolean { + return this.reverseIndex === 0; + } + /** * Number of items in a container. */ @@ -140,14 +148,6 @@ export class TuiPaginationComponent return this.size === 'm' ? 'xs' : 's'; } - public get arrowIsDisabledLeft(): boolean { - return this.index === 0; - } - - public get arrowIsDisabledRight(): boolean { - return this.reverseIndex === 0; - } - protected elementIsFocusable(index: number): boolean { return this.index === index && !this.focused; } diff --git a/projects/kit/components/push/push-alert.directive.ts b/projects/kit/components/push/push-alert.directive.ts index 5b689857defa..4d88598c7cd5 100644 --- a/projects/kit/components/push/push-alert.directive.ts +++ b/projects/kit/components/push/push-alert.directive.ts @@ -20,11 +20,6 @@ export class TuiPushAlertDirective extends PolymorpheusTemplate { private readonly push: TuiPushService = inject(forwardRef(() => TuiPushService)); private readonly show$ = new Subject(); - @Input() - public set tuiPush(show: boolean) { - this.show$.next(show); - } - constructor() { super(inject(TemplateRef), inject(ChangeDetectorRef)); @@ -35,4 +30,9 @@ export class TuiPushAlertDirective extends PolymorpheusTemplate { ) .subscribe(); } + + @Input() + public set tuiPush(show: boolean) { + this.show$.next(show); + } } diff --git a/projects/kit/components/radio-list/radio-list.component.ts b/projects/kit/components/radio-list/radio-list.component.ts index fa9dca90f25b..e49a422bac2b 100644 --- a/projects/kit/components/radio-list/radio-list.component.ts +++ b/projects/kit/components/radio-list/radio-list.component.ts @@ -58,10 +58,9 @@ export class TuiRadioListComponent extends AbstractTuiNullableControl { @Input() public disabledItemHandler: TuiBooleanHandler = ALWAYS_FALSE_HANDLER; - // @bad TODO: Remove & { index: number } - @Input() - public itemContent: PolymorpheusContent & {index: number}> = - ({$implicit}) => String($implicit); + public get focused(): boolean { + return tuiIsNativeFocusedIn(this.el); + } public get nativeFocusableElement(): TuiNativeFocusableElement | null { const focusableRadioButton = this.radioButtons.find( @@ -71,9 +70,10 @@ export class TuiRadioListComponent extends AbstractTuiNullableControl { return focusableRadioButton?.nativeFocusableElement ?? null; } - public get focused(): boolean { - return tuiIsNativeFocusedIn(this.el); - } + // @bad TODO: Remove & { index: number } + @Input() + public itemContent: PolymorpheusContent & {index: number}> = + ({$implicit}) => String($implicit); protected computeId(index: number): string { return `${this.id}-${index}`; diff --git a/projects/kit/components/radio/radio.component.ts b/projects/kit/components/radio/radio.component.ts index b47ca1cfedbd..ba7117c38d67 100644 --- a/projects/kit/components/radio/radio.component.ts +++ b/projects/kit/components/radio/radio.component.ts @@ -58,27 +58,11 @@ export class TuiRadioComponent @Input() public pseudoDisabled = false; - protected get appearance(): string { - return this.checked - ? this.options.appearances.checked - : this.options.appearances.unchecked; - } - @HostBinding('class._disabled') public override get computedDisabled(): boolean { return this.disabled || this.pseudoDisabled; } - public get nativeFocusableElement(): TuiNativeFocusableElement | null { - return !this.focusableElement || this.computedDisabled - ? null - : this.focusableElement.nativeElement; - } - - public get focused(): boolean { - return tuiIsNativeFocused(this.nativeFocusableElement); - } - public get checked(): boolean { return this.value === null ? this.item === null @@ -91,6 +75,22 @@ export class TuiRadioComponent return this.name || this.radioGroupName || this.controlName || ''; } + public get nativeFocusableElement(): TuiNativeFocusableElement | null { + return !this.focusableElement || this.computedDisabled + ? null + : this.focusableElement.nativeElement; + } + + public get focused(): boolean { + return tuiIsNativeFocused(this.nativeFocusableElement); + } + + protected get appearance(): string { + return this.checked + ? this.options.appearances.checked + : this.options.appearances.unchecked; + } + protected get isFocusable(): boolean { return !this.readOnly && this.computedFocusable; } diff --git a/projects/kit/components/range/range.component.ts b/projects/kit/components/range/range.component.ts index 1ecfe65eb3b5..270ff83c01f8 100644 --- a/projects/kit/components/range/range.component.ts +++ b/projects/kit/components/range/range.component.ts @@ -67,6 +67,16 @@ export class TuiRangeComponent protected lastActiveThumb: 'left' | 'right' = 'right'; + @HostBinding('style.--left.%') + public get left(): number { + return this.getPercentageFromValue(this.value[0]); + } + + @HostBinding('style.--right.%') + public get right(): number { + return 100 - this.getPercentageFromValue(this.value[1]); + } + public get nativeFocusableElement(): TuiNativeFocusableElement | null { const [sliderLeftRef, sliderRightRef] = this.slidersRefs; @@ -90,6 +100,22 @@ export class TuiRangeComponent return tuiIsNativeFocusedIn(this.el); } + public processValue(value: number, right: boolean): void { + if (right) { + this.updateEnd(value); + } else { + this.updateStart(value); + } + + this.lastActiveThumb = right ? 'right' : 'left'; + } + + public getValueFromFraction(fraction: number): number { + const guardedFraction = tuiClamp(tuiQuantize(fraction, this.fractionStep), 0, 1); + + return tuiPercentageToKeyStepValue(guardedFraction * 100, this.computedKeySteps); + } + protected get fractionStep(): number { return this.step / (this.max - this.min); } @@ -102,16 +128,6 @@ export class TuiRangeComponent return 1 / this.segments; } - @HostBinding('style.--left.%') - public get left(): number { - return this.getPercentageFromValue(this.value[0]); - } - - @HostBinding('style.--right.%') - public get right(): number { - return 100 - this.getPercentageFromValue(this.value[1]); - } - @HostListener('focusin', ['true']) @HostListener('focusout', ['false']) protected onFocused(focused: boolean): void { @@ -144,22 +160,6 @@ export class TuiRangeComponent } } - public processValue(value: number, right: boolean): void { - if (right) { - this.updateEnd(value); - } else { - this.updateStart(value); - } - - this.lastActiveThumb = right ? 'right' : 'left'; - } - - public getValueFromFraction(fraction: number): number { - const guardedFraction = tuiClamp(tuiQuantize(fraction, this.fractionStep), 0, 1); - - return tuiPercentageToKeyStepValue(guardedFraction * 100, this.computedKeySteps); - } - protected getPercentageFromValue(value: number): number { return tuiKeyStepValueToPercentage(value, this.computedKeySteps); } diff --git a/projects/kit/components/rating/rating.component.ts b/projects/kit/components/rating/rating.component.ts index e7a3a0e047cc..702e3c0d94b3 100644 --- a/projects/kit/components/rating/rating.component.ts +++ b/projects/kit/components/rating/rating.component.ts @@ -59,20 +59,10 @@ export class TuiRatingComponent return tuiIsNativeFocused(this.nativeFocusableElement); } - protected get isFocusable(): boolean { - return !(this.readOnly || this.disabled); - } - public get percent(): number { return tuiClamp((100 * this.value) / this.max, 0, 100); } - @HostListener('focusin', ['true']) - @HostListener('focusout', ['false']) - protected onFocused(focused: boolean): void { - this.updateFocused(focused); - } - public setRateByReverseIndex(index: number): void { const reversedIndex = this.max - index; @@ -87,6 +77,16 @@ export class TuiRatingComponent this.value = value; } + protected get isFocusable(): boolean { + return !(this.readOnly || this.disabled); + } + + @HostListener('focusin', ['true']) + @HostListener('focusout', ['false']) + protected onFocused(focused: boolean): void { + this.updateFocused(focused); + } + protected getFallbackValue(): number { return 0; } diff --git a/projects/kit/components/select-option/select-option.component.ts b/projects/kit/components/select-option/select-option.component.ts index a36dc67477f5..57d7a2711e00 100644 --- a/projects/kit/components/select-option/select-option.component.ts +++ b/projects/kit/components/select-option/select-option.component.ts @@ -54,10 +54,6 @@ export class TuiSelectOptionComponent implements OnInit, DoCheck { distinctUntilChanged(), ); - protected get matcher(): TuiIdentityMatcher { - return this.host.identityMatcher || TUI_DEFAULT_IDENTITY_MATCHER; - } - public ngOnInit(): void { /** * This would cause changes inside already checked parent component (during the same change detection cycle), @@ -80,6 +76,10 @@ export class TuiSelectOptionComponent implements OnInit, DoCheck { return this.abstractControl?.value ?? this.control.value; } + protected get matcher(): TuiIdentityMatcher { + return this.host.identityMatcher || TUI_DEFAULT_IDENTITY_MATCHER; + } + protected get selected(): boolean { return ( tuiIsPresent(this.option.value) && diff --git a/projects/kit/components/select/select.component.ts b/projects/kit/components/select/select.component.ts index 64813021d425..416a4160c882 100644 --- a/projects/kit/components/select/select.component.ts +++ b/projects/kit/components/select/select.component.ts @@ -88,17 +88,6 @@ export class TuiSelectComponent protected readonly isMobile = inject(TUI_IS_MOBILE); - @HostBinding('attr.data-size') - protected get size(): TuiSizeL | TuiSizeS { - return this.textfieldSize.size; - } - - protected get arrow(): PolymorpheusContent< - TuiContext - > { - return !this.interactive ? this.arrowMode.disabled : this.arrowMode.interactive; - } - public get nativeFocusableElement(): HTMLInputElement | null { return this.textfield?.nativeFocusableElement ?? null; } @@ -110,22 +99,39 @@ export class TuiSelectComponent ); } - protected get nativeDropdownMode(): boolean { - return !!this.nativeSelect && this.isMobile; - } - public get computedValue(): string { return this.value === null ? '' : this.stringify(this.value) || ' '; } - protected get computedContent(): PolymorpheusContent> { - return this.valueContent || this.computedValue; - } - public onValueChange(value: T): void { this.value = value || null; } + public handleOption(option: T): void { + this.focusInput(); + this.value = option; + this.hostedDropdown?.updateOpen(false); + } + + @HostBinding('attr.data-size') + protected get size(): TuiSizeL | TuiSizeS { + return this.textfieldSize.size; + } + + protected get arrow(): PolymorpheusContent< + TuiContext + > { + return !this.interactive ? this.arrowMode.disabled : this.arrowMode.interactive; + } + + protected get nativeDropdownMode(): boolean { + return !!this.nativeSelect && this.isMobile; + } + + protected get computedContent(): PolymorpheusContent> { + return this.valueContent || this.computedValue; + } + protected onActiveZone(active: boolean): void { this.updateFocused(active); } @@ -136,12 +142,6 @@ export class TuiSelectComponent } } - public handleOption(option: T): void { - this.focusInput(); - this.value = option; - this.hostedDropdown?.updateOpen(false); - } - private focusInput(preventScroll = false): void { if (this.nativeFocusableElement) { this.nativeFocusableElement.focus({preventScroll}); diff --git a/projects/kit/components/slider/helpers/slider-key-steps.directive.ts b/projects/kit/components/slider/helpers/slider-key-steps.directive.ts index 297ea58d8761..9a1300aeda46 100644 --- a/projects/kit/components/slider/helpers/slider-key-steps.directive.ts +++ b/projects/kit/components/slider/helpers/slider-key-steps.directive.ts @@ -50,6 +50,22 @@ export class TuiSliderKeyStepsDirective return tuiIsNativeFocused(this.nativeFocusableElement); } + public override writeValue(controlValue: number | null): void { + if (controlValue === null) { + return; + } + + const clampedControlValue = tuiClamp(controlValue, this.min, this.max); + + ngDevMode && + tuiAssert.assert( + controlValue === clampedControlValue, + '\n[SliderKeySteps]: You cannot programmatically set value which is less/more than min/max', + ); + + this.slider.value = this.transformToNativeValue(clampedControlValue); + } + protected get min(): number { return this.keySteps[0][1]; } @@ -67,22 +83,6 @@ export class TuiSliderKeyStepsDirective ); } - public override writeValue(controlValue: number | null): void { - if (controlValue === null) { - return; - } - - const clampedControlValue = tuiClamp(controlValue, this.min, this.max); - - ngDevMode && - tuiAssert.assert( - controlValue === clampedControlValue, - '\n[SliderKeySteps]: You cannot programmatically set value which is less/more than min/max', - ); - - this.slider.value = this.transformToNativeValue(clampedControlValue); - } - protected getFallbackValue(): number { return 0; } diff --git a/projects/kit/components/slider/helpers/slider-thumb-label/slider-thumb-label.component.ts b/projects/kit/components/slider/helpers/slider-thumb-label/slider-thumb-label.component.ts index 043b98f2aa80..3f9b043e0c25 100644 --- a/projects/kit/components/slider/helpers/slider-thumb-label/slider-thumb-label.component.ts +++ b/projects/kit/components/slider/helpers/slider-thumb-label/slider-thumb-label.component.ts @@ -24,6 +24,15 @@ export class TuiSliderThumbLabelComponent implements AfterContentInit { @ContentChild(NgControl) protected readonly control?: NgControl; + public ngAfterContentInit(): void { + ngDevMode && + tuiAssert.assert( + Boolean(this.control?.valueChanges), + '\n[tuiSliderThumbLabel] expected to use Angular Forms.\n' + + 'Use [(ngModel)] or [formControl] or formControlName for correct work.', + ); + } + protected get size(): TuiSizeS { return this.slider?.size || 'm'; } @@ -35,13 +44,4 @@ export class TuiSliderThumbLabelComponent implements AfterContentInit { protected get ghostLeft(): number { return this.ratio * (this.slider?.el.offsetWidth || 0); } - - public ngAfterContentInit(): void { - ngDevMode && - tuiAssert.assert( - Boolean(this.control?.valueChanges), - '\n[tuiSliderThumbLabel] expected to use Angular Forms.\n' + - 'Use [(ngModel)] or [formControl] or formControlName for correct work.', - ); - } } diff --git a/projects/kit/components/slider/slider.component.ts b/projects/kit/components/slider/slider.component.ts index 2778c3e53d79..b8342fea33ec 100644 --- a/projects/kit/components/slider/slider.component.ts +++ b/projects/kit/components/slider/slider.component.ts @@ -34,14 +34,14 @@ import {TUI_SLIDER_OPTIONS} from './slider.options'; * This function triggers change detection (for {@link valuePercentage} function) when we drag thumb of the input. */ '(input)': '0', - '[style.--tui-slider-track-color]': 'options.trackColor', + '[style.--tui-slider-track-color]': 'trackColor', }, changeDetection: ChangeDetectionStrategy.OnPush, }) export class TuiSliderComponent { private readonly injector = inject(INJECTOR); private readonly control = inject(NgControl, {self: true, optional: true}); - protected readonly options = inject(TUI_SLIDER_OPTIONS); + private readonly options = inject(TUI_SLIDER_OPTIONS); @Input() @HostBinding('attr.data-size') @@ -52,6 +52,35 @@ export class TuiSliderComponent { public readonly el: HTMLInputElement = inject(ElementRef).nativeElement; + constructor() { + if (this.control instanceof NgModel) { + /** + * The ValueAccessor.writeValue method is called twice on any value accessor during component initialization, + * when a control is bound using [(ngModel)], first time with a phantom null value. + * With `changeDetection: ChangeDetectionStrategy.OnPush` the second call of writeValue with real value don't re-render the view. + * ___ + * See this {@link https://github.com/angular/angular/issues/14988 issue} + */ + this.control.valueChanges + ?.pipe(tuiWatch(inject(ChangeDetectorRef)), take(1)) + .subscribe(); + } + } + + @HostBinding('style.--tui-slider-fill-ratio') + public get valueRatio(): number { + return (this.value - this.min) / (this.max - this.min) || 0; + } + + @HostBinding('style.--tui-slider-fill-percentage.%') + public get valuePercentage(): number { + return 100 * this.valueRatio; + } + + public get trackColor(): string { + return this.options.trackColor; + } + public get min(): number { return Number(this.el.min); } @@ -60,10 +89,6 @@ export class TuiSliderComponent { return Number(this.el.max || 100); } - protected get step(): number { - return Number(this.el.step) || 1; - } - public get value(): number { if (!this.hasKeySteps && this.control instanceof NgModel) { /** @@ -80,16 +105,6 @@ export class TuiSliderComponent { this.el.value = `${newValue}`; } - @HostBinding('style.--tui-slider-fill-ratio') - public get valueRatio(): number { - return (this.value - this.min) / (this.max - this.min) || 0; - } - - @HostBinding('style.--tui-slider-fill-percentage.%') - public get valuePercentage(): number { - return 100 * this.valueRatio; - } - @HostBinding('style.--tui-slider-segment-width.%') protected get segmentWidth(): number { return 100 / Math.max(1, this.segments); @@ -100,18 +115,7 @@ export class TuiSliderComponent { return Boolean(this.injector.get(TuiSliderKeyStepsDirective, null)); } - constructor() { - if (this.control instanceof NgModel) { - /** - * The ValueAccessor.writeValue method is called twice on any value accessor during component initialization, - * when a control is bound using [(ngModel)], first time with a phantom null value. - * With `changeDetection: ChangeDetectionStrategy.OnPush` the second call of writeValue with real value don't re-render the view. - * ___ - * See this {@link https://github.com/angular/angular/issues/14988 issue} - */ - this.control.valueChanges - ?.pipe(tuiWatch(inject(ChangeDetectorRef)), take(1)) - .subscribe(); - } + protected get step(): number { + return Number(this.el.step) || 1; } } diff --git a/projects/kit/components/stepper/stepper.component.ts b/projects/kit/components/stepper/stepper.component.ts index 79881a1becda..39f75a7a9418 100644 --- a/projects/kit/components/stepper/stepper.component.ts +++ b/projects/kit/components/stepper/stepper.component.ts @@ -51,12 +51,6 @@ export class TuiStepperComponent { @HostBinding('attr.data-orientation') public orientation: TuiOrientation = 'horizontal'; - @Input('activeItemIndex') - public set activeIndex(index: number) { - this.activeItemIndex = index; - this.scrollIntoView(index); - } - @Output() public readonly activeItemIndexChange = new EventEmitter(); @@ -68,6 +62,33 @@ export class TuiStepperComponent { .subscribe(() => this.scrollIntoView(this.activeItemIndex)); } + @Input('activeItemIndex') + public set activeIndex(index: number) { + this.activeItemIndex = index; + this.scrollIntoView(index); + } + + public indexOf(step: HTMLElement): number { + return tuiGetOriginalArrayFromQueryList(this.steps).findIndex( + ({nativeElement}) => nativeElement === step, + ); + } + + public isActive(index: number): boolean { + return index === this.activeItemIndex; + } + + public activate(index: number): void { + if (this.activeItemIndex === index) { + return; + } + + this.activeItemIndex = index; + this.activeItemIndexChange.emit(index); + this.cdr.markForCheck(); + this.scrollIntoView(index); + } + @tuiPure protected get changes$(): Observable { // Delay is required to trigger change detection after steps are rendered, @@ -97,27 +118,6 @@ export class TuiStepperComponent { this.moveFocus(event.target, step); } - public indexOf(step: HTMLElement): number { - return tuiGetOriginalArrayFromQueryList(this.steps).findIndex( - ({nativeElement}) => nativeElement === step, - ); - } - - public isActive(index: number): boolean { - return index === this.activeItemIndex; - } - - public activate(index: number): void { - if (this.activeItemIndex === index) { - return; - } - - this.activeItemIndex = index; - this.activeItemIndexChange.emit(index); - this.cdr.markForCheck(); - this.scrollIntoView(index); - } - @tuiPure private getNativeElements( queryList: QueryList>, diff --git a/projects/kit/components/tabs/tab/tab.component.ts b/projects/kit/components/tabs/tab/tab.component.ts index 42d73f7f99f0..9a01f67cdbea 100644 --- a/projects/kit/components/tabs/tab/tab.component.ts +++ b/projects/kit/components/tabs/tab/tab.component.ts @@ -41,14 +41,14 @@ export class TuiTabComponent implements OnDestroy { protected readonly event$ = inject(TUI_TAB_EVENT); protected readonly margin = inject(TUI_TAB_MARGIN); - @HostBinding('class._active') - protected get isActive(): boolean { - return !!this.routerLinkActive?.isActive; - } - public ngOnDestroy(): void { if (tuiIsNativeFocused(this.el)) { this.el.blur(); } } + + @HostBinding('class._active') + protected get isActive(): boolean { + return !!this.routerLinkActive?.isActive; + } } diff --git a/projects/kit/components/tabs/tabs-with-more/tabs-with-more.component.ts b/projects/kit/components/tabs/tabs-with-more/tabs-with-more.component.ts index 5ecb15b2ce83..ad35621cd46f 100644 --- a/projects/kit/components/tabs/tabs-with-more/tabs-with-more.component.ts +++ b/projects/kit/components/tabs/tabs-with-more/tabs-with-more.component.ts @@ -62,28 +62,52 @@ export class TuiTabsWithMoreComponent implements AfterViewInit { @HostBinding('class._underline') public underline = this.options.underline; - @Input('activeItemIndex') - public set itemIndex(activeItemIndex: number) { - this.activeItemIndex = activeItemIndex; - this.maxIndex = this.getMaxIndex(); - } - @Input() public itemsLimit = this.options.itemsLimit; @Output() public readonly activeItemIndexChange = new EventEmitter(); + public activeItemIndex = 0; + @ContentChildren(TuiItemDirective, {read: TemplateRef}) protected readonly items: QueryList>> = EMPTY_QUERY; protected readonly moreWord$ = inject(TUI_MORE_WORD); protected readonly arrowOptions = inject(TUI_ARROW_OPTIONS); + protected open = false; - public activeItemIndex = 0; + @Input('activeItemIndex') + public set itemIndex(activeItemIndex: number) { + this.activeItemIndex = activeItemIndex; + this.maxIndex = this.getMaxIndex(); + } - protected open = false; + public get lastVisibleIndex(): number { + if (this.itemsLimit + 1 >= this.items.length) { + return this.maxIndex; + } + + const offset = + this.itemsLimit - 1 > this.activeItemIndex || !this.options.exposeActive + ? 1 + : 2; + + return Math.min(this.itemsLimit - offset, this.maxIndex); + } + + public ngAfterViewInit(): void { + this.refresh$ + .pipe( + map(() => this.getMaxIndex()), + filter(maxIndex => this.maxIndex !== maxIndex), + ) + .subscribe(maxIndex => { + this.maxIndex = maxIndex; + this.cdr.detectChanges(); + }); + } // TODO: Improve performance protected get tabs(): readonly HTMLElement[] { @@ -118,31 +142,6 @@ export class TuiTabsWithMoreComponent implements AfterViewInit { ); } - protected get lastVisibleIndex(): number { - if (this.itemsLimit + 1 >= this.items.length) { - return this.maxIndex; - } - - const offset = - this.itemsLimit - 1 > this.activeItemIndex || !this.options.exposeActive - ? 1 - : 2; - - return Math.min(this.itemsLimit - offset, this.maxIndex); - } - - public ngAfterViewInit(): void { - this.refresh$ - .pipe( - map(() => this.getMaxIndex()), - filter(maxIndex => this.maxIndex !== maxIndex), - ) - .subscribe(maxIndex => { - this.maxIndex = maxIndex; - this.cdr.detectChanges(); - }); - } - protected onActiveItemIndexChange(activeItemIndex: number): void { this.updateActiveItemIndex(activeItemIndex); } diff --git a/projects/kit/components/tabs/tabs.directive.ts b/projects/kit/components/tabs/tabs.directive.ts index 90bdb5e25012..968dbe8ffe34 100644 --- a/projects/kit/components/tabs/tabs.directive.ts +++ b/projects/kit/components/tabs/tabs.directive.ts @@ -32,20 +32,6 @@ export class TuiTabsDirective implements AfterViewChecked { return this.tabs[this.activeItemIndex] || null; } - @HostListener(TUI_TAB_ACTIVATE, ['$event', '$event.target']) - protected onActivate(event: Event, element: HTMLElement): void { - const index = this.tabs.findIndex(tab => tab === element); - - event.stopPropagation(); - - if (index === this.activeItemIndex) { - return; - } - - this.activeItemIndexChange.emit(index); - this.activeItemIndex = index; - } - public moveFocus(current: HTMLElement, step: number): void { const {tabs} = this; @@ -62,4 +48,18 @@ export class TuiTabsDirective implements AfterViewChecked { nativeElement.setAttribute('tabIndex', active ? '0' : '-1'); }); } + + @HostListener(TUI_TAB_ACTIVATE, ['$event', '$event.target']) + protected onActivate(event: Event, element: HTMLElement): void { + const index = this.tabs.findIndex(tab => tab === element); + + event.stopPropagation(); + + if (index === this.activeItemIndex) { + return; + } + + this.activeItemIndexChange.emit(index); + this.activeItemIndex = index; + } } diff --git a/projects/kit/components/tabs/tabs/tabs.component.ts b/projects/kit/components/tabs/tabs/tabs.component.ts index bc89ae1c9f3e..1c3a18c0b777 100644 --- a/projects/kit/components/tabs/tabs/tabs.component.ts +++ b/projects/kit/components/tabs/tabs/tabs.component.ts @@ -49,13 +49,13 @@ export class TuiTabsComponent implements AfterViewChecked { private readonly cdr = inject(ChangeDetectorRef); private readonly tabs = inject(TuiTabsDirective); - @ContentChildren(forwardRef(() => TuiTabComponent)) - protected readonly children: QueryList = EMPTY_QUERY; - @Input() @HostBinding('class._underline') public underline = this.options.underline; + @ContentChildren(forwardRef(() => TuiTabComponent)) + protected readonly children: QueryList = EMPTY_QUERY; + constructor() { this.resize$ .pipe( @@ -65,6 +65,10 @@ export class TuiTabsComponent implements AfterViewChecked { .subscribe(() => this.cdr.detectChanges()); } + public ngAfterViewChecked(): void { + this.scrollTo(this.tabs.activeItemIndex); + } + /** @deprecated use `activeItemIndex` from {@link TuiTabsDirective} instead */ protected get activeItemIndex(): number { return this.tabs.activeItemIndex; @@ -85,10 +89,6 @@ export class TuiTabsComponent implements AfterViewChecked { this.tabs.moveFocus(current, step); } - public ngAfterViewChecked(): void { - this.scrollTo(this.tabs.activeItemIndex); - } - @tuiPure private scrollTo(index: number): void { const element = this.tabs.tabs[index]; diff --git a/projects/kit/components/tabs/underline/underline.component.ts b/projects/kit/components/tabs/underline/underline.component.ts index ad35163a6c4b..7809d5267646 100644 --- a/projects/kit/components/tabs/underline/underline.component.ts +++ b/projects/kit/components/tabs/underline/underline.component.ts @@ -40,11 +40,6 @@ export class TuiUnderlineComponent { share(), ); - @Input() - public set element(element: HTMLElement | null) { - this.el$.next(element); - } - @HostListener('$.style.transitionProperty') protected readonly transition$ = asCallable( this.el$.pipe( @@ -74,4 +69,9 @@ export class TuiUnderlineComponent { (this.el as any)['$.style.transform'] = this.transform$; (this.el as any)['$.style.width.px'] = this.width$; } + + @Input() + public set element(element: HTMLElement | null) { + this.el$.next(element); + } } diff --git a/projects/kit/components/textarea/textarea.component.ts b/projects/kit/components/textarea/textarea.component.ts index 73c02f16092e..b1f8fb72d5fc 100644 --- a/projects/kit/components/textarea/textarea.component.ts +++ b/projects/kit/components/textarea/textarea.component.ts @@ -77,11 +77,6 @@ export class TuiTextareaComponent protected readonly controller = inject(TUI_TEXTFIELD_WATCHED_CONTROLLER); protected readonly hintOptions = inject(TuiHintOptionsDirective, {optional: true}); - @HostBinding('class._label-outside') - protected get labelOutside(): boolean { - return this.controller.labelOutside; - } - public get nativeFocusableElement(): HTMLTextAreaElement | null { if (this.computedDisabled) { return null; @@ -96,8 +91,17 @@ export class TuiTextareaComponent return tuiIsNativeFocused(this.nativeFocusableElement); } - protected get appearance(): string { - return this.controller.appearance; + public get computeMaxHeight(): number | null { + return this.expandable ? this.rows * this.lineHeight : null; + } + + public onValueChange(value: string): void { + this.value = value; + } + + @HostBinding('class._label-outside') + protected get labelOutside(): boolean { + return this.controller.labelOutside; } @HostBinding('attr.data-size') @@ -121,10 +125,6 @@ export class TuiTextareaComponent ); } - protected get hasCleaner(): boolean { - return this.controller.cleaner && this.hasValue && this.interactive; - } - @HostBinding('class._has-tooltip') protected get hasTooltip(): boolean { return ( @@ -143,6 +143,14 @@ export class TuiTextareaComponent return !!this.maxLength && this.interactive; } + protected get appearance(): string { + return this.controller.appearance; + } + + protected get hasCleaner(): boolean { + return this.controller.cleaner && this.hasValue && this.interactive; + } + protected get hasPlaceholder(): boolean { return this.placeholderRaisable || (!this.hasValue && !this.hasExampleText); } @@ -174,10 +182,6 @@ export class TuiTextareaComponent ); } - public get computeMaxHeight(): number | null { - return this.expandable ? this.rows * this.lineHeight : null; - } - protected get placeholderRaised(): boolean { return ( this.placeholderRaisable && @@ -199,10 +203,6 @@ export class TuiTextareaComponent this.updateFocused(focused); } - public onValueChange(value: string): void { - this.value = value; - } - protected onMouseDown(event: MouseEvent): void { if (event.target === this.nativeFocusableElement) { return; diff --git a/projects/kit/components/tiles/tile.component.ts b/projects/kit/components/tiles/tile.component.ts index 63b0f1f0a1eb..f0cc18dc816a 100644 --- a/projects/kit/components/tiles/tile.component.ts +++ b/projects/kit/components/tiles/tile.component.ts @@ -33,25 +33,10 @@ export class TuiTileComponent implements OnDestroy, AfterViewInit { @Input() public height = 1; - @HostBinding('class._dragged') - protected dragged = false; - public readonly element: HTMLElement = inject(ElementRef).nativeElement; - @HostBinding('style.gridColumn') - protected get column(): string { - return `span var(--tui-width, ${this.width})`; - } - - @HostBinding('style.gridRow') - protected get row(): string { - return `span var(--tui-height, ${this.height})`; - } - - @HostListener('pointerenter') - protected onEnter(): void { - this.tiles.rearrange(this.element); - } + @HostBinding('class._dragged') + protected dragged = false; public onDrag(offset: readonly [number, number]): void { const dragged = !Number.isNaN(offset[0]); @@ -61,10 +46,6 @@ export class TuiTileComponent implements OnDestroy, AfterViewInit { this.service.setOffset(offset); } - protected onTransitionEnd(): void { - this.dragged = false; - } - public ngAfterViewInit(): void { if (this.wrapper) { this.service.init(this.wrapper.nativeElement); @@ -76,4 +57,23 @@ export class TuiTileComponent implements OnDestroy, AfterViewInit { this.tiles.element = null; } } + + @HostBinding('style.gridColumn') + protected get column(): string { + return `span var(--tui-width, ${this.width})`; + } + + @HostBinding('style.gridRow') + protected get row(): string { + return `span var(--tui-height, ${this.height})`; + } + + @HostListener('pointerenter') + protected onEnter(): void { + this.tiles.rearrange(this.element); + } + + protected onTransitionEnd(): void { + this.dragged = false; + } } diff --git a/projects/kit/components/tiles/tiles.component.ts b/projects/kit/components/tiles/tiles.component.ts index b6306241d0d4..cdbeaf4c272f 100644 --- a/projects/kit/components/tiles/tiles.component.ts +++ b/projects/kit/components/tiles/tiles.component.ts @@ -38,15 +38,6 @@ export class TuiTilesComponent { @Input() public debounce = 0; - @Input() - public set order(map: Map) { - this.order$.next(map); - } - - public get order(): Map { - return this.order$.value; - } - @Output() public readonly orderChange = this.el$.pipe( debounce(() => timer(this.debounce)), @@ -59,6 +50,15 @@ export class TuiTilesComponent { public readonly order$ = new BehaviorSubject(new Map()); + @Input() + public set order(map: Map) { + this.order$.next(map); + } + + public get order(): Map { + return this.order$.value; + } + @HostListener('pointerleave.silent') public rearrange(element?: Element): void { this.el$.next(element); diff --git a/projects/kit/components/toggle/toggle.component.ts b/projects/kit/components/toggle/toggle.component.ts index 8a4000149d80..2e57f3b2acf1 100644 --- a/projects/kit/components/toggle/toggle.component.ts +++ b/projects/kit/components/toggle/toggle.component.ts @@ -39,9 +39,9 @@ export class TuiToggleComponent @ViewChild('focusableElement') private readonly focusableElement?: ElementRef; - private readonly modeDirective = inject(TuiModeDirective, {optional: true}); + private readonly options = inject(TUI_TOGGLE_OPTIONS); - protected readonly options = inject(TUI_TOGGLE_OPTIONS); + private readonly modeDirective = inject(TuiModeDirective, {optional: true}); @Input() public singleColor = this.options.singleColor; @@ -56,14 +56,6 @@ export class TuiToggleComponent @HostBinding('attr.data-size') public size: TuiSizeL = this.options.size; - protected get iconOn(): PolymorpheusContent> { - return this.options.icons.toggleOn; - } - - protected get iconOff(): PolymorpheusContent> { - return this.options.icons.toggleOff; - } - public get nativeFocusableElement(): TuiNativeFocusableElement | null { return this.focusableElement?.nativeElement ?? null; } @@ -72,6 +64,19 @@ export class TuiToggleComponent return tuiIsNativeFocused(this.nativeFocusableElement); } + @HostBinding('attr.data-mode') + protected get hostMode(): TuiBrightness | null { + return this.modeDirective?.mode ?? null; + } + + protected get iconOn(): PolymorpheusContent> { + return this.options.icons.toggleOn; + } + + protected get iconOff(): PolymorpheusContent> { + return this.options.icons.toggleOff; + } + protected get appearance(): string { return this.singleColor || this.value ? this.options.appearances.checked @@ -86,11 +91,6 @@ export class TuiToggleComponent return this.sizeM ? 'xs' : 's'; } - @HostBinding('attr.data-mode') - protected get hostMode(): TuiBrightness | null { - return this.modeDirective?.mode ?? null; - } - /** @deprecated use 'value' setter */ protected onChecked(checked: boolean): void { this.value = checked; diff --git a/projects/kit/components/tree/components/tree-item-content/tree-item-content.component.ts b/projects/kit/components/tree/components/tree-item-content/tree-item-content.component.ts index e29d6ace3586..b18b27ea4c99 100644 --- a/projects/kit/components/tree/components/tree-item-content/tree-item-content.component.ts +++ b/projects/kit/components/tree/components/tree-item-content/tree-item-content.component.ts @@ -26,10 +26,6 @@ export class TuiTreeItemContentComponent { protected readonly icons = inject(TUI_COMMON_ICONS); protected readonly context = inject(POLYMORPHEUS_CONTEXT); - protected get isExpanded(): boolean { - return this.context.$implicit.isExpanded; - } - @HostBinding('class._expandable') protected get isExpandable(): boolean { return ( @@ -38,6 +34,10 @@ export class TuiTreeItemContentComponent { ); } + protected get isExpanded(): boolean { + return this.context.$implicit.isExpanded; + } + protected onClick(): void { this.controller.toggle(this.context.$implicit); } diff --git a/projects/kit/directives/highlight/highlight.directive.ts b/projects/kit/directives/highlight/highlight.directive.ts index 4fe9b8db825d..7fdc7b61fd60 100644 --- a/projects/kit/directives/highlight/highlight.directive.ts +++ b/projects/kit/directives/highlight/highlight.directive.ts @@ -35,14 +35,14 @@ export class TuiHighlightDirective implements OnChanges { .subscribe(() => this.updateStyles()); } - protected get match(): boolean { - return this.indexOf(this.el.textContent) !== -1; - } - public ngOnChanges(): void { this.updateStyles(); } + protected get match(): boolean { + return this.indexOf(this.el.textContent) !== -1; + } + private updateStyles(): void { this.highlight.style.display = 'none'; diff --git a/projects/kit/directives/lazy-loading/lazy-loading.directive.ts b/projects/kit/directives/lazy-loading/lazy-loading.directive.ts index fa57d3ec44f4..87cf2064bc33 100644 --- a/projects/kit/directives/lazy-loading/lazy-loading.directive.ts +++ b/projects/kit/directives/lazy-loading/lazy-loading.directive.ts @@ -20,12 +20,6 @@ export class TuiLazyLoadingDirective { private readonly el: HTMLImageElement = inject(ElementRef).nativeElement; private readonly src$ = inject(TuiLazyLoadingService); - @Input('src') - public set srcSetter(src: SafeResourceUrl | string) { - this.src = this.supported ? src : null; - this.src$.next(src); - } - @HostBinding('style.animation') protected animation = 'tuiSkeletonVibe ease-in-out 1s infinite alternate'; @@ -43,8 +37,10 @@ export class TuiLazyLoadingDirective { } } - private get supported(): boolean { - return 'loading' in this.el; + @Input('src') + public set srcSetter(src: SafeResourceUrl | string) { + this.src = this.supported ? src : null; + this.src$.next(src); } @HostListener('load') @@ -52,4 +48,8 @@ export class TuiLazyLoadingDirective { this.background = ''; this.animation = ''; } + + private get supported(): boolean { + return 'loading' in this.el; + } } diff --git a/projects/kit/directives/present/present.directive.ts b/projects/kit/directives/present/present.directive.ts index 875bf58d2e2b..cd045ddf7127 100644 --- a/projects/kit/directives/present/present.directive.ts +++ b/projects/kit/directives/present/present.directive.ts @@ -17,13 +17,13 @@ export class TuiPresentDirective implements OnDestroy { skip(1), ); + public ngOnDestroy(): void { + this.visibility$.next(false); + } + @HostListener('animationcancel.self', ['false']) @HostListener('animationstart.self', ['true']) protected onAnimation(visibility: boolean): void { this.visibility$.next(visibility); } - - public ngOnDestroy(): void { - this.visibility$.next(false); - } } diff --git a/projects/kit/internal/primitive-calendar-range/primitive-calendar-range.component.ts b/projects/kit/internal/primitive-calendar-range/primitive-calendar-range.component.ts index 168db6e39737..17b4c6f6c01a 100644 --- a/projects/kit/internal/primitive-calendar-range/primitive-calendar-range.component.ts +++ b/projects/kit/internal/primitive-calendar-range/primitive-calendar-range.component.ts @@ -59,10 +59,10 @@ export class TuiPrimitiveCalendarRangeComponent implements OnInit { @Output() public readonly dayClick = new EventEmitter(); - protected hoveredItem: TuiDay | null = null; public userViewedMonthFirst: TuiMonth = this.defaultViewedMonthFirst; public userViewedMonthSecond: TuiMonth = this.defaultViewedMonthSecond; + protected hoveredItem: TuiDay | null = null; protected valueChanges = inject | null>( TUI_CALENDAR_DATE_STREAM, {optional: true}, @@ -86,6 +86,10 @@ export class TuiPrimitiveCalendarRangeComponent implements OnInit { : this.max; } + public ngOnInit(): void { + this.setInitialMonths(); + } + protected get cappedUserViewedMonthFirst(): TuiMonth { return this.userViewedMonthFirst.monthSameOrBefore(this.userViewedMonthSecond) ? this.userViewedMonthFirst @@ -97,10 +101,6 @@ export class TuiPrimitiveCalendarRangeComponent implements OnInit { offset, ) => value.append({month: offset}); - public ngOnInit(): void { - this.setInitialMonths(); - } - protected onSectionFirstViewedMonth(month: TuiMonth): void { this.userViewedMonthFirst = month; diff --git a/projects/kit/pipes/field-error/field-error-pipe.ts b/projects/kit/pipes/field-error/field-error-pipe.ts index 1af86471e83c..f2c17c6a709a 100644 --- a/projects/kit/pipes/field-error/field-error-pipe.ts +++ b/projects/kit/pipes/field-error/field-error-pipe.ts @@ -49,10 +49,6 @@ export class TuiFieldErrorPipe implements PipeTransform, ControlValueAccessor { return this.computedError; } - protected get computedError(): Observable { - return (this.invalid && this.touched && this.error) || of(null); - } - public registerOnChange(): void {} public registerOnTouched(): void {} @@ -61,6 +57,10 @@ export class TuiFieldErrorPipe implements PipeTransform, ControlValueAccessor { public writeValue(): void {} + protected get computedError(): Observable { + return (this.invalid && this.touched && this.error) || of(null); + } + private get error(): Observable | null { const {errorId} = this; @@ -94,17 +94,6 @@ export class TuiFieldErrorPipe implements PipeTransform, ControlValueAccessor { return this.control?.errors || EMPTY_RECORD; } - @tuiPure - private getErrorId( - order: readonly string[], - controlErrors: Record, - ): string { - const id = order?.find(errorId => controlErrors[errorId]); - const fallback = Object.keys(controlErrors)[0]; - - return id || fallback || ''; - } - @tuiPure private getError( context: any, @@ -134,4 +123,15 @@ export class TuiFieldErrorPipe implements PipeTransform, ControlValueAccessor { return defaultError(content, context); } + + @tuiPure + private getErrorId( + order: readonly string[], + controlErrors: Record, + ): string { + const id = order?.find(errorId => controlErrors[errorId]); + const fallback = Object.keys(controlErrors)[0]; + + return id || fallback || ''; + } }