diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/hover/firefox/hover.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/hover/firefox/hover.png new file mode 100644 index 00000000000..951b3e416b6 --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/hover/firefox/hover.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:088f722f18aa990b22dc9b391b494957c38f9f596c75d4d329f382768489e9c0 +size 1774 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/hover/firefox2022/hover.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/hover/firefox2022/hover.png new file mode 100644 index 00000000000..7ce2481f0b1 --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/hover/firefox2022/hover.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:941a54965451987d524dae2a678b78af0d30bf5284798fa8c2be63c4d022cfa6 +size 1961 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/hover/firefox2022Dark/hover.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/hover/firefox2022Dark/hover.png new file mode 100644 index 00000000000..9f8d828c5a9 --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/hover/firefox2022Dark/hover.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:12ec4e01e502d01cec02b70a679bf2d8ab00462a714c67697268d0efe05dd037 +size 1937 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/hover/firefox8px/hover.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/hover/firefox8px/hover.png new file mode 100644 index 00000000000..cd1b79e7316 --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/hover/firefox8px/hover.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:058e613fd88da37b6dfc8df072bfd118035e4c5388a550fc99bbc47b653314c7 +size 2098 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/hover/firefoxDark/hover.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/hover/firefoxDark/hover.png new file mode 100644 index 00000000000..6f033090bc1 --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/hover/firefoxDark/hover.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95e63273318a2872b3ec83ac4f10cf14572fa9f377b1f7e56bd692c8299a6ba4 +size 1769 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/hover/firefoxFlat8px/hover.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/hover/firefoxFlat8px/hover.png new file mode 100644 index 00000000000..a18298d9043 --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/hover/firefoxFlat8px/hover.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:35923a4c0ad0935dd737169c93ca25725e9e5269a678b7a15862cd6878a04a51 +size 1771 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/chrome/idle.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/chrome/idle.png new file mode 100644 index 00000000000..2e8e060c40f --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/chrome/idle.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f72b2d324f826eb6cc5889b70ae2d40726081677d51e1ac641c0455b8276245e +size 1672 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/chrome2022/idle.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/chrome2022/idle.png new file mode 100644 index 00000000000..b1d7b5f7d77 --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/chrome2022/idle.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4ef057723203d9c5330c4b60d3ad40b81d6c51d3228eb2130513a32fb27f10ea +size 1961 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/chrome2022Dark/idle.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/chrome2022Dark/idle.png new file mode 100644 index 00000000000..5a69ef17869 --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/chrome2022Dark/idle.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:197f5dccf1076e1f5e62a1627314a5894e124f6fe14ac367eca8111233f2a339 +size 2016 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/chrome8px/idle.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/chrome8px/idle.png new file mode 100644 index 00000000000..37efb623473 --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/chrome8px/idle.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a30e1e89e14cd82b0519ed1a353efbfff2d48e72d0f35b2ddefd68e603bf1442 +size 1891 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/chromeDark/idle.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/chromeDark/idle.png new file mode 100644 index 00000000000..73d6f8ebeb3 --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/chromeDark/idle.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:13887d4a12d9965476d0d56a12fb8da7c85d43577ffae21ff752611cea1ef0c2 +size 1733 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/chromeFlat8px/idle.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/chromeFlat8px/idle.png new file mode 100644 index 00000000000..c8a3b73b8ba --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/chromeFlat8px/idle.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1f4041ff37ac6a0cfce0319e27f882dbe6d8069366f3fce5390097bb145a0f80 +size 1677 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/firefox/idle.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/firefox/idle.png new file mode 100644 index 00000000000..38826afd2e3 --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/firefox/idle.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f9ae9ef8b0d9ac19b8ffab3c98feab66dced7e8a192a0dd71db0c2b73048bd0f +size 1758 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/firefox2022/idle.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/firefox2022/idle.png new file mode 100644 index 00000000000..32c5464a91e --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/firefox2022/idle.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:96c32f534c0c290a82fcd14983730ec0fe2b313be9fc851c2bcc550035b50713 +size 1940 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/firefox2022Dark/idle.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/firefox2022Dark/idle.png new file mode 100644 index 00000000000..1061e7e039f --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/firefox2022Dark/idle.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:40b5881b8540db333db50207cee6cb4bd8e622162ec80d7ea41b02363227d23a +size 1966 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/firefox8px/idle.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/firefox8px/idle.png new file mode 100644 index 00000000000..e5c5c70e567 --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/firefox8px/idle.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:69b8bd018286369a981050016a5777031ee6993da98d93f191060209a0aaddf4 +size 2093 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/firefoxDark/idle.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/firefoxDark/idle.png new file mode 100644 index 00000000000..1357e1fdf8a --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/firefoxDark/idle.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:db811c5175cae23e85ec2d1ffec633b2833028b58df1c789060205f51e4d56df +size 1776 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/firefoxFlat8px/idle.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/firefoxFlat8px/idle.png new file mode 100644 index 00000000000..3e531707e0a --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Color/idle/firefoxFlat8px/idle.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0fecd275b962ba80e0531297cdfaa718ecf1206d2518a7e09560a0746f83562b +size 1749 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Disabled Color/chrome2022.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Disabled Color/chrome2022.png new file mode 100644 index 00000000000..829bb621a4d --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Disabled Color/chrome2022.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d10594fef7b6bc2f6460b3678b415d30747891041e1f1236bfec1ba447aa32e2 +size 1783 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Disabled Color/chrome2022Dark.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Disabled Color/chrome2022Dark.png new file mode 100644 index 00000000000..7e409a01993 --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Disabled Color/chrome2022Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7455bac9a637752caa2cf18e99aba88e3a99baac135cdd22d052d44f408cd0eb +size 1668 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Disabled Color/firefox2022.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Disabled Color/firefox2022.png new file mode 100644 index 00000000000..4f08aba61ea --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Disabled Color/firefox2022.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6d1ba042558464eacffb433101bb3980e53200ce8ecf7ddb6a25498b59f183aa +size 1708 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link Icon Disabled Color/firefox2022Dark.png b/packages/react-ui/.creevey/images/Button/Button As Link Icon Disabled Color/firefox2022Dark.png new file mode 100644 index 00000000000..e3d9f94ecb0 --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link Icon Disabled Color/firefox2022Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8cd1db2e9d0e1ed5c1dcab127540a67be550be09f54287f879df31ddc6d1f137 +size 1599 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link/chrome2022.png b/packages/react-ui/.creevey/images/Button/Button As Link/chrome2022.png new file mode 100644 index 00000000000..006a987a208 --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link/chrome2022.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:286409d0a3c29ec9ce42d5d97531f815d4f46a3c27d6a79823ccedc9b54a3c4f +size 73710 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link/chrome2022Dark.png b/packages/react-ui/.creevey/images/Button/Button As Link/chrome2022Dark.png new file mode 100644 index 00000000000..5be9e2c21cf --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link/chrome2022Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:102d66b21beee916d9a90416f5db46319d4aa382145ea675717dc150140f00cd +size 76436 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link/firefox2022.png b/packages/react-ui/.creevey/images/Button/Button As Link/firefox2022.png new file mode 100644 index 00000000000..f2a6a3718d9 --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link/firefox2022.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e1e55d14ef0b0330c846f2568f78ede4441418bc5dbe92fc00e54398dc4bf18b +size 86385 diff --git a/packages/react-ui/.creevey/images/Button/Button As Link/firefox2022Dark.png b/packages/react-ui/.creevey/images/Button/Button As Link/firefox2022Dark.png new file mode 100644 index 00000000000..b191d421691 --- /dev/null +++ b/packages/react-ui/.creevey/images/Button/Button As Link/firefox2022Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1aa6a20d1bb933ee6d7ec46a645522e4dcf886e5480c1091c6b9781abdf49a6f +size 87301 diff --git a/packages/react-ui/.creevey/images/Link/Focused Styled Link/tab press/firefox2022/tabPressHovered.png b/packages/react-ui/.creevey/images/Link/Focused Styled Link/tab press/firefox2022/tabPressHovered.png index d7376641711..70838ff6ec5 100644 --- a/packages/react-ui/.creevey/images/Link/Focused Styled Link/tab press/firefox2022/tabPressHovered.png +++ b/packages/react-ui/.creevey/images/Link/Focused Styled Link/tab press/firefox2022/tabPressHovered.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad5ce98a4d5a3028e7cc83aebdbe6b5040a2fb1fda8888e910e51360be598310 -size 1332 +oid sha256:8ef4fb6d6619d3d3fb4a2c2f6b57c04cff1b2db51194941cc1dfcd005f087a35 +size 1447 diff --git a/packages/react-ui/.creevey/images/Link/Link As Button Validation/chrome2022.png b/packages/react-ui/.creevey/images/Link/Link As Button Validation/chrome2022.png new file mode 100644 index 00000000000..de72c58a703 --- /dev/null +++ b/packages/react-ui/.creevey/images/Link/Link As Button Validation/chrome2022.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11680a63f5b6ec43dfd49361ea9109e64b12ba97f5b0b5499fda21289af51302 +size 1969 diff --git a/packages/react-ui/.creevey/images/Link/Link As Button Validation/chrome2022Dark.png b/packages/react-ui/.creevey/images/Link/Link As Button Validation/chrome2022Dark.png new file mode 100644 index 00000000000..2a76598b5c4 --- /dev/null +++ b/packages/react-ui/.creevey/images/Link/Link As Button Validation/chrome2022Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f5a114a8740c33d59fb5515719695a005e1d3d0b99d3189a150e117695cfd358 +size 1952 diff --git a/packages/react-ui/.creevey/images/Link/Link As Button Validation/firefox2022.png b/packages/react-ui/.creevey/images/Link/Link As Button Validation/firefox2022.png new file mode 100644 index 00000000000..7f1d82709a9 --- /dev/null +++ b/packages/react-ui/.creevey/images/Link/Link As Button Validation/firefox2022.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b1341a6b081dcc91165737e5fb022a0f92c10051b21d3be4f94572ef5f0181e0 +size 2103 diff --git a/packages/react-ui/.creevey/images/Link/Link As Button Validation/firefox2022Dark.png b/packages/react-ui/.creevey/images/Link/Link As Button Validation/firefox2022Dark.png new file mode 100644 index 00000000000..44e06a895dc --- /dev/null +++ b/packages/react-ui/.creevey/images/Link/Link As Button Validation/firefox2022Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:30c175515954fda00ddbc9b3abb4365fe20320a21861e29f901a5ab4a3dc83c7 +size 2102 diff --git a/packages/react-ui/.creevey/images/Link/Link As Button/chrome2022.png b/packages/react-ui/.creevey/images/Link/Link As Button/chrome2022.png new file mode 100644 index 00000000000..d9ed3e26c2d --- /dev/null +++ b/packages/react-ui/.creevey/images/Link/Link As Button/chrome2022.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a547d5555e0da8f417f96f99357f3c815812b6f2ee71dea1c0fc7ff79169d37b +size 47940 diff --git a/packages/react-ui/.creevey/images/Link/Link As Button/chrome2022Dark.png b/packages/react-ui/.creevey/images/Link/Link As Button/chrome2022Dark.png new file mode 100644 index 00000000000..81671010f38 --- /dev/null +++ b/packages/react-ui/.creevey/images/Link/Link As Button/chrome2022Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:084e54b0ab4a4a7af63f515ed71a46b63b99b41958d8c6c2b02ab72c51924e98 +size 47878 diff --git a/packages/react-ui/.creevey/images/Link/Link As Button/firefox2022.png b/packages/react-ui/.creevey/images/Link/Link As Button/firefox2022.png new file mode 100644 index 00000000000..33bd2acf45b --- /dev/null +++ b/packages/react-ui/.creevey/images/Link/Link As Button/firefox2022.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:372e2ab0e49ad87ae50ec55bdad02c56f291d7ab0168b356ce953b02c5322436 +size 48335 diff --git a/packages/react-ui/.creevey/images/Link/Link As Button/firefox2022Dark.png b/packages/react-ui/.creevey/images/Link/Link As Button/firefox2022Dark.png new file mode 100644 index 00000000000..ab5f29adf89 --- /dev/null +++ b/packages/react-ui/.creevey/images/Link/Link As Button/firefox2022Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:572d2bb4c3011b3d57044a787aaac6eccfbc109b2d00971ce789ce2a1f200770 +size 48191 diff --git a/packages/react-ui/.creevey/images/Link/With Icon/tab press/chrome2022/tabPress.png b/packages/react-ui/.creevey/images/Link/With Icon/tab press/chrome2022/tabPress.png index 4708afff2d7..6f4eacf0be7 100644 --- a/packages/react-ui/.creevey/images/Link/With Icon/tab press/chrome2022/tabPress.png +++ b/packages/react-ui/.creevey/images/Link/With Icon/tab press/chrome2022/tabPress.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0507c617925b991e544ed52664a6d7ece3b6feced30b5540bfad53a1201957f0 -size 6767 +oid sha256:badae556c55d13faf5c893178cbe641ea2c98e3ddcddc6753441915a4520fd9d +size 6725 diff --git a/packages/react-ui/.creevey/images/Link/With Icon/tab press/chrome2022/tabPressHovered.png b/packages/react-ui/.creevey/images/Link/With Icon/tab press/chrome2022/tabPressHovered.png index 4708afff2d7..6f4eacf0be7 100644 --- a/packages/react-ui/.creevey/images/Link/With Icon/tab press/chrome2022/tabPressHovered.png +++ b/packages/react-ui/.creevey/images/Link/With Icon/tab press/chrome2022/tabPressHovered.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0507c617925b991e544ed52664a6d7ece3b6feced30b5540bfad53a1201957f0 -size 6767 +oid sha256:badae556c55d13faf5c893178cbe641ea2c98e3ddcddc6753441915a4520fd9d +size 6725 diff --git a/packages/react-ui/.creevey/images/Link/With Icon/tab press/chrome2022Dark/tabPress.png b/packages/react-ui/.creevey/images/Link/With Icon/tab press/chrome2022Dark/tabPress.png index 7a39a9e3077..dab5a93fc81 100644 --- a/packages/react-ui/.creevey/images/Link/With Icon/tab press/chrome2022Dark/tabPress.png +++ b/packages/react-ui/.creevey/images/Link/With Icon/tab press/chrome2022Dark/tabPress.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:da66723e80f41b9711d3a7b50e6ed167e7043c091df464cdefb6ede623b95b91 -size 7094 +oid sha256:158cb77dec9427f0c6d799c53decbf8d607b961a287c6a81e7848ec6bb779264 +size 7087 diff --git a/packages/react-ui/.creevey/images/Link/With Icon/tab press/chrome2022Dark/tabPressHovered.png b/packages/react-ui/.creevey/images/Link/With Icon/tab press/chrome2022Dark/tabPressHovered.png index 7a39a9e3077..dab5a93fc81 100644 --- a/packages/react-ui/.creevey/images/Link/With Icon/tab press/chrome2022Dark/tabPressHovered.png +++ b/packages/react-ui/.creevey/images/Link/With Icon/tab press/chrome2022Dark/tabPressHovered.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:da66723e80f41b9711d3a7b50e6ed167e7043c091df464cdefb6ede623b95b91 -size 7094 +oid sha256:158cb77dec9427f0c6d799c53decbf8d607b961a287c6a81e7848ec6bb779264 +size 7087 diff --git a/packages/react-ui/.creevey/images/Link/With Icon/tab press/firefox2022/tabPress.png b/packages/react-ui/.creevey/images/Link/With Icon/tab press/firefox2022/tabPress.png index 2dc3454bd34..2de0e3494fc 100644 --- a/packages/react-ui/.creevey/images/Link/With Icon/tab press/firefox2022/tabPress.png +++ b/packages/react-ui/.creevey/images/Link/With Icon/tab press/firefox2022/tabPress.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:280665dff3b5b421eccd0fc3aec1eb2a500e07aae5d2aaa3540500e9c58a6503 -size 6198 +oid sha256:3640274fc38697cf4c2442e0db871e3d3d6f7c660fe59c7579f8fcad7a0b79b9 +size 6335 diff --git a/packages/react-ui/.creevey/images/Link/With Icon/tab press/firefox2022/tabPressHovered.png b/packages/react-ui/.creevey/images/Link/With Icon/tab press/firefox2022/tabPressHovered.png index ec594a5b39c..2de0e3494fc 100644 --- a/packages/react-ui/.creevey/images/Link/With Icon/tab press/firefox2022/tabPressHovered.png +++ b/packages/react-ui/.creevey/images/Link/With Icon/tab press/firefox2022/tabPressHovered.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f42dd601bfa666eae86e7f61255b9bcfa527da00677abcb4599aac840c8d0de3 -size 6202 +oid sha256:3640274fc38697cf4c2442e0db871e3d3d6f7c660fe59c7579f8fcad7a0b79b9 +size 6335 diff --git a/packages/react-ui/.creevey/images/Link/With Icon/tab press/firefox2022Dark/tabPress.png b/packages/react-ui/.creevey/images/Link/With Icon/tab press/firefox2022Dark/tabPress.png index 1e11219c8d7..2183ac8f0de 100644 --- a/packages/react-ui/.creevey/images/Link/With Icon/tab press/firefox2022Dark/tabPress.png +++ b/packages/react-ui/.creevey/images/Link/With Icon/tab press/firefox2022Dark/tabPress.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aded080490f56cce7b6a32dedaa355d2dce422f8bf4afcdcd208c0da6139d05b -size 6122 +oid sha256:3aa3032d835a0df524f55ee78fc3d3008c896a0df6139d1ea458b65343316b92 +size 6415 diff --git a/packages/react-ui/.creevey/images/Link/With Icon/tab press/firefox2022Dark/tabPressHovered.png b/packages/react-ui/.creevey/images/Link/With Icon/tab press/firefox2022Dark/tabPressHovered.png index e399282958c..2183ac8f0de 100644 --- a/packages/react-ui/.creevey/images/Link/With Icon/tab press/firefox2022Dark/tabPressHovered.png +++ b/packages/react-ui/.creevey/images/Link/With Icon/tab press/firefox2022Dark/tabPressHovered.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:430c612536736dd3b44333bf437ac22ac152d06e08f77090632bd6e3bdbc9d7f -size 6281 +oid sha256:3aa3032d835a0df524f55ee78fc3d3008c896a0df6139d1ea458b65343316b92 +size 6415 diff --git a/packages/react-ui/components/Button/Button.md b/packages/react-ui/components/Button/Button.md index 4da57022a21..c31c45c17c9 100644 --- a/packages/react-ui/components/Button/Button.md +++ b/packages/react-ui/components/Button/Button.md @@ -1,9 +1,17 @@ -Базовый пример кнопки. +По умолчанию, кнопка принимает все пропы `HTMLButtonElement`. ```jsx harmony import { Button } from '@skbkontur/react-ui'; -; +; +``` + +Кнопка может рендерить ссылку в качестве корневого элемента, c помощью пропа `component`. Кнопка принимает все пропы переданного в `component` компонента. + +```jsx harmony +import { Button } from '@skbkontur/react-ui'; + + ``` У кнопки есть различные стили. @@ -212,7 +220,6 @@ const renderExampleRow = (title, styles, index) => { ``` - Кнопка может быть узкой. ```jsx harmony diff --git a/packages/react-ui/components/Button/Button.styles.ts b/packages/react-ui/components/Button/Button.styles.ts index ba6ae0f228c..1eb3271966d 100644 --- a/packages/react-ui/components/Button/Button.styles.ts +++ b/packages/react-ui/components/Button/Button.styles.ts @@ -16,6 +16,7 @@ export const globalClasses = prefix('button')({ caption: 'caption', text: 'text', innerShadow: 'inner-shadow', + disabled: 'disabled', }); export const styles = memoizeStyle({ @@ -59,13 +60,13 @@ export const styles = memoizeStyle({ width: 0; } - &:hover:enabled svg { + &:hover svg { color: ${t.btnIconHoverColor}; } - &:disabled svg { + &.${globalClasses.disabled} svg { color: ${t.btnIconDisabledColor}; } - &:enabled svg { + & svg { color: ${t.btnIconColor}; } `; @@ -324,6 +325,7 @@ export const styles = memoizeStyle({ disabled(t: Theme) { return css` cursor: default; + pointer-events: none; box-shadow: 0 0 0 ${t.btnBorderWidth} ${t.btnDisabledBorderColor}; background-image: none; @@ -389,7 +391,7 @@ export const styles = memoizeStyle({ t.btnBorderWidth, )}; - &:hover:enabled { + &:hover { ${buttonHoverMixin( t.btnDefaultHoverBg, t.btnDefaultHoverBgStart, @@ -400,7 +402,7 @@ export const styles = memoizeStyle({ )}; } - &:active:enabled { + &:active { ${activeStyles.default(t)}; } `; @@ -417,7 +419,7 @@ export const styles = memoizeStyle({ t.btnBorderWidth, )}; - &:hover:enabled { + &:hover { ${buttonHoverMixin( t.btnPrimaryHoverBg, t.btnPrimaryHoverBgStart, @@ -428,7 +430,7 @@ export const styles = memoizeStyle({ )}; } - &:active:enabled { + &:active { ${activeStyles.primary(t)} } `; @@ -445,7 +447,7 @@ export const styles = memoizeStyle({ t.btnBorderWidth, )}; - &:hover:enabled { + &:hover { ${buttonHoverMixin( t.btnSuccessHoverBg, t.btnSuccessHoverBgStart, @@ -456,7 +458,7 @@ export const styles = memoizeStyle({ )}; } - &:active:enabled { + &:active { ${activeStyles.success(t)} } `; @@ -473,7 +475,7 @@ export const styles = memoizeStyle({ t.btnBorderWidth, )}; - &:hover:enabled { + &:hover { ${buttonHoverMixin( t.btnDangerHoverBg, t.btnDangerHoverBgStart, @@ -484,7 +486,7 @@ export const styles = memoizeStyle({ )}; } - &:active:enabled { + &:active { ${activeStyles.danger(t)} } `; @@ -501,7 +503,7 @@ export const styles = memoizeStyle({ t.btnBorderWidth, )}; - &:hover:enabled { + &:hover { ${buttonHoverMixin( t.btnPayHoverBg, t.btnPayHoverBgStart, @@ -512,7 +514,7 @@ export const styles = memoizeStyle({ )}; } - &:active:enabled { + &:active { ${activeStyles.pay(t)} } `; @@ -522,13 +524,13 @@ export const styles = memoizeStyle({ return css` &, &:enabled, - &:hover:enabled { + &:hover { box-shadow: none; } ${buttonUseMixin(t.btnTextBg, '', '', t.btnTextTextColor, t.btnTextBorderColor, t.btnBorderWidth)}; - &:hover:enabled { + &:hover { ${buttonHoverMixin( t.btnTextHoverBg, '', @@ -539,7 +541,7 @@ export const styles = memoizeStyle({ )}; } - &:active:enabled { + &:active { ${activeStyles.text(t)} } `; @@ -552,7 +554,7 @@ export const styles = memoizeStyle({ color: ${t.btnDefaultTextColor}; background: transparent; - &:hover:enabled { + &:hover { ${buttonHoverMixin( t.btnBacklessHoverBg, '', @@ -563,7 +565,7 @@ export const styles = memoizeStyle({ )}; } - &:active:enabled { + &:active { ${activeStyles.backless(t)} } `; @@ -746,6 +748,18 @@ export const styles = memoizeStyle({ visibility: hidden; `; }, + + disableTextSelect() { + return css` + -webkit-touch-callout: none; /* iOS Safari */ + -webkit-user-select: none; /* Safari */ + -khtml-user-select: none; /* Konqueror HTML */ + -moz-user-select: none; /* Old versions of Firefox */ + -ms-user-select: none; /* Internet Explorer/Edge */ + user-select: none; /* Non-prefixed version, currently + supported by Chrome, Edge, Opera and Firefox */ + `; + }, }); export const activeStyles = memoizeStyle({ diff --git a/packages/react-ui/components/Button/Button.tsx b/packages/react-ui/components/Button/Button.tsx index 8a993b327e8..eb4365da2f6 100644 --- a/packages/react-ui/components/Button/Button.tsx +++ b/packages/react-ui/components/Button/Button.tsx @@ -1,19 +1,21 @@ -import React, { AriaAttributes, HTMLAttributes } from 'react'; +import React, { HTMLAttributes } from 'react'; import { globalObject } from '@skbkontur/global-object'; +import warning from 'warning'; -import { HTMLProps } from '../../typings/html'; +import { ButtonLinkAllowedValues } from '../../typings/button-link'; import { isKonturIcon, isReactUIComponent } from '../../lib/utils'; import { isIE11, isEdge, isSafari } from '../../lib/client'; import { keyListener } from '../../lib/events/keyListener'; import { Theme, ThemeIn } from '../../lib/theming/Theme'; import { ThemeContext } from '../../lib/theming/ThemeContext'; -import { CommonWrapper, CommonProps } from '../../internal/CommonWrapper'; +import { CommonWrapper, CommonProps, CommonWrapperRestProps } from '../../internal/CommonWrapper'; import { cx } from '../../lib/theming/Emotion'; import { rootNode, TSetRootNode } from '../../lib/rootNode'; import { ThemeFactory } from '../../lib/theming/ThemeFactory'; import { createPropsGetter } from '../../lib/createPropsGetter'; -import { Link, LinkProps } from '../Link'; +import { Link } from '../Link'; import { SizeProp } from '../../lib/types/props'; +import { PolymorphicPropsWithoutRef } from '../../typings/polymorphic-component'; import { styles, activeStyles, globalClasses } from './Button.styles'; import { ButtonIcon, ButtonIconProps, getButtonIconSizes } from './ButtonIcon'; @@ -28,14 +30,7 @@ export type ButtonSize = SizeProp; export type ButtonType = 'button' | 'submit' | 'reset'; export type ButtonUse = 'default' | 'primary' | 'success' | 'danger' | 'pay' | 'link' | 'text' | 'backless'; -export interface ButtonProps - extends CommonProps, - Pick< - AriaAttributes, - 'aria-haspopup' | 'aria-describedby' | 'aria-controls' | 'aria-label' | 'aria-checked' | 'aria-expanded' - >, - Pick, 'role' | 'id'>, - Pick { +export interface ButtonInnerProps extends CommonProps { /** @ignore */ _noPadding?: boolean; @@ -110,41 +105,6 @@ export interface ButtonProps */ narrow?: boolean; - /** - * HTML-событие `onblur`. - */ - onBlur?: React.FocusEventHandler; - - /** - * HTML-событие `onclick`. - */ - onClick?: React.MouseEventHandler; - - /** - * HTML-событие `onfocus`. - */ - onFocus?: React.FocusEventHandler; - - /** - * HTML-событие `keydown`. - */ - onKeyDown?: React.KeyboardEventHandler; - - /** - * HTML-событие `onmouseenter`. - */ - onMouseEnter?: React.MouseEventHandler; - - /** - * HTML-событие `mouseleave`. - */ - onMouseLeave?: React.MouseEventHandler; - - /** - * HTML-событие `onmouseover`. - */ - onMouseOver?: React.MouseEventHandler; - /** * Задаёт размер кнопки. * @@ -166,6 +126,9 @@ export interface ButtonProps * Стиль кнопки. * * **Допустимые значения**: `"default"`, `"primary"`, `"success"`, `"danger"`, `"pay"`, `"link"`, `"text"`, `"backless"`. + * + * **Вариант `link` устарел.** + * Если нужна кнопка, выглядящая как ссылка, используйте `Link component=button`. */ use?: ButtonUse; @@ -189,6 +152,11 @@ export interface ButtonProps theme?: ThemeIn; } +export const BUTTON_DEFAULT_COMPONENT: ButtonLinkAllowedValues = 'button'; + +export type ButtonProps = + PolymorphicPropsWithoutRef; + export interface ButtonState { focusedByTab: boolean; } @@ -199,10 +167,17 @@ export const ButtonDataTids = { spinner: 'Button__spinner', } as const; -type DefaultProps = Required>; +type DefaultProps = Required, 'use' | 'size' | 'type' | 'component'>>; + +const SpanComponent: React.FunctionComponent> = ({ children, ...rest }) => { + return {children}; +}; @rootNode -export class Button extends React.Component { +export class Button extends React.Component< + ButtonProps, + ButtonState +> { public static __KONTUR_REACT_UI__ = 'Button'; public static displayName = 'Button'; public static __BUTTON__ = true; @@ -210,7 +185,11 @@ export class Button extends React.Component { public static defaultProps: DefaultProps = { use: 'default', size: 'small', + // By default the type attribute is 'submit'. IE8 will fire a click event + // on this button if somewhere on the page user presses Enter while some + // input is focused. So we set type to 'button' by default. type: 'button', + component: BUTTON_DEFAULT_COMPONENT, }; private getProps = createPropsGetter(Button.defaultProps); @@ -220,7 +199,7 @@ export class Button extends React.Component { }; private theme!: Theme; - private node: HTMLButtonElement | null = null; + private node: HTMLElement | null = null; private setRootNode!: TSetRootNode; public componentDidMount() { @@ -228,6 +207,10 @@ export class Button extends React.Component { keyListener.isTabPressed = true; this.focus(); } + warning( + this.props.use !== 'link', + `[Button]: Use 'Link' has been deprecated. Please, use Link with 'component=button' prop instead.`, + ); } public static getDerivedStateFromProps(props: ButtonProps) { @@ -256,18 +239,29 @@ export class Button extends React.Component { {(theme) => { this.theme = this.props.theme ? ThemeFactory.create(this.props.theme as Theme, theme) : theme; - return this.renderMain(); + return ( + + {this.renderMain} + + ); }} ); } - private renderLinkRootWithoutHandlers(props: LinkProps) { - const { onClick, onFocus, onBlur, children, ...rest } = props; - return {children}; + private getTabIndex({ + disableFocus, + disabled, + tabIndex = 0, + }: Pick) { + if (disableFocus || disabled) { + return -1; + } + + return tabIndex; } - private renderMain() { + private renderMain = (props: CommonWrapperRestProps) => { const { corners, active, @@ -278,6 +272,7 @@ export class Button extends React.Component { warning, loading, narrow, + arrow, icon, rightIcon, _noPadding, @@ -285,26 +280,16 @@ export class Button extends React.Component { visuallyFocused, align, disableFocus, - onMouseEnter, - onMouseLeave, - onMouseOver, - onMouseDown, - onMouseUp, - onKeyDown, - onClick, - onClickCapture, width, - children, - 'aria-describedby': ariaDescribedby, - 'aria-haspopup': ariaHasPopup, - 'aria-controls': ariaControls, - 'aria-label': ariaLabel, - 'aria-checked': ariaChecked, - 'aria-expanded': ariaExpanded, - role, - id, - } = this.props; - const { use, type, size } = this.getProps(); + tabIndex, + component: _component, + use: useProp, + size: sizeProp, + theme, + ...rest + } = props; + const { use, size, component, children } = this.getProps(); + const sizeClass = this.getSizeClassName(); const isFocused = this.state.focusedByTab || visuallyFocused; @@ -322,6 +307,7 @@ export class Button extends React.Component { styles.root(this.theme), styles[use](this.theme), sizeClass, + styles.disableTextSelect(), narrow && styles.narrow(), _noPadding && styles.noPadding(), _noRightPadding && styles.noRightPadding(), @@ -334,6 +320,7 @@ export class Button extends React.Component { borderless && styles.borderless(), use === 'backless' && styles.backlessDisabled(this.theme), use === 'text' && styles.textDisabled(), + globalClasses.disabled, ] : [ active && !checked && activeStyles[use](this.theme), @@ -345,35 +332,16 @@ export class Button extends React.Component { ); const rootProps = { - // By default the type attribute is 'submit'. IE8 will fire a click event - // on this button if somewhere on the page user presses Enter while some - // input is focused. So we set type to 'button' by default. - type, - role, - 'aria-describedby': ariaDescribedby, - 'aria-haspopup': ariaHasPopup, - 'aria-controls': ariaControls, - 'aria-label': ariaLabel, - 'aria-checked': ariaChecked, - 'aria-expanded': ariaExpanded, + ...rest, className: rootClassName, style: { textAlign: align, ...corners, }, - disabled: disabled || loading, - onClick, + disabled: trueDisabled, onFocus: this.handleFocus, onBlur: this.handleBlur, - onKeyDown, - onMouseEnter, - onMouseLeave, - onMouseOver, - onMouseDown, - onMouseUp, - onClickCapture, - tabIndex: disableFocus ? -1 : 0, - title: this.props.title, + tabIndex: this.getTabIndex({ disableFocus, disabled: trueDisabled, tabIndex }), }; const wrapProps = { @@ -424,12 +392,13 @@ export class Button extends React.Component { [styles.linkLineHeight()]: !isSafari, [styles.linkLineHeightSafariFallback()]: isSafari, [styles.linkFocus(this.theme)]: isFocused, - [styles.linkDisabled(this.theme)]: disabled || loading, + [styles.linkDisabled(this.theme)]: trueDisabled, }); Object.assign(wrapProps, { className: cx(styles.wrap(this.theme), styles.wrapLink()), style: { width: wrapProps.style.width }, }); + rootProps.style.textAlign = undefined; } @@ -458,33 +427,35 @@ export class Button extends React.Component { if (isLink && !loading) { captionNode = ( - - {children} - + { + + focused={isFocused} + disabled={disabled} + icon={this.renderIcon2022(icon)} + rightIcon={this.renderIcon2022(rightIcon)} + tabIndex={-1} + component={SpanComponent} + > + {children} + + } ); } + const Root: React.ElementType = component; + return ( - - - - - + + + {innerShadowNode} + {outlineNode} + {arrowNode} + {captionNode} + + ); - } + }; private renderIcon2022(icon: React.ReactElement | undefined) { if (icon && isKonturIcon(icon)) { @@ -531,7 +502,7 @@ export class Button extends React.Component { } } - private handleFocus = (e: React.FocusEvent) => { + private handleFocus = (e: React.FocusEvent) => { if (!this.props.disabled && !this.props.disableFocus) { // focus event fires before keyDown eventlistener // so we should check tabPressed in async way @@ -544,14 +515,14 @@ export class Button extends React.Component { } }; - private handleBlur = (e: React.FocusEvent) => { + private handleBlur = (e: React.FocusEvent) => { this.setState({ focusedByTab: false }); if (!this.props.disabled && !this.props.disableFocus) { this.props.onBlur?.(e); } }; - private _ref = (node: HTMLButtonElement | null) => { + private _ref = (node: HTMLElement | null) => { this.node = node; }; } diff --git a/packages/react-ui/components/Button/ButtonArrow.tsx b/packages/react-ui/components/Button/ButtonArrow.tsx index c1e42499f5a..c6790a98683 100644 --- a/packages/react-ui/components/Button/ButtonArrow.tsx +++ b/packages/react-ui/components/Button/ButtonArrow.tsx @@ -6,10 +6,13 @@ import { Theme } from '../../lib/theming/Theme'; import { ArrowRightIcon } from './ArrowRightIcon'; import { ArrowLeftIcon } from './ArrowLeftIcon'; -import { Button, ButtonProps } from './Button'; +import { Button, ButtonInnerProps } from './Button'; import { globalClasses, styles } from './Button.styles'; -type ButtonArrowProps = Pick & { +type ButtonArrowProps = Pick< + ButtonInnerProps, + 'size' | 'arrow' | 'checked' | 'disabled' | 'error' | 'use' | 'warning' +> & { isFocused: boolean; }; diff --git a/packages/react-ui/components/Button/ButtonIcon.tsx b/packages/react-ui/components/Button/ButtonIcon.tsx index 1b032926849..71b1267cacb 100644 --- a/packages/react-ui/components/Button/ButtonIcon.tsx +++ b/packages/react-ui/components/Button/ButtonIcon.tsx @@ -6,11 +6,11 @@ import { cx } from '../../lib/theming/Emotion'; import { ThemeContext } from '../../lib/theming/ThemeContext'; import { SizeProp } from '../../lib/types/props'; -import { ButtonProps } from './Button'; +import { ButtonInnerProps } from './Button'; import { styles } from './ButtonIcon.styles'; import { LoadingButtonIcon } from './LoadingButtonIcon'; -export interface ButtonIconProps extends Pick { +export interface ButtonIconProps extends Pick { position: 'right' | 'left'; hasChildren: boolean; hasBothIcons?: boolean; diff --git a/packages/react-ui/components/Button/__creevey__/Button.creevey.ts b/packages/react-ui/components/Button/__creevey__/Button.creevey.ts index e0d1934d043..415774f96ec 100644 --- a/packages/react-ui/components/Button/__creevey__/Button.creevey.ts +++ b/packages/react-ui/components/Button/__creevey__/Button.creevey.ts @@ -90,6 +90,22 @@ kind('Button', () => { buttonTests(); }); + story('ButtonAsLinkIconColor', ({ setStoryParameters }) => { + setStoryParameters({ + skip: { + 'focus goes out of page and breaks other tests': { + tests: ['pressed', 'clicked', 'tabPress'], + }, + 'hover does not work in chrome': { + in: /^(?!\b(firefox.*)\b)/, + tests: ['hover'], + }, + }, + }); + + buttonTests(); + }); + story('BtnTextBgHoverActive', ({ setStoryParameters }) => { setStoryParameters({ skip: { diff --git a/packages/react-ui/components/Button/__stories__/Button.stories.tsx b/packages/react-ui/components/Button/__stories__/Button.stories.tsx index 389237e73b3..942d245d3a8 100644 --- a/packages/react-ui/components/Button/__stories__/Button.stories.tsx +++ b/packages/react-ui/components/Button/__stories__/Button.stories.tsx @@ -22,7 +22,7 @@ export default { title: 'Button', }; -type ButtonState = Partial; +type ButtonState = Partial>; const useStates: ButtonState[] = [ { use: 'default' }, @@ -50,6 +50,31 @@ const testingButtonUseStates2022: ButtonState[] = [ { use: 'backless' }, { use: 'link' }, ]; + +const buttonAsLinkUseStates: ButtonState[] = [ + { use: 'default' }, + { use: 'primary' }, + { use: 'danger' }, + { use: 'pay' }, + { use: 'success' }, + { use: 'text' }, + { use: 'backless' }, +]; + +const buttonAsLinkTestingProps: ButtonState[] = [ + { children: 'Link' }, + { disabled: true }, + { loading: true }, + { icon: }, + { icon: , disabled: true }, + { rightIcon: }, + { rightIcon: , disabled: true }, + { icon: , rightIcon: }, + { icon: , rightIcon: , disabled: true }, + { error: true }, + { warning: true }, +]; + const testingLinkState: ButtonState[] = [{ use: 'link' }]; const getButtonUseStates = (theme: string) => { @@ -582,6 +607,38 @@ export const BtnBacklessBgHoverActive: Story = () => { ); }; +export const ButtonAsLink: Story = () => { + return ( + ({ props: x }))} + rows={buttonAsLinkTestingProps.map((x) => ({ props: x }))} + presetProps={{ children: 'Link', component: 'a' }} + /> + ); +}; + +export const ButtonAsLinkIconColor: Story = () => { + return ( + + ); +}; + +export const ButtonAsLinkIconDisabledColor: Story = () => { + return ( + + ); +}; + export const BtnTextBgHoverActive: Story = () => { const myTheme = ThemeFactory.create( { diff --git a/packages/react-ui/components/Button/__tests__/Button-test.tsx b/packages/react-ui/components/Button/__tests__/Button-test.tsx index f27d037c8a3..a97c5b8d067 100644 --- a/packages/react-ui/components/Button/__tests__/Button-test.tsx +++ b/packages/react-ui/components/Button/__tests__/Button-test.tsx @@ -25,7 +25,7 @@ describe('Button', () => { }); }); - it('handels click event', async () => { + it('handles click event', async () => { const onClick = jest.fn(); render(); + + const button = screen.getByRole('button'); + expect(button).not.toHaveClass('', { exact: true }); + }); + + it(`data-tid prop shouldn't override value on root`, () => { + const props = { 'data-tid': 'foo' }; + + render(); + const button = screen.getByRole('button'); + + expect(button).toHaveAttribute('data-tid', ButtonDataTids.root); + }); + describe('with use=link prop', () => { const handleSubmit = jest.fn(); const handleReset = jest.fn(); @@ -241,4 +258,44 @@ describe('Button', () => { expect(handleReset).toHaveBeenCalled(); }); }); + + describe('with component=a prop', () => { + it('should render tag', () => { + render( + , + ); + + expect(screen.getByRole('link')).toBeInTheDocument(); + }); + + it('should render ); + + expect(screen.getByRole('button')).toBeInTheDocument(); + }); + + it.each([{ disabled: true }, { loading: true }])(`shouldn't be focusable when %p`, (prop) => { + render( + , + ); + + userEvent.tab(); + expect(screen.getByRole('link')).not.toHaveFocus(); + }); + + it(`should have correct tabIndex`, () => { + render( + // eslint-disable-next-line jsx-a11y/tabindex-no-positive + , + ); + + expect(screen.getByRole('link')).toHaveAttribute('tabindex', '1'); + }); + }); }); diff --git a/packages/react-ui/components/Link/Link.md b/packages/react-ui/components/Link/Link.md index 688ea1eef65..7c12969df97 100644 --- a/packages/react-ui/components/Link/Link.md +++ b/packages/react-ui/components/Link/Link.md @@ -1,7 +1,28 @@ -Базовый пример ссылки. +По умолчанию, ссылка принимает все пропы `HTMLAnchorElement`. ```jsx harmony -Обычная ссылка +Обычная ссылка +``` + +Cсылка может рендерить кнопку в качестве корневого элемента, c помощью пропа `component`. Cсылка принимает все пропы переданного в `component` компонента. + +Рекомендуется к использованию вместо кнопки с `use=link`, если нужна кнопка с визуалом ссылки. + +```jsx harmony +import { Link } from '@skbkontur/react-ui'; + +Кнопка, но выглядит как ссылка +``` + +Также, c помощью пропа `component`, ссылка может рендерить компонент `Link` из `react router` в качестве корневого элемента. + +```jsx static +import { Link } from '@skbkontur/react-ui'; +import { Link as RouterLink, BrowserRouter } from 'react-router-dom'; + + + react-router-dom link + ``` Ссылка может иметь различные стили, а также быть отключенной. @@ -158,4 +179,3 @@ const renderExampleRow = (title, styles, index) => { {renderExampleRow('Изменение цвета ссылки', differentColorStyles)} ``` - diff --git a/packages/react-ui/components/Link/Link.styles.ts b/packages/react-ui/components/Link/Link.styles.ts index cabe92eb76e..8740282a82a 100644 --- a/packages/react-ui/components/Link/Link.styles.ts +++ b/packages/react-ui/components/Link/Link.styles.ts @@ -25,6 +25,9 @@ const oldLineText = function (t: Theme) { export const styles = memoizeStyle({ root(t: Theme) { return css` + cursor: pointer; + position: relative; + border-radius: 1px; text-decoration: ${t.linkTextDecoration}; text-decoration-style: ${t.linkTextDecorationStyle}; @@ -166,4 +169,28 @@ export const styles = memoizeStyle({ margin-left: ${t.linkIconMarginLeft}; `; }, + + outline(t: Theme) { + return css` + border-radius: ${t.btnLinkBorderRadius}; + position: absolute; + box-shadow: none; + left: -2px; + right: -2px; + bottom: -2px; + top: -2px; + `; + }, + + outlineWarning(t: Theme) { + return css` + background-color: ${t.btnWarningSecondary}; + `; + }, + + outlineError(t: Theme) { + return css` + background-color: ${t.btnErrorSecondary}; + `; + }, }); diff --git a/packages/react-ui/components/Link/Link.tsx b/packages/react-ui/components/Link/Link.tsx index c9bb08ba8b2..727d8cac33f 100644 --- a/packages/react-ui/components/Link/Link.tsx +++ b/packages/react-ui/components/Link/Link.tsx @@ -1,8 +1,9 @@ -import React, { AriaAttributes } from 'react'; -import PropTypes from 'prop-types'; +import React from 'react'; import { globalObject } from '@skbkontur/global-object'; -import { Override } from '../../typings/utility-types'; +import { ButtonLinkAllowedValues } from '../../typings/button-link'; +import { resetButton } from '../../lib/styles/Mixins'; +import { PolymorphicPropsWithoutRef } from '../../typings/polymorphic-component'; import { keyListener } from '../../lib/events/keyListener'; import { Theme, ThemeIn } from '../../lib/theming/Theme'; import { ThemeContext } from '../../lib/theming/ThemeContext'; @@ -17,70 +18,64 @@ import { getVisualStateDataAttributes } from '../../internal/CommonWrapper/utils import { styles } from './Link.styles'; import { LinkIcon } from './LinkIcon'; -export interface LinkProps - extends Pick, - CommonProps, - Override< - React.AnchorHTMLAttributes, - { - /** - * Отключенное состояние. - */ - disabled?: boolean; - /** - * HTML-атрибут `href`. - */ - href?: string; - /** - * Добавляет ссылке иконку слева. - */ - icon?: React.ReactElement; - /** - * Добавляет ссылке иконку справа. - */ - rightIcon?: React.ReactElement; - /** - * Тема ссылки. - */ - use?: 'default' | 'success' | 'danger' | 'grayed'; - /** - * @ignore - */ - _button?: boolean; - /** - * @ignore - */ - _buttonOpened?: boolean; - /** - * HTML-атрибут `tabindex`. - */ - tabIndex?: number; - /** - * Переводит ссылку в состояние загрузки. - */ - loading?: boolean; - /** - * HTML-событие `onclick`. - */ - onClick?: (event: React.MouseEvent) => void; - - /** - * Обычный объект с переменными темы. - * Он будет объединён с темой из контекста. - */ - theme?: ThemeIn; - /** - * Компонент, используемый в качестве корневого узла. - * @ignore - */ - as?: React.ElementType | keyof React.ReactHTML; - /** - * @ignore - */ - focused?: boolean; - } - > {} +export interface LinkInnerProps extends CommonProps { + /** + * Отключенное состояние. + */ + disabled?: boolean; + /** + * Добавляет ссылке иконку слева. + */ + icon?: React.ReactElement; + /** + * Добавляет ссылке иконку справа. + */ + rightIcon?: React.ReactElement; + /** + * Тема ссылки. + */ + use?: 'default' | 'success' | 'danger' | 'grayed'; + /** + * @ignore + */ + _button?: boolean; + /** + * @ignore + */ + _buttonOpened?: boolean; + /** + * HTML-атрибут `tabindex`. + */ + tabIndex?: number; + /** + * Переводит ссылку в состояние загрузки. + */ + loading?: boolean; + /** + * Обычный объект с переменными темы. + * Он будет объединён с темой из контекста. + */ + theme?: ThemeIn; + /** + * @ignore + */ + focused?: boolean; + /** + * Состояние валидации при ошибке. + */ + error?: boolean; + /** + * Состояние валидации при предупреждении. + */ + warning?: boolean; +} + +const LINK_DEFAULT_COMPONENT: ButtonLinkAllowedValues = 'a'; +export type LinkProps = PolymorphicPropsWithoutRef< + LinkInnerProps, + C +>; export interface LinkState { focusedByTab: boolean; } @@ -89,31 +84,23 @@ export const LinkDataTids = { root: 'Link__root', } as const; -type DefaultProps = Required>; -type DefaultizedLinkProps = DefaultizedProps; +type DefaultProps = Required, 'use' | 'component'>>; +type DefaultizedLinkProps = DefaultizedProps, DefaultProps>; /** * Элемент ссылки из HTML. */ @rootNode -export class Link extends React.Component { +export class Link extends React.Component< + LinkProps, + LinkState +> { public static __KONTUR_REACT_UI__ = 'Link'; public static displayName = 'Link'; - public static propTypes = { - disabled: PropTypes.bool, - - href: PropTypes.string, - - icon: PropTypes.node, - - use: PropTypes.oneOf(['default', 'success', 'danger', 'grayed']), - }; - public static defaultProps: DefaultProps = { - href: '', use: 'default', - as: 'a', + component: LINK_DEFAULT_COMPONENT, }; private getProps = createPropsGetter(Link.defaultProps); @@ -140,19 +127,43 @@ export class Link extends React.Component { ); } + private getTabIndex = ({ + nonInteractive, + tabIndex = 0, + }: { + nonInteractive: boolean | undefined; + tabIndex: number | undefined; + }) => { + return nonInteractive ? -1 : tabIndex; + }; + + private getRel = () => { + if (isAnchorProps(this.props)) { + const { rel, href } = this.props; + if (!rel && href) { + return `noopener${isExternalLink(href) ? ' noreferrer' : ''}`; + } + return rel; + } + + return undefined; + }; + private renderMain = (props: CommonWrapperRestProps) => { const { disabled, - href, icon, rightIcon, use, loading, _button, _buttonOpened, - rel: relOrigin, - as: Component, + component: Root, focused = false, + error, + warning, + tabIndex, + theme, ...rest } = props; @@ -161,20 +172,30 @@ export class Link extends React.Component { arrow = ; } - let rel = relOrigin; - if (typeof rel === 'undefined' && href) { - rel = `noopener${isExternalLink(href) ? ' noreferrer' : ''}`; - } - const isFocused = !disabled && (this.state.focusedByTab || focused); const leftIconElement = icon && ; const rightIconElement = rightIcon && ( ); - const linkProps = { + const nonInteractive = disabled || loading; + + const outlineNode = ( +
+ ); + + const rootProps = { + ...rest, className: cx({ [styles.root(this.theme)]: true, + [resetButton()]: Root === 'button', [styles.focus(this.theme)]: isFocused, [styles.disabled(this.theme)]: disabled || loading, [styles.useDefault(this.theme)]: use === 'default', @@ -189,21 +210,21 @@ export class Link extends React.Component { [styles.lineFocusDanger(this.theme)]: isFocused && use === 'danger', [styles.lineFocusGrayed(this.theme)]: isFocused && use === 'grayed', }), - href, - rel, onClick: this.handleClick, onFocus: this.handleFocus, onBlur: this.handleBlur, - tabIndex: disabled || loading ? -1 : this.props.tabIndex, + tabIndex: this.getTabIndex({ nonInteractive, tabIndex }), + rel: this.getRel(), }; return ( - + {leftIconElement} + {outlineNode} {this.props.children} {rightIconElement} {arrow} - + ); }; @@ -223,14 +244,15 @@ export class Link extends React.Component { this.setState({ focusedByTab: false }); }; - private handleClick = (event: React.MouseEvent) => { + private handleClick = (event: React.MouseEvent) => { const { onClick, disabled, loading } = this.props; - const href = this.getProps().href; - if (!href) { - event.preventDefault(); - } + if (onClick && !disabled && !loading) { onClick(event); } }; } + +const isAnchorProps = (props: LinkProps): props is LinkProps<'a'> => { + return props.component === 'a'; +}; diff --git a/packages/react-ui/components/Link/__stories__/Link.stories.tsx b/packages/react-ui/components/Link/__stories__/Link.stories.tsx index c081fb7e65b..7fd2f767964 100644 --- a/packages/react-ui/components/Link/__stories__/Link.stories.tsx +++ b/packages/react-ui/components/Link/__stories__/Link.stories.tsx @@ -3,7 +3,9 @@ import OkIcon from '@skbkontur/react-icons/Ok'; import { CheckAIcon16Light } from '@skbkontur/icons/icons/CheckAIcon'; import { Story } from '../../../typings/stories'; -import { Link } from '../Link'; +import { ComponentTable } from '../../../internal/ComponentTable'; +import { Link, LinkProps } from '../Link'; +import { Button } from '../../Button'; import { Toast } from '../../Toast'; import { Gapped } from '../../Gapped'; import { ThemeContext } from '../../../lib/theming/ThemeContext'; @@ -85,3 +87,45 @@ export const FocusedStyledLink: Story = () => { ); }; + +type LinkState = Partial>; + +const linkUseStates: LinkState[] = [{ use: 'default' }, { use: 'danger' }, { use: 'success' }, { use: 'grayed' }]; +const componentPropStates: LinkState[] = [ + { children: 'Button' }, + { disabled: true }, + { icon: }, + { icon: , loading: true }, + { rightIcon: }, + { rightIcon: , loading: true }, + { icon: , rightIcon: }, + { icon: , rightIcon: , loading: true }, + { warning: true }, + { error: true }, +]; + +export const LinkAsButton: Story = () => { + return ( + ({ props: state }))} + rows={componentPropStates.map((x) => ({ props: x }))} + presetProps={{ children: 'Button', component: 'button' }} + /> + ); +}; + +export const LinkAsButtonValidation: Story = () => { + return ( + + + Warning + + Error + + ); +}; diff --git a/packages/react-ui/components/Link/__tests__/Link-test.tsx b/packages/react-ui/components/Link/__tests__/Link-test.tsx index b6a5b5e7b9d..e1150c7c679 100644 --- a/packages/react-ui/components/Link/__tests__/Link-test.tsx +++ b/packages/react-ui/components/Link/__tests__/Link-test.tsx @@ -79,9 +79,45 @@ describe('Link', () => { describe('a11y', () => { it('sets value for aria-label attribute', () => { const ariaLabel = 'aria-label'; - render(); + render(); expect(screen.getByTestId(LinkDataTids.root)).toHaveAttribute('aria-label', ariaLabel); }); }); + + describe('with component prop', () => { + it('should render tag when omitted', () => { + renderRTL({ href: 'https://kontur.ru' }); + + expect(screen.getByRole('link')).toBeInTheDocument(); + }); + + it('should render