diff --git a/.github/workflows/list-storybook-branches.sh b/.github/workflows/list-storybook-branches.sh
index d2d5c9eed..a28b2a405 100755
--- a/.github/workflows/list-storybook-branches.sh
+++ b/.github/workflows/list-storybook-branches.sh
@@ -1,7 +1,7 @@
#!/bin/bash
# Number of days to check
-DAYS=10
+DAYS=30
# Get the current date in seconds since epoch
CURRENT_DATE=$(date +%s)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6a29a7671..3d8e36d2b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,154 @@
+# [16.0.0-rc.20](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.19...react-16.0.0-rc.20) (2026-02-26)
+
+
+### Bug Fixes
+
+* **separator:** fix custom size application [#535](https://github.com/TEDI-Design-System/react/issues/535) ([#536](https://github.com/TEDI-Design-System/react/issues/536)) ([130edcd](https://github.com/TEDI-Design-System/react/commit/130edcd158944b90c62788e76fc97e015f1f228c))
+
+# [16.0.0-rc.19](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.18...react-16.0.0-rc.19) (2026-02-25)
+
+
+### Bug Fixes
+
+* **text-field:** fix small textfield right area padding, fix small textfield font size [#527](https://github.com/TEDI-Design-System/react/issues/527) ([#528](https://github.com/TEDI-Design-System/react/issues/528)) ([bd8bd16](https://github.com/TEDI-Design-System/react/commit/bd8bd1640c40be40199d881efead665ce45bd0a3))
+
+# [16.0.0-rc.18](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.17...react-16.0.0-rc.18) (2026-02-25)
+
+
+### Features
+
+* **separator:** redesign with new spacing API, dotPosition and dotStyle support [#30](https://github.com/TEDI-Design-System/react/issues/30) ([#525](https://github.com/TEDI-Design-System/react/issues/525)) ([93e9e11](https://github.com/TEDI-Design-System/react/commit/93e9e118aab73d40347029089c5370851a7b551c))
+
+
+### BREAKING CHANGES
+
+* **separator:** legacy spacing props removed, dotSize enum changed, variant values simplified
+
+# [16.0.0-rc.17](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.16...react-16.0.0-rc.17) (2026-02-25)
+
+
+### Bug Fixes
+
+* **checkbox,radio:** show pointer on label hover [#532](https://github.com/TEDI-Design-System/react/issues/532) ([#533](https://github.com/TEDI-Design-System/react/issues/533)) ([097627d](https://github.com/TEDI-Design-System/react/commit/097627db68e23afaa27dd288319b34ccba3e5888))
+
+# [16.0.0-rc.16](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.15...react-16.0.0-rc.16) (2026-02-20)
+
+
+### Bug Fixes
+
+* **number-field:** fix variables [#516](https://github.com/TEDI-Design-System/react/issues/516) ([#522](https://github.com/TEDI-Design-System/react/issues/522)) ([dcf6240](https://github.com/TEDI-Design-System/react/commit/dcf62404afa9543c13277623a9aaa6daed1b93df))
+
+# [16.0.0-rc.15](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.14...react-16.0.0-rc.15) (2026-02-19)
+
+
+### Bug Fixes
+
+* **choice-group:** segmented item borders and focus behaviour [#101](https://github.com/TEDI-Design-System/react/issues/101) ([#513](https://github.com/TEDI-Design-System/react/issues/513)) ([455c491](https://github.com/TEDI-Design-System/react/commit/455c491a753dbfc35d7c996fb94aa15639bbdc51))
+
+# [16.0.0-rc.14](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.13...react-16.0.0-rc.14) (2026-02-19)
+
+
+### Features
+
+* **closing-button:** add brand and inverted color [#6](https://github.com/TEDI-Design-System/react/issues/6) ([#519](https://github.com/TEDI-Design-System/react/issues/519)) ([cfeb5f2](https://github.com/TEDI-Design-System/react/commit/cfeb5f206b9137041b581c610c577e8e600b4fd7))
+
+# [16.0.0-rc.13](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.12...react-16.0.0-rc.13) (2026-02-19)
+
+
+### Bug Fixes
+
+* **feedback-text:** fix error/success text color variables [#517](https://github.com/TEDI-Design-System/react/issues/517) ([#521](https://github.com/TEDI-Design-System/react/issues/521)) ([c019e79](https://github.com/TEDI-Design-System/react/commit/c019e793c5126baba67c516255f3ad3ecfcb2fd7))
+
+# [16.0.0-rc.12](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.11...react-16.0.0-rc.12) (2026-02-19)
+
+
+### Features
+
+* **sidenav:** subheading as ReactNode, fix mobile sidenav items padding [#421](https://github.com/TEDI-Design-System/react/issues/421) ([#512](https://github.com/TEDI-Design-System/react/issues/512)) ([bb7fbe8](https://github.com/TEDI-Design-System/react/commit/bb7fbe8637895adfd5f331bbdbca5e3853d807ef))
+
+# [16.0.0-rc.11](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.10...react-16.0.0-rc.11) (2026-02-19)
+
+
+### Bug Fixes
+
+* **link:** fix link icon sizes in relation to figma design [#46](https://github.com/TEDI-Design-System/react/issues/46) ([#520](https://github.com/TEDI-Design-System/react/issues/520)) ([f32bd83](https://github.com/TEDI-Design-System/react/commit/f32bd83b549b195ecb70b4f9191dd8ef9f6b0a42))
+
+# [16.0.0-rc.10](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.9...react-16.0.0-rc.10) (2026-02-19)
+
+
+### Features
+
+* **button-group:** add size prop, add small example, fix examples on storybook [#14](https://github.com/TEDI-Design-System/react/issues/14) ([#511](https://github.com/TEDI-Design-System/react/issues/511)) ([73cd4f1](https://github.com/TEDI-Design-System/react/commit/73cd4f11348e4cccc9dfbfd84b7a333ce59f2023))
+
+# [16.0.0-rc.9](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.8...react-16.0.0-rc.9) (2026-02-19)
+
+
+### Features
+
+* **alert:** new size prop with default and small values [#11](https://github.com/TEDI-Design-System/react/issues/11) ([#509](https://github.com/TEDI-Design-System/react/issues/509)) ([35c4962](https://github.com/TEDI-Design-System/react/commit/35c4962ec56612c5e5b727a27f813eb96fd7fb1e))
+
+# [16.0.0-rc.8](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.7...react-16.0.0-rc.8) (2026-02-16)
+
+
+### Bug Fixes
+
+* **tooltip,overlay:** wcag improvements [#468](https://github.com/TEDI-Design-System/react/issues/468) ([#491](https://github.com/TEDI-Design-System/react/issues/491)) ([fa60e46](https://github.com/TEDI-Design-System/react/commit/fa60e46c2492734c29d3af2ac3d7cb4df9779c69))
+
+# [16.0.0-rc.7](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.6...react-16.0.0-rc.7) (2026-02-13)
+
+
+### Bug Fixes
+
+* **choice-group:** selected disabled choice-group item fixes [#27](https://github.com/TEDI-Design-System/react/issues/27) ([#510](https://github.com/TEDI-Design-System/react/issues/510)) ([be8884e](https://github.com/TEDI-Design-System/react/commit/be8884e83e0fb26925b155e13143061ba485aa82))
+
+# [16.0.0-rc.6](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.5...react-16.0.0-rc.6) (2026-02-13)
+
+
+### Bug Fixes
+
+* **sidenav:** apply linkAs for flyout items [#40](https://github.com/TEDI-Design-System/react/issues/40) ([#501](https://github.com/TEDI-Design-System/react/issues/501)) ([6007ede](https://github.com/TEDI-Design-System/react/commit/6007ede51b75c6382db9ee3caf689f2a51a04bc3))
+
+# [16.0.0-rc.5](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.4...react-16.0.0-rc.5) (2026-02-13)
+
+
+### Features
+
+* **info-button:** added inverted variant and new color prop [#420](https://github.com/TEDI-Design-System/react/issues/420) ([#508](https://github.com/TEDI-Design-System/react/issues/508)) ([6ca2d7f](https://github.com/TEDI-Design-System/react/commit/6ca2d7fb3b5f609f3f51b884db074ee30fae457a))
+
+# [16.0.0-rc.4](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.3...react-16.0.0-rc.4) (2026-02-10)
+
+
+### Bug Fixes
+
+* **choice-group:** prevent calling onchange twice on card variant [#484](https://github.com/TEDI-Design-System/react/issues/484) ([#502](https://github.com/TEDI-Design-System/react/issues/502)) ([27799cc](https://github.com/TEDI-Design-System/react/commit/27799cc2c4db6381f911ada2697e1bd0b53d2a4d))
+* **choice-group:** prevent double change events and unify card click behavior [#504](https://github.com/TEDI-Design-System/react/issues/504) ([#505](https://github.com/TEDI-Design-System/react/issues/505)) ([7ea1fed](https://github.com/TEDI-Design-System/react/commit/7ea1fedf754e4828df7b508f8cd9ab4428ad3fe6))
+
+# [16.0.0-rc.3](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.2...react-16.0.0-rc.3) (2026-02-02)
+
+
+### Bug Fixes
+
+* **checkbox,radio:** pass required prop to label [#115](https://github.com/TEDI-Design-System/react/issues/115) ([#498](https://github.com/TEDI-Design-System/react/issues/498)) ([a569636](https://github.com/TEDI-Design-System/react/commit/a569636453c865b142ec53761949b97afd436546)), closes [#486](https://github.com/TEDI-Design-System/react/issues/486)
+
+# [16.0.0-rc.2](https://github.com/TEDI-Design-System/react/compare/react-16.0.0-rc.1...react-16.0.0-rc.2) (2026-02-02)
+
+
+### Features
+
+* **form-label:** update label prop type to ReactNode [#486](https://github.com/TEDI-Design-System/react/issues/486) ([#490](https://github.com/TEDI-Design-System/react/issues/490)) ([2c1152a](https://github.com/TEDI-Design-System/react/commit/2c1152a549aef92cb3225f092b0519c13440b756))
+
+# [16.0.0-rc.1](https://github.com/TEDI-Design-System/react/compare/react-15.0.0...react-16.0.0-rc.1) (2026-01-30)
+
+
+### Features
+
+* **closing-button:** align size and icon behavior with the design [#43](https://github.com/TEDI-Design-System/react/issues/43) ([#481](https://github.com/TEDI-Design-System/react/issues/481)) ([cdd92a8](https://github.com/TEDI-Design-System/react/commit/cdd92a88115f9ba5b6a5265bf495640178f02b9c))
+
+
+### BREAKING CHANGES
+
+* **closing-button:** size, iconSize changes, new default values
+
# [15.0.0](https://github.com/TEDI-Design-System/react/compare/react-14.3.0...react-15.0.0) (2026-01-29)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000..f05362f4a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2026 TEDI Design System
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/package-lock.json b/package-lock.json
index 1604a4dfe..6268efb2f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,7 +14,7 @@
"@mui/material": "^5.15.13",
"@mui/x-date-pickers": "^5.0.20",
"@tanstack/react-table": "^8.13.2",
- "@tedi-design-system/core": "3.0.1",
+ "@tedi-design-system/core": "3.2.0",
"classnames": "^2.5.1",
"draft-js": "^0.11.7",
"draftjs-md-converter": "^1.5.2",
@@ -33,7 +33,7 @@
"@babel/preset-env": "^7.26.0",
"@babel/preset-react": "^7.26.3",
"@babel/preset-typescript": "^7.26.0",
- "@commitlint/cli": "^19.8.1",
+ "@commitlint/cli": "^20.4.0",
"@commitlint/config-conventional": "^20.0.0",
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
@@ -2131,17 +2131,17 @@
}
},
"node_modules/@commitlint/cli": {
- "version": "19.8.1",
- "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-19.8.1.tgz",
- "integrity": "sha512-LXUdNIkspyxrlV6VDHWBmCZRtkEVRpBKxi2Gtw3J54cGWhLCTouVD/Q6ZSaSvd2YaDObWK8mDjrz3TIKtaQMAA==",
+ "version": "20.4.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.4.0.tgz",
+ "integrity": "sha512-2lqrFrYNxjKxgMqeYiO3zNM14XN9v72/5xIJyvdLw7sHEGlfg6sweW01PGNWiqZa6/AuZwsb0uzkgWJy6F4N2w==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@commitlint/format": "^19.8.1",
- "@commitlint/lint": "^19.8.1",
- "@commitlint/load": "^19.8.1",
- "@commitlint/read": "^19.8.1",
- "@commitlint/types": "^19.8.1",
+ "@commitlint/format": "^20.4.0",
+ "@commitlint/lint": "^20.4.0",
+ "@commitlint/load": "^20.4.0",
+ "@commitlint/read": "^20.4.0",
+ "@commitlint/types": "^20.4.0",
"tinyexec": "^1.0.0",
"yargs": "^17.0.0"
},
@@ -2166,28 +2166,14 @@
"node": ">=v18"
}
},
- "node_modules/@commitlint/config-conventional/node_modules/@commitlint/types": {
- "version": "20.0.0",
- "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-20.0.0.tgz",
- "integrity": "sha512-bVUNBqG6aznYcYjTjnc3+Cat/iBgbgpflxbIBTnsHTX0YVpnmINPEkSRWymT2Q8aSH3Y7aKnEbunilkYe8TybA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/conventional-commits-parser": "^5.0.0",
- "chalk": "^5.3.0"
- },
- "engines": {
- "node": ">=v18"
- }
- },
"node_modules/@commitlint/config-validator": {
- "version": "19.8.1",
- "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.8.1.tgz",
- "integrity": "sha512-0jvJ4u+eqGPBIzzSdqKNX1rvdbSU1lPNYlfQQRIFnBgLy26BtC0cFnr7c/AyuzExMxWsMOte6MkTi9I3SQ3iGQ==",
+ "version": "20.4.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-20.4.0.tgz",
+ "integrity": "sha512-zShmKTF+sqyNOfAE0vKcqnpvVpG0YX8F9G/ZIQHI2CoKyK+PSdladXMSns400aZ5/QZs+0fN75B//3Q5CHw++w==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@commitlint/types": "^19.8.1",
+ "@commitlint/types": "^20.4.0",
"ajv": "^8.11.0"
},
"engines": {
@@ -2195,27 +2181,23 @@
}
},
"node_modules/@commitlint/ensure": {
- "version": "19.8.1",
- "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-19.8.1.tgz",
- "integrity": "sha512-mXDnlJdvDzSObafjYrOSvZBwkD01cqB4gbnnFuVyNpGUM5ijwU/r/6uqUmBXAAOKRfyEjpkGVZxaDsCVnHAgyw==",
+ "version": "20.4.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-20.4.0.tgz",
+ "integrity": "sha512-F3qwnanJUisFWwh44GYYmMOxfgJL1FKV73FCB5zxo8pw1CHkxXadGfDfzNkN8B3iqgSGusDN2+oDH6upBmLszA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@commitlint/types": "^19.8.1",
- "lodash.camelcase": "^4.3.0",
- "lodash.kebabcase": "^4.1.1",
- "lodash.snakecase": "^4.1.1",
- "lodash.startcase": "^4.4.0",
- "lodash.upperfirst": "^4.3.1"
+ "@commitlint/types": "^20.4.0",
+ "kasi": "^2.0.1"
},
"engines": {
"node": ">=v18"
}
},
"node_modules/@commitlint/execute-rule": {
- "version": "19.8.1",
- "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-19.8.1.tgz",
- "integrity": "sha512-YfJyIqIKWI64Mgvn/sE7FXvVMQER/Cd+s3hZke6cI1xgNT/f6ZAz5heND0QtffH+KbcqAwXDEE1/5niYayYaQA==",
+ "version": "20.0.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-20.0.0.tgz",
+ "integrity": "sha512-xyCoOShoPuPL44gVa+5EdZsBVao/pNzpQhkzq3RdtlFdKZtjWcLlUFQHSWBuhk5utKYykeJPSz2i8ABHQA+ZZw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2223,27 +2205,27 @@
}
},
"node_modules/@commitlint/format": {
- "version": "19.8.1",
- "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-19.8.1.tgz",
- "integrity": "sha512-kSJj34Rp10ItP+Eh9oCItiuN/HwGQMXBnIRk69jdOwEW9llW9FlyqcWYbHPSGofmjsqeoxa38UaEA5tsbm2JWw==",
+ "version": "20.4.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-20.4.0.tgz",
+ "integrity": "sha512-i3ki3WR0rgolFVX6r64poBHXM1t8qlFel1G1eCBvVgntE3fCJitmzSvH5JD/KVJN/snz6TfaX2CLdON7+s4WVQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@commitlint/types": "^19.8.1",
- "chalk": "^5.3.0"
+ "@commitlint/types": "^20.4.0",
+ "picocolors": "^1.1.1"
},
"engines": {
"node": ">=v18"
}
},
"node_modules/@commitlint/is-ignored": {
- "version": "19.8.1",
- "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-19.8.1.tgz",
- "integrity": "sha512-AceOhEhekBUQ5dzrVhDDsbMaY5LqtN8s1mqSnT2Kz1ERvVZkNihrs3Sfk1Je/rxRNbXYFzKZSHaPsEJJDJV8dg==",
+ "version": "20.4.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-20.4.0.tgz",
+ "integrity": "sha512-E8AHpedEfuf+lZatFvFiJXA4TtZgBZ10+A7HzFudaEmTPPE5o6MGswxbxUIGAciaHAFj/oTTmyFc6A5tcvxE3Q==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@commitlint/types": "^19.8.1",
+ "@commitlint/types": "^20.4.0",
"semver": "^7.6.0"
},
"engines": {
@@ -2264,47 +2246,59 @@
}
},
"node_modules/@commitlint/lint": {
- "version": "19.8.1",
- "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-19.8.1.tgz",
- "integrity": "sha512-52PFbsl+1EvMuokZXLRlOsdcLHf10isTPlWwoY1FQIidTsTvjKXVXYb7AvtpWkDzRO2ZsqIgPK7bI98x8LRUEw==",
+ "version": "20.4.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-20.4.0.tgz",
+ "integrity": "sha512-W90YCbm5h3Yg+btF5/X+cxsY6vd/H3tsFt6U7WBmDQSkKV8NmitYg89zeoSQyYEiQCwAsH0dcA+99aQtLZiSnw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@commitlint/is-ignored": "^19.8.1",
- "@commitlint/parse": "^19.8.1",
- "@commitlint/rules": "^19.8.1",
- "@commitlint/types": "^19.8.1"
+ "@commitlint/is-ignored": "^20.4.0",
+ "@commitlint/parse": "^20.4.0",
+ "@commitlint/rules": "^20.4.0",
+ "@commitlint/types": "^20.4.0"
},
"engines": {
"node": ">=v18"
}
},
"node_modules/@commitlint/load": {
- "version": "19.8.1",
- "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.8.1.tgz",
- "integrity": "sha512-9V99EKG3u7z+FEoe4ikgq7YGRCSukAcvmKQuTtUyiYPnOd9a2/H9Ak1J9nJA1HChRQp9OA/sIKPugGS+FK/k1A==",
+ "version": "20.4.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-20.4.0.tgz",
+ "integrity": "sha512-Dauup/GfjwffBXRJUdlX/YRKfSVXsXZLnINXKz0VZkXdKDcaEILAi9oflHGbfydonJnJAbXEbF3nXPm9rm3G6A==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@commitlint/config-validator": "^19.8.1",
- "@commitlint/execute-rule": "^19.8.1",
- "@commitlint/resolve-extends": "^19.8.1",
- "@commitlint/types": "^19.8.1",
- "chalk": "^5.3.0",
+ "@commitlint/config-validator": "^20.4.0",
+ "@commitlint/execute-rule": "^20.0.0",
+ "@commitlint/resolve-extends": "^20.4.0",
+ "@commitlint/types": "^20.4.0",
"cosmiconfig": "^9.0.0",
"cosmiconfig-typescript-loader": "^6.1.0",
- "lodash.isplainobject": "^4.0.6",
- "lodash.merge": "^4.6.2",
- "lodash.uniq": "^4.5.0"
+ "is-plain-obj": "^4.1.0",
+ "lodash.mergewith": "^4.6.2",
+ "picocolors": "^1.1.1"
},
"engines": {
"node": ">=v18"
}
},
+ "node_modules/@commitlint/load/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,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/@commitlint/message": {
- "version": "19.8.1",
- "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-19.8.1.tgz",
- "integrity": "sha512-+PMLQvjRXiU+Ae0Wc+p99EoGEutzSXFVwQfa3jRNUZLNW5odZAyseb92OSBTKCu+9gGZiJASt76Cj3dLTtcTdg==",
+ "version": "20.4.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-20.4.0.tgz",
+ "integrity": "sha512-B5lGtvHgiLAIsK5nLINzVW0bN5hXv+EW35sKhYHE8F7V9Uz1fR4tx3wt7mobA5UNhZKUNgB/+ldVMQE6IHZRyA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2312,29 +2306,29 @@
}
},
"node_modules/@commitlint/parse": {
- "version": "19.8.1",
- "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-19.8.1.tgz",
- "integrity": "sha512-mmAHYcMBmAgJDKWdkjIGq50X4yB0pSGpxyOODwYmoexxxiUCy5JJT99t1+PEMK7KtsCtzuWYIAXYAiKR+k+/Jw==",
+ "version": "20.4.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-20.4.0.tgz",
+ "integrity": "sha512-NcRkqo/QUnuc1RgxRCIKTqobKzF0BKJ8h3i1jRyeZ+SEy5rO9dPNOh4BqrFsSznb5mnwETYB7ph9tUcthNkwAQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@commitlint/types": "^19.8.1",
- "conventional-changelog-angular": "^7.0.0",
- "conventional-commits-parser": "^5.0.0"
+ "@commitlint/types": "^20.4.0",
+ "conventional-changelog-angular": "^8.1.0",
+ "conventional-commits-parser": "^6.2.1"
},
"engines": {
"node": ">=v18"
}
},
"node_modules/@commitlint/read": {
- "version": "19.8.1",
- "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-19.8.1.tgz",
- "integrity": "sha512-03Jbjb1MqluaVXKHKRuGhcKWtSgh3Jizqy2lJCRbRrnWpcM06MYm8th59Xcns8EqBYvo0Xqb+2DoZFlga97uXQ==",
+ "version": "20.4.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-20.4.0.tgz",
+ "integrity": "sha512-QfpFn6/I240ySEGv7YWqho4vxqtPpx40FS7kZZDjUJ+eHxu3azfhy7fFb5XzfTqVNp1hNoI3tEmiEPbDB44+cg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@commitlint/top-level": "^19.8.1",
- "@commitlint/types": "^19.8.1",
+ "@commitlint/top-level": "^20.4.0",
+ "@commitlint/types": "^20.4.0",
"git-raw-commits": "^4.0.0",
"minimist": "^1.2.8",
"tinyexec": "^1.0.0"
@@ -2344,14 +2338,14 @@
}
},
"node_modules/@commitlint/resolve-extends": {
- "version": "19.8.1",
- "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-19.8.1.tgz",
- "integrity": "sha512-GM0mAhFk49I+T/5UCYns5ayGStkTt4XFFrjjf0L4S26xoMTSkdCf9ZRO8en1kuopC4isDFuEm7ZOm/WRVeElVg==",
+ "version": "20.4.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-20.4.0.tgz",
+ "integrity": "sha512-ay1KM8q0t+/OnlpqXJ+7gEFQNlUtSU5Gxr8GEwnVf2TPN3+ywc5DzL3JCxmpucqxfHBTFwfRMXxPRRnR5Ki20g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@commitlint/config-validator": "^19.8.1",
- "@commitlint/types": "^19.8.1",
+ "@commitlint/config-validator": "^20.4.0",
+ "@commitlint/types": "^20.4.0",
"global-directory": "^4.0.1",
"import-meta-resolve": "^4.0.0",
"lodash.mergewith": "^4.6.2",
@@ -2362,25 +2356,25 @@
}
},
"node_modules/@commitlint/rules": {
- "version": "19.8.1",
- "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-19.8.1.tgz",
- "integrity": "sha512-Hnlhd9DyvGiGwjfjfToMi1dsnw1EXKGJNLTcsuGORHz6SS9swRgkBsou33MQ2n51/boIDrbsg4tIBbRpEWK2kw==",
+ "version": "20.4.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-20.4.0.tgz",
+ "integrity": "sha512-E+UoAA7WA4xrre9lDyX2vL4Df26I+vqMN4D8JoW/L2xE/VRDvn533/ibhgSlGYDltB9nm2S+1lti3PagEwO0ag==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@commitlint/ensure": "^19.8.1",
- "@commitlint/message": "^19.8.1",
- "@commitlint/to-lines": "^19.8.1",
- "@commitlint/types": "^19.8.1"
+ "@commitlint/ensure": "^20.4.0",
+ "@commitlint/message": "^20.4.0",
+ "@commitlint/to-lines": "^20.0.0",
+ "@commitlint/types": "^20.4.0"
},
"engines": {
"node": ">=v18"
}
},
"node_modules/@commitlint/to-lines": {
- "version": "19.8.1",
- "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-19.8.1.tgz",
- "integrity": "sha512-98Mm5inzbWTKuZQr2aW4SReY6WUukdWXuZhrqf1QdKPZBCCsXuG87c+iP0bwtD6DBnmVVQjgp4whoHRVixyPBg==",
+ "version": "20.0.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-20.0.0.tgz",
+ "integrity": "sha512-2l9gmwiCRqZNWgV+pX1X7z4yP0b3ex/86UmUFgoRt672Ez6cAM2lOQeHFRUTuE6sPpi8XBCGnd8Kh3bMoyHwJw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2388,27 +2382,27 @@
}
},
"node_modules/@commitlint/top-level": {
- "version": "19.8.1",
- "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-19.8.1.tgz",
- "integrity": "sha512-Ph8IN1IOHPSDhURCSXBz44+CIu+60duFwRsg6HqaISFHQHbmBtxVw4ZrFNIYUzEP7WwrNPxa2/5qJ//NK1FGcw==",
+ "version": "20.4.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-20.4.0.tgz",
+ "integrity": "sha512-NDzq8Q6jmFaIIBC/GG6n1OQEaHdmaAAYdrZRlMgW6glYWGZ+IeuXmiymDvQNXPc82mVxq2KiE3RVpcs+1OeDeA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "find-up": "^7.0.0"
+ "escalade": "^3.2.0"
},
"engines": {
"node": ">=v18"
}
},
"node_modules/@commitlint/types": {
- "version": "19.8.1",
- "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-19.8.1.tgz",
- "integrity": "sha512-/yCrWGCoA1SVKOks25EGadP9Pnj0oAIHGpl2wH2M2Y46dPM2ueb8wyCVOD7O3WCTkaJ0IkKvzhl1JY7+uCT2Dw==",
+ "version": "20.4.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-20.4.0.tgz",
+ "integrity": "sha512-aO5l99BQJ0X34ft8b0h7QFkQlqxC6e7ZPVmBKz13xM9O8obDaM1Cld4sQlJDXXU/VFuUzQ30mVtHjVz74TuStw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/conventional-commits-parser": "^5.0.0",
- "chalk": "^5.3.0"
+ "conventional-commits-parser": "^6.2.1",
+ "picocolors": "^1.1.1"
},
"engines": {
"node": ">=v18"
@@ -6110,48 +6104,6 @@
"semantic-release": ">=20.1.0"
}
},
- "node_modules/@semantic-release/commit-analyzer/node_modules/conventional-changelog-angular": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.0.0.tgz",
- "integrity": "sha512-CLf+zr6St0wIxos4bmaKHRXWAcsCXrJU6F4VdNDrGRK3B8LDLKoX3zuMV5GhtbGkVR/LohZ6MT6im43vZLSjmA==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "compare-func": "^2.0.0"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@semantic-release/commit-analyzer/node_modules/conventional-commits-parser": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.2.0.tgz",
- "integrity": "sha512-uLnoLeIW4XaoFtH37qEcg/SXMJmKF4vi7V0H2rnPueg+VEtFGA/asSCNTcq4M/GQ6QmlzchAEtOoDTtKqWeHag==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "meow": "^13.0.0"
- },
- "bin": {
- "conventional-commits-parser": "dist/cli/index.js"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@semantic-release/commit-analyzer/node_modules/meow": {
- "version": "13.2.0",
- "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz",
- "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/@semantic-release/error": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-3.0.0.tgz",
@@ -6607,35 +6559,6 @@
"semantic-release": ">=20.1.0"
}
},
- "node_modules/@semantic-release/release-notes-generator/node_modules/conventional-changelog-angular": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.0.0.tgz",
- "integrity": "sha512-CLf+zr6St0wIxos4bmaKHRXWAcsCXrJU6F4VdNDrGRK3B8LDLKoX3zuMV5GhtbGkVR/LohZ6MT6im43vZLSjmA==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "compare-func": "^2.0.0"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@semantic-release/release-notes-generator/node_modules/conventional-commits-parser": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.2.0.tgz",
- "integrity": "sha512-uLnoLeIW4XaoFtH37qEcg/SXMJmKF4vi7V0H2rnPueg+VEtFGA/asSCNTcq4M/GQ6QmlzchAEtOoDTtKqWeHag==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "meow": "^13.0.0"
- },
- "bin": {
- "conventional-commits-parser": "dist/cli/index.js"
- },
- "engines": {
- "node": ">=18"
- }
- },
"node_modules/@semantic-release/release-notes-generator/node_modules/get-stream": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-7.0.1.tgz",
@@ -6649,19 +6572,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/@semantic-release/release-notes-generator/node_modules/meow": {
- "version": "13.2.0",
- "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz",
- "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/@sinclair/typebox": {
"version": "0.27.8",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
@@ -7979,9 +7889,9 @@
}
},
"node_modules/@tedi-design-system/core": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@tedi-design-system/core/-/core-3.0.1.tgz",
- "integrity": "sha512-ioet8RlFmWjg8fic4WUuYeavLiqUsKx3vFGZzzXkL91xNNjHexNVKhhtMLLkpCywzOc2tKXMx3AYdDhu2dsbwg==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/@tedi-design-system/core/-/core-3.2.0.tgz",
+ "integrity": "sha512-R9gpmprRT8qCGeJ8Frhz2yiJQ9bJM1Yp3mvWHeX2a6600hWh3mKXvhARSLFAF6im83FEFmOoKwdIOr4nfy8Qbg==",
"engines": {
"node": ">=18.0.0",
"npm": ">=8.0.0"
@@ -8504,16 +8414,6 @@
"@babel/types": "^7.28.2"
}
},
- "node_modules/@types/conventional-commits-parser": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.1.tgz",
- "integrity": "sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/node": "*"
- }
- },
"node_modules/@types/css-modules": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/css-modules/-/css-modules-1.0.5.tgz",
@@ -8738,15 +8638,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/@types/minimist": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz",
- "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true
- },
"node_modules/@types/ms": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
@@ -9494,43 +9385,6 @@
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
}
},
- "node_modules/@volar/language-core": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-1.11.1.tgz",
- "integrity": "sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@volar/source-map": "1.11.1"
- }
- },
- "node_modules/@volar/source-map": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-1.11.1.tgz",
- "integrity": "sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "muggle-string": "^0.3.1"
- }
- },
- "node_modules/@volar/typescript": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-1.11.1.tgz",
- "integrity": "sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@volar/language-core": "1.11.1",
- "path-browserify": "^1.0.1"
- }
- },
"node_modules/@vue/compiler-core": {
"version": "3.5.22",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.22.tgz",
@@ -9567,34 +9421,6 @@
"he": "^1.2.0"
}
},
- "node_modules/@vue/language-core": {
- "version": "1.8.27",
- "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.27.tgz",
- "integrity": "sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@volar/language-core": "~1.11.1",
- "@volar/source-map": "~1.11.1",
- "@vue/compiler-dom": "^3.3.0",
- "@vue/shared": "^3.3.0",
- "computeds": "^0.0.1",
- "minimatch": "^9.0.3",
- "muggle-string": "^0.3.1",
- "path-browserify": "^1.0.1",
- "vue-template-compiler": "^2.7.14"
- },
- "peerDependencies": {
- "typescript": "*"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
"node_modules/@vue/shared": {
"version": "3.5.22",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.22.tgz",
@@ -10033,18 +9859,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/arrify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
- "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
@@ -10655,38 +10469,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/camelcase-keys": {
- "version": "6.2.2",
- "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz",
- "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "camelcase": "^5.3.1",
- "map-obj": "^4.0.0",
- "quick-lru": "^4.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/camelcase-keys/node_modules/camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/caniuse-lite": {
"version": "1.0.30001749",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001749.tgz",
@@ -11275,15 +11057,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/computeds": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz",
- "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true
- },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -11317,16 +11090,16 @@
"license": "ISC"
},
"node_modules/conventional-changelog-angular": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz",
- "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==",
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.1.0.tgz",
+ "integrity": "sha512-GGf2Nipn1RUCAktxuVauVr1e3r8QrLP/B0lEUsFktmGqc3ddbQkhoJZHJctVU829U1c6mTSWftrVOCHaL85Q3w==",
"dev": true,
"license": "ISC",
"dependencies": {
"compare-func": "^2.0.0"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/conventional-changelog-conventionalcommits": {
@@ -11398,32 +11171,29 @@
}
},
"node_modules/conventional-commits-parser": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz",
- "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==",
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.2.1.tgz",
+ "integrity": "sha512-20pyHgnO40rvfI0NGF/xiEoFMkXDtkF8FwHvk5BokoFoCuTQRI8vrNCNFWUOfuolKJMm1tPCHc8GgYEtr1XRNA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "is-text-path": "^2.0.0",
- "JSONStream": "^1.3.5",
- "meow": "^12.0.1",
- "split2": "^4.0.0"
+ "meow": "^13.0.0"
},
"bin": {
- "conventional-commits-parser": "cli.mjs"
+ "conventional-commits-parser": "dist/cli/index.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/conventional-commits-parser/node_modules/meow": {
- "version": "12.1.1",
- "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz",
- "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==",
+ "version": "13.2.0",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz",
+ "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=16.10"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -11933,49 +11703,6 @@
}
}
},
- "node_modules/decamelize": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
- "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/decamelize-keys": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz",
- "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "decamelize": "^1.1.0",
- "map-obj": "^1.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/decamelize-keys/node_modules/map-obj": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
- "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/decimal.js": {
"version": "10.6.0",
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz",
@@ -14228,24 +13955,6 @@
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
"license": "MIT"
},
- "node_modules/find-up": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz",
- "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "locate-path": "^7.2.0",
- "path-exists": "^5.0.0",
- "unicorn-magic": "^0.1.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/find-up-simple": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz",
@@ -14953,18 +14662,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/hard-rejection": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz",
- "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/harmony-reflect": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz",
@@ -16007,19 +15704,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-text-path": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz",
- "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "text-extensions": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/is-typed-array": {
"version": "1.1.15",
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
@@ -17732,33 +17416,6 @@
"graceful-fs": "^4.1.6"
}
},
- "node_modules/jsonparse": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
- "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==",
- "dev": true,
- "engines": [
- "node >= 0.2.0"
- ],
- "license": "MIT"
- },
- "node_modules/JSONStream": {
- "version": "1.3.5",
- "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
- "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
- "dev": true,
- "license": "(MIT OR Apache-2.0)",
- "dependencies": {
- "jsonparse": "^1.2.0",
- "through": ">=2.2.7 <3"
- },
- "bin": {
- "JSONStream": "bin.js"
- },
- "engines": {
- "node": "*"
- }
- },
"node_modules/jsx-ast-utils": {
"version": "3.3.5",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
@@ -17775,6 +17432,13 @@
"node": ">=4.0"
}
},
+ "node_modules/kasi": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/kasi/-/kasi-2.0.1.tgz",
+ "integrity": "sha512-8qhiHZ1BN26ig1+jQ9fWEk6dj8T1wuxs00QRJfXIANI4scto1EuPUgqj+mxHls52WBfdTNJGQ8yYw9rDpWUcgQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -18149,22 +17813,6 @@
"url": "https://github.com/sponsors/antfu"
}
},
- "node_modules/locate-path": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz",
- "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-locate": "^6.0.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
@@ -18219,13 +17867,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/lodash.kebabcase": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz",
- "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -18247,20 +17888,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/lodash.snakecase": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz",
- "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash.startcase": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz",
- "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/lodash.truncate": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
@@ -18268,13 +17895,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/lodash.uniq": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
- "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/lodash.uniqby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz",
@@ -18282,13 +17902,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/lodash.upperfirst": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz",
- "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/log-update": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz",
@@ -18462,21 +18075,6 @@
"tmpl": "1.0.5"
}
},
- "node_modules/map-obj": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
- "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/map-or-similar": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz",
@@ -19216,134 +18814,6 @@
"map-or-similar": "^1.5.0"
}
},
- "node_modules/meow": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz",
- "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@types/minimist": "^1.2.0",
- "camelcase-keys": "^6.2.2",
- "decamelize": "^1.2.0",
- "decamelize-keys": "^1.1.0",
- "hard-rejection": "^2.1.0",
- "minimist-options": "4.1.0",
- "normalize-package-data": "^3.0.0",
- "read-pkg-up": "^7.0.1",
- "redent": "^3.0.0",
- "trim-newlines": "^3.0.0",
- "type-fest": "^0.18.0",
- "yargs-parser": "^20.2.3"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/meow/node_modules/hosted-git-info": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
- "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
- "dev": true,
- "license": "ISC",
- "optional": true,
- "peer": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/meow/node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "license": "ISC",
- "optional": true,
- "peer": true,
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/meow/node_modules/normalize-package-data": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz",
- "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==",
- "dev": true,
- "license": "BSD-2-Clause",
- "optional": true,
- "peer": true,
- "dependencies": {
- "hosted-git-info": "^4.0.1",
- "is-core-module": "^2.5.0",
- "semver": "^7.3.4",
- "validate-npm-package-license": "^3.0.1"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/meow/node_modules/semver": {
- "version": "7.7.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
- "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
- "dev": true,
- "license": "ISC",
- "optional": true,
- "peer": true,
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/meow/node_modules/type-fest": {
- "version": "0.18.1",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz",
- "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==",
- "dev": true,
- "license": "(MIT OR CC0-1.0)",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/meow/node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true,
- "license": "ISC",
- "optional": true,
- "peer": true
- },
- "node_modules/meow/node_modules/yargs-parser": {
- "version": "20.2.9",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
- "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
- "dev": true,
- "license": "ISC",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -20087,35 +19557,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/minimist-options": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz",
- "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "arrify": "^1.0.1",
- "is-plain-obj": "^1.1.0",
- "kind-of": "^6.0.3"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/minimist-options/node_modules/is-plain-obj": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
- "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/minipass": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
@@ -20164,15 +19605,6 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
- "node_modules/muggle-string": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.3.1.tgz",
- "integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true
- },
"node_modules/mz": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
@@ -23462,51 +22894,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/p-locate": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz",
- "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-limit": "^4.0.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/p-locate/node_modules/p-limit": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
- "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "yocto-queue": "^1.0.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/p-locate/node_modules/yocto-queue": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz",
- "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12.20"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/p-map": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz",
@@ -23661,16 +23048,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/path-exists": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz",
- "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- }
- },
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
@@ -24460,18 +23837,6 @@
],
"license": "MIT"
},
- "node_modules/quick-lru": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz",
- "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/rc": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
@@ -24733,180 +24098,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/read-pkg-up": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
- "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "find-up": "^4.1.0",
- "read-pkg": "^5.2.0",
- "type-fest": "^0.8.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/read-pkg-up/node_modules/find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/read-pkg-up/node_modules/hosted-git-info": {
- "version": "2.8.9",
- "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
- "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
- "dev": true,
- "license": "ISC",
- "optional": true,
- "peer": true
- },
- "node_modules/read-pkg-up/node_modules/locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "p-locate": "^4.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/read-pkg-up/node_modules/normalize-package-data": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
- "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
- "dev": true,
- "license": "BSD-2-Clause",
- "optional": true,
- "peer": true,
- "dependencies": {
- "hosted-git-info": "^2.1.4",
- "resolve": "^1.10.0",
- "semver": "2 || 3 || 4 || 5",
- "validate-npm-package-license": "^3.0.1"
- }
- },
- "node_modules/read-pkg-up/node_modules/p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "p-try": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/read-pkg-up/node_modules/p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "p-limit": "^2.2.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/read-pkg-up/node_modules/path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/read-pkg-up/node_modules/read-pkg": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
- "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@types/normalize-package-data": "^2.4.0",
- "normalize-package-data": "^2.5.0",
- "parse-json": "^5.0.0",
- "type-fest": "^0.6.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/read-pkg-up/node_modules/read-pkg/node_modules/type-fest": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
- "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
- "dev": true,
- "license": "(MIT OR CC0-1.0)",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/read-pkg-up/node_modules/semver": {
- "version": "5.7.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
- "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
- "dev": true,
- "license": "ISC",
- "optional": true,
- "peer": true,
- "bin": {
- "semver": "bin/semver"
- }
- },
- "node_modules/read-pkg-up/node_modules/type-fest": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
- "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
- "dev": true,
- "license": "(MIT OR CC0-1.0)",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/read-pkg/node_modules/parse-json": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz",
@@ -28069,19 +27260,6 @@
"node": "*"
}
},
- "node_modules/text-extensions": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz",
- "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -28112,13 +27290,6 @@
"node": ">=0.8"
}
},
- "node_modules/through": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/through2": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
@@ -28166,11 +27337,14 @@
"license": "MIT"
},
"node_modules/tinyexec": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz",
- "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz",
+ "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
},
"node_modules/tinyglobby": {
"version": "0.2.15",
@@ -28281,18 +27455,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/trim-newlines": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
- "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/trough": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz",
@@ -30270,54 +29432,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/vue-template-compiler": {
- "version": "2.7.16",
- "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz",
- "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "de-indent": "^1.0.2",
- "he": "^1.2.0"
- }
- },
- "node_modules/vue-tsc": {
- "version": "1.8.27",
- "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.8.27.tgz",
- "integrity": "sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@volar/typescript": "~1.11.1",
- "@vue/language-core": "1.8.27",
- "semver": "^7.5.4"
- },
- "bin": {
- "vue-tsc": "bin/vue-tsc.js"
- },
- "peerDependencies": {
- "typescript": "*"
- }
- },
- "node_modules/vue-tsc/node_modules/semver": {
- "version": "7.7.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
- "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
- "dev": true,
- "license": "ISC",
- "optional": true,
- "peer": true,
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/w3c-xmlserializer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
diff --git a/package.json b/package.json
index 6fcde260d..33819bf54 100644
--- a/package.json
+++ b/package.json
@@ -43,7 +43,7 @@
"@mui/material": "^5.15.13",
"@mui/x-date-pickers": "^5.0.20",
"@tanstack/react-table": "^8.13.2",
- "@tedi-design-system/core": "3.0.1",
+ "@tedi-design-system/core": "3.2.0",
"classnames": "^2.5.1",
"draft-js": "^0.11.7",
"draftjs-md-converter": "^1.5.2",
@@ -67,7 +67,7 @@
"@babel/preset-env": "^7.26.0",
"@babel/preset-react": "^7.26.3",
"@babel/preset-typescript": "^7.26.0",
- "@commitlint/cli": "^19.8.1",
+ "@commitlint/cli": "^20.4.0",
"@commitlint/config-conventional": "^20.0.0",
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
diff --git a/src/community/components/layout/header/components/header-modal/header-modal.tsx b/src/community/components/layout/header/components/header-modal/header-modal.tsx
index df3b57160..5794e99ae 100644
--- a/src/community/components/layout/header/components/header-modal/header-modal.tsx
+++ b/src/community/components/layout/header/components/header-modal/header-modal.tsx
@@ -55,7 +55,7 @@ export const HeaderModal = (props: HeaderModalProps) => {
diff --git a/src/community/components/map-components/directions/direction-item.tsx b/src/community/components/map-components/directions/direction-item.tsx
index 6ce1b16a3..18696e06e 100644
--- a/src/community/components/map-components/directions/direction-item.tsx
+++ b/src/community/components/map-components/directions/direction-item.tsx
@@ -61,6 +61,7 @@ export const DirectionItem = (props: DirectionItemProps): JSX.Element => {
className={styles['tedi-directions__remove']}
onClick={onDelete}
aria-label={getLabel('remove')}
+ iconSize={18}
/>
)}
diff --git a/src/community/components/map-components/left-panel/left-panel-footer.tsx b/src/community/components/map-components/left-panel/left-panel-footer.tsx
index 526f38fc9..f3d725cbc 100644
--- a/src/community/components/map-components/left-panel/left-panel-footer.tsx
+++ b/src/community/components/map-components/left-panel/left-panel-footer.tsx
@@ -7,7 +7,7 @@ const LeftPanelFooter = () => {
Tume režiim} />
-
+
diff --git a/src/community/components/map-components/right-panel/right-panel.tsx b/src/community/components/map-components/right-panel/right-panel.tsx
index 65a2be2b2..d6b47b2c8 100644
--- a/src/community/components/map-components/right-panel/right-panel.tsx
+++ b/src/community/components/map-components/right-panel/right-panel.tsx
@@ -69,7 +69,7 @@ type DefaultCloseButtonProps = { id: string; isSingleItem: boolean; onClose: (id
export const DefaultCloseButton = ({ id, isSingleItem, onClose }: DefaultCloseButtonProps): JSX.Element => (
onClose(id)}
title="Sulge aken"
/>
diff --git a/src/community/components/map-components/sheet/sheet.tsx b/src/community/components/map-components/sheet/sheet.tsx
index 4e6215294..cf64b65be 100644
--- a/src/community/components/map-components/sheet/sheet.tsx
+++ b/src/community/components/map-components/sheet/sheet.tsx
@@ -229,7 +229,7 @@ export const Sheet = (props: SheetProps): JSX.Element | null => {
{actions}
diff --git a/src/community/components/modal/modal.tsx b/src/community/components/modal/modal.tsx
index 2948f7dc1..122ac4b7d 100644
--- a/src/community/components/modal/modal.tsx
+++ b/src/community/components/modal/modal.tsx
@@ -109,7 +109,7 @@ export const Modal = (props: ModalProps): JSX.Element | null => {
children: (
<>
-
+
{child.props.children}
>
diff --git a/src/community/docs/scale-layout/development.mdx b/src/community/docs/scale-layout/development.mdx
deleted file mode 100644
index a413dfb5c..000000000
--- a/src/community/docs/scale-layout/development.mdx
+++ /dev/null
@@ -1,12 +0,0 @@
-import { Meta, Title, Subtitle, Unstyled } from '@storybook/blocks';
-
-
-
-# Grid in development
-
-Every layout in design is makeable with `
` and `` components.
-All examples of Grid usage are under [Grid docs](/docs/components-grid--docs)
-
-To create vertical spacing between elements use `` [component](/docs/components-vertical-spacing--docs).
-
-{/* TODO: Need more information how to use Row, Col, VerticalSpacing and Card correctly */}
diff --git a/src/tedi/components/buttons/button-content/button-content.module.scss b/src/tedi/components/buttons/button-content/button-content.module.scss
index 27c5ab3c1..15a153cd0 100644
--- a/src/tedi/components/buttons/button-content/button-content.module.scss
+++ b/src/tedi/components/buttons/button-content/button-content.module.scss
@@ -399,11 +399,16 @@ $btn-width-large: 3.72rem;
height: auto;
min-height: auto;
padding: 0;
+ font-size: var(--body-link-size-regular);
text-align: left;
text-decoration: none;
background: none;
border: none;
+ &.tedi-btn--small {
+ font-size: var(--body-link-size-responsive);
+ }
+
@include link-variant(
var(--link-primary-default),
var(--link-primary-hover),
@@ -411,12 +416,22 @@ $btn-width-large: 3.72rem;
var(--link-primary-focus)
);
- .tedi-btn__icon--left {
- margin-right: var(--button-sm-inner-spacing);
+ .tedi-btn__inner {
+ .tedi-btn__icon--left {
+ display: inline;
+ margin-right: var(--button-sm-inner-spacing);
+ vertical-align: middle;
+ }
+
+ .tedi-btn__icon--right {
+ display: inline;
+ margin-left: var(--button-sm-inner-spacing);
+ vertical-align: middle;
+ }
}
- .tedi-btn__icon--right {
- margin-left: var(--button-sm-inner-spacing);
+ .tedi-btn__icon-responsive {
+ font-size: var(--link-icon-responsive);
}
}
diff --git a/src/tedi/components/buttons/button-content/button-content.tsx b/src/tedi/components/buttons/button-content/button-content.tsx
index dff0edabc..604d47c7a 100644
--- a/src/tedi/components/buttons/button-content/button-content.tsx
+++ b/src/tedi/components/buttons/button-content/button-content.tsx
@@ -144,14 +144,12 @@ const InternalButtonContent = forwardRef(
const getIcon = (location: string, icon: string | IconWithoutBackgroundProps): JSX.Element => {
const iconBEM = cn(styles['tedi-btn__icon'], styles[`tedi-btn__icon--${location}`], {
[styles['tedi-btn__spinner']]: isLoading,
+ [styles['tedi-btn__icon-responsive']]: Component === 'a' && size === 'small',
});
- const isLink = visualType === 'link';
-
const defaultIconProps: Partial = {
size: size === 'large' ? 24 : 18,
className: iconBEM,
- ...(isLink ? { display: 'inline' } : {}),
};
const iconProps: IconWithoutBackgroundProps =
diff --git a/src/tedi/components/buttons/button-group/button-group.module.scss b/src/tedi/components/buttons/button-group/button-group.module.scss
index fe4ab8aee..61910972d 100644
--- a/src/tedi/components/buttons/button-group/button-group.module.scss
+++ b/src/tedi/components/buttons/button-group/button-group.module.scss
@@ -11,8 +11,6 @@
align-items: center;
justify-content: center;
height: auto;
- min-height: 2.5rem;
- padding: calc(var(--button-md-padding-y) - 1px) var(--button-md-padding-x);
text-align: center;
cursor: pointer;
border-radius: 0;
@@ -38,6 +36,17 @@
@include breakpoints.media-breakpoint-down(md) {
flex: 1;
}
+
+ &--size-default {
+ min-height: var(--button-md-height);
+ padding: calc(var(--button-md-padding-y) - 1px) var(--button-md-padding-x);
+ }
+
+ &--size-small {
+ min-height: var(--button-sm-height);
+ padding: calc(var(--button-sm-padding-y) - 1px) var(--button-sm-padding-x);
+ font-size: var(--button-text-size-sm);
+ }
}
}
@@ -65,6 +74,12 @@
background-color: var(--button-group-primary-selected-background);
border-color: var(--button-group-primary-selected-border);
}
+
+ &:focus-visible:not(:disabled, .tedi-button-group__item--active) {
+ color: var(--button-group-primary-inactive-text);
+ background-color: var(--button-group-primary-inactive-background);
+ border: 1px solid var(--button-group-primary-inactive-border);
+ }
}
}
@@ -93,6 +108,12 @@
outline: 2px solid var(--button-group-secondary-selected-border);
outline-offset: -2px;
}
+
+ &:focus-visible:not(:disabled, .tedi-button-group__item--active) {
+ color: var(--button-group-secondary-inactive-text);
+ background-color: var(--button-group-secondary-inactive-background);
+ border: 1px solid var(--button-group-secondary-inactive-border);
+ }
}
}
diff --git a/src/tedi/components/buttons/button-group/button-group.stories.tsx b/src/tedi/components/buttons/button-group/button-group.stories.tsx
index d3b692e0d..14adb9282 100644
--- a/src/tedi/components/buttons/button-group/button-group.stories.tsx
+++ b/src/tedi/components/buttons/button-group/button-group.stories.tsx
@@ -1,6 +1,7 @@
import { Meta, StoryFn, StoryObj } from '@storybook/react';
import { useState } from 'react';
+import { Text } from '../../base/typography/text/text';
import { Col, Row } from '../../layout/grid';
import { VerticalSpacing } from '../../layout/vertical-spacing';
import { Button } from '../button/button';
@@ -24,7 +25,8 @@ const meta: Meta = {
export default meta;
type Story = StoryObj;
-const buttonStates = ['Default', 'Hover', 'Active', 'Disabled'];
+const buttonStates = ['Default', 'Hover', 'Active', 'Focus', 'Disabled'];
+const sizeArray: ButtonGroupProps['size'][] = ['default', 'small'];
const Template: StoryFn = (args) => (
@@ -36,6 +38,40 @@ const Template: StoryFn = (args) => (
);
+interface TemplateMultipleProps extends ButtonGroupProps {
+ array: Type[];
+ property: keyof ButtonGroupProps;
+}
+
+const TemplateSizes: StoryFn = (args) => {
+ const { array, property, ...buttonGroupProps } = args;
+
+ return (
+
+ {array.map((value, key) => {
+ return (
+
+
+ {value ? value.charAt(0).toUpperCase() + value.slice(1) : ''}
+
+
+
+
+
+
+
+
+
+
+
+ );
+ })}
+
+ );
+};
+
const TemplateTypes: StoryFn = (args) => {
return (
@@ -73,6 +109,14 @@ export const Default: Story = {
},
};
+export const Sizes: StoryObj = {
+ render: TemplateSizes,
+ args: {
+ property: 'size',
+ array: sizeArray,
+ },
+};
+
export const Types: StoryObj = {
render: TemplateTypes,
};
@@ -130,7 +174,7 @@ export const Primary: StoryObj<{ states: string[] }> = {
pseudo: {
hover: ['#Hover-primary'],
active: ['#Active-primary'],
- focus: ['#Focus-primary'],
+ focusVisible: ['#Focus-primary'],
},
},
};
@@ -144,7 +188,7 @@ export const Secondary: StoryObj<{ states: string[] }> = {
pseudo: {
hover: ['#Hover-secondary'],
active: ['#Active-secondary'],
- focus: ['#Focus-secondary'],
+ focusVisible: ['#Focus-secondary'],
},
},
};
diff --git a/src/tedi/components/buttons/button-group/button-group.tsx b/src/tedi/components/buttons/button-group/button-group.tsx
index b2e0ecbaa..f830c304c 100644
--- a/src/tedi/components/buttons/button-group/button-group.tsx
+++ b/src/tedi/components/buttons/button-group/button-group.tsx
@@ -36,10 +36,22 @@ export type ButtonGroupProps = {
* Additional custom CSS classes to apply to the ButtonGroup container
*/
className?: string;
+ /**
+ * Size of the buttons in ButtonGroup
+ */
+ size?: 'default' | 'small';
};
export const ButtonGroup = (props: ButtonGroupProps): JSX.Element => {
- const { children, className, type = 'primary', onSelectionChange, stretch = false, ariaLabel } = props;
+ const {
+ children,
+ className,
+ type = 'primary',
+ onSelectionChange,
+ stretch = false,
+ ariaLabel,
+ size = 'default',
+ } = props;
return (
{
className: cn(styles['tedi-button-group__item'], {
[styles['tedi-button-group__item--active']]: child.props.isActive,
[styles['tedi-button-group__item--disabled']]: child.props.disabled,
+ [styles[`tedi-button-group__item--size-${size}`]]: size,
}),
- noStyle: true,
+ size: size,
onClick: () => {
if (!child.props.disabled) {
child.props.onClick?.();
diff --git a/src/tedi/components/buttons/closing-button/closing-button.module.scss b/src/tedi/components/buttons/closing-button/closing-button.module.scss
index 16f010cfb..628e9b58e 100644
--- a/src/tedi/components/buttons/closing-button/closing-button.module.scss
+++ b/src/tedi/components/buttons/closing-button/closing-button.module.scss
@@ -1,36 +1,78 @@
.tedi-closing-button {
- --general-icon-primary: var(--button-close-text-default);
-
display: flex;
align-items: center;
justify-content: center;
padding: 0;
cursor: pointer;
- background-color: var(--button-close-background-default);
- border: 1px solid var(--button-close-background-default);
+ border: 0;
border-radius: var(--button-radius-default);
- transition: background 0.5s ease;
+ transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
- @each $state in hover, active {
- &:#{ $state } {
- --general-icon-primary: var(--button-close-text-#{$state});
+ &--default {
+ width: var(--button-sm-icon-size);
+ height: var(--button-sm-icon-size);
+ }
- background-color: var(--button-close-background-#{$state});
- }
+ &--small {
+ width: var(--button-xs-icon-size);
+ height: var(--button-xs-icon-size);
}
- &:focus-visible {
- outline: 2px solid var(--button-main-primary-border-focus);
- outline-offset: -2px;
+ &--color-primary {
+ color: var(--button-close-text-default);
+ background-color: var(--button-close-background-default);
+
+ &:hover {
+ color: var(--button-close-text-hover);
+ background-color: var(--button-close-background-hover);
+ }
+
+ &:active {
+ color: var(--button-close-text-active);
+ background-color: var(--button-close-background-active);
+ }
+
+ &:focus-visible {
+ color: var(--button-close-text-focus);
+ outline: 2px solid var(--button-main-primary-border-focus);
+ }
}
- &--medium {
- width: var(--button-xs-icon-size);
- height: var(--button-xs-icon-size);
+ &--color-brand {
+ color: var(--button-main-neutral-text-default);
+ background-color: var(--button-main-neutral-icon-only-background-default);
+
+ &:hover {
+ color: var(--button-main-neutral-text-hover);
+ background-color: var(--button-main-neutral-icon-only-background-hover);
+ }
+
+ &:active {
+ color: var(--button-main-neutral-text-active);
+ background-color: var(--button-main-neutral-icon-only-background-active);
+ }
+
+ &:focus-visible {
+ outline: 2px solid var(--button-main-primary-border-focus);
+ }
}
- &--large {
- width: var(--button-sm-icon-size);
- height: var(--button-sm-icon-size);
+ &--color-white {
+ color: var(--button-neutral-inverted-text-default);
+ background-color: var(--button-neutral-inverted-icon-only-background-default);
+
+ &:hover {
+ color: var(--button-neutral-inverted-text-hover);
+ background-color: var(--button-main-neutral-inverted-icon-only-background-hover);
+ }
+
+ &:active {
+ color: var(--button-neutral-inverted-text-active);
+ background-color: var(--button-main-neutral-inverted-icon-only-background-hover);
+ }
+
+ &:focus-visible {
+ outline: 2px solid var(--button-main-neutral-inverted-text-focus);
+ }
}
}
diff --git a/src/tedi/components/buttons/closing-button/closing-button.spec.tsx b/src/tedi/components/buttons/closing-button/closing-button.spec.tsx
index 8bc45184d..9e27d065a 100644
--- a/src/tedi/components/buttons/closing-button/closing-button.spec.tsx
+++ b/src/tedi/components/buttons/closing-button/closing-button.spec.tsx
@@ -10,72 +10,94 @@ jest.mock('../../../providers/label-provider', () => ({
describe('ClosingButton component', () => {
it('renders the ClosingButton with default props', () => {
- render(
-
{
- console.log('Button pressed');
- }}
- />
- );
+ render();
const button = screen.getByRole('button', { name: /close/i });
expect(button).toBeInTheDocument();
- expect(button).toHaveClass('tedi-closing-button');
+ expect(button).toHaveClass('tedi-closing-button tedi-closing-button--default tedi-closing-button--color-primary');
const icon = button.querySelector('span[data-name="icon"]');
expect(icon).toBeInTheDocument();
- expect(icon).toHaveClass('tedi-icon--size-18');
+ expect(icon).toHaveClass('tedi-icon--size-24');
});
- it('renders with the correct large size class and icon size', () => {
+ it('renders with the correct small size class and icon size', () => {
+ render();
+
+ const button = screen.getByRole('button', { name: /close/i });
+ expect(button).toHaveClass('tedi-closing-button tedi-closing-button--small tedi-closing-button--color-primary');
render(
{
console.log('Button pressed');
}}
/>
);
- const button = screen.getByRole('button', { name: /close/i });
expect(button).toBeInTheDocument();
- expect(button).toHaveClass('tedi-closing-button tedi-closing-button--large');
+ expect(button).toHaveClass('tedi-closing-button');
+ expect(button).toHaveClass('tedi-closing-button--small');
const icon = button.querySelector('span[data-name="icon"]');
- expect(icon).toBeInTheDocument();
expect(icon).toHaveClass('tedi-icon--size-24');
});
+ it('forces small size when iconSize is 18', () => {
+ render();
+
+ const button = screen.getByRole('button', { name: /close/i });
+ expect(button).toHaveClass('tedi-closing-button--small');
+
+ const icon = button.querySelector('span[data-name="icon"]');
+ expect(icon).toBeInTheDocument();
+ expect(icon).toHaveClass('tedi-icon--size-18');
+ });
+
it('applies custom class names', () => {
- render();
+ render();
- const button = screen.getByRole('button', { name: /Close/i });
- expect(button).toHaveClass('tedi-closing-button tedi-closing-button--large custom-class');
+ const button = screen.getByRole('button', { name: /close/i });
+ expect(button).toHaveClass(
+ 'tedi-closing-button tedi-closing-button--default tedi-closing-button--color-primary custom-class'
+ );
+ const customButton = screen.getByRole('button', { name: /Close/i });
+ expect(customButton).toHaveClass('tedi-closing-button');
+ expect(customButton).toHaveClass('tedi-closing-button--default');
+ expect(customButton).toHaveClass('custom-class');
});
it('triggers onClick handler when clicked', () => {
const onClickMock = jest.fn();
- render();
+ render();
- const button = screen.getByRole('button', { name: /Close/i });
+ const button = screen.getByRole('button', { name: /close/i });
fireEvent.click(button);
expect(onClickMock).toHaveBeenCalledTimes(1);
});
it('uses fallback label from label provider when title is not provided', () => {
- render();
+ render();
- const button = screen.getByRole('button', { name: /Close/i });
+ const button = screen.getByRole('button', { name: /close/i });
expect(button).toHaveAttribute('title', 'Close');
expect(button).toHaveAttribute('aria-label', 'Close');
});
it('uses custom title if provided', () => {
- render();
+ render();
const button = screen.getByRole('button', { name: /Custom Close/i });
expect(button).toHaveAttribute('title', 'Custom Close');
expect(button).toHaveAttribute('aria-label', 'Custom Close');
});
+
+ it('applies the correct color classes', () => {
+ const colors: Array<'primary' | 'brand' | 'white'> = ['primary', 'brand', 'white'];
+
+ colors.forEach((color) => {
+ const { container } = render();
+ const button = container.querySelector('button[data-name="closing-button"]');
+ expect(button).toHaveClass(`tedi-closing-button--color-${color}`);
+ });
+ });
});
diff --git a/src/tedi/components/buttons/closing-button/closing-button.stories.tsx b/src/tedi/components/buttons/closing-button/closing-button.stories.tsx
index 69528a74f..d2e0a084b 100644
--- a/src/tedi/components/buttons/closing-button/closing-button.stories.tsx
+++ b/src/tedi/components/buttons/closing-button/closing-button.stories.tsx
@@ -1,5 +1,6 @@
import { Meta, StoryFn, StoryObj } from '@storybook/react';
+import { Text } from '../../base/typography/text/text';
import { Col, Row } from '../../layout/grid';
import ClosingButton, { ClosingButtonProps } from './closing-button';
@@ -19,7 +20,8 @@ const meta: Meta = {
},
};
-const sizeArray: ClosingButtonProps['size'][] = ['medium', 'large'];
+const sizeArray: ClosingButtonProps['size'][] = ['default', 'small'];
+const iconSizeArray: ClosingButtonProps['iconSize'][] = [18, 24];
export default meta;
type Story = StoryObj;
@@ -41,16 +43,43 @@ const SizeTemplate: StoryFn = () => {
const stateArray = ['Default', 'Hover', 'Active', 'Focus'];
-const StatesTemplate: StoryFn = () => {
+const StatesTemplate: StoryFn = (args) => {
return (
{stateArray.map((state) => (
- {state}
+
+ {state}
+
-
+
+
+
+ ))}
+
+ );
+};
+
+const IconSizeTemplate: StoryFn = () => {
+ return (
+
+ {iconSizeArray.map((iconSize, key) => (
+
+ {`${iconSize}px`}
+
+ alert(`${iconSize}px icon clicked`)} className="hover" />
+ {iconSize === 24 && (
+
+ alert(`${iconSize}px icon clicked`)}
+ className="hover"
+ />
+
+ )}
))}
@@ -61,7 +90,6 @@ const StatesTemplate: StoryFn = () => {
export const Default: Story = {
args: {
title: 'close',
- size: 'medium',
},
};
@@ -69,6 +97,18 @@ export const Size: Story = {
render: SizeTemplate,
};
+/**
+ * Hover state is shown on all buttons for size preview.
+ */
+export const IconSizes: Story = {
+ render: IconSizeTemplate,
+ parameters: {
+ pseudo: {
+ hover: '.hover',
+ },
+ },
+};
+
export const States: Story = {
render: StatesTemplate,
parameters: {
@@ -79,3 +119,32 @@ export const States: Story = {
},
},
};
+
+export const ColorBrand: Story = {
+ render: StatesTemplate,
+ args: {
+ color: 'brand',
+ },
+ parameters: {
+ pseudo: {
+ hover: '#Hover',
+ active: '#Active',
+ focusVisible: '#Focus',
+ },
+ },
+};
+
+export const ColorInverted: Story = {
+ render: StatesTemplate,
+ args: {
+ color: 'white',
+ },
+ parameters: {
+ pseudo: {
+ hover: '#Hover',
+ active: '#Active',
+ focusVisible: '#Focus',
+ },
+ backgrounds: { default: 'brand' },
+ },
+};
diff --git a/src/tedi/components/buttons/closing-button/closing-button.tsx b/src/tedi/components/buttons/closing-button/closing-button.tsx
index b718964f6..0eb7c77a5 100644
--- a/src/tedi/components/buttons/closing-button/closing-button.tsx
+++ b/src/tedi/components/buttons/closing-button/closing-button.tsx
@@ -6,7 +6,9 @@ import { useLabels } from '../../../providers/label-provider';
import { Icon } from '../../base/icon/icon';
import styles from './closing-button.module.scss';
-type ClosingButtonSize = 'medium' | 'large';
+type ClosingButtonColor = 'primary' | 'brand' | 'white';
+export type ClosingButtonSize = 'default' | 'small';
+export type ClosingButtonIconSize = 18 | 24;
export interface ClosingButtonProps extends ButtonHTMLAttributes
{
/**
@@ -15,7 +17,7 @@ export interface ClosingButtonProps extends ButtonHTMLAttributes {
const { getLabel } = useLabels();
- const { title = getLabel('close'), onClick, size = 'medium', className, ...rest } = props;
+ const {
+ title = getLabel('close'),
+ onClick,
+ size = 'default',
+ iconSize = 24,
+ color = 'primary',
+ className,
+ ...rest
+ } = props;
+
+ const resolvedSize: ClosingButtonSize = iconSize === 18 ? 'small' : size;
const buttonClass = cn(
styles['tedi-closing-button'],
{
[styles[`tedi-closing-button--${size}`]]: size,
+ [styles[`tedi-closing-button--color-${color}`]]: color,
+ [styles[`tedi-closing-button--${resolvedSize}`]]: resolvedSize,
},
className
);
- const iconSize = size === 'large' ? 24 : 18;
+ const resolvedIconSize: ClosingButtonIconSize = iconSize ?? 24;
return (
);
};
diff --git a/src/tedi/components/buttons/info-button/info-button.module.scss b/src/tedi/components/buttons/info-button/info-button.module.scss
index 6f2fc8dbf..8a7ac2a79 100644
--- a/src/tedi/components/buttons/info-button/info-button.module.scss
+++ b/src/tedi/components/buttons/info-button/info-button.module.scss
@@ -3,4 +3,12 @@
height: var(--button-xs-icon-size);
min-height: var(--button-xs-icon-size);
vertical-align: bottom;
+
+ &[data-variant='inverted']:hover:not(:disabled) {
+ background-color: var(--button-main-neutral-inverted-icon-only-background-hover);
+ }
+
+ &[data-variant='inverted']:active:not(:disabled) {
+ background-color: var(--button-main-neutral-inverted-icon-only-background-active);
+ }
}
diff --git a/src/tedi/components/buttons/info-button/info-button.spec.tsx b/src/tedi/components/buttons/info-button/info-button.spec.tsx
index b450f9a3c..ad642916e 100644
--- a/src/tedi/components/buttons/info-button/info-button.spec.tsx
+++ b/src/tedi/components/buttons/info-button/info-button.spec.tsx
@@ -66,4 +66,30 @@ describe('InfoButton Component', () => {
expect(button).toHaveAttribute('title', 'Info button');
expect(button).toHaveAttribute('id', 'info-button-id');
});
+
+ it('applies default color variant correctly', () => {
+ render(Info);
+ const button = screen.getByRole('button');
+ expect(button).not.toHaveAttribute('data-variant');
+ });
+
+ it('applies inverted color variant correctly', () => {
+ render(Info);
+ const button = screen.getByRole('button');
+ expect(button).toHaveAttribute('data-variant', 'inverted');
+ });
+
+ it('applies the inverted variant and still renders children', () => {
+ render(
+
+ Child content
+
+ );
+ const button = screen.getByRole('button');
+ expect(button).toHaveAttribute('data-variant', 'inverted');
+
+ const child = screen.getByTestId('child');
+ expect(child).toBeInTheDocument();
+ expect(child).toHaveTextContent('Child content');
+ });
});
diff --git a/src/tedi/components/buttons/info-button/info-button.stories.tsx b/src/tedi/components/buttons/info-button/info-button.stories.tsx
index 6cf4a3cb0..2f5f1869e 100644
--- a/src/tedi/components/buttons/info-button/info-button.stories.tsx
+++ b/src/tedi/components/buttons/info-button/info-button.stories.tsx
@@ -28,20 +28,29 @@ const buttonStateArray = ['Default', 'Hover', 'Active', 'Focus'];
type TemplateMultipleProps = {
array: typeof buttonStateArray;
+ color?: 'default' | 'inverted';
};
const TemplateColumn: StoryFn = (args) => {
- const { array, ...buttonProps } = args;
+ const { array, color = 'default', ...buttonProps } = args;
return (
{array.map((state, index) => (
- {state}
+
+ {state}
+
-
+
Info button
@@ -57,7 +66,7 @@ export const Default: Story = {
},
};
-export const InfoButtonStates: StoryObj = {
+export const States: StoryObj = {
render: TemplateColumn,
args: {
array: buttonStateArray,
@@ -70,3 +79,19 @@ export const InfoButtonStates: StoryObj = {
},
},
};
+
+export const Inverted: StoryObj = {
+ render: TemplateColumn,
+ args: {
+ array: buttonStateArray,
+ color: 'inverted',
+ },
+ parameters: {
+ pseudo: {
+ hover: '#Hover',
+ active: '#Active',
+ focusVisible: '#Focus',
+ },
+ backgrounds: { default: 'brand' },
+ },
+};
diff --git a/src/tedi/components/buttons/info-button/info-button.tsx b/src/tedi/components/buttons/info-button/info-button.tsx
index 69d524cef..0669f1288 100644
--- a/src/tedi/components/buttons/info-button/info-button.tsx
+++ b/src/tedi/components/buttons/info-button/info-button.tsx
@@ -4,27 +4,33 @@ import React from 'react';
import { Button, ButtonProps } from '../button/button';
import styles from './info-button.module.scss';
-export interface InfoButtonProps extends Omit {
+export interface InfoButtonProps extends Omit {
/**
- * If true, applies a small size to the InfoButton.
+ * If true, applies a small size to the InfoButton
* @default false
*/
isSmall?: boolean;
/**
- * Children elements to be rendered inside the InfoButton.
+ * Children elements to be rendered inside the InfoButton
*/
children?: React.ReactNode;
+ /*
+ * Color variant of the InfoButton
+ * @default 'default'
+ */
+ color?: 'default' | 'inverted';
}
export const InfoButton = React.forwardRef(
- ({ isSmall, children, ...props }, ref): JSX.Element => (
+ ({ isSmall, children, color = 'default', ...props }, ref): JSX.Element => (
+
+
+ Required
+
+
+
+
+
diff --git a/src/tedi/components/form/checkbox/checkbox.tsx b/src/tedi/components/form/checkbox/checkbox.tsx
index b91ccb453..303f766db 100644
--- a/src/tedi/components/form/checkbox/checkbox.tsx
+++ b/src/tedi/components/form/checkbox/checkbox.tsx
@@ -34,6 +34,7 @@ export const Checkbox = (props: CheckboxProps): JSX.Element => {
tooltip,
invalid,
size = 'default',
+ required,
...rest
} = props;
const [innerChecked, setInnerChecked] = React.useState(defaultChecked || false);
@@ -53,10 +54,14 @@ export const Checkbox = (props: CheckboxProps): JSX.Element => {
const helperId = helper ? helper.id ?? `${id}-helper` : undefined;
const tooltipId = tooltip ? `${id}-tooltip` : undefined;
- const LabelBEM = cn(styles['tedi-checkbox'], { [styles['tedi-checkbox--disabled']]: disabled });
+ const LabelBEM = cn(styles['tedi-checkbox__label'], { [styles['tedi-checkbox--disabled']]: disabled });
return (
-
+
@@ -100,8 +105,8 @@ export const Checkbox = (props: CheckboxProps): JSX.Element => {
-
- {label && typeof label === 'string' ? (
+ {label && (
+
{
hideLabel={hideLabel}
label={label}
tooltip={tooltip}
+ required={required}
/>
- ) : (
-
- )}
-
+
+ )}
{helper && (
diff --git a/src/tedi/components/form/choice-group/choice-group.stories.tsx b/src/tedi/components/form/choice-group/choice-group.stories.tsx
index 1f61927d7..2b211d093 100644
--- a/src/tedi/components/form/choice-group/choice-group.stories.tsx
+++ b/src/tedi/components/form/choice-group/choice-group.stories.tsx
@@ -49,11 +49,11 @@ interface GenerateItemsArgs {
variant?: 'primary' | 'secondary';
withHelper?: boolean;
withIndicator?: boolean;
- extraLongTitle?: boolean;
tooltip?: boolean;
colProps?: ColProps;
layout?: 'separated' | 'segmented';
justifyContent?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly';
+ withIcons?: boolean;
}
const generateItems = ({
@@ -66,36 +66,44 @@ const generateItems = ({
colProps,
layout,
justifyContent,
-}: GenerateItemsArgs): ExtendedChoiceGroupItemProps[] => [
- {
- id: `${inputType}-${variant}-value-${index * 10 + 1}-${withHelper}-${withIndicator}-${layout}`,
- label: 'Text',
- value: `${inputType}-${variant}-value-${index * 10 + 1}-${withHelper}-${withIndicator}-${layout}`,
- ...(withHelper && { helper: { text: 'Description' } }),
- colProps,
- tooltip: tooltip ? 'Tooltip' : undefined,
- justifyContent,
- },
- {
- id: `${inputType}-${variant}-value-${index * 10 + 2}-${withHelper}-${withIndicator}-${layout}`,
- label: 'Text',
- value: `${inputType}-${variant}-value-${index * 10 + 2}-${withHelper}-${withIndicator}-${layout}`,
- ...(withHelper && { helper: { text: 'Description' } }),
- colProps,
- tooltip: tooltip ? 'Tooltip' : undefined,
- justifyContent,
- },
- {
- id: `${inputType}-${variant}-value-${index * 10 + 3}-${withHelper}-${withIndicator}-${layout}`,
- label: 'Text',
- value: `${inputType}-${variant}-value-${index * 10 + 3}-${withHelper}-${withIndicator}-${layout}`,
- ...(withHelper && { helper: { text: 'Description', type: 'error' } }),
- disabled: true,
- colProps,
- tooltip: tooltip ? 'Tooltip' : undefined,
- justifyContent,
- },
-];
+ withIcons = false,
+}: GenerateItemsArgs): ExtendedChoiceGroupItemProps[] => {
+ const baseId = withIcons ? `icon-${inputType}-${variant}` : `${inputType}-${variant}`;
+ const icons = withIcons ? ['train', 'directions_walk', 'directions_car'] : [];
+
+ return [1, 2, 3].map((i) => {
+ const itemIndex = index * 10 + i;
+ const suffix = `${withHelper}-${withIndicator}-${layout ?? 'default'}`;
+
+ let label: React.ReactNode = 'Text';
+
+ if (withIcons) {
+ label = (
+
+
+ {' Text'}
+
+ );
+ }
+
+ return {
+ id: `${baseId}-value-${itemIndex}-${suffix}`,
+ label,
+ value: `${baseId}-value-${itemIndex}`,
+ ...(withHelper && {
+ helper: {
+ text: 'Description',
+ ...(i === 3 && { type: 'error' }),
+ },
+ }),
+ disabled: i === 3,
+ colProps,
+ tooltip: tooltip ? 'Tooltip' : undefined,
+ justifyContent,
+ ...(withIcons && i === 1 && { defaultChecked: true }),
+ };
+ });
+};
const renderGroup = (
inputType: 'radio' | 'checkbox',
@@ -104,13 +112,14 @@ const renderGroup = (
withIndicator: boolean,
layout: 'segmented' | 'separated',
index: number,
- justifyContent: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'
+ justifyContent: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly' = 'start',
+ withIcons = false
) => (
-
+
);
-const renderChoiceGroups = (inputType: 'radio' | 'checkbox', layout: 'segmented' | 'separated') => (
+const renderChoiceGroups = (inputType: 'radio' | 'checkbox', layout: 'segmented' | 'separated', withIcons = false) => (
@@ -164,12 +175,12 @@ const renderChoiceGroups = (inputType: 'radio' | 'checkbox', layout: 'segmented'
Secondary
- {renderGroup(inputType, 'primary', false, true, layout, 1, 'start')}
- {renderGroup(inputType, 'primary', true, true, layout, 2, 'start')}
+ {renderGroup(inputType, 'primary', false, true, layout, 1, 'start', withIcons)}
+ {renderGroup(inputType, 'primary', true, true, layout, 2, 'start', withIcons)}
{inputType !== 'radio' ||
- (layout !== 'separated' && renderGroup(inputType, 'primary', false, false, layout, 3, 'start'))}
+ (layout !== 'separated' && renderGroup(inputType, 'primary', false, false, layout, 3, 'start', withIcons))}
{inputType !== 'radio' ||
- (layout !== 'separated' && renderGroup(inputType, 'primary', true, false, layout, 4, 'start'))}
+ (layout !== 'separated' && renderGroup(inputType, 'primary', true, false, layout, 4, 'start', withIcons))}
);
@@ -223,6 +234,40 @@ export const RadioCardSegmented = () => {renderChoiceGroups('ra
export const RadioCardSeparated = () => {renderChoiceGroups('radio', 'separated')};
export const CheckboxCard = () => {renderChoiceGroups('checkbox', 'separated')};
+export const RadioCardWithIcon: Story = {
+ render: () => (
+
+
+
+ Primary
+
+
+ Secondary
+
+
+ {renderGroup('radio', 'primary', false, true, 'segmented', 1, 'start', true)}
+ {renderGroup('radio', 'secondary', true, true, 'segmented', 2, 'start', true)}
+
+ ),
+};
+
+export const CheckboxCardWithIcon: Story = {
+ render: () => (
+
+
+
+ Primary
+
+
+ Secondary
+
+
+ {renderGroup('checkbox', 'primary', false, true, 'separated', 5, 'start', true)}
+ {renderGroup('checkbox', 'secondary', true, true, 'separated', 6, 'start', true)}
+
+ ),
+};
+
export const WithError: Story = {
render: function Render(args) {
const [selectedValues, setSelectedValues] = useState([]);
diff --git a/src/tedi/components/form/choice-group/choice-group.tsx b/src/tedi/components/form/choice-group/choice-group.tsx
index e2ade8d04..e3856bba7 100644
--- a/src/tedi/components/form/choice-group/choice-group.tsx
+++ b/src/tedi/components/form/choice-group/choice-group.tsx
@@ -67,7 +67,7 @@ export const ChoiceGroup = (props: ChoiceGroupProps): React.ReactElement => {
indeterminateCheck,
indeterminateCheckProps = {},
color,
- layout,
+ layout = 'separated',
showIndicator,
...rest
} = getCurrentBreakpointProps(props);
@@ -188,8 +188,8 @@ export const ChoiceGroup = (props: ChoiceGroupProps): React.ReactElement => {
)}
{
it('renders the radio input correctly', () => {
renderWithContext();
- const radioInput = screen.getByRole('radio', { name: 'Test Label' });
+ const radioInput = screen.getByLabelText('Test Label');
expect(radioInput).toBeInTheDocument();
+ expect(radioInput).toHaveAttribute('type', 'radio');
});
it('renders the checkbox input correctly when type is checkbox', () => {
renderWithContext({ type: 'checkbox' });
- const checkboxInput = screen.getByRole('checkbox', { name: 'Test Label' });
+ const checkboxInput = screen.getByLabelText('Test Label');
expect(checkboxInput).toBeInTheDocument();
+ expect(checkboxInput).toHaveAttribute('type', 'checkbox');
});
it('renders the card variant correctly', () => {
renderWithContext({ variant: 'card' });
- const cardInput = screen.getByRole('radio', { name: 'Test Label' });
- expect(cardInput).toBeInTheDocument();
- });
-
- it('calls onChange handler when input is clicked', () => {
- const onChange = jest.fn();
- renderWithContext({ onChange }, { currentValue: '', name: 'test-name', onChange, inputType: 'radio' });
- const radioInput = screen.getByRole('radio', { name: 'Test Label' });
- fireEvent.click(radioInput);
- expect(onChange).toHaveBeenCalledWith('test-value', true);
+ const input = screen.getByLabelText('Test Label');
+ expect(input).toBeInTheDocument();
});
it('renders with disabled state correctly', () => {
renderWithContext({ disabled: true });
- const radioInput = screen.getByRole('radio', { name: 'Test Label' });
+ const radioInput = screen.getByLabelText('Test Label');
expect(radioInput).toBeDisabled();
});
@@ -76,20 +70,9 @@ describe('ChoiceGroupItem', () => {
expect(indicator).toBeInTheDocument();
});
- it('calls onChange handler when card input is clicked', () => {
- const onChange = jest.fn();
- renderWithContext(
- { variant: 'card', onChange },
- { currentValue: '', name: 'test-name', onChange, inputType: 'radio' }
- );
- const cardInput = screen.getByRole('radio', { name: 'Test Label' });
- fireEvent.click(cardInput);
- expect(onChange).toHaveBeenCalledWith('test-value', true);
- });
-
it('renders the card variant with disabled state correctly', () => {
renderWithContext({ variant: 'card', disabled: true });
- const cardInput = screen.getByRole('radio', { name: 'Test Label' });
+ const cardInput = screen.getByLabelText('Test Label');
expect(cardInput).toBeDisabled();
});
@@ -99,4 +82,47 @@ describe('ChoiceGroupItem', () => {
const helperText = screen.getByText('Helper text');
expect(helperText).toBeInTheDocument();
});
+
+ it('calls onChange handler when label is clicked', () => {
+ const onChange = jest.fn();
+ renderWithContext({ onChange }, { currentValue: '', name: 'test-name', onChange, inputType: 'radio' });
+ const label = screen.getByText('Test Label');
+ fireEvent.click(label);
+ expect(onChange).toHaveBeenCalled();
+ });
+
+ it('calls onChange handler when card is clicked', () => {
+ const onChange = jest.fn();
+ renderWithContext(
+ { variant: 'card', onChange },
+ { currentValue: '', name: 'test-name', onChange, inputType: 'radio' }
+ );
+
+ const card = screen.getByText('Test Label');
+ fireEvent.click(card);
+ expect(onChange).toHaveBeenCalled();
+ });
+
+ it('programmatically clicks the input when card background is clicked', () => {
+ renderWithContext({ variant: 'card' });
+
+ const input = screen.getByLabelText('Test Label') as HTMLInputElement;
+ const clickSpy = jest.spyOn(input, 'click');
+ const card = input.closest('.tedi-choice-group-item') as HTMLElement;
+ fireEvent.click(card);
+
+ expect(clickSpy).toHaveBeenCalledTimes(1);
+ clickSpy.mockRestore();
+ });
+
+ it('does NOT programmatically click input when clicking the native input directly', () => {
+ const mockInputClick = jest.fn();
+ const mockInput = { click: mockInputClick } as unknown as HTMLInputElement;
+
+ jest.spyOn(document, 'getElementById').mockReturnValue(mockInput);
+ renderWithContext({ variant: 'card' });
+ const input = screen.getByLabelText('Test Label');
+ fireEvent.click(input);
+ expect(mockInputClick).not.toHaveBeenCalled();
+ });
});
diff --git a/src/tedi/components/form/choice-group/components/choice-group-item/choice-group-item.tsx b/src/tedi/components/form/choice-group/components/choice-group-item/choice-group-item.tsx
index 4f919120b..85de3d1b3 100644
--- a/src/tedi/components/form/choice-group/components/choice-group-item/choice-group-item.tsx
+++ b/src/tedi/components/form/choice-group/components/choice-group-item/choice-group-item.tsx
@@ -83,16 +83,23 @@ export const ChoiceGroupItem = (props: ExtendedChoiceGroupItemProps): React.Reac
const InputComponent = type === 'radio' ? Radio : Checkbox;
- const handleClick = (e: React.MouseEvent) => {
- if ((e.target as HTMLElement).tagName === 'LABEL') return;
- if (!disabled && variant === 'card') {
- onChangeHandler(value, !isChecked);
- }
- };
+ const handleClick = (e: React.MouseEvent) => {
+ if (disabled || variant !== 'card') return;
+
+ const target = e.target as HTMLElement;
+ if (target.closest('input, label')) return;
+ document.getElementById(id)?.click();
+ };
return (
-
+
{variant === 'default' || showIndicator ? (
onChangeHandler(value, e.target.checked)}
- className={styles['tedi-choice-group-item__input']}
+ onChange={(e) => {
+ onChangeHandler(value, e.target.checked);
+ }}
+ className="visually-hidden"
role={type === 'radio' ? 'radio' : undefined}
aria-checked={isChecked}
+ tabIndex={-1}
/>
- {helper &&
}
+ {helper &&
}
{inputUpdated && (
{inputUpdated}
diff --git a/src/tedi/components/form/radio/radio.module.scss b/src/tedi/components/form/radio/radio.module.scss
index 4c4aa6cc4..bca07f7dc 100644
--- a/src/tedi/components/form/radio/radio.module.scss
+++ b/src/tedi/components/form/radio/radio.module.scss
@@ -6,12 +6,13 @@
@include mixins.print-grayscale;
- &:hover:not(.tedi-radio--disabled) {
+ &:hover:not(.tedi-radio--disabled) label {
cursor: pointer;
}
&--disabled {
color: var(--general-text-disabled);
+ cursor: not-allowed;
}
&__input {
diff --git a/src/tedi/components/form/radio/radio.spec.tsx b/src/tedi/components/form/radio/radio.spec.tsx
index 9021d7256..8581dbd9a 100644
--- a/src/tedi/components/form/radio/radio.spec.tsx
+++ b/src/tedi/components/form/radio/radio.spec.tsx
@@ -222,4 +222,10 @@ describe('Radio component', () => {
expect(label.click).toHaveBeenCalled();
});
+
+ it('renders required indicator when required prop is true', () => {
+ render(
);
+
+ expect(screen.getByText('*')).toBeInTheDocument();
+ });
});
diff --git a/src/tedi/components/form/radio/radio.stories.tsx b/src/tedi/components/form/radio/radio.stories.tsx
index ec0eb4ed2..7a1772ef4 100644
--- a/src/tedi/components/form/radio/radio.stories.tsx
+++ b/src/tedi/components/form/radio/radio.stories.tsx
@@ -131,6 +131,14 @@ export const States = () => {
/>
+
+
+ Required
+
+
+
+
+
diff --git a/src/tedi/components/form/radio/radio.tsx b/src/tedi/components/form/radio/radio.tsx
index 639c54161..d49a6cda6 100644
--- a/src/tedi/components/form/radio/radio.tsx
+++ b/src/tedi/components/form/radio/radio.tsx
@@ -26,6 +26,7 @@ export const Radio = (props: RadioProps): JSX.Element => {
tooltip,
size = 'default',
invalid,
+ required,
...rest
} = props;
@@ -46,10 +47,14 @@ export const Radio = (props: RadioProps): JSX.Element => {
const helperId = helper ? helper.id ?? `${id}-helper` : undefined;
const tooltipId = tooltip ? `${id}-tooltip` : undefined;
- const LabelBEM = cn(styles['tedi-radio'], { [styles['tedi-radio--disabled']]: disabled });
+ const LabelBEM = cn(styles['tedi-radio__label'], { [styles['tedi-radio--disabled']]: disabled });
return (
-
+
@@ -78,8 +83,8 @@ export const Radio = (props: RadioProps): JSX.Element => {
/>
-
- {label && typeof label === 'string' ? (
+ {label && (
+
{
hideLabel={hideLabel}
label={label}
tooltip={tooltip}
+ required={required}
/>
- ) : (
-
- )}
-
+
+ )}
{helper && (
diff --git a/src/tedi/components/form/select/components/select-clear-indicator.tsx b/src/tedi/components/form/select/components/select-clear-indicator.tsx
index 7f1d24767..368284589 100644
--- a/src/tedi/components/form/select/components/select-clear-indicator.tsx
+++ b/src/tedi/components/form/select/components/select-clear-indicator.tsx
@@ -17,7 +17,7 @@ export const SelectClearIndicator = ({
return isClearIndicatorVisible ? (
<>
-
+
{getLabel('clear')}
diff --git a/src/tedi/components/form/select/components/select-multi-value-remove.tsx b/src/tedi/components/form/select/components/select-multi-value-remove.tsx
index 8ed9a4e08..828e3a88b 100644
--- a/src/tedi/components/form/select/components/select-multi-value-remove.tsx
+++ b/src/tedi/components/form/select/components/select-multi-value-remove.tsx
@@ -28,6 +28,7 @@ export const SelectMultiValueRemove = ({ innerProps, data }: MultiValueRemovePro
onClick={handleClick}
onKeyDown={handleKeyDown}
className={styles['tedi-select__multi-value-clear']}
+ iconSize={18}
title={`${getLabel('clear')} ${data.label}`}
/>
diff --git a/src/tedi/components/form/textfield/textfield.module.scss b/src/tedi/components/form/textfield/textfield.module.scss
index 850f10a8f..fa91f068c 100644
--- a/src/tedi/components/form/textfield/textfield.module.scss
+++ b/src/tedi/components/form/textfield/textfield.module.scss
@@ -1,7 +1,32 @@
@use '@tedi-design-system/core/bootstrap-utility/breakpoints';
@use '@tedi-design-system/core/mixins';
+@use 'sass:map';
$input-height-large: 3.5rem;
+$input-padding-right-map: (
+ default: (
+ normal: 2rem,
+ both: 4rem,
+ ),
+ small: (
+ normal: 2rem,
+ both: 4rem,
+ ),
+ large: (
+ normal: 3.5rem,
+ both: 6rem,
+ ),
+);
+
+@function get-padding-right($size, $clearable, $icon) {
+ @if $clearable and $icon {
+ @return map.get(map.get($input-padding-right-map, $size), both);
+ } @else if $clearable or $icon {
+ @return map.get(map.get($input-padding-right-map, $size), normal);
+ } @else {
+ @return null;
+ }
+}
@mixin textfield-focus($border-color: null) {
@if $border-color {
@@ -69,29 +94,45 @@ $input-height-large: 3.5rem;
@include textfield-focus(var(--form-general-feedback-success-border));
}
- .tedi-textfield--clearable &,
- .tedi-textfield--with-icon & {
- padding-right: 2rem;
- }
-
- .tedi-textfield--clearable.tedi-textfield--with-icon & {
- padding-right: 4rem;
- }
-
&::placeholder {
color: var(--form-input-text-placeholder);
opacity: 1;
}
}
-// hide arrows on number inputs
-.tedi-textfield__input--hidden-arrows[type='number'] {
- appearance: textfield; // for Firefox
+@each $size in default, small, large {
+ $selector: if($size == default, '.tedi-textfield', '.tedi-textfield--#{$size}');
+ #{$selector} {
+ $padding: get-padding-right($size, true, false);
- &::-webkit-outer-spin-button,
- &::-webkit-inner-spin-button {
- margin: 0;
- appearance: none;
+ &.tedi-textfield--clearable .tedi-textfield__input {
+ padding-right: get-padding-right($size, true, false);
+ }
+
+ &.tedi-textfield--with-icon .tedi-textfield__input {
+ padding-right: get-padding-right($size, false, true);
+ }
+
+ &.tedi-textfield--clearable.tedi-textfield--with-icon .tedi-textfield__input {
+ padding-right: get-padding-right($size, true, true);
+ }
+
+ @if $size == small {
+ .tedi-textfield__input {
+ height: var(--form-field-height-sm);
+ padding: var(--form-field-padding-y-sm) var(--form-field-padding-x-md-default);
+ font-size: var(--body-regular-size);
+ }
+ } @else if $size == large {
+ .tedi-textfield__input {
+ height: $input-height-large;
+ padding: var(--form-field-padding-y-lg) var(--form-field-padding-x-lg);
+
+ @include breakpoints.media-breakpoint-down(md) {
+ height: var(--form-field-height);
+ }
+ }
+ }
}
}
@@ -100,26 +141,24 @@ $input-height-large: 3.5rem;
top: 0;
right: 0;
display: flex;
+ gap: var(--layout-grid-gutters-04);
align-items: center;
height: 100%;
- padding: 0.75rem 0.5rem;
+ padding: var(--form-field-padding-y-md-default) var(--form-field-padding-x-md-default);
.tedi-textfield--small & {
- padding: 0.25rem 0.5rem;
+ padding: var(--form-field-padding-y-sm) var(--form-field-padding-x-md-default);
}
.tedi-textfield--large & {
- padding: 1rem;
+ padding: var(--form-field-padding-y-lg) var(--form-field-padding-x-lg);
}
}
-.tedi-textfield__separator {
- margin-right: 0.5rem;
- margin-left: 0.25rem;
-}
-
.tedi-textfield__icon-wrapper {
display: flex;
+ justify-content: center;
+ width: var(--icon-04);
color: var(--form-input-text-filled);
transition: color 0.2s ease;
@@ -150,50 +189,6 @@ div.tedi-textfield__icon-wrapper {
vertical-align: text-top;
}
-/* Small */
-.tedi-textfield--small {
- .tedi-textfield__input {
- height: var(--form-field-height-sm);
- padding: var(--form-field-padding-y-sm) var(--form-field-padding-x-md-default);
- font-size: var(--body-small-regular-size);
- }
-
- &.tedi-textfield--clearable &,
- &.tedi-textfield--with-icon & {
- padding-right: 2rem;
- }
-
- &.tedi-textfield--clearable.tedi-textfield--with-icon & {
- padding-right: 4rem;
- }
-}
-
-/* Large */
-.tedi-textfield--large {
- .tedi-textfield__input {
- height: $input-height-large;
- padding: 1rem;
-
- @include breakpoints.media-breakpoint-down(md) {
- height: var(--form-field-height);
- }
- }
-
- .tedi-textfield__separator {
- margin-right: 0.5rem;
- margin-left: 0.5rem;
- }
-
- &.tedi-textfield--clearable .tedi-textfield__input,
- &.tedi-textfield--with-icon .tedi-textfield__input {
- padding-right: 3.5rem;
- }
-
- &.tedi-textfield--clearable.tedi-textfield--with-icon .tedi-textfield__input {
- padding-right: 6rem;
- }
-}
-
.tedi-textfield__feedback-wrapper {
display: flex;
}
diff --git a/src/tedi/components/form/textfield/textfield.tsx b/src/tedi/components/form/textfield/textfield.tsx
index f94f5acb3..ff1de6a5c 100644
--- a/src/tedi/components/form/textfield/textfield.tsx
+++ b/src/tedi/components/form/textfield/textfield.tsx
@@ -10,6 +10,11 @@ import { FeedbackText, FeedbackTextProps } from '../feedback-text/feedback-text'
import FormLabel, { FormLabelProps } from '../form-label/form-label';
import styles from './textfield.module.scss';
+const iconSizes = {
+ large: 24,
+ default: 18,
+} as const;
+
type TextFieldBreakpointProps = {
/**
* Input field size
@@ -333,7 +338,7 @@ export const TextField = forwardRef((props,
const renderClearButton = React.useMemo(() => {
const clearButtonProps = {
- size: (size === 'large' ? 'large' : 'medium') as 'medium' | 'large',
+ iconSize: iconSizes[size === 'large' ? 'large' : 'default'],
onClick: disabled ? () => {} : clearInput,
disabled,
'aria-disabled': disabled || undefined,
diff --git a/src/tedi/components/layout/grid/col.stories.tsx b/src/tedi/components/layout/grid/col.stories.tsx
new file mode 100644
index 000000000..b2ea48bf9
--- /dev/null
+++ b/src/tedi/components/layout/grid/col.stories.tsx
@@ -0,0 +1,59 @@
+import { Meta, StoryFn, StoryObj } from '@storybook/react';
+
+import { Heading } from '../../base/typography/heading/heading';
+import { VerticalSpacing } from '../vertical-spacing';
+import { Col } from './col';
+import { Row } from './row';
+
+/**
+ * Zeroheight ↗
+ * Bootstrap docs ↗
+ * Row and Col components are inspired by Bootstrap V5 Grid System.
You can use different Bootstrap grid classes
+ * through component props.
+ */
+
+const meta: Meta = {
+ title: 'Tedi-Ready/Layout/Grid/Col',
+ component: Col,
+ subcomponents: { Row } as never,
+ parameters: {
+ status: { type: 'devComponent' },
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: StoryFn = () => (
+
+
+ Label/Value pairs
+
+
+
+
+
+ Label
+
+ Value
+
+
+
+ Label
+
+ Value
+
+
+
+
+
+
+
+ Lists
+
+ Item 1
+ Item 2
+
+
+
+);
diff --git a/src/tedi/components/layout/grid/grid.stories.tsx b/src/tedi/components/layout/grid/grid.stories.tsx
deleted file mode 100644
index 78ec8ed9d..000000000
--- a/src/tedi/components/layout/grid/grid.stories.tsx
+++ /dev/null
@@ -1,120 +0,0 @@
-import { Meta, StoryFn, StoryObj } from '@storybook/react';
-
-import { Heading } from '../../base/typography/heading/heading';
-import { VerticalSpacing } from '../vertical-spacing';
-import { Col } from './col';
-import { Row, RowProps } from './row';
-
-/**
- * Zeroheight ↗
- * Boostrap docs ↗
- * Row and Col components are inspired by Bootstrap V5 Grid System.
You can use different Bootstrap grid classes
- * through component props.
- */
-const meta: Meta = {
- title: 'Tedi-Ready/Components/Helpers/Grid',
- component: Row,
- subcomponents: { Col: Col } as never,
- parameters: {
- status: {
- type: 'devComponent',
- },
- },
-};
-
-export default meta;
-type Story = StoryObj;
-
-const Template: StoryFn = (args) => (
-
-
- Col-1
- Col-2
- Col-3
-
-
-
- Col-1
-
-
- Col-2
-
-
- Col-3
-
-
-
-
- Col-1
-
-
- Col-2
-
-
- Col-3
-
-
-
- Col-1
- Col-2
- Col-3
-
-
-);
-
-export const Default: Story = {
- render: Template,
-};
-
-export const CustomTags: StoryFn = () => (
-
-
- Label/Value pairs
-
-
- {/* Grouped rows */}
-
-
-
- Label
-
- Value
-
-
-
- Label
-
- Value
-
-
-
-
- {/* Non grouped rows */}
-
-
-
- Label
-
-
- Value
-
-
- Label
-
-
- Value
-
-
-
-
-
-
-
- Lists
-
- Item 1
- Item 2
-
-
-
-);
diff --git a/src/tedi/components/layout/grid/row.stories.tsx b/src/tedi/components/layout/grid/row.stories.tsx
new file mode 100644
index 000000000..1904bb382
--- /dev/null
+++ b/src/tedi/components/layout/grid/row.stories.tsx
@@ -0,0 +1,59 @@
+import { Meta, StoryFn, StoryObj } from '@storybook/react';
+
+import { Col } from './col';
+import { Row, RowProps } from './row';
+
+/**
+ * Zeroheight ↗
+ * Bootstrap docs ↗
+ * Row and Col components are inspired by Bootstrap V5 Grid System.
You can use different Bootstrap grid classes
+ * through component props.
+ */
+
+const meta: Meta = {
+ title: 'Tedi-Ready/Layout/Grid/Row',
+ component: Row,
+ subcomponents: { Col } as never,
+ parameters: {
+ status: { type: 'devComponent' },
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+const Template: StoryFn = (args) => (
+
+
+ Col-1
+ Col-2
+ Col-3
+
+
+
+
+ Col-1
+
+
+ Col-2
+
+
+ Col-3
+
+
+
+
+
+ Col-1
+
+
+ Col-2
+
+
+ Col-3
+
+
+
+);
+
+export const Default: Story = { render: Template };
diff --git a/src/tedi/components/layout/sidenav/components/sidenav-dropdown/sidenav-dropdown.spec.tsx b/src/tedi/components/layout/sidenav/components/sidenav-dropdown/sidenav-dropdown.spec.tsx
index 3b6b1f33d..be299eef3 100644
--- a/src/tedi/components/layout/sidenav/components/sidenav-dropdown/sidenav-dropdown.spec.tsx
+++ b/src/tedi/components/layout/sidenav/components/sidenav-dropdown/sidenav-dropdown.spec.tsx
@@ -144,7 +144,7 @@ describe('SideNavDropdown', () => {
const parentItem = screen.getByRole('menuitem', { name: /parent/i });
expect(parentItem).toHaveAttribute('aria-haspopup', 'true');
- expect(parentItem).toHaveAttribute('aria-expanded', 'false');
+ expect(parentItem).toHaveAttribute('aria-expanded', 'true');
});
it('calls onOpenChange when closing', () => {
diff --git a/src/tedi/components/layout/sidenav/components/sidenav-dropdown/sidenav-dropdown.tsx b/src/tedi/components/layout/sidenav/components/sidenav-dropdown/sidenav-dropdown.tsx
index 6a2fe9e67..ce1f65895 100644
--- a/src/tedi/components/layout/sidenav/components/sidenav-dropdown/sidenav-dropdown.tsx
+++ b/src/tedi/components/layout/sidenav/components/sidenav-dropdown/sidenav-dropdown.tsx
@@ -22,10 +22,11 @@ type SideNavDropdownProps = {
trigger: React.ReactNode;
groups: Group[];
onOpenChange?: (isOpen: boolean) => void;
+ as?: C;
};
type Group = {
- subHeading?: string;
+ subHeading?: React.ReactNode;
subItems: SideNavItemProps[];
};
@@ -33,6 +34,7 @@ export const SideNavDropdown = ({
trigger,
groups,
onOpenChange,
+ as,
}: SideNavDropdownProps) => {
const { getLabel } = useLabels();
const [open, setOpen] = useState(false);
@@ -68,7 +70,7 @@ export const SideNavDropdown = ({
{...item}
role="menuitem"
aria-haspopup={hasChildren ? 'true' : undefined}
- aria-expanded={hasChildren ? false : undefined}
+ aria-expanded={hasChildren ? open : undefined}
aria-controls={hasChildren ? `${id}-submenu` : undefined}
className={styles['tedi-sidenav-dropdown__link']}
data-active={item.isActive}
@@ -78,6 +80,7 @@ export const SideNavDropdown = ({
item.onClick?.(e);
setOpen(false);
}}
+ as={item.as ?? as}
>
{item.children}
{hasChildren && }
diff --git a/src/tedi/components/layout/sidenav/components/sidenav-item/sidenav-item.tsx b/src/tedi/components/layout/sidenav/components/sidenav-item/sidenav-item.tsx
index ae95b7d5f..fd6472309 100644
--- a/src/tedi/components/layout/sidenav/components/sidenav-item/sidenav-item.tsx
+++ b/src/tedi/components/layout/sidenav/components/sidenav-item/sidenav-item.tsx
@@ -23,7 +23,7 @@ export type SideNavItemProps = LinkProps &
* Grouped submenu items (preferred for headings)
*/
subItemGroups?: {
- subHeading?: string;
+ subHeading?: React.ReactNode;
subItems: SideNavItemProps[];
}[];
/**
@@ -73,6 +73,7 @@ export const SideNavItem = (
const groupsToRender = subItemGroups ?? (subItems ? [{ subItems }] : null);
const hasChildren = !!groupsToRender;
+ const hasTreeIndicator = level > 1 && hasChildren;
const SideNavItemBEM = cn(
styles['tedi-sidenav__item'],
@@ -81,6 +82,7 @@ export const SideNavItem = (
[styles[`tedi-sidenav__item--level-${level}`]]: level > 1,
[styles['tedi-sidenav__item--current']]: isActive,
[styles['tedi-sidenav__item--has-children']]: hasChildren,
+ [styles['tedi-sidenav__item--with-tree']]: hasTreeIndicator,
},
className
);
@@ -186,6 +188,7 @@ export const SideNavItem = (
}
+ as={as}
groups={groupsToRender}
onOpenChange={setIsDropdownOpen}
/>
@@ -264,7 +267,7 @@ export const SideNavItem = (
);
return level === 1 && isCollapsed ? (
-
+
{children}
{content}
diff --git a/src/tedi/components/layout/sidenav/components/sidenav-toggle/sidenav-toggle.module.scss b/src/tedi/components/layout/sidenav/components/sidenav-toggle/sidenav-toggle.module.scss
index 1830947fe..fac53cbac 100644
--- a/src/tedi/components/layout/sidenav/components/sidenav-toggle/sidenav-toggle.module.scss
+++ b/src/tedi/components/layout/sidenav/components/sidenav-toggle/sidenav-toggle.module.scss
@@ -1,8 +1,9 @@
@use '@tedi-design-system/core/bootstrap-utility/breakpoints';
.tedi-sidenav-toggle {
- width: 3.5rem;
- height: 3.5rem;
+ z-index: var(--z-index-sidenav);
+ width: var(--button-sm-height);
+ height: var(--button-sm-height);
margin: 0;
border-radius: 0;
diff --git a/src/tedi/components/layout/sidenav/examples.ts b/src/tedi/components/layout/sidenav/examples.tsx
similarity index 78%
rename from src/tedi/components/layout/sidenav/examples.ts
rename to src/tedi/components/layout/sidenav/examples.tsx
index 152583eff..0bb8ac52e 100644
--- a/src/tedi/components/layout/sidenav/examples.ts
+++ b/src/tedi/components/layout/sidenav/examples.tsx
@@ -1,4 +1,6 @@
/* istanbul ignore file */
+import { Text } from '../../base/typography/text/text';
+import { InfoButton } from '../../buttons/info-button/info-button';
import { SideNavItemProps } from './components/sidenav-item/sidenav-item';
export const exampleNavItems: SideNavItemProps[] = [
@@ -248,3 +250,63 @@ export const exampleThirdLevelMenuItemsLinks: SideNavItemProps[] = [
{ href: '#', children: 'Inventory Management', icon: 'inventory' },
{ href: '#', children: 'Billing & Finance', icon: 'payments' },
];
+
+export const exampleThirdLevelMenuItemsLinksWithSubTitles: SideNavItemProps[] = [
+ { href: '#', children: 'Dashboard', icon: 'dashboard' },
+ { href: '#', children: 'Patient Records', icon: 'people' },
+ {
+ children: 'Clinical Management',
+ icon: 'medical_services',
+ subItemGroups: [
+ {
+ subHeading: (
+
+ Minu tervise ajalugu Lorem ipsum
+
+ ),
+ subItems: [
+ { href: '#', children: 'Active Treatments' },
+ { href: '#', children: 'Treatment History' },
+ { href: '#', children: 'Treatment Plans' },
+ { href: '#', children: 'Clinical Protocols' },
+ ],
+ },
+ ],
+ subItems: [
+ { href: '#', children: 'Vital Signs' },
+ { href: '#', children: 'Assessments' },
+ {
+ href: '#',
+ children: 'Treatments',
+ subItems: [
+ { href: '#', children: 'Active Treatments' },
+ { href: '#', children: 'Treatment History' },
+ { href: '#', children: 'Treatment Plans' },
+ { href: '#', children: 'Clinical Protocols' },
+ ],
+ },
+ {
+ href: '#',
+ children: 'Documentation',
+ subItems: [
+ { href: '#', children: 'Clinical Notes' },
+ { href: '#', children: 'Medical Forms' },
+ { href: '#', children: 'Consent Forms' },
+ { href: '#', children: 'Reports' },
+ ],
+ },
+ ],
+ isDefaultOpen: true,
+ },
+ {
+ href: '#',
+ children: 'Administration',
+ icon: 'admin_panel_settings',
+ subItems: [
+ { href: '#', children: 'Staff Management' },
+ { href: '#', children: 'Scheduling' },
+ ],
+ },
+ { href: '#', children: 'Inventory Management', icon: 'inventory' },
+ { href: '#', children: 'Billing & Finance', icon: 'payments' },
+];
diff --git a/src/tedi/components/layout/sidenav/sidenav.module.scss b/src/tedi/components/layout/sidenav/sidenav.module.scss
index 194aa458c..bc48c812f 100644
--- a/src/tedi/components/layout/sidenav/sidenav.module.scss
+++ b/src/tedi/components/layout/sidenav/sidenav.module.scss
@@ -197,7 +197,8 @@
}
}
-.tedi-sidenav__item.tedi-sidenav__sub-item .tedi-sidenav__link {
+.tedi-sidenav__item--with-tree .tedi-sidenav__item.tedi-sidenav__sub-item .tedi-sidenav__link,
+.tedi-sidenav__item--level-2 .tedi-sidenav__link {
min-height: var(--navigation-vertical-item-min-height-medium);
padding-top: var(--navigation-vertical-item-padding-y);
padding-bottom: var(--navigation-vertical-item-padding-y);
@@ -208,11 +209,21 @@
);
}
+.tedi-sidenav__item:not(.tedi-sidenav__item--with-tree) .tedi-sidenav__sub-item.tedi-sidenav__item .tedi-sidenav__link,
+.tedi-sidenav__item--level-2 .tedi-sidenav__link,
+.tedi-sidenav__item--with-tree.tedi-sidenav__item--level-2 .tedi-sidenav__link.tedi-sidenav__link--has-children-link {
+ @include breakpoints.media-breakpoint-down(md) {
+ padding-left: var(--navigation-vertical-item-padding-right);
+ }
+}
+
.tedi-sidenav__item .tedi-sidenav__link--has-children-link {
padding-right: calc(var(--navigation-vertical-item-padding-right) + var(--button-xs-icon-size));
@include breakpoints.media-breakpoint-down(md) {
+ z-index: 1;
margin-left: calc(var(--navigation-vertical-item-padding-right) + var(--button-xs-icon-size));
+ background-color: var(--navigation-vertical-item-background-default);
}
}
@@ -227,7 +238,7 @@
+ .tedi-sidenav__link-collapse-wrapper
[data-name='collapse-trigger'] {
position: absolute;
- top: calc(var(--navigation-vertical-item-min-height-medium) / 3);
+ top: calc((var(--navigation-vertical-item-min-height-large) - var(--button-xs-icon-size)) / 2);
right: var(--navigation-vertical-item-padding-right);
display: flex;
align-items: center;
@@ -359,7 +370,7 @@ button.tedi-sidenav__link.tedi-sidenav__back-button {
.tedi-sidenav__subheading {
padding: var(--layout-grid-gutters-02) var(--navigation-vertical-item-padding-left-level-1)
var(--layout-grid-gutters-04) var(--navigation-vertical-item-padding-right);
- font-size: var(--size-00);
+ font-size: var(--body-extra-small-bold-size);
color: var(--navigation-vertical-group-title-text);
text-transform: uppercase;
diff --git a/src/tedi/components/layout/sidenav/sidenav.stories.tsx b/src/tedi/components/layout/sidenav/sidenav.stories.tsx
index 0648731f3..30537b06e 100644
--- a/src/tedi/components/layout/sidenav/sidenav.stories.tsx
+++ b/src/tedi/components/layout/sidenav/sidenav.stories.tsx
@@ -11,6 +11,7 @@ import {
exampleNavItems,
exampleThirdLevelMenuItems,
exampleThirdLevelMenuItemsLinks,
+ exampleThirdLevelMenuItemsLinksWithSubTitles,
} from './examples';
import { SideNav } from './sidenav';
@@ -278,3 +279,10 @@ export const SmallSideNavItems: Story = {
sideNavItemSize: 'small',
},
};
+
+export const SubTitles: Story = {
+ render: Template,
+ args: {
+ navItems: exampleThirdLevelMenuItemsLinksWithSubTitles,
+ },
+};
diff --git a/src/tedi/components/layout/vertical-spacing/vertical-spacing.stories.tsx b/src/tedi/components/layout/vertical-spacing/vertical-spacing.stories.tsx
index 4af447580..a3fcaffe9 100644
--- a/src/tedi/components/layout/vertical-spacing/vertical-spacing.stories.tsx
+++ b/src/tedi/components/layout/vertical-spacing/vertical-spacing.stories.tsx
@@ -11,7 +11,7 @@ import { VerticalSpacing, VerticalSpacingProps } from './vertical-spacing';
const meta: Meta = {
component: VerticalSpacing,
- title: 'Tedi-Ready/Components/Helpers/VerticalSpacing',
+ title: 'Tedi-Ready/Layout/VerticalSpacing',
subcomponents: {
'VerticalSpacing.Item': VerticalSpacing.Item,
} as never,
diff --git a/src/tedi/components/misc/separator/separator.module.scss b/src/tedi/components/misc/separator/separator.module.scss
index 0e17b456e..85741e1e7 100644
--- a/src/tedi/components/misc/separator/separator.module.scss
+++ b/src/tedi/components/misc/separator/separator.module.scss
@@ -1,24 +1,21 @@
@use '@tedi-design-system/core/mixins';
-$sizes: (
- '0': 0,
- '0-25': 0.25rem,
- '0-5': 0.5rem,
- '0-75': 0.75rem,
- '1': 1rem,
- '1-25': 1.25rem,
- '1-5': 1.5rem,
- '1-75': 1.75rem,
- '2': 2rem,
- '2-5': 2.5rem,
- '5': 5rem,
+$thicknesses: (
+ '1': 1px,
+ '2': 2px,
+);
+$dot-colors: (
+ 'primary': var(--general-border-primary),
+ 'secondary': var(--general-border-secondary),
+ 'accent': var(--general-border-accent),
);
.tedi-separator {
--vertical-separator-height: 100%;
position: relative;
- margin: 0;
+ margin: var(--separator-margin-top) var(--separator-margin-right) var(--separator-margin-bottom)
+ var(--separator-margin-left);
border: 0;
border-top: 1px solid var(--general-border-primary);
@@ -30,12 +27,8 @@ $sizes: (
border-left: 1px solid var(--general-border-primary);
}
- &--secondary {
- border-color: var(--general-border-secondary);
- }
-
- &--accent {
- border-color: var(--general-border-accent);
+ &--horizontal {
+ display: block;
}
&--block {
@@ -45,84 +38,38 @@ $sizes: (
&--inline {
display: inline;
}
-}
-
-.tedi-separator--dotted,
-.tedi-separator--dotted-small {
- &::before {
- position: absolute;
- top: 1.25rem;
- width: var(--separator-dotted-dot-lg);
- height: var(--separator-dotted-dot-lg);
- content: '';
- background-color: var(--general-border-primary);
- border-radius: 100%;
- transform: translateX(-8px);
-
- @include mixins.print-grayscale;
- }
- &.tedi-separator--secondary::before {
- background-color: var(--general-border-secondary);
+ &--secondary {
+ border-color: var(--general-border-secondary);
}
- &.tedi-separator--accent::before {
- background-color: var(--general-border-accent);
+ &--accent {
+ border-color: var(--general-border-accent);
}
-}
-
-.tedi-separator--dotted-small::before {
- top: 1.5rem;
- width: var(--separator-dotted-dot-md);
- height: var(--separator-dotted-dot-md);
- transform: translateX(-5px);
-}
-.tedi-separator--is-stretched {
- margin-right: calc(var(--card-content-padding-right) * -1);
- margin-left: calc(var(--card-content-padding-left) * -1);
+ &--is-stretched {
+ margin-right: calc(var(--card-content-padding-right) * -1);
+ margin-left: calc(var(--card-content-padding-left) * -1);
- &.tedi-separator--vertical {
- height: calc(100% + (var(--card-content-padding-top) + var(--card-content-padding-bottom)));
- margin: calc(var(--card-content-padding-top) * -1) 0 calc(var(--card-content-padding-bottom) * -1);
+ &.tedi-separator--vertical {
+ height: calc(100% + (var(--card-content-padding-top) + var(--card-content-padding-bottom)));
+ margin: calc(var(--card-content-padding-top) * -1) 0 calc(var(--card-content-padding-bottom) * -1);
+ }
}
}
-@each $size, $value in $sizes {
- .tedi-separator--horizontal.tedi-separator--top-#{$size} {
- margin-top: #{$value};
- }
-
- .tedi-separator--horizontal.tedi-separator--bottom-#{$size} {
- margin-bottom: #{$value};
- }
-
- .tedi-separator--horizontal.tedi-separator--spacing-#{$size}:not(.tedi-separator--dot-only) {
- margin-top: #{$value};
- margin-bottom: #{$value};
- }
+.tedi-separator--dotted {
+ &::before {
+ position: absolute;
+ content: '';
+ background-color: var(--general-border-primary);
+ border-radius: 50%;
- .tedi-separator--horizontal.tedi-separator--dot-only.tedi-separator--spacing-#{$size},
- .tedi-separator--vertical.tedi-separator--spacing-#{$size} {
- margin-right: #{$value};
- margin-left: #{$value};
+ @include mixins.print-grayscale;
}
-}
-
-$thicknesses: (
- '1': 1px,
- '2': 2px,
-);
-@each $thickness, $value in $thicknesses {
- .tedi-separator {
- &.tedi-separator--thickness-#{$thickness} {
- border-top-width: #{$value};
- }
-
- &--vertical.tedi-separator--thickness-#{$thickness} {
- border-left-width: #{$value};
- }
+ &.tedi-separator--vertical {
+ min-height: 3rem;
}
}
@@ -138,58 +85,115 @@ $thicknesses: (
width: var(--separator-dotted-dot-sm);
height: var(--separator-dotted-dot-sm);
content: '';
- border-radius: 100%;
+ border-radius: 50%;
@include mixins.print-grayscale;
}
- &.tedi-separator--dot-only-extra-small::before {
- width: var(--separator-dotted-dot-xs);
- height: var(--separator-dotted-dot-xs);
+ &.tedi-separator--dot-style-outlined::before {
+ background: transparent;
}
+}
- &.tedi-separator--dot-only-small::before {
- width: var(--separator-dotted-dot-sm);
- height: var(--separator-dotted-dot-sm);
- }
+@each $name, $color in $dot-colors {
+ .tedi-separator--#{$name} {
+ border-color: $color;
- &.tedi-separator--dot-only-medium::before {
- width: var(--separator-dotted-dot-md);
- height: var(--separator-dotted-dot-md);
- }
+ &::before {
+ background-color: $color;
+ }
- &.tedi-separator--dot-only-large::before {
- width: var(--separator-dotted-dot-lg);
- height: var(--separator-dotted-dot-lg);
+ &.tedi-separator--dot-style-outlined:not(.tedi-separator--dot-only)::before {
+ border-color: $color;
+ }
}
+}
- &.tedi-separator--primary::before {
- background-color: var(--general-border-primary);
+@each $size, $var in (extra-small: xs, small: sm, medium: md, large: lg) {
+ .tedi-separator--dot-only-#{$size}::before,
+ .tedi-separator--dotted-#{$size}::before,
+ .tedi-separator--dot-style-outlined.tedi-separator--dotted-#{$size}::before {
+ width: var(--separator-dot-size-#{$var});
+ height: var(--separator-dot-size-#{$var});
}
+}
- &.tedi-separator--secondary::before {
- background-color: var(--general-border-secondary);
+@each $axis in (horizontal, vertical) {
+ @each $pos in (start, center, end) {
+ .tedi-separator--#{$axis}.tedi-separator--dot-position-#{$pos}::before {
+ @if $axis == horizontal {
+ @if $pos == start {
+ right: auto;
+ left: 0;
+ } @else if $pos == center {
+ right: 0;
+ left: 0;
+ margin: auto;
+ } @else {
+ right: 0;
+ left: auto;
+ }
+ } @else {
+ @if $pos == start {
+ top: 0;
+ bottom: auto;
+ } @else if $pos == center {
+ top: 0;
+ bottom: 0;
+ margin: auto 0;
+ } @else {
+ top: auto;
+ bottom: 0;
+ }
+ }
+ }
}
+}
+
+.tedi-separator--horizontal.tedi-separator--dot-position-custom::before {
+ right: auto;
+ left: var(--separator-dot-position);
+}
+
+.tedi-separator--vertical.tedi-separator--dot-position-custom::before {
+ top: var(--separator-dot-position);
+ bottom: auto;
+}
- &.tedi-separator--accent::before {
- background-color: var(--general-border-accent);
+@each $thickness, $value in $thicknesses {
+ .tedi-separator--thickness-#{$thickness} {
+ border-top-width: $value;
+ }
+ .tedi-separator--vertical.tedi-separator--thickness-#{$thickness} {
+ border-left-width: $value;
}
}
-.tedi-separator--horizontal {
- &.tedi-separator--dotted::before,
- &.tedi-separator--dotted-small::before {
- right: 0;
- left: 0;
- margin: 0 auto;
- transform: initial;
+@each $axis in (horizontal, vertical) {
+ @each $size, $var in (extra-small: xs, small: sm, medium: md, large: lg) {
+ .tedi-separator--#{$axis}.tedi-separator--dotted-#{$size}::before,
+ .tedi-separator--#{$axis}.tedi-separator--dot-style-outlined.tedi-separator--dotted-#{$size}::before {
+ @if $axis == horizontal {
+ top: calc((var(--separator-dot-size-#{$var}) / 2 + var(--separator-thickness)) * -1);
+ } @else {
+ left: calc((var(--separator-dot-size-#{$var}) / 2 + var(--separator-thickness) / 2) * -1);
+ }
+ }
}
+}
- &.tedi-separator--dotted::before {
- top: calc(var(--separator-dotted-dot-lg) / 2 * -1);
+.tedi-separator--dot-style-outlined {
+ &::before {
+ background-color: var(--general-surface-primary);
+ border-style: solid;
+ border-width: var(--separator-thickness);
}
- &.tedi-separator--dotted-small::before {
- top: calc(var(--separator-dotted-dot-md) / 2 * -1);
+ @each $name, $color in $dot-colors {
+ &.tedi-separator--#{$name}::before,
+ &.tedi-separator--dotted-#{$name}::before {
+ z-index: 10;
+ border-color: $color;
+ }
}
}
diff --git a/src/tedi/components/misc/separator/separator.spec.tsx b/src/tedi/components/misc/separator/separator.spec.tsx
index 65d9c7e20..0f465e37e 100644
--- a/src/tedi/components/misc/separator/separator.spec.tsx
+++ b/src/tedi/components/misc/separator/separator.spec.tsx
@@ -17,132 +17,148 @@ describe('Separator Component', () => {
});
});
- const renderComponent = (props: SeparatorProps) => render();
+ const renderComponent = (props: P) =>
+ render();
- it('should render a div element by default', () => {
- const { getByTestId } = renderComponent({});
+ it('renders a div by default', () => {
+ const { getByTestId } = renderComponent({ element: 'div' });
expect(getByTestId('separator').tagName).toBe('DIV');
});
- it('should render the specified element', () => {
+ it('renders the specified element', () => {
const { getByTestId } = renderComponent({ element: 'hr' });
expect(getByTestId('separator').tagName).toBe('HR');
});
- it('should apply default classes', () => {
- const { getByTestId } = renderComponent({});
- const separator = getByTestId('separator');
- expect(separator).toHaveClass(styles['tedi-separator']);
- expect(separator).toHaveClass(styles['tedi-separator--thickness-1']);
- expect(separator).toHaveClass(styles['tedi-separator--horizontal']);
- });
-
- it('should apply additional classes from className prop', () => {
- const { getByTestId } = renderComponent({ className: 'custom-class' });
- expect(getByTestId('separator')).toHaveClass('custom-class');
- });
-
- it('should apply correct spacing class', () => {
- const { getByTestId } = renderComponent({ spacing: 1.25 });
- expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--spacing-1-25']);
- });
+ it('applies base and default classes', () => {
+ const { getByTestId } = renderComponent({ axis: 'horizontal' });
+ const el = getByTestId('separator');
- it('should apply correct top and bottom spacing classes', () => {
- const { getByTestId } = renderComponent({ topSpacing: 0.5, bottomSpacing: 1 });
- expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--top-0-5']);
- expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--bottom-1']);
+ expect(el).toHaveClass(styles['tedi-separator']);
+ expect(el).toHaveClass(styles['tedi-separator--horizontal']);
+ expect(el).toHaveClass(styles['tedi-separator--thickness-1']);
});
- it('should apply axis specific class', () => {
- const { getByTestId } = renderComponent({ axis: 'vertical' });
- expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--vertical']);
+ it('applies custom className', () => {
+ const { getByTestId } = renderComponent({ className: 'my-extra-class' });
+ expect(getByTestId('separator')).toHaveClass('my-extra-class');
});
- it('should apply color class', () => {
+ it('applies color modifier', () => {
const { getByTestId } = renderComponent({ color: 'accent' });
expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--accent']);
});
- it('should apply variant class', () => {
- const { getByTestId } = renderComponent({ variant: 'dotted' });
- expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--dotted']);
+ it('applies vertical axis class and allows height', () => {
+ const { getByTestId } = renderComponent({ axis: 'vertical', height: 5.5 });
+ const el = getByTestId('separator');
+
+ expect(el).toHaveClass(styles['tedi-separator--vertical']);
+ expect(el).toHaveStyle('--vertical-separator-height: 5.5rem');
});
- it('should apply thickness class when no variant is used', () => {
- const { getByTestId } = renderComponent({ thickness: 2 });
- expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--thickness-2']);
+ it('applies spacing — number value', () => {
+ const { getByTestId } = renderComponent({ spacing: 1.5 });
+ const el = getByTestId('separator');
+
+ expect(el).toHaveStyle({
+ '--separator-margin-top': '1.5rem',
+ '--separator-margin-bottom': '1.5rem',
+ '--separator-margin-left': '0rem',
+ '--separator-margin-right': '0rem',
+ });
});
- it('should not apply thickness class when variant is used', () => {
- const { getByTestId } = renderComponent({ variant: 'dotted', thickness: 2 });
- expect(getByTestId('separator')).not.toHaveClass(styles['tedi-separator--thickness-2']);
+ it('applies spacing — object value', () => {
+ const { getByTestId } = renderComponent({
+ spacing: { top: 2, bottom: 0.5, left: 1 },
+ axis: 'horizontal',
+ });
+ const el = getByTestId('separator');
+
+ expect(el).toHaveStyle({
+ '--separator-margin-top': '2rem',
+ '--separator-margin-bottom': '0.5rem',
+ '--separator-margin-left': '1rem',
+ '--separator-margin-right': '0rem',
+ });
});
- it('should apply isStretched class', () => {
+ it('applies isStretched class', () => {
const { getByTestId } = renderComponent({ isStretched: true });
expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--is-stretched']);
});
- it('should set height CSS variable for vertical separator', () => {
- const { getByTestId } = renderComponent({ axis: 'vertical', height: 2 });
- expect(getByTestId('separator')).toHaveStyle('--vertical-separator-height: 2rem');
+ it('applies thickness class when no variant', () => {
+ const { getByTestId } = renderComponent({ thickness: 2 });
+ expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--thickness-2']);
});
+ it('applies dotted class and dot size', () => {
+ const { getByTestId } = renderComponent({
+ variant: 'dotted',
+ dotSize: 'small',
+ dotPosition: 'center',
+ });
+ const el = getByTestId('separator');
- it('should apply dot-only variant class', () => {
- const { getByTestId } = renderComponent({ variant: 'dot-only' });
- expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--dot-only']);
+ expect(el).toHaveClass(styles['tedi-separator--dotted']);
+ expect(el).toHaveClass(styles['tedi-separator--dotted-small']);
+ expect(el).toHaveClass(styles['tedi-separator--dot-position-center']);
});
- it('should apply correct dot size class when variant is dot-only and dotSize is extra small', () => {
- const { getByTestId } = renderComponent({ variant: 'dot-only', dotSize: 'extra-small' });
- expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--dot-only-extra-small']);
+ it('applies custom dot position via CSS var', () => {
+ const { getByTestId } = renderComponent({
+ variant: 'dotted',
+ dotPosition: 2.75,
+ });
+ expect(getByTestId('separator')).toHaveStyle('--separator-dot-position: 2.75rem');
+ expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--dot-position-custom']);
});
- it('should apply correct dot size class when variant is dot-only and dotSize is small', () => {
- const { getByTestId } = renderComponent({ variant: 'dot-only', dotSize: 'small' });
- expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--dot-only-small']);
- });
+ it('applies dot-only and dot size class', () => {
+ const { getByTestId } = renderComponent({
+ variant: 'dot-only',
+ dotSize: 'large',
+ dotStyle: 'filled',
+ });
+ const el = getByTestId('separator');
- it('should apply correct dot size class when variant is dot-only and dotSize is medium', () => {
- const { getByTestId } = renderComponent({ variant: 'dot-only', dotSize: 'medium' });
- expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--dot-only-medium']);
+ expect(el).toHaveClass(styles['tedi-separator--dot-only']);
+ expect(el).toHaveClass(styles['tedi-separator--dot-only-large']);
+ expect(el).not.toHaveClass(styles['tedi-separator--dot-style-outlined']);
});
- it('should apply correct dot size class when variant is dot-only and dotSize is large', () => {
- const { getByTestId } = renderComponent({ variant: 'dot-only', dotSize: 'large' });
- expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--dot-only-large']);
- });
+ it('applies outlined style and thickness var when outlined', () => {
+ const { getByTestId } = renderComponent({
+ variant: 'dot-only',
+ dotSize: 'medium',
+ dotStyle: 'outlined',
+ thickness: 2,
+ });
+ const el = getByTestId('separator');
- it('should not apply dot size class when variant is not dot-only', () => {
- const { getByTestId } = renderComponent({ variant: 'dotted', dotSize: 'large' });
- expect(getByTestId('separator')).not.toHaveClass(styles['tedi-separator--dot-only-large']);
+ expect(el).toHaveClass(styles['tedi-separator--dot-style-outlined']);
+ expect(el).toHaveStyle('--separator-thickness: 2px');
+ expect(el).toHaveClass(styles['tedi-separator--thickness-2']);
});
- it('should default vertical separator display to block', () => {
+ it('requires dotSize (but test fallback/default)', () => {
+ const { getByTestId } = renderComponent({
+ variant: 'dot-only',
+ dotSize: 'large',
+ });
+ expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--dot-only-large']);
+ });
+ it('defaults to block display in vertical mode', () => {
const { getByTestId } = renderComponent({ axis: 'vertical' });
expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--block']);
});
- it('should apply inline display class to vertical separator when specified', () => {
- const { getByTestId } = renderComponent({ axis: 'vertical', display: 'inline' });
- expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--inline']);
- });
-
- it('should not apply inline display class to horizontal separator', () => {
- const { getByTestId } = renderComponent({ axis: 'horizontal', display: 'block' });
- expect(getByTestId('separator')).not.toHaveClass(styles['tedi-separator--inline']);
- });
- it('should apply dotSize class when variant is dot-only', () => {
- const { getByTestId } = renderComponent({ variant: 'dot-only', dotSize: 'medium' });
- const separator = getByTestId('separator');
- expect(separator).toHaveClass(styles['tedi-separator--dot-only']);
- expect(separator).toHaveClass(styles['tedi-separator--dot-only-medium']);
- });
-
- it('should ignore dotSize when variant is not dot-only', () => {
- const { getByTestId } = renderComponent({ variant: 'dotted', dotSize: 'medium' });
- const separator = getByTestId('separator');
- expect(separator).toHaveClass(styles['tedi-separator--dotted']);
- expect(separator).not.toHaveClass(styles['tedi-separator--dot-only-medium']);
+ it('applies inline display when specified (vertical)', () => {
+ const { getByTestId } = renderComponent({
+ axis: 'vertical',
+ display: 'inline-block',
+ });
+ expect(getByTestId('separator')).toHaveClass(styles['tedi-separator--inline-block']);
});
});
diff --git a/src/tedi/components/misc/separator/separator.stories.tsx b/src/tedi/components/misc/separator/separator.stories.tsx
index 5d5a4f6f5..385b2a01d 100644
--- a/src/tedi/components/misc/separator/separator.stories.tsx
+++ b/src/tedi/components/misc/separator/separator.stories.tsx
@@ -1,11 +1,10 @@
import { Meta, StoryFn, StoryObj } from '@storybook/react';
-import { Fragment } from 'react/jsx-runtime';
import { Text } from '../../base/typography/text/text';
import { Card, CardContent } from '../../cards/card';
import { Col, Row } from '../../layout/grid';
import { VerticalSpacing } from '../../layout/vertical-spacing';
-import Separator, { SeparatorProps } from './separator';
+import Separator, { DotSize, SeparatorProps } from './separator';
/**
* Figma ↗
@@ -32,86 +31,254 @@ const meta: Meta = {
export default meta;
type Story = StoryObj;
-const colorArray: SeparatorProps['color'][] = ['primary', 'secondary', 'accent'];
+const spacingArray: SeparatorProps['spacing'][] = [0, 0.5, 1, 1.5, 2, 2.5];
+const sizeArray: SeparatorProps['dotSize'][] = ['large', 'medium'];
+type TemplateMultipleProps = SeparatorProps & {
+ array: Type[];
+ property: keyof SeparatorProps;
+};
+const Template: StoryFn = (args) => ;
-const Template: StoryFn = (args) => (
- <>
- Some content
-
- Other content
- >
-);
+const SizesTemplate: StoryFn = (args) => {
+ const { array } = args;
-const ColorsAndThickness: StoryFn = (args) => (
- <>
- {colorArray.map((color) => (
-
-
-
-
+ return (
+
+ {array.map((value, key) => (
+
+
+ {value === 'large' ? 'Large' : 'Medium'}
-
-
-
-
+
+
+
+
+
-
- ))}
- >
-);
+ ))}
+
+ );
+};
-const VerticalColorTemplate: StoryFn = (args) => (
+const ColorsAndThickness: StoryFn = (args) => (
- {colorArray.map((color) => (
-
-
-
-
-
-
-
-
-
-
- ))}
+
+
+
+
);
-const DotOnlyTemplate: StoryFn = (args) => (
+const SpacingHorizontal: StoryFn = (args) => (
-
-
-
-
+ {spacingArray.map((spacing, index) => (
+
+ ))}
);
+const SpacingVertical: StoryFn = (args) => (
+
+ {spacingArray.map((spacing, index) => (
+
+
+
+ ))}
+
+);
+
export const Default: Story = {
render: Template,
args: { spacing: 1 },
};
-export const HorizontalColors: Story = {
+export const HorizontalSpacings: Story = {
+ render: SpacingHorizontal,
+ args: {
+ axis: 'horizontal',
+ },
+};
+
+export const HorizontalThickness: Story = {
render: ColorsAndThickness,
- args: { spacing: 1 },
};
-export const VerticalColors: Story = {
- render: VerticalColorTemplate,
- args: { axis: 'vertical', height: 5 },
+export const Vertical: Story = {
+ render: Template,
+ args: { axis: 'vertical', height: 3 },
+};
+
+export const VerticalSpacings: Story = {
+ render: SpacingVertical,
+ args: {
+ axis: 'vertical',
+ height: 3,
+ display: 'inline-block',
+ },
+};
+
+export const VerticalThickness: Story = {
+ render: ColorsAndThickness,
+ args: { axis: 'vertical', height: 3, display: 'inline' },
};
-export const PaddedEven: Story = {
+export const DottedLineHorizontal: Story = {
render: Template,
- args: { spacing: 1 },
+ args: { axis: 'horizontal', variant: 'dotted', color: 'accent', dotPosition: 'center' },
};
-export const PaddedUneven: Story = {
+export const DottedLineVertical: Story = {
render: Template,
- args: { topSpacing: 2.5, bottomSpacing: 0.5 },
+ args: { axis: 'vertical', variant: 'dotted', color: 'accent', height: 5, dotPosition: 'center' },
+};
+
+export const Sizes: StoryObj = {
+ render: SizesTemplate,
+
+ args: {
+ property: 'dotSize',
+ array: sizeArray,
+ },
+};
+
+export const SpacingTopDefault: Story = {
+ render: () => {
+ return (
+
+
+
+
+
+
+
+
+ );
+ },
+};
+
+export const SpacingTopSmall: Story = {
+ render: () => {
+ return (
+
+
+
+
+
+
+
+
+ );
+ },
+};
+
+export const Position: Story = {
+ render: () => {
+ return (
+ <>
+
+
+
+ Start
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Center
+
+
+
+
+
+
+
+
+
+
+
+
+ End
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+ },
};
const TemplateVertical: StoryFn = (args) => (
@@ -137,88 +304,132 @@ const TemplateVertical: StoryFn = (args) => (
);
-export const VerticalThick: Story = {
- render: TemplateVertical,
+export const DotFilled: Story = {
+ render: () => {
+ return (
+ <>
+
+ >
+ );
+ },
+};
+
+export const DotOutlined: Story = {
+ render: () => {
+ return (
+ <>
+
+ >
+ );
+ },
+};
+
+const dotSizeToPxMap: Record = {
+ xs: '2px',
+ sm: '4px',
+ md: '8px',
+ lg: '15px',
+};
+
+const DottedSizesTemplate: StoryFn = (args) => {
+ const { array } = args;
+
+ return (
+
+ {array.map((value, key) => (
+
+
+ {value !== undefined ? dotSizeToPxMap[value] || value : '—'}
+
+
+
+
+
+
+
+
+ ))}
+
+ );
+};
+
+export const DottedSizes: StoryObj = {
+ render: DottedSizesTemplate,
args: {
- axis: 'horizontal',
- thickness: 1,
- isStretched: true,
- topSpacing: 1,
- bottomSpacing: 1,
- md: { axis: 'vertical', thickness: 1 },
+ property: 'dotSize',
+ array: ['extra-small', 'small', 'medium', 'large'],
},
};
-export const VerticalDotted: Story = {
+const InlineSeparatorTemplate: StoryFn = (args) => {
+ const { dotPosition, ...safeArgs } = args;
+
+ return (
+ <>
+
+ Lorem ipsum dolor sit, amet
+
+ consectetur adipisicing elit.
+
+
+ Lorem ipsum dolor sit, amet
+
+ consectetur adipisicing elit.
+
+
+ Lorem ipsum dolor sit, amet
+
+ consectetur adipisicing elit.
+
+
+ Lorem ipsum dolor sit, amet
+
+ consectetur adipisicing elit.
+
+ >
+ );
+};
+
+export const InlineSeparatorUsage: Story = {
+ render: InlineSeparatorTemplate,
+ args: { axis: 'vertical', display: 'inline' },
+};
+
+export const VerticalDottedCardExample: Story = {
render: TemplateVertical,
args: {
axis: 'horizontal',
variant: 'dotted',
color: 'accent',
- topSpacing: 1,
- bottomSpacing: 1,
+ spacing: 1,
isStretched: true,
+ dotPosition: 1.25,
md: { axis: 'vertical' },
},
};
-export const VerticalDottedSmall: Story = {
+export const VerticalDottedSmallCardExample: Story = {
render: TemplateVertical,
args: {
axis: 'horizontal',
- topSpacing: 1,
- bottomSpacing: 1,
- variant: 'dotted-small',
+ spacing: 1,
+ variant: 'dotted',
+ dotSize: 'medium',
color: 'accent',
isStretched: true,
+ dotPosition: 1.25,
md: { axis: 'vertical' },
},
};
-
-export const HorizontalDottedSeparator: Story = {
- render: () => (
-
-
-
-
-
-
-
-
- ),
-};
-
-export const DotOnly: Story = {
- render: DotOnlyTemplate,
- args: { spacing: 0.5 },
-};
-
-const InlineSeparatorTemplate: StoryFn = (args) => (
-
-
- Lorem ipsum dolor sit, amet
-
- consectetur adipisicing elit.
-
-
- Lorem ipsum dolor sit, amet
-
- consectetur adipisicing elit.
-
-
- Lorem ipsum dolor sit, amet
-
- consectetur adipisicing elit.
-
-
- Lorem ipsum dolor sit, amet
-
- consectetur adipisicing elit.
-
-
-);
-
-export const InlineSeparatorUsedInText: Story = {
- render: InlineSeparatorTemplate,
- args: { axis: 'vertical', display: 'inline' },
-};
diff --git a/src/tedi/components/misc/separator/separator.tsx b/src/tedi/components/misc/separator/separator.tsx
index bcf4f7682..d343f08b3 100644
--- a/src/tedi/components/misc/separator/separator.tsx
+++ b/src/tedi/components/misc/separator/separator.tsx
@@ -4,154 +4,201 @@ import { CSSProperties } from 'react';
import { BreakpointSupport, useBreakpointProps } from '../../../helpers';
import styles from './separator.module.scss';
-export type SeparatorSpacing = 0 | 0.25 | 0.5 | 0.75 | 1 | 1.25 | 1.5 | 1.75 | 2 | 2.5 | 5;
+export type SeparatorVariant = 'dotted' | 'dot-only';
+export type DotSize = 'large' | 'medium' | 'small' | 'extra-small';
+export type DotStyle = 'filled' | 'outlined';
+export type DotPosition = 'start' | 'center' | 'end' | number;
+
+/**
+ * Margin/padding-like spacing around the separator
+ * - number → uniform spacing on main axis
+ * - object → fine-grained control (top/bottom/left/right)
+ */
+export type SeparatorSpacing =
+ | number
+ | {
+ top?: number;
+ bottom?: number;
+ left?: number;
+ right?: number;
+ };
export interface SeparatorSharedProps {
/**
- * Additional class.
+ * Additional class names
*/
className?: string;
/**
- * Rendered HTML element.
- * @default div
+ * HTML element to render — most common are 'hr', 'div', 'span'
*/
element?: 'hr' | 'div' | 'span';
/**
- * Whether the separator should stretch to fill the full spacing inside cardContent.
+ * When true, the separator stretches to fill available space (100%)
*/
isStretched?: boolean;
- /*
- * Color of separator
- * @default default
+ /**
+ * Semantic color token
+ * @default primary
*/
color?: 'primary' | 'secondary' | 'accent';
- /*
- * Separator style variant.
- */
- variant?: 'dotted' | 'dotted-small' | 'dot-only';
- /*
- * Dot size.
- * Only used when variant="dot-only"
+ /**
+ * Visual style — line with dots vs standalone centered dot(s)
*/
- dotSize?: 'large' | 'medium' | 'small' | 'extra-small';
- /*
- * Thickness in pixels (ignored if variant is used).
- * @default 1
+ variant?: SeparatorVariant;
+ /**
+ * Line thickness in pixels (1 or 2) — affects outlined & solid lines
*/
thickness?: 1 | 2;
/**
- * Spacing applied based on the axis:
- * - For horizontal axis, spacing is applied to top and bottom of the separator.
- * - For vertical axis, spacing is applied to left and right of the separator.
+ * Spacing (margin) around the separator
+ * @example
+ * spacing={16} // 16px top & bottom (horizontal) or left & right (vertical)
+ * spacing={{ top: 24, bottom: 8 }}
*/
spacing?: SeparatorSpacing;
}
-
export interface SeparatorVerticalProps extends SeparatorSharedProps {
/**
- * Height of separator. Use with vertical axis, when full-width separator is not needed.
- * Height can be number in rem units. It's customizable to allow for more flexibility around X components.
+ * Must be set to 'vertical'
+ */
+ axis: 'vertical';
+ /**
+ * Height of the vertical separator in rem units
*/
height?: number;
/**
- * Axis of separator, vertical and horizontal separators support different props
+ * CSS display value — usually 'block' or 'inline-block'
*/
- axis: 'vertical';
- topSpacing?: undefined;
- bottomSpacing?: undefined;
- display?: 'block' | 'inline';
+ display?: 'block' | 'inline' | 'inline-block';
}
-
export interface SeparatorHorizontalProps extends SeparatorSharedProps {
/**
- * Spacing on top of separator. Ignored when spacing is also used. Only for horizontal axis.
+ * Must be set to 'horizontal' or left undefined (defaults to horizontal)
*/
- topSpacing?: SeparatorSpacing;
+ axis?: 'horizontal';
/**
- * Spacing on bottom of separator. Ignored when spacing is also used. Only for horizontal axis.
- */
- bottomSpacing?: SeparatorSpacing;
+ Vertical height is not used in horizontal mode
+ */
+ height?: undefined;
/**
- * Axis of separator, vertical and horizontal separators support different props
+ * Display is forced to 'block' in horizontal mode
*/
- axis?: 'horizontal';
- height?: undefined;
display?: 'block';
}
-export type SeparatorBreakpointProps = {
- /**
- * Spacing values based on breakpoints.
- */
- spacing?: Omit;
+type DottedSeparatorProps = {
+ variant?: 'dotted';
+ dotSize?: DotSize;
+ dotStyle?: DotStyle;
/**
- * Height values based on breakpoints (for vertical separators).
+ * Position of the single dot
+ * @example
+ * 'center' | 'start' | 'end' | 2.5 // 2.5rem from start
*/
- height?: Omit;
+ dotPosition?: DotPosition;
+};
+
+type DotOnlySeparatorProps = {
+ variant: 'dot-only';
+ dotSize: DotSize;
+ dotStyle?: DotStyle;
+ dotPosition?: never;
+};
+
+export type SeparatorBreakpointProps = {
+ spacing?: SeparatorSpacing;
+ height?: number;
axis?: 'horizontal' | 'vertical';
};
export type SeparatorProps = BreakpointSupport<
- | (
- | SeparatorHorizontalProps
- | (SeparatorVerticalProps & {
- variant?: 'dotted' | 'dotted-small';
- dotSize?: undefined;
- })
- )
- | (
- | SeparatorHorizontalProps
- | (SeparatorVerticalProps & {
- variant: 'dot-only';
- dotSize: 'large' | 'medium' | 'small' | 'extra-small';
- })
- )
+ | (SeparatorHorizontalProps & (DottedSeparatorProps | DotOnlySeparatorProps))
+ | (SeparatorVerticalProps & (DottedSeparatorProps | DotOnlySeparatorProps))
> &
SeparatorBreakpointProps;
export const Separator = (props: SeparatorProps): JSX.Element => {
const { getCurrentBreakpointProps } = useBreakpointProps(props.defaultServerBreakpoint);
+
const {
className,
element: Element = 'div',
isStretched,
spacing,
- topSpacing,
- bottomSpacing,
axis = 'horizontal',
- color = 'default',
+ color = 'primary',
variant,
thickness = 1,
height,
- dotSize,
+ dotSize = 'large',
+ dotStyle = 'filled',
+ dotPosition,
display = 'block',
...rest
} = getCurrentBreakpointProps(props);
+ const isNumericDotPosition = typeof dotPosition === 'number';
+ const resolvedDotPosition = variant !== 'dot-only' && !isNumericDotPosition ? dotPosition : undefined;
+
+ let top = 0;
+ let bottom = 0;
+ let left = 0;
+ let right = 0;
+
+ if (typeof spacing === 'number') {
+ if (axis === 'horizontal') {
+ top = bottom = spacing;
+ } else {
+ left = right = spacing;
+ }
+ }
+
+ if (typeof spacing === 'object' && spacing !== null) {
+ top = spacing.top ?? top;
+ bottom = spacing.bottom ?? bottom;
+ left = spacing.left ?? left;
+ right = spacing.right ?? right;
+ }
+
const SeparatorBEM = cn(
styles['tedi-separator'],
className,
- { [styles[`tedi-separator--${color}`]]: color },
- { [styles[`tedi-separator--${axis}`]]: axis },
- { [styles[`tedi-separator--${variant}`]]: variant },
- { [styles[`tedi-separator--${display}`]]: display },
- { [styles[`tedi-separator--${variant}-${dotSize}`]]: variant && dotSize },
- { [styles[`tedi-separator--thickness-${thickness}`]]: thickness && !variant },
- { [styles['tedi-separator--is-stretched']]: isStretched },
- { [styles[`tedi-separator--spacing-${spacing}`.replace('.', '-')]]: spacing },
- { [styles[`tedi-separator--top-${topSpacing}`.replace('.', '-')]]: !spacing && topSpacing },
- { [styles[`tedi-separator--bottom-${bottomSpacing}`.replace('.', '-')]]: !spacing && bottomSpacing }
+ styles[`tedi-separator--${axis}`],
+ styles[`tedi-separator--${color}`],
+ {
+ [styles[`tedi-separator--${variant}`]]: variant,
+ [styles[`tedi-separator--${display}`]]: display,
+ [styles[`tedi-separator--dotted-${dotSize}`]]: variant === 'dotted',
+ [styles[`tedi-separator--dot-only-${dotSize}`]]: variant === 'dot-only',
+ [styles[`tedi-separator--dot-style-${dotStyle}`]]: variant,
+ [styles[`tedi-separator--dot-position-${resolvedDotPosition}`]]:
+ typeof resolvedDotPosition === 'string' && variant !== 'dot-only',
+ [styles['tedi-separator--dot-position-custom']]: isNumericDotPosition,
+ [styles['tedi-separator--is-stretched']]: isStretched,
+ [styles[`tedi-separator--thickness-${thickness}`]]: thickness || dotStyle === 'outlined' ? thickness : undefined,
+ }
);
- const getCssVars = () => {
- const cssvars: CSSProperties = {};
+ const cssVars: CSSProperties = {
+ '--separator-margin-top': `${top}rem`,
+ '--separator-margin-bottom': `${bottom}rem`,
+ '--separator-margin-left': `${left}rem`,
+ '--separator-margin-right': `${right}rem`,
+ } as CSSProperties;
+
+ if (height) {
+ cssVars['--vertical-separator-height'] = `${height}rem`;
+ }
- if (height) cssvars['--vertical-separator-height'] = `${height}rem`;
+ if (thickness) {
+ cssVars['--separator-thickness'] = `${thickness}px`;
+ }
- return cssvars;
- };
+ if (variant === 'dotted' && isNumericDotPosition) {
+ cssVars['--separator-dot-position'] = `${dotPosition}rem`;
+ }
- return ;
+ return ;
};
export default Separator;
diff --git a/src/tedi/components/notifications/alert/alert.module.scss b/src/tedi/components/notifications/alert/alert.module.scss
index e84a27354..ba7710e83 100644
--- a/src/tedi/components/notifications/alert/alert.module.scss
+++ b/src/tedi/components/notifications/alert/alert.module.scss
@@ -5,8 +5,6 @@
}
.tedi-alert {
- padding: var(--alert-default-padding-y) var(--alert-default-padding-x);
- font-size: var(--body-regular-size);
border: 1px solid;
border-radius: var(--alert-radius);
@@ -14,14 +12,32 @@
&__content {
display: flex;
- gap: var(--layout-grid-gutters-08);
- align-items: flex-start;
+ align-self: center;
.tedi-alert__icon {
line-height: var(--body-regular-line-height);
}
}
+ &--size-default {
+ padding: var(--alert-default-padding-y) var(--alert-default-padding-x);
+ font-size: var(--body-regular-size);
+
+ .tedi-alert__content {
+ gap: var(--layout-grid-gutters-08);
+ }
+ }
+
+ &--size-small {
+ padding: var(--alert-default-padding-y-sm) var(--alert-default-padding-x-sm);
+ font-size: var(--body-small-regular-size);
+ line-height: var(--body-small-regular-line-height);
+
+ .tedi-alert__content {
+ gap: var(--layout-grid-gutters-04);
+ }
+ }
+
&--info {
@include alert-variant(var(--alert-default-background-info), var(--alert-default-border-info));
}
diff --git a/src/tedi/components/notifications/alert/alert.spec.tsx b/src/tedi/components/notifications/alert/alert.spec.tsx
index 336858a85..ae944d37d 100644
--- a/src/tedi/components/notifications/alert/alert.spec.tsx
+++ b/src/tedi/components/notifications/alert/alert.spec.tsx
@@ -118,4 +118,23 @@ describe('Alert component', () => {
const title = screen.getByText(text);
expect(title.tagName).toBe(level.toUpperCase());
});
+
+ it('renders with small size and applies correct size class', () => {
+ render(Small Alert);
+
+ const alert = screen.getByRole('alert');
+ expect(alert).toHaveClass('tedi-alert--size-small');
+ });
+
+ it('renders danger alert with small size', () => {
+ render(
+
+ Danger Small Alert
+
+ );
+
+ const alert = screen.getByRole('alert');
+ expect(alert).toHaveClass('tedi-alert--danger');
+ expect(alert).toHaveClass('tedi-alert--size-small');
+ });
});
diff --git a/src/tedi/components/notifications/alert/alert.stories.tsx b/src/tedi/components/notifications/alert/alert.stories.tsx
index ca3d894ff..51d7a59f4 100644
--- a/src/tedi/components/notifications/alert/alert.stories.tsx
+++ b/src/tedi/components/notifications/alert/alert.stories.tsx
@@ -1,5 +1,7 @@
import { Meta, StoryFn, StoryObj } from '@storybook/react';
+import { Text } from '../../base/typography/text/text';
+import { Col, Row } from '../../layout/grid';
import { VerticalSpacing } from '../../layout/vertical-spacing';
import Link from '../../navigation/link/link';
import Alert, { AlertProps } from '../alert/alert';
@@ -36,6 +38,8 @@ const alertTypes: { type: AlertProps['type']; icon: string }[] = [
{ type: 'danger', icon: 'error' },
];
+const sizeArray: AlertProps['size'][] = ['default', 'small'];
+
const TypesTemplate: StoryFn = (args) => (
{alertTypes.map(({ type, icon }) => (
@@ -46,6 +50,31 @@ const TypesTemplate: StoryFn = (args) => (
);
+interface TemplateMultipleProps extends AlertProps {
+ array: Type[];
+}
+
+const TemplateColumn: StoryFn = (args) => {
+ const { array, ...alertProps } = args;
+
+ return (
+
+ {array.map((value, key) => (
+
+
+ {value ? value.charAt(0).toUpperCase() + value.slice(1) : ''}
+
+
+
+ Content description
+
+
+
+ ))}
+
+ );
+};
+
const Template: StoryFn = (args) => ;
export const Default: Story = {
args: {
@@ -69,6 +98,15 @@ const WithAndWithoutHeading: StoryFn = (args) => {
);
};
+export const Sizes: StoryObj = {
+ render: TemplateColumn,
+ args: {
+ array: sizeArray,
+ type: 'info',
+ children: 'Content description',
+ onClose: () => null,
+ },
+};
export const Headless: Story = {
render: Template,
args: {
diff --git a/src/tedi/components/notifications/alert/alert.tsx b/src/tedi/components/notifications/alert/alert.tsx
index a926d0aa6..911e5826c 100644
--- a/src/tedi/components/notifications/alert/alert.tsx
+++ b/src/tedi/components/notifications/alert/alert.tsx
@@ -29,6 +29,13 @@ type AlertBreakpointProps = {
* @default false
*/
noSideBorders?: boolean;
+ /**
+ * Alert size variant.
+ * - 'default': Standard alert size with padding and border radius.
+ * - 'small': More compact alert size with reduced padding.
+ * @default default
+ */
+ size?: 'default' | 'small';
};
export interface AlertProps extends BreakpointSupport {
@@ -79,7 +86,7 @@ export interface AlertProps extends BreakpointSupport {
* // For secondary notifications
* titleElement="h4"
*
- * @default 'h3'
+ * @default h3
*/
titleElement?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
}
@@ -97,12 +104,14 @@ export const Alert = (props: AlertProps): JSX.Element | null => {
isGlobal = false,
noSideBorders = false,
titleElement = 'h3',
+ size = 'default',
...rest
} = getCurrentBreakpointProps(props);
const alertBEM = cn(
styles['tedi-alert'],
styles[`tedi-alert--${type}`],
+ styles[`tedi-alert--size-${size}`],
{
[styles['tedi-alert--global']]: isGlobal,
[styles['tedi-alert--no-side-borders']]: noSideBorders,
@@ -149,7 +158,7 @@ export const Alert = (props: AlertProps): JSX.Element | null => {
{onClose && (
-
+
)}
diff --git a/src/tedi/components/overlays/overlay/overlay-content.tsx b/src/tedi/components/overlays/overlay/overlay-content.tsx
index 9b49ec2b8..0008458c6 100644
--- a/src/tedi/components/overlays/overlay/overlay-content.tsx
+++ b/src/tedi/components/overlays/overlay/overlay-content.tsx
@@ -61,6 +61,7 @@ export const OverlayContent = (props: OverlayContentProps) => {
context,
arrow,
scrollLock,
+ contentId,
} = useContext(OverlayContext);
useEffect(() => {
@@ -88,6 +89,7 @@ export const OverlayContent = (props: OverlayContentProps) => {
{...getFloatingProps({
ref: floating,
tabIndex: -1,
+ id: contentId,
'aria-labelledby': labelledBy,
'aria-describedby': describedBy,
style: {
diff --git a/src/tedi/components/overlays/overlay/overlay-trigger.spec.tsx b/src/tedi/components/overlays/overlay/overlay-trigger.spec.tsx
new file mode 100644
index 000000000..d82fb26e3
--- /dev/null
+++ b/src/tedi/components/overlays/overlay/overlay-trigger.spec.tsx
@@ -0,0 +1,126 @@
+import { render, screen } from '@testing-library/react';
+
+import { useLabels } from '../../../providers/label-provider';
+import { Icon } from '../../base/icon/icon';
+import Button from '../../buttons/button/button';
+import Overlay from './overlay';
+import { OverlayTrigger } from './overlay-trigger';
+
+jest.mock('../../../providers/label-provider', () => ({
+ useLabels: jest.fn(() => ({
+ getLabel: jest.fn((key) => `Mocked Label for ${key}`),
+ })),
+}));
+
+jest.mock('../../../helpers', () => ({
+ ...jest.requireActual('../../../helpers'),
+ useIsTouchDevice: jest.fn(),
+ useIsMounted: jest.fn(() => true),
+}));
+
+describe('Overlay.Trigger', () => {
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('applies correct class names when children is text', () => {
+ render(
+
+ Click me
+ Content
+
+ );
+
+ const trigger = screen.getByText('Click me');
+
+ expect(trigger).toHaveClass('tedi-overlay__trigger');
+ expect(trigger).toHaveClass('tedi-overlay__trigger--text');
+ expect(trigger).toHaveClass('my-extra-class');
+ });
+
+ it('applies correct aria attributes when child is an Icon', () => {
+ const { getLabel } = useLabels();
+
+ render(
+
+
+
+
+ Content
+
+ );
+
+ const icon = screen.getByTestId('icon-child');
+ expect(icon).toHaveAttribute('aria-label', getLabel('tooltip.icon-trigger'));
+ });
+
+ it('does NOT apply aria-label when child is not an Icon', () => {
+ const { getLabel } = useLabels();
+
+ render(
+
+
+
+
+ Content
+
+ );
+
+ const btn = screen.getByTestId('btn-child');
+ expect(btn).not.toHaveAttribute('aria-label', getLabel('tooltip.icon-trigger'));
+ });
+
+ it('adds tabindex=0 to non-Icon valid elements (cloneElement path)', () => {
+ render(
+
+
+ Hover me
+
+ Content
+
+ );
+
+ const span = screen.getByTestId('span-child');
+ expect(span).toHaveAttribute('tabindex', '0');
+ });
+
+ it('does NOT add aria-describedby when role is not "tooltip"', () => {
+ render(
+
+
+ Trigger
+
+ Dialog content
+
+ );
+
+ const trigger = screen.getByTestId('trigger-dialog');
+ expect(trigger).not.toHaveAttribute('aria-describedby');
+ });
+
+ it.each([
+ { role: 'tooltip' as const, open: true, expectDescribedBy: true },
+ { role: 'tooltip' as const, open: false, expectDescribedBy: false },
+ { role: 'dialog' as const, open: true, expectDescribedBy: false },
+ ])('aria-describedby behavior - role=$role open=$open → $expectDescribedBy', ({ role, open, expectDescribedBy }) => {
+ const onToggle = jest.fn();
+
+ render(
+
+
+ Trigger
+
+ Content
+
+ );
+
+ const trigger = screen.getByTestId('trigger');
+
+ if (expectDescribedBy) {
+ const content = screen.getByTestId('overlay-content');
+ expect(trigger).toHaveAttribute('aria-describedby', content.id);
+ } else {
+ expect(trigger).not.toHaveAttribute('aria-describedby');
+ }
+ });
+});
diff --git a/src/tedi/components/overlays/overlay/overlay-trigger.tsx b/src/tedi/components/overlays/overlay/overlay-trigger.tsx
index 9fb4dc97e..936305cba 100644
--- a/src/tedi/components/overlays/overlay/overlay-trigger.tsx
+++ b/src/tedi/components/overlays/overlay/overlay-trigger.tsx
@@ -21,9 +21,15 @@ export interface OverlayTriggerProps {
export const OverlayTrigger = (props: OverlayTriggerProps) => {
const { children, className } = props;
const { getLabel } = useLabels();
- const { getReferenceProps, reference, openWith } = useContext(OverlayContext);
+ const { getReferenceProps, reference, openWith, open, role, contentId } = useContext(OverlayContext);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const refs = useMergeRefs([reference, (children as React.ComponentPropsWithRef).ref]);
+ const extraProps =
+ role === 'tooltip'
+ ? {
+ 'aria-describedby': open ? contentId : undefined,
+ }
+ : {};
if (isValidElement(children)) {
return cloneElement(
@@ -31,6 +37,7 @@ export const OverlayTrigger = (props: OverlayTriggerProps) => {
getReferenceProps({
ref: refs,
tabIndex: 0,
+ ...extraProps,
label: children.type === Icon ? getLabel('tooltip.icon-trigger') : undefined,
...children.props,
})
@@ -50,6 +57,7 @@ export const OverlayTrigger = (props: OverlayTriggerProps) => {
},
className
),
+ ...extraProps,
})}
>
{children}
diff --git a/src/tedi/components/overlays/overlay/overlay.spec.tsx b/src/tedi/components/overlays/overlay/overlay.spec.tsx
index c9c38bf48..34ef8eef7 100644
--- a/src/tedi/components/overlays/overlay/overlay.spec.tsx
+++ b/src/tedi/components/overlays/overlay/overlay.spec.tsx
@@ -207,4 +207,49 @@ describe('Overlay component', () => {
expect(document.body.style.overflow).toBe('');
});
});
+
+ it('does NOT add aria-label when child is valid element but NOT an Icon (cloneElement path)', () => {
+ const { getLabel } = useLabels();
+
+ render(
+
+
+ Hover me
+
+ Content
+
+ );
+
+ const span = screen.getByTestId('span-child');
+
+ expect(span).toHaveAttribute('tabindex', '0');
+ expect(span).not.toHaveAttribute('aria-label');
+ expect(span).not.toHaveAttribute('aria-label', getLabel('tooltip.icon-trigger'));
+ });
+
+ it('removes aria-describedby when tooltip is closed', async () => {
+ render(
+
+
+ Trigger div
+
+ Hidden tooltip
+
+ );
+
+ const trigger = screen.getByTestId('div-trigger');
+ expect(trigger).not.toHaveAttribute('aria-describedby');
+
+ await act(async () => {
+ fireEvent.mouseEnter(trigger);
+ });
+
+ expect(trigger).toHaveAttribute('aria-describedby');
+
+ await act(async () => {
+ fireEvent.mouseLeave(trigger);
+ });
+
+ expect(trigger).not.toHaveAttribute('aria-describedby');
+ });
});
diff --git a/src/tedi/components/overlays/overlay/overlay.tsx b/src/tedi/components/overlays/overlay/overlay.tsx
index 279258685..338062c87 100644
--- a/src/tedi/components/overlays/overlay/overlay.tsx
+++ b/src/tedi/components/overlays/overlay/overlay.tsx
@@ -20,7 +20,7 @@ import {
useRole,
UseRoleProps,
} from '@floating-ui/react';
-import { ComponentProps, createContext, ReactNode, useCallback, useMemo, useRef, useState } from 'react';
+import { ComponentProps, createContext, ReactNode, useCallback, useId, useMemo, useRef, useState } from 'react';
import { useIsMounted, useIsTouchDevice } from '../../../helpers';
import { OverlayContent } from './overlay-content';
@@ -117,6 +117,8 @@ export interface OverlayContextType {
placement: Placement;
context: FloatingContext;
scrollLock?: boolean;
+ role?: UseRoleProps['role'];
+ contentId: string;
}
export const OverlayContext = createContext({
@@ -143,6 +145,7 @@ export const OverlayContext = createContext({
placement: 'top',
context: {} as FloatingContext,
scrollLock: undefined,
+ contentId: '',
});
export const Overlay = (props: OverlayProps) => {
@@ -220,42 +223,70 @@ export const Overlay = (props: OverlayProps) => {
}),
]);
- return (
-
- {children}
-
+ const contentId = useId();
+ const contextValue = useMemo(
+ () => ({
+ open: isOpen,
+ onOpenChange,
+ isMounted,
+ openWith,
+ focusManager: focusManager
+ ? {
+ order,
+ modal,
+ initialFocus: resolvedInitialFocus,
+ ...restFocusManager,
+ }
+ : undefined,
+ reference: refs.setReference,
+ floating: refs.setFloating,
+ arrowRef,
+ x,
+ y,
+ strategy,
+ getReferenceProps,
+ getFloatingProps,
+ arrow: {
+ width: arrowDimensions?.width,
+ height: arrowDimensions?.height,
+ ...middlewareData.arrow,
+ },
+ context,
+ placement,
+ scrollLock,
+ role,
+ contentId,
+ }),
+ [
+ isOpen,
+ onOpenChange,
+ isMounted,
+ openWith,
+ focusManager,
+ refs.setReference,
+ refs.setFloating,
+ arrowRef,
+ x,
+ y,
+ strategy,
+ getReferenceProps,
+ getFloatingProps,
+ arrowDimensions?.width,
+ arrowDimensions?.height,
+ middlewareData.arrow,
+ context,
+ placement,
+ scrollLock,
+ role,
+ contentId,
+ modal,
+ order,
+ resolvedInitialFocus,
+ restFocusManager,
+ ]
);
+
+ return {children};
};
Overlay.Trigger = OverlayTrigger;
diff --git a/src/tedi/components/overlays/popover/popover-content.tsx b/src/tedi/components/overlays/popover/popover-content.tsx
index 1086962e4..0dedfac18 100644
--- a/src/tedi/components/overlays/popover/popover-content.tsx
+++ b/src/tedi/components/overlays/popover/popover-content.tsx
@@ -45,7 +45,7 @@ export const PopoverContent = (props: PopoverContentProps) => {
title,
titleProps = { element: 'h4' },
close,
- closeProps = { size: 'large' },
+ closeProps = { size: 'default' },
} = props;
const { onOpenChange } = useContext(OverlayContext);
const titleId = useId();
diff --git a/src/tedi/components/overlays/tooltip/tooltip.tsx b/src/tedi/components/overlays/tooltip/tooltip.tsx
index 916df9ef9..554435b69 100644
--- a/src/tedi/components/overlays/tooltip/tooltip.tsx
+++ b/src/tedi/components/overlays/tooltip/tooltip.tsx
@@ -22,7 +22,7 @@ export interface TooltipProps
}
export const Tooltip = (props: TooltipProps) => {
- const { openWith = 'hover', ...rest } = props;
+ const { openWith = 'hover', focusManager, ...rest } = props;
return (
{
height: ARROW_HEIGHT,
}}
openWith={openWith}
+ role="tooltip"
+ focusManager={{
+ modal: false,
+ order: ['reference', 'content'],
+ returnFocus: true,
+ ...focusManager,
+ }}
{...rest}
/>
);
diff --git a/src/tedi/components/tags/tag/tag.tsx b/src/tedi/components/tags/tag/tag.tsx
index 61405973e..ed1194a15 100644
--- a/src/tedi/components/tags/tag/tag.tsx
+++ b/src/tedi/components/tags/tag/tag.tsx
@@ -71,7 +71,7 @@ export const Tag = (props: TagProps): JSX.Element => {
)}
- {!isLoading && onClose &&
}
+ {!isLoading && onClose &&
}
);
};
diff --git a/src/community/docs/scale-layout/breaking-points.tsx b/src/tedi/docs/scale-layout/breaking-points.tsx
similarity index 96%
rename from src/community/docs/scale-layout/breaking-points.tsx
rename to src/tedi/docs/scale-layout/breaking-points.tsx
index 174567782..ccb5c4244 100644
--- a/src/community/docs/scale-layout/breaking-points.tsx
+++ b/src/tedi/docs/scale-layout/breaking-points.tsx
@@ -1,7 +1,7 @@
import { ColumnDef, createColumnHelper } from '@tanstack/react-table';
-import { Text } from '../../../tedi/components/base/typography/text/text';
-import { Breakpoint, CustomizeTableCell, getBackgroundColorClass, Table } from '../../index';
+import { Breakpoint, CustomizeTableCell, getBackgroundColorClass, Table } from '../../../community/index';
+import { Text } from '../../components/base/typography/text/text';
interface BreakpointRow {
type: 'mobile' | 'tablet' | 'desktop';
diff --git a/src/community/docs/scale-layout/grid.mdx b/src/tedi/docs/scale-layout/grid.mdx
similarity index 59%
rename from src/community/docs/scale-layout/grid.mdx
rename to src/tedi/docs/scale-layout/grid.mdx
index 907fc622f..6d4bb22fd 100644
--- a/src/community/docs/scale-layout/grid.mdx
+++ b/src/tedi/docs/scale-layout/grid.mdx
@@ -1,7 +1,7 @@
import { Meta, Title, Subtitle, Unstyled } from '@storybook/blocks';
import Grid from './grid.tsx';
-
+
diff --git a/src/community/docs/scale-layout/grid.tsx b/src/tedi/docs/scale-layout/grid.tsx
similarity index 92%
rename from src/community/docs/scale-layout/grid.tsx
rename to src/tedi/docs/scale-layout/grid.tsx
index e89db1d09..04998c322 100644
--- a/src/community/docs/scale-layout/grid.tsx
+++ b/src/tedi/docs/scale-layout/grid.tsx
@@ -1,9 +1,9 @@
import { Title } from '@storybook/blocks';
-import { Heading } from '../../../tedi/components/base/typography/heading/heading';
-import { Col, Row } from '../../../tedi/components/layout/grid';
-import { VerticalSpacing } from '../../../tedi/components/layout/vertical-spacing';
-import { Separator } from '../../../tedi/components/misc/separator/separator';
+import { Heading } from '../../components/base/typography/heading/heading';
+import { Col, Row } from '../../components/layout/grid';
+import { VerticalSpacing } from '../../components/layout/vertical-spacing';
+import { Separator } from '../../components/misc/separator/separator';
import BreakingpointsTable from './breaking-points';
const Grid = () => {
diff --git a/src/community/docs/scale-layout/spacing.mdx b/src/tedi/docs/scale-layout/spacing.mdx
similarity index 60%
rename from src/community/docs/scale-layout/spacing.mdx
rename to src/tedi/docs/scale-layout/spacing.mdx
index 547603667..4dd24520b 100644
--- a/src/community/docs/scale-layout/spacing.mdx
+++ b/src/tedi/docs/scale-layout/spacing.mdx
@@ -2,7 +2,7 @@ import { Meta, Unstyled } from '@storybook/blocks';
import Spacing from './spacing.tsx';
-
+
diff --git a/src/community/docs/scale-layout/spacing.tsx b/src/tedi/docs/scale-layout/spacing.tsx
similarity index 88%
rename from src/community/docs/scale-layout/spacing.tsx
rename to src/tedi/docs/scale-layout/spacing.tsx
index f22458635..03fe96afa 100644
--- a/src/community/docs/scale-layout/spacing.tsx
+++ b/src/tedi/docs/scale-layout/spacing.tsx
@@ -1,11 +1,11 @@
import { Title } from '@storybook/blocks';
import { ColumnDef, createColumnHelper } from '@tanstack/react-table';
-import { Heading } from '../../../tedi/components/base/typography/heading/heading';
-import { Col, Row } from '../../../tedi/components/layout/grid';
-import { VerticalSpacing } from '../../../tedi/components/layout/vertical-spacing';
-import { Separator } from '../../../tedi/components/misc/separator/separator';
-import { Table } from '../../index';
+import { Table } from '../../../community/index';
+import { Heading } from '../../components/base/typography/heading/heading';
+import { Col, Row } from '../../components/layout/grid';
+import { VerticalSpacing } from '../../components/layout/vertical-spacing';
+import { Separator } from '../../components/misc/separator/separator';
const Spacing = () => {
return (