From 21ab55d5f7c17db03d09f0d75b1066b2515b7647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20I=C3=9Fbr=C3=BCcker?= Date: Wed, 2 Oct 2024 14:43:58 +0200 Subject: [PATCH] fix!: make prefix, suffix and clear button stick to top (#7895) * make prefix/suffix/clear button sticky * add test * fix material theme * simplify selectors --- .../text-area/baseline/clear-button.png | Bin 1511 -> 1515 bytes ...rolled-with-prefix-suffix-clear-button.png | Bin 0 -> 2050 bytes .../test/visual/lumo/text-area.test.js | 18 ++++++++++++++++++ .../text-area/baseline/clear-button.png | Bin 1177 -> 1176 bytes ...rolled-with-prefix-suffix-clear-button.png | Bin 0 -> 1739 bytes .../test/visual/material/text-area.test.js | 18 ++++++++++++++++++ .../theme/lumo/vaadin-text-area-styles.js | 14 ++++++++++++-- .../theme/material/vaadin-text-area-styles.js | 8 ++++++++ 8 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 packages/text-area/test/visual/lumo/screenshots/text-area/baseline/scrolled-with-prefix-suffix-clear-button.png create mode 100644 packages/text-area/test/visual/material/screenshots/text-area/baseline/scrolled-with-prefix-suffix-clear-button.png diff --git a/packages/text-area/test/visual/lumo/screenshots/text-area/baseline/clear-button.png b/packages/text-area/test/visual/lumo/screenshots/text-area/baseline/clear-button.png index eecddd9e26fd68fc12b6181bc3c3c66e769d360c..6d948da86901a5236496c5784ea32ecf05dfa7a3 100644 GIT binary patch literal 1515 zcmb`HYd8}M9L7hIu=UWHgKa!sG53Qyg;5))vcc^tfz9 zv8Ul+birI&wvr`8%~`Iw%%zRfalZ6Coe$@HIUoN2_xXK#KfS+f49XR#tfdS90DwpY z9JiYv<~iuTnx_D8PLennFRp$RwLm~9*L!k6RC)o2|9f%V$b$^NksHeqzRWY9_s`X=td-$zLI~vLb}LY%G2N>2mcz_ffk@r6O7u?~yg+#_!LSmp|p& z2&9sYLF%((-7Oms^V6~s3N_sKiF&G>L+Z87SB1EpK32ild`#UG^2bjq%Zr`ki`%0G zx0|DU0rakGMy3hT%g!aU=F~?G1dq4N>oIxzhti`d18g3$$}_V9FiqJkVvmkRO*J$n z{#so9t!`%R${c|ACW$K8GfL}480G{y7KH9>Ix+~qF1RnFG ze@Lk`kbf*yO8!N_4R9bgcdnO4(qV;Si?|t3l*%f1H5R!4VvTeQuXW}5n%n%jIU->j z859a=u}Q2f*9Wi_8N#tk;`}Zp`N==^FWz-&5xcK(MMpRd9Rmrn`XIdC?E48d`xJ$= zG$yMVIpKHaTm#JOF&<=d(6_K?BQbQ@m8}quD{3Z<4CZq4>3N$As6y%q)rG16s3Q9| zR+99*EW*y-s(<*!ygVF~yV{i+fpxij`xuncV}il@p(mI}FT7**Ba%BzeF(P9ekm9x?}%+0A@6H?QOnQW7N(p)C6B89~XLmYNeI1Eu6GFoL9{JwO1a# znUTZgfWTw|gofyC$766P-yE3N^wpa9#i%|9P9=C>9U_1Rmt{mBMR%!=C;!1mpn@GR zO)}H?b`@^Lby$1-2R4aDJIBA5e%0>5os$i68e*gAxClYwf-=PmOs?)Dz{V8>Yj3;f z%bk+8Q$Jqs=(jNoNV@5UIvcy&EFQf4gEu3r7}*%PO<62&$rXCiGHcn?llqII-)y_* z9`~o{4^jH(bmg|2ydkn=Tcg@w$Qb*UBqBYyUn+9rKuWXE`wjFy>`8u5U8-noiG%`G zCQTyOwO%;dtym)H>aRyQq|f=n{K7Y%9T6c}IR)B>1lFDBoxhspKUVtxB8KbK=HH0m z!9s?W#bXC-7+Ax&P~#`(|8|DqrQW=yF9r#0RUBT59gg4B(>wcxCNFLA> kqBdJnuK8b*`-cLh+NjQZ@@+sz!(Dp=kS-{AqjON&UmuOoo&W#< literal 1511 zcmai!dpr{g6vtN?HF*tJSP!oyy2(~-mtmU6WI`UfA~gDxS7si0$1PKd!j&1u6)IFq zjL4Xnwze#<8hU7xJZqS8m%ID<-1|@W)90Sg=bYa;pWh$noPWMK?ru&>ARQ0@08qj@ zV?1R#C`+Hs^0L}eLubomL#(HhJ)n^bnFauWl~@egE0Hocp6*Y^W#!LDWm}~X#hxZWC zBH~c@;Aur}+A6-)mgZSJkCX-qznnY2Zq1t%r>K-$^28|}R@B*c;8YOjA`plAfa#*;(pe3bcVM14&fq~NOxTym4 zGAa>K(?xP6o~NueXYt_$u0FDkEL8u|J=9{Dak|jA`jqf(WZHm%+7`}X?Lrpj=0BHf zD?hE8pRwjY03jw&iRTn2DAs)Ok>|jrz=qyO3A!^6K0EUW;+QmTZ%fCC8F^IeAWqz1t;2U}VDV9u+?J;Dixa}?)?e#PTS$Rr zIC6N9db*s#VqlKdb2Z-*JyLZH|`e;>(-($MhFx1W=5)~)=ON7sdoi&}h+aRI?!z~~AeR2cmn5(S{N*%`o z@El#h;K2mzfYG$F<}QJu;kC_!WzkQB1m!jJwa*wwaG|LN2P%{r8k_W$23>28(iY1P zBMiDX)FEaK%oA)nwAje_6;0~No(?tJ3JA68eXdk!L`zVpj;eqL{BRwE|wBrS|)7#qVd2il{t zEYg(|{bX-ul@8>^?c+YZ*$Q!6+k^%Alk1aOX^8kDUGC}jr>Sj9J=Oj;B~AL1zBDKt zRKG^_UyK(ipgUox8mi&aSUcm^?b-yd;yZ3isWl*dpiyNg3x0G*g-Uu22qv2*ZPish zc;$7QWtLu50o;HiQp)`Z2|z~x0 zkT5U!remHFcqgyiDq%W#F&~hI!*|CZAiv?t?0Y!cbjr$lY?K{3hxK78$nZZv`@!yi baVS;fZs^%Td$GchksE+@aKkj(2W9>R7bd}| diff --git a/packages/text-area/test/visual/lumo/screenshots/text-area/baseline/scrolled-with-prefix-suffix-clear-button.png b/packages/text-area/test/visual/lumo/screenshots/text-area/baseline/scrolled-with-prefix-suffix-clear-button.png new file mode 100644 index 0000000000000000000000000000000000000000..b7d31811b29f5a84db9c770edc4891a8cfcecf44 GIT binary patch literal 2050 zcmb7_Sya-C7RLXMm9s!)X;$bloQOJ>4NfS6I3TF0Y1z?^WSL10shDG0s5p?OWezx0 z4&_jGqfk;Ds4Q`yaZ_{H3us1iwh z$!y7hGY*GKrl3sRP6Gs(Kb<0f0FO%6fxj(6m>9>rhavLQhe(t^2IT>eDU!=2?Ulc^{ZylmS&r ze5_ehyQUStRy3M}$&YR<<$P|XCcY)3d(_K0ZMfJ!$I?Adys ze4}S46C9)NN-uNk&!afGV0J#N`WdUO7WjJ&EQvkhyn9i0?=jn>MK~VMoNZ}kB}{r9 zdl}}H@l)8zmm2>%?|ZRqD-V@sUDvnzW_37mX$#ZO_U|KbUvxjQtc{+o|AT+q1DF)D>k=9K2+k z?uz(`k<>GzHecY*ZIQTxRbGFT*24$2ey*OhEUG*3CEj$Cv6o5g1$d$uq}1Tnd}xu3-=UR6vURVz*eF8iMHdLm+PRP5n?KgT3=#kbnJA1ZmT zFsy{pRrSMxEq@L1!nHrtpS{g~+q<;6Yk^5)^&plE>8#*)4B;cj?q@SP9@o#QfZj3Wy={!9BZG4FIC$=it$?%qoI>=Ac!r$S>a7i z5k(!R(>A`exkdn=LQ4uj1^4z;WKvQ7ZMqk^2PXS(1y@yvCb!Rt1Up++R{O|P8P%Le z<}91VmiRfhS?cG0y&D5*%BAMx|1Q?;=+d9tBDzv<7Y!cIMyM>jQD};=E}kb zL*ug_!gXJsBZmyv0*M)_UZod2#KxZsLD{hj&!g9-F%kgy*M4T@epjUazF6=_legEN zE`NHc_gMQQPIdgyvDtL6drxYJz=$mJ9$sFE~Tf%JB? zMq*R9o_1)>Pi{YQyRvR4bW6JI%=H-_m(--jFY-;f77Iq;1G~PZAHVQsFR0uAZ>fqH zeBLNp&J~Xy&t}P%(lYbB!5=N_E1^(L$AvQV@kb2+zh(LLy1q)awnv_wKH9~7vhPy< z<&kBIEw%7;_Dygj#FO_dqCIc^jySyHYvBp|qYwihU*C1Bea6P!^;7Rh?CxFaRL?cS zyODJ`UqdT;t2#&1mCRJ@WJpd}ED8j9XZK6M7^m|{02PV(v700sJi!QFQ^@*)#k;G~ zG!Dhy1;5kd`mk)QzF#)oO_TlmSpDDB-8hV%`ND@nf}2l97t-9%`3-u4JJ!XbdPn}E zso?O(=Jy1$ip1%nLySNRmv9wizhe{@v#9^JxW)*oR8**Wfvy-h6P1&|rrP;RpEaV0 zXie4&JoVS7A&7g#o-mp6R4kT`9)1)gpQ!FqwMH7sXtC2$&@h(<5-7r`1j@NGVhXuQ zK$|lsLLQa=EZ?Rq*`7#gb`MkET2Po}2IS}aQqucz5_f_oP34eF+H^7O;DtVdAGP8^ zO)vkFov)KzPqC5RRMpLN3JNw-8K{xpZ(a7VW=F^sps}{Gow411aWNSwE`~KLeBG}F zGDQh@z*50X)VznMCppg4+FE+2zWW{qlHZ(akb{s>fuuIhO>8l92ITDhd%(~%gv>=p zyw+{*eR<4(m{lrwuP^Aoq}hfcA@m9}xrS+JAKnG-LhWsvwV5l2(lmBwyz10k6Jw@R oxgp`u!d;=%e?q>$Ueuc)Q%j15WZ@XMH=qt+?Qy6&+uxG^1PBMxPyhe` literal 0 HcmV?d00001 diff --git a/packages/text-area/test/visual/lumo/text-area.test.js b/packages/text-area/test/visual/lumo/text-area.test.js index c1e2c8c2bb..ab636c0761 100644 --- a/packages/text-area/test/visual/lumo/text-area.test.js +++ b/packages/text-area/test/visual/lumo/text-area.test.js @@ -66,6 +66,24 @@ describe('text-area', () => { await visualDiff(div, 'scrolled'); }); + it('scrolled with prefix, suffix, clear button', async () => { + const prefix = document.createElement('span'); + prefix.setAttribute('slot', 'prefix'); + prefix.textContent = '$'; + element.appendChild(prefix); + + const suffix = document.createElement('span'); + suffix.setAttribute('slot', 'suffix'); + suffix.textContent = '$'; + element.appendChild(suffix); + + element.clearButtonVisible = true; + element.style.height = '70px'; + element.value = 'a\nb\nc\nd\ne'; + element.focus(); + await visualDiff(div, 'scrolled-with-prefix-suffix-clear-button'); + }); + it('error message', async () => { element.label = 'Label'; element.errorMessage = 'This field is required'; diff --git a/packages/text-area/test/visual/material/screenshots/text-area/baseline/clear-button.png b/packages/text-area/test/visual/material/screenshots/text-area/baseline/clear-button.png index c971b0f769f21e61e025567f16bf8eba40ed4bc4..7cac865fee39eeb94cab8d44cea6b04432f5aead 100644 GIT binary patch delta 898 zcmV-|1AY9N3783xF2%m+znxB}lK`0b=TA=n zcqEe%1R;^1Gk^NhpvG=3=W4~Td{W>GafZT!nKX_!jJjpeI}j8e%5i8^mbLohwL!g_ zvQ#}>8}vRm2X$z3xqPRKDU6-gE~wf6ykSyoHd>`l&Us~ddG!~IwUb+S8ZU4B&$4ie zjW(-P&N-#4joSTm>$LHgNqkVYIH;@Mi0as@t~wnSnSX*$%%A_}pcZM6A3DXeSN}Nd z)Vm<>UVe^cs#TY$XrtoLYO{=5hw5Y3OtDtJ>NLx14RKJtnpB0gcJ^;BcnFEob@6&s zXE7D)RQ5UDv*b&>g738(eik)pKlF0J>!qite($u|7V^nVv-v{lDpxwz8s1&hL2X%S z+HAGWoPXxCxm+k!hC$_ytqr{8m8iZTCh4wgs6;+^^?lSNNmEqUI)$I7CoNSpjdFMP zkl6=kH}2KPxiWuwQ0KkIc+}@yR^l<7N43%B3u2O_@AnK&e30MtirZ9v->Y>&yYtuj z7}Zvlnr_hH?A5+}@9f4=qefN1srvoCxz|zB{C~a2#$O;&nx%?$uj7yJKQkuj&Y)hF zeH(SL&}`Vrg+{-6imI};4n?hIyZkZnsM@XGKfC!{b9rrdwZh`}J7*t00ph_Od)0NX z<6^0$qWZeltXM1k#H#MxHh)?6wOy^Qb;`4|(^DK&k4t6Q^6Xt;(zU&VB=OQT>0-}r zI)8h_d?D`!^@mZj+3f5~A74)5v0Ypbh1Az@MlcNUd>JlS9kM{ z>g$~pa;1swwF5x`hWJ}Pk)A=3sW%w!w+?)Me*VmP0RL-GPfs_EmdaKV6djJ3c07*qoM6N<$f*h6N^#A|> delta 952 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 literal 0 HcmV?d00001 diff --git a/packages/text-area/test/visual/material/text-area.test.js b/packages/text-area/test/visual/material/text-area.test.js index 1db94534b7..10e6adfc31 100644 --- a/packages/text-area/test/visual/material/text-area.test.js +++ b/packages/text-area/test/visual/material/text-area.test.js @@ -66,6 +66,24 @@ describe('text-area', () => { await visualDiff(div, 'scrolled'); }); + it('scrolled with prefix, suffix, clear button', async () => { + const prefix = document.createElement('span'); + prefix.setAttribute('slot', 'prefix'); + prefix.textContent = '$'; + element.appendChild(prefix); + + const suffix = document.createElement('span'); + suffix.setAttribute('slot', 'suffix'); + suffix.textContent = '$'; + element.appendChild(suffix); + + element.clearButtonVisible = true; + element.style.height = '70px'; + element.value = 'a\nb\nc\nd\ne'; + element.focus(); + await visualDiff(div, 'scrolled-with-prefix-suffix-clear-button'); + }); + it('error message', async () => { element.label = 'Label'; element.errorMessage = 'This field is required'; diff --git a/packages/text-area/theme/lumo/vaadin-text-area-styles.js b/packages/text-area/theme/lumo/vaadin-text-area-styles.js index 6f537ab37c..9e98c96941 100644 --- a/packages/text-area/theme/lumo/vaadin-text-area-styles.js +++ b/packages/text-area/theme/lumo/vaadin-text-area-styles.js @@ -56,8 +56,18 @@ const textArea = css` --_lumo-text-field-overflow-mask-image: none; } - /* Vertically align icon prefix/suffix with the first line of text */ - [part='input-field'] ::slotted(vaadin-icon) { + /* Use sticky positioning to keep prefix/suffix/clear button visible when scrolling textarea container */ + [part='input-field'] ::slotted([slot$='fix']), + [part='clear-button'] { + position: sticky; + top: 0; + align-self: flex-start; + } + + /* Vertically align icon prefix/suffix/clear button with the first line of text */ + [part='input-field'] ::slotted(vaadin-icon[slot$='fix']), + [part='clear-button'] { + top: calc((var(--lumo-icon-size-m) - 1em * var(--lumo-line-height-s)) / -2); margin-top: calc((var(--lumo-icon-size-m) - 1em * var(--lumo-line-height-s)) / -2); } `; diff --git a/packages/text-area/theme/material/vaadin-text-area-styles.js b/packages/text-area/theme/material/vaadin-text-area-styles.js index 6caed8360c..acaa640bb0 100644 --- a/packages/text-area/theme/material/vaadin-text-area-styles.js +++ b/packages/text-area/theme/material/vaadin-text-area-styles.js @@ -22,6 +22,14 @@ const textArea = css` [part='input-field']::after { bottom: calc(var(--_text-area-vertical-scroll-position) * -1); } + + /* Use sticky positioning to keep prefix/suffix/clear button visible when scrolling textarea container */ + [part='input-field'] ::slotted([slot$='fix']), + [part='clear-button'] { + position: sticky; + top: 0; + align-self: flex-start; + } `; registerStyles('vaadin-text-area', [inputFieldShared, textArea], { moduleId: 'material-text-area' });