Compare commits
613 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
27acc9a80e | |
![]() |
43ad5dec90 | |
![]() |
aa8802679f | |
![]() |
aa211fd789 | |
![]() |
61d39be86f | |
![]() |
b80bd37f6e | |
![]() |
3db5e191b8 | |
![]() |
45c7109212 | |
![]() |
b58d0fb723 | |
![]() |
a21a1ca533 | |
![]() |
4a37016f4e | |
![]() |
5d6ebb30ac | |
![]() |
888457238d | |
![]() |
b0d9309471 | |
![]() |
f64d0718ae | |
![]() |
968317ca9f | |
![]() |
22dad3ba6d | |
![]() |
4f7bd6f28d | |
![]() |
12fcfa15b1 | |
![]() |
e46d537d45 | |
![]() |
ac9d1b0a7f | |
![]() |
2c7008d786 | |
![]() |
49d4b3166e | |
![]() |
339fb4a230 | |
![]() |
bb443a05e2 | |
![]() |
3a79f72816 | |
![]() |
89eec07145 | |
![]() |
c69a6d29b2 | |
![]() |
2666cb79ab | |
![]() |
35d5185634 | |
![]() |
4492086aac | |
![]() |
4b7c6ac02c | |
![]() |
208b8d3085 | |
![]() |
f41fec26ba | |
![]() |
9118d6cd42 | |
![]() |
5c7aaf0dd6 | |
![]() |
b82d8dd2ad | |
![]() |
1d0fa8533a | |
![]() |
4318147fc6 | |
![]() |
312bcc5127 | |
![]() |
6594fe3964 | |
![]() |
82f28ce3d0 | |
![]() |
6e2c5a6a83 | |
![]() |
307148e2df | |
![]() |
afebeb9ffa | |
![]() |
aeda2637f6 | |
![]() |
f42d8ad1ce | |
![]() |
33a0708eb4 | |
![]() |
085eb398a4 | |
![]() |
9c27414cd0 | |
![]() |
014e86bd27 | |
![]() |
40ad45bc05 | |
![]() |
1c82940160 | |
![]() |
7ce0f115d5 | |
![]() |
54434b0931 | |
![]() |
e01f26c541 | |
![]() |
9a45b35511 | |
![]() |
8e8073d17e | |
![]() |
d6cc262c3a | |
![]() |
9d7c171940 | |
![]() |
48a3ceb921 | |
![]() |
23c620ea3a | |
![]() |
752686e334 | |
![]() |
9b0f0e71e7 | |
![]() |
42d33e963c | |
![]() |
ed27700ef4 | |
![]() |
eedd7f3302 | |
![]() |
c28c38d02e | |
![]() |
162d1fcf95 | |
![]() |
4815ee6f20 | |
![]() |
2b41e56520 | |
![]() |
ab874ffd4b | |
![]() |
61ade6b8ec | |
![]() |
4d35b8caa3 | |
![]() |
040af82eb9 | |
![]() |
a8c72fc5e7 | |
![]() |
c25736d57d | |
![]() |
4a48bfc66b | |
![]() |
4138d3c822 | |
![]() |
dec67a6d65 | |
![]() |
85c48c0566 | |
![]() |
966bc1004c | |
![]() |
457d0fde0b | |
![]() |
ff184b3969 | |
![]() |
75886a8cbf | |
![]() |
2b0c2da232 | |
![]() |
ffd4d8fe92 | |
![]() |
49e1323baa | |
![]() |
35d1de9ea6 | |
![]() |
fa46999963 | |
![]() |
01300d01da | |
![]() |
9a5f83ed06 | |
![]() |
ce6b7f3b4e | |
![]() |
4a2f95fe88 | |
![]() |
7c73beb309 | |
![]() |
0cbf3ca354 | |
![]() |
7afb7ce465 | |
![]() |
9cc73011c5 | |
![]() |
4b21210700 | |
![]() |
a80ca17461 | |
![]() |
ad8d32ab09 | |
![]() |
d870f3f8e0 | |
![]() |
c717473568 | |
![]() |
1e07544e74 | |
![]() |
8ab008d255 | |
![]() |
f034a7759e | |
![]() |
3f33cefa81 | |
![]() |
81e43c56ef | |
![]() |
f400c803e1 | |
![]() |
502c11cc4c | |
![]() |
2cdb69f706 | |
![]() |
2eed8e62ec | |
![]() |
61c0d0cc9d | |
![]() |
d7f9bd27dc | |
![]() |
4ed2868137 | |
![]() |
8696e01039 | |
![]() |
a3fd390619 | |
![]() |
a9198e44df | |
![]() |
509ec682f2 | |
![]() |
73f0a29acf | |
![]() |
f93dd9170d | |
![]() |
cfa0a68568 | |
![]() |
afcff32fcc | |
![]() |
b989cf2d97 | |
![]() |
0e6fd652b8 | |
![]() |
6625d39118 | |
![]() |
67efafca4a | |
![]() |
a8a774a5ff | |
![]() |
1fc109704b | |
![]() |
d140523c89 | |
![]() |
91fe1b0d71 | |
![]() |
c1b4941def | |
![]() |
af383a34bc | |
![]() |
1dccce4e16 | |
![]() |
8aa8e5a778 | |
![]() |
42952b713a | |
![]() |
07c36192b8 | |
![]() |
562623c091 | |
![]() |
e362571719 | |
![]() |
e32ae99bfd | |
![]() |
ccbeb44264 | |
![]() |
3499b11a47 | |
![]() |
dae7262f13 | |
![]() |
8cf6be11f7 | |
![]() |
2510608665 | |
![]() |
b22875db33 | |
![]() |
2bdeed1432 | |
![]() |
49a6b588c1 | |
![]() |
bd080cde2a | |
![]() |
c1454bc7b5 | |
![]() |
61402142f8 | |
![]() |
242982301d | |
![]() |
9bdf882517 | |
![]() |
88ec06b717 | |
![]() |
6c39bec277 | |
![]() |
82f407d396 | |
![]() |
bfcdba251f | |
![]() |
0abcd25b2a | |
![]() |
72b8d09b92 | |
![]() |
b4c29d927b | |
![]() |
bf917f36eb | |
![]() |
0f9c80b86e | |
![]() |
61e5746b0d | |
![]() |
7786a81e76 | |
![]() |
6f89185fe1 | |
![]() |
449adb03df | |
![]() |
4428423be4 | |
![]() |
380fcd4aa9 | |
![]() |
4a1296bb3f | |
![]() |
b9c65656db | |
![]() |
f1bcf2093a | |
![]() |
398710cf1b | |
![]() |
858c4ec409 | |
![]() |
77eab3637c | |
![]() |
664711373c | |
![]() |
21d85ea82c | |
![]() |
b3ef24963f | |
![]() |
f953482a4d | |
![]() |
a9f9899185 | |
![]() |
c99e9b00bd | |
![]() |
3084ced55f | |
![]() |
c5ea668e88 | |
![]() |
3c5fb84542 | |
![]() |
2f7f0e6928 | |
![]() |
2c4d4650da | |
![]() |
0f1ffc99cd | |
![]() |
83d6c93765 | |
![]() |
a6c945caaa | |
![]() |
d0f7c34497 | |
![]() |
2b8f2adcbf | |
![]() |
f25bf6e189 | |
![]() |
93415d0442 | |
![]() |
d185a3af21 | |
![]() |
d3800b54a3 | |
![]() |
b7eed32484 | |
![]() |
46be19531d | |
![]() |
089548ed74 | |
![]() |
ce72484623 | |
![]() |
31d00bf7d1 | |
![]() |
deada0aeb8 | |
![]() |
418d8b33dd | |
![]() |
3c05b7704b | |
![]() |
1254677805 | |
![]() |
f7cc27b7ad | |
![]() |
9855e43805 | |
![]() |
1f01ae0728 | |
![]() |
9464158c0c | |
![]() |
13a4470fd8 | |
![]() |
84fb4b4b3d | |
![]() |
106750ed62 | |
![]() |
cac650737c | |
![]() |
95fa2547fe | |
![]() |
70102039c4 | |
![]() |
7a0c2a384c | |
![]() |
72e148cae8 | |
![]() |
6c13c964c5 | |
![]() |
367ddff30e | |
![]() |
e3ad856543 | |
![]() |
61df5e656f | |
![]() |
439fe840b4 | |
![]() |
197a00f6ea | |
![]() |
3f99a7e985 | |
![]() |
9c0311546b | |
![]() |
7f5b630d72 | |
![]() |
65ccb447c9 | |
![]() |
18405e13b2 | |
![]() |
9e78b4a985 | |
![]() |
6cf5d79e2e | |
![]() |
1abc33a9e7 | |
![]() |
e39e998ecc | |
![]() |
cfd4aadc29 | |
![]() |
38dd977b4c | |
![]() |
72f9262d0a | |
![]() |
c2d71fa7c3 | |
![]() |
969dadb265 | |
![]() |
9c3bf46108 | |
![]() |
141f0100d2 | |
![]() |
6ced156342 | |
![]() |
42608a5121 | |
![]() |
22b21cdac8 | |
![]() |
80a5b531f6 | |
![]() |
cacbde3e03 | |
![]() |
e3f09a18a1 | |
![]() |
7bfe30d280 | |
![]() |
53dc5daaaf | |
![]() |
531ae16553 | |
![]() |
d2b6eb9d94 | |
![]() |
27a4d8ceff | |
![]() |
12074a0dca | |
![]() |
8f95cdd5a3 | |
![]() |
cb0abe5fd5 | |
![]() |
ed87500e77 | |
![]() |
c01630113d | |
![]() |
5279d1289a | |
![]() |
9d406ab7ba | |
![]() |
826c183d0b | |
![]() |
bc576d6255 | |
![]() |
2c39273cc6 | |
![]() |
b49540a339 | |
![]() |
37059c38fd | |
![]() |
4fe57fa322 | |
![]() |
a3ccdeffc2 | |
![]() |
e8c2860c7d | |
![]() |
f1f89191ee | |
![]() |
0c863c1803 | |
![]() |
7591d5c3e6 | |
![]() |
4ea318be30 | |
![]() |
5fd00c05b5 | |
![]() |
0a738a36b6 | |
![]() |
10f990d534 | |
![]() |
8b5d71663a | |
![]() |
058e8ec542 | |
![]() |
f70b04c74f | |
![]() |
2ce4e7da82 | |
![]() |
fc5181d1d8 | |
![]() |
994707bd50 | |
![]() |
e9d26f2a7d | |
![]() |
7fd0e4a225 | |
![]() |
e229248053 | |
![]() |
10159941b9 | |
![]() |
9c26ab05d3 | |
![]() |
6861a77d29 | |
![]() |
308c30c738 | |
![]() |
afc1b84ed0 | |
![]() |
58f6d6ee28 | |
![]() |
7270855ce8 | |
![]() |
19f0aea965 | |
![]() |
6f032c9722 | |
![]() |
6be947aeb9 | |
![]() |
45ede0853b | |
![]() |
afb2619a81 | |
![]() |
2bf85998ba | |
![]() |
42cb6871ee | |
![]() |
508e8e3706 | |
![]() |
fe3c2bdf89 | |
![]() |
64b9347fce | |
![]() |
96f940d834 | |
![]() |
d3d37f08a2 | |
![]() |
d49082008e | |
![]() |
1d0a2737a4 | |
![]() |
c9f0841628 | |
![]() |
03760e3e3d | |
![]() |
c36f7e701f | |
![]() |
83017269ab | |
![]() |
1c7b7a35f6 | |
![]() |
28263bbe33 | |
![]() |
5aad611d4c | |
![]() |
429172b345 | |
![]() |
e5787c2ed2 | |
![]() |
698c0ff3b4 | |
![]() |
db4148af5a | |
![]() |
21cf533664 | |
![]() |
4c8cc0129f | |
![]() |
a694167f37 | |
![]() |
3ed455b3f7 | |
![]() |
e49e72d24a | |
![]() |
149cedd262 | |
![]() |
8bf8515933 | |
![]() |
0d24755ee3 | |
![]() |
f2f7cfd94d | |
![]() |
d933605b56 | |
![]() |
266482deca | |
![]() |
fd8af2322c | |
![]() |
9fdc297686 | |
![]() |
fded418b8a | |
![]() |
feffe70ebb | |
![]() |
02ed988cba | |
![]() |
6eb4d8f5c5 | |
![]() |
b61c88e5df | |
![]() |
ac93c476d1 | |
![]() |
db46965761 | |
![]() |
5578c14a8e | |
![]() |
69640c0af8 | |
![]() |
0df6abe3a7 | |
![]() |
b103b7570d | |
![]() |
61d6312783 | |
![]() |
98be7071e5 | |
![]() |
5439e0c164 | |
![]() |
9be58078d2 | |
![]() |
063c06f9c6 | |
![]() |
43009f0c59 | |
![]() |
678ec079bc | |
![]() |
eba8f6b960 | |
![]() |
760c4c2695 | |
![]() |
8ab50b1757 | |
![]() |
b0990b7323 | |
![]() |
5376014b33 | |
![]() |
bccd9204e8 | |
![]() |
8932aff13f | |
![]() |
de00607dc7 | |
![]() |
118ae9a50b | |
![]() |
0683ede0fb | |
![]() |
838aa71b4b | |
![]() |
2bf654da71 | |
![]() |
515ab9e38c | |
![]() |
d4f2e97ca9 | |
![]() |
be90b53527 | |
![]() |
0b85b84dcf | |
![]() |
4e277ea9bb | |
![]() |
bf97057c2c | |
![]() |
637656b0c3 | |
![]() |
0e1b7fd94f | |
![]() |
33d1553908 | |
![]() |
2eaad16331 | |
![]() |
58998c4978 | |
![]() |
7db4265616 | |
![]() |
8a3ed32254 | |
![]() |
1151bdad0f | |
![]() |
84037f8eef | |
![]() |
3e46f27b59 | |
![]() |
719847901e | |
![]() |
fbfec0a062 | |
![]() |
9a5cbeee50 | |
![]() |
b0125de963 | |
![]() |
bf1e6fec95 | |
![]() |
5f1cb0d240 | |
![]() |
f6daa8d28f | |
![]() |
48ab5a2f99 | |
![]() |
ae27d430e5 | |
![]() |
9dbe035efe | |
![]() |
6d60eba281 | |
![]() |
bfcbd5bdef | |
![]() |
4d2a37fcd3 | |
![]() |
dcc3bb10cb | |
![]() |
7d1418d9f4 | |
![]() |
3653f37d6b | |
![]() |
f265a7bb02 | |
![]() |
89314fb4d0 | |
![]() |
b1f38eb2ec | |
![]() |
d95861aa90 | |
![]() |
5cc85f3cc1 | |
![]() |
f3935ebb4f | |
![]() |
11c52d487d | |
![]() |
295c417f49 | |
![]() |
27c5a6c96a | |
![]() |
fc7cadb3f9 | |
![]() |
ad1d6443f2 | |
![]() |
77d0d188f0 | |
![]() |
b22bd85828 | |
![]() |
f819a1b209 | |
![]() |
dde2ff140d | |
![]() |
f429148734 | |
![]() |
23a213acda | |
![]() |
d241a06f9d | |
![]() |
1d9a521669 | |
![]() |
a04cae1221 | |
![]() |
add208aefb | |
![]() |
355c41b4aa | |
![]() |
3f5f3ecabf | |
![]() |
41a455f881 | |
![]() |
eda7247c2c | |
![]() |
f85485e733 | |
![]() |
a1e967dfc2 | |
![]() |
6058ca5576 | |
![]() |
dd063b8275 | |
![]() |
9c6a9fb47c | |
![]() |
516b2e5a0c | |
![]() |
d3a919b0bf | |
![]() |
261e7d0857 | |
![]() |
b393a0a2dd | |
![]() |
2b80870461 | |
![]() |
33a47bc27a | |
![]() |
53b146ab88 | |
![]() |
f3ffcdbc7e | |
![]() |
37b5d02b6d | |
![]() |
1b51e6ffb3 | |
![]() |
f39d4894e4 | |
![]() |
975d70e7ed | |
![]() |
c301c63e8b | |
![]() |
e04f73dfef | |
![]() |
8fcb3fdfe3 | |
![]() |
c7b15a96a8 | |
![]() |
e8918ce589 | |
![]() |
62dda88ea0 | |
![]() |
3741931363 | |
![]() |
7af22a70f9 | |
![]() |
087dfa2f1b | |
![]() |
799eeed346 | |
![]() |
124aae72a4 | |
![]() |
39e5824699 | |
![]() |
9df8317ece | |
![]() |
62e7f94aba | |
![]() |
47385347ee | |
![]() |
6240ab2885 | |
![]() |
328e42a9be | |
![]() |
634675e032 | |
![]() |
7ddf882a99 | |
![]() |
895b43338d | |
![]() |
9f53d53cb8 | |
![]() |
cd47a277da | |
![]() |
adec5211f1 | |
![]() |
a6a270b44a | |
![]() |
8472c25633 | |
![]() |
c1ed77f67a | |
![]() |
df6a1fdb71 | |
![]() |
321989b9c2 | |
![]() |
2f51f2d3af | |
![]() |
dc9987aea8 | |
![]() |
3715ded674 | |
![]() |
04e3819b0b | |
![]() |
587c1ca89d | |
![]() |
8a233d7c3a | |
![]() |
0464c84afc | |
![]() |
7e29eb2163 | |
![]() |
92795a828f | |
![]() |
44e5d09f22 | |
![]() |
f6afd7fffc | |
![]() |
7de1be6a9a | |
![]() |
19ec975deb | |
![]() |
4ccb1c3e19 | |
![]() |
68d295d7ef | |
![]() |
bbfb3cef7d | |
![]() |
e9ce4eb2d5 | |
![]() |
cb08f8551a | |
![]() |
f0e5da3b69 | |
![]() |
2f049329a5 | |
![]() |
350dbfedbb | |
![]() |
4b2ffd7127 | |
![]() |
a5389a22ea | |
![]() |
7a34c99935 | |
![]() |
dc480bd4b3 | |
![]() |
1d774507c0 | |
![]() |
80918cba98 | |
![]() |
197e209b4e | |
![]() |
82c4c8f0d3 | |
![]() |
23b81b0e17 | |
![]() |
f0649999fb | |
![]() |
e2d4f8c2e3 | |
![]() |
de77b0175d | |
![]() |
26f98b7b10 | |
![]() |
a9fbf98f0e | |
![]() |
fee7c04d67 | |
![]() |
8658806e3f | |
![]() |
4f3ce35e74 | |
![]() |
69c17dc255 | |
![]() |
a40816880a | |
![]() |
2c1afa5e72 | |
![]() |
81e26a900e | |
![]() |
fc0f0d8a96 | |
![]() |
a205615af9 | |
![]() |
9b5a07220b | |
![]() |
47c84cdbad | |
![]() |
989bedda47 | |
![]() |
dd57d1e305 | |
![]() |
158cca7f8a | |
![]() |
8099391e97 | |
![]() |
7939eb1718 | |
![]() |
34373ca05d | |
![]() |
4ef70b1503 | |
![]() |
31776a2cf8 | |
![]() |
31ca070a18 | |
![]() |
1d01df4b85 | |
![]() |
337d958c67 | |
![]() |
94e981e00b | |
![]() |
221b203cbb | |
![]() |
dfe462ec6f | |
![]() |
8110d8cbbd | |
![]() |
c903de3c0e | |
![]() |
44d7917afd | |
![]() |
73ce708868 | |
![]() |
d211688059 | |
![]() |
9d5343ae9c | |
![]() |
2d54e2124f | |
![]() |
b5d7d582cd | |
![]() |
0399ce0ec7 | |
![]() |
94c2887c81 | |
![]() |
75e4b72c21 | |
![]() |
287a8d0c4e | |
![]() |
1e4e3cb3b4 | |
![]() |
e64a19a05a | |
![]() |
6c735fee67 | |
![]() |
f8ddc430cf | |
![]() |
641714734a | |
![]() |
46862d749b | |
![]() |
1f33babc89 | |
![]() |
b2841a27ae | |
![]() |
c0d7d041b4 | |
![]() |
10b52e0072 | |
![]() |
d64c6a8d53 | |
![]() |
2eb071ce30 | |
![]() |
6bd8a9b984 | |
![]() |
040956819f | |
![]() |
0f634e27d5 | |
![]() |
9815f817d4 | |
![]() |
d933f3edd5 | |
![]() |
dd60465373 | |
![]() |
60a8be3014 | |
![]() |
a26ac3e9f4 | |
![]() |
e7fdb128e3 | |
![]() |
8d0155878e | |
![]() |
e5e98e5776 | |
![]() |
05357a8c3f | |
![]() |
86450c2a1b | |
![]() |
9ea87fb973 | |
![]() |
dae579a88e | |
![]() |
58e8fd3e2e | |
![]() |
aae9a48dd0 | |
![]() |
09c5a3e53f | |
![]() |
e42fdd7a06 | |
![]() |
8b6a771318 | |
![]() |
bb4b86a82e | |
![]() |
9280b418d7 | |
![]() |
efe600e89e | |
![]() |
8b34bdfa5e | |
![]() |
3b1d48b4b4 | |
![]() |
dd1a535943 | |
![]() |
5b583962db | |
![]() |
37d35f7801 | |
![]() |
a4b6c0aee4 | |
![]() |
03f559a0dc | |
![]() |
bf1226d3bb | |
![]() |
527dec6078 | |
![]() |
af9371fe6f | |
![]() |
5c136e0286 | |
![]() |
a32d29149f | |
![]() |
e6a46b43ac | |
![]() |
9d1e5d72b5 | |
![]() |
63a688f94c | |
![]() |
21f9a1178a | |
![]() |
76573fc252 | |
![]() |
208c7ac6de | |
![]() |
44be8722f8 | |
![]() |
a435e2c090 | |
![]() |
8475542b2f | |
![]() |
40a65d19da | |
![]() |
8ad9317d11 | |
![]() |
76585f75b9 | |
![]() |
3656dd5dbb | |
![]() |
7b60f2a8e6 | |
![]() |
5cf2707e11 | |
![]() |
d716421745 | |
![]() |
c6f692222d | |
![]() |
c1a1b93553 | |
![]() |
6e41fbd01f | |
![]() |
093fa555ba | |
![]() |
e9d41efcec | |
![]() |
d5348f0361 | |
![]() |
e4f678f665 | |
![]() |
f00b9535d2 | |
![]() |
a1ac22443e | |
![]() |
4eb8088645 | |
![]() |
353f470c11 | |
![]() |
73f7f9e3b9 | |
![]() |
5bc17f0578 | |
![]() |
dbe7fe78ce | |
![]() |
6e1f30666b | |
![]() |
c4a61f210f | |
![]() |
0244e7f5b4 | |
![]() |
3aedf48eaf | |
![]() |
78045b4b5b | |
![]() |
894a5b955c | |
![]() |
a8dbea7c32 | |
![]() |
1d08e80165 |
|
@ -7,4 +7,7 @@ es/
|
|||
lib/
|
||||
_site/
|
||||
dist/
|
||||
components/version/version.tsx
|
||||
site/dist/
|
||||
components/version/version.ts
|
||||
site/src/router/demoRoutes.js
|
||||
locale/
|
32
.eslintrc.js
32
.eslintrc.js
|
@ -15,9 +15,21 @@ module.exports = {
|
|||
'plugin:vue/vue3-recommended',
|
||||
'plugin:import/recommended',
|
||||
'plugin:import/typescript',
|
||||
'prettier',
|
||||
'@vue/typescript/recommended',
|
||||
'@vue/prettier',
|
||||
// 'prettier',
|
||||
],
|
||||
// extends: [
|
||||
// 'eslint:recommended',
|
||||
// 'plugin:vue/vue3-recommended',
|
||||
// '@vue/typescript/recommended',
|
||||
// '@vue/prettier',
|
||||
// ],
|
||||
plugins: ['markdown', 'jest', '@typescript-eslint', 'import'],
|
||||
globals: {
|
||||
h: true,
|
||||
defineProps: 'readonly',
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.md'],
|
||||
|
@ -28,12 +40,11 @@ module.exports = {
|
|||
},
|
||||
{
|
||||
files: ['*.ts', '*.tsx'],
|
||||
extends: ['@vue/typescript/recommended', '@vue/prettier', '@vue/prettier/@typescript-eslint'],
|
||||
// extends: ['@vue/typescript/recommended', '@vue/prettier'],
|
||||
parserOptions: {
|
||||
project: './tsconfig.json',
|
||||
},
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': 0,
|
||||
'@typescript-eslint/ban-types': 0,
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 0,
|
||||
|
@ -51,17 +62,21 @@ module.exports = {
|
|||
parser: 'vue-eslint-parser',
|
||||
parserOptions: {
|
||||
parser: '@typescript-eslint/parser',
|
||||
ecmaVersion: 2021,
|
||||
},
|
||||
rules: {
|
||||
'no-console': 'off',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{ vars: 'all', args: 'after-used', ignoreRestSiblings: true },
|
||||
],
|
||||
'vue/no-reserved-component-names': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': 0,
|
||||
'@typescript-eslint/no-empty-function': 0,
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{ vars: 'all', args: 'after-used', ignoreRestSiblings: true, argsIgnorePattern: '^_' },
|
||||
],
|
||||
'import/no-named-as-default': 'off',
|
||||
'import/namespace': [2, { allowComputed: true }],
|
||||
'import/no-named-as-default-member': 'off',
|
||||
|
@ -94,7 +109,4 @@ module.exports = {
|
|||
],
|
||||
'vue/multi-word-component-names': 'off',
|
||||
},
|
||||
globals: {
|
||||
h: true,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
blank_issues_enabled: false
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Create new issue
|
||||
url: https://vuecomponent.github.io/issue-helper/
|
||||
|
@ -13,5 +13,5 @@ contact_links:
|
|||
url: https://www.paypal.me/tangjinzhou
|
||||
about: Love Ant Design Vue? Please consider supporting us via Paypal.
|
||||
- name: 支付宝/微信 赞助
|
||||
url: https://qn.antdv.com/alipay-and-wechat.png
|
||||
url: https://aliyuncdn.antdv.com/alipay-and-wechat.png
|
||||
about: Ant Design Vue 的健康持续发展需要您的支持,🙏
|
||||
|
|
|
@ -4,12 +4,15 @@ on:
|
|||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
close-issues:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: need reproduce
|
||||
uses: actions-cool/issues-helper@v1.7
|
||||
uses: actions-cool/issues-helper@v3
|
||||
with:
|
||||
actions: 'close-issues'
|
||||
labels: '🤔 Need Reproduce'
|
||||
|
|
|
@ -1,18 +1,25 @@
|
|||
name: Issue Reply
|
||||
name: Issue Labeled
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [labeled]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
issue-reply:
|
||||
issue-labeled:
|
||||
permissions:
|
||||
issues: write # for actions-cool/issues-helper to update issues
|
||||
pull-requests: write # for actions-cool/issues-helper to update PRs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Need Reproduce
|
||||
if: github.event.label.name == '🤔 Need Reproduce'
|
||||
uses: actions-cool/issues-helper@v1.2
|
||||
uses: actions-cool/issues-helper@v3
|
||||
with:
|
||||
actions: 'create-comment'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
body: |
|
||||
Hello @${{ github.event.issue.user.login }}. Please provide a online reproduction by forking this [link for vue2](https://codesandbox.io/s/2wpk21kzvr)、 [link for vue3](https://codesandbox.io/s/agitated-franklin-1w72v) or a minimal GitHub repository. Make sure to choose the correct version.
|
||||
|
@ -21,9 +28,10 @@ jobs:
|
|||
|
||||
- name: help wanted
|
||||
if: github.event.label.name == 'help wanted'
|
||||
uses: actions-cool/issues-helper@v1.2
|
||||
uses: actions-cool/issues-helper@v3
|
||||
with:
|
||||
actions: 'create-comment'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
body: |
|
||||
Hello @${{ github.event.issue.user.login }}. We totally like your proposal/feedback, welcome to send us a Pull Request for it. Please send your Pull Request to proper branch, fill the Pull Request Template here, provide changelog/TypeScript/documentation/test cases if needed and make sure CI passed, we will review it soon. We appreciate your effort in advance and looking forward to your contribution!
|
||||
|
@ -32,12 +40,37 @@ jobs:
|
|||
|
||||
- name: Usage
|
||||
if: github.event.label.name == 'Usage'
|
||||
uses: actions-cool/issues-helper@v1.2
|
||||
uses: actions-cool/issues-helper@v3
|
||||
with:
|
||||
actions: 'create-comment, close-issue'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
body: |
|
||||
Hello @${{ github.event.issue.user.login }}, we use GitHub issues to trace bugs or discuss plans of Ant Design Vue. So, please don't ask usage questions here. You can try to open a new discussion in [antdv discussions](https://github.com/vueComponent/ant-design-vue/discussions), select `Q&A` to ask questions, also can ask questions on [Stack Overflow](http://stackoverflow.com/questions/) or [Segment Fault](https://segmentfault.com).
|
||||
|
||||
你好 @${{ github.event.issue.user.login }},Ant Design Vue Issue 板块是用于 bug 反馈与需求讨论的地方。请勿询问如何使用的问题,你可以试着在 [antdv discussions](https://github.com/vueComponent/ant-design-vue/discussions) 新开一个 discussion,选择 `Q&A` 类别进行提问,也可以在 [Stack Overflow](http://stackoverflow.com/questions/) 或者 [Segment Fault](https://segmentfault.com/) 中提问。
|
||||
|
||||
|
||||
- name: 1.x
|
||||
if: github.event.label.name == '1.x'
|
||||
uses: actions-cool/issues-helper@v3
|
||||
with:
|
||||
actions: 'create-comment,close-issue'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
body: |
|
||||
Hi @${{ github.event.issue.user.login }}. Current version (1.x) is off the maintenance period. We may not accept pull request or fix bug with it anymore. This topic will be auto closed.
|
||||
|
||||
你好 @${{ github.event.issue.user.login }},当前版本(1.x)已经过了维护期。我们不会再接受对其的相关 PR 与 issue。当前 topic 会被自动关闭。
|
||||
|
||||
- name: 2.x
|
||||
if: github.event.label.name == '2.x'
|
||||
uses: actions-cool/issues-helper@v3
|
||||
with:
|
||||
actions: 'create-comment,close-issue'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
body: |
|
||||
Hi @${{ github.event.issue.user.login }}. Current version (2.x) is off the maintenance period. We may not accept pull request or fix bug with it anymore. This topic will be auto closed.
|
||||
|
||||
你好 @${{ github.event.issue.user.login }},当前版本(2.x)已经过了维护期。我们不会再接受对其的相关 PR 与 issue。当前 topic 会被自动关闭。
|
||||
|
|
@ -4,8 +4,16 @@ on:
|
|||
issues:
|
||||
types: [opened]
|
||||
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check-issue:
|
||||
issue-open-check:
|
||||
permissions:
|
||||
contents: read # for visiky/dingtalk-release-notify to get latest release
|
||||
issues: write # for actions-cool/issues-helper to update issues
|
||||
pull-requests: write # for actions-cool/issues-helper to update PRs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions-cool/check-user-permission@v1.0.0
|
||||
|
@ -15,7 +23,7 @@ jobs:
|
|||
|
||||
- name: check invalid
|
||||
if: (contains(github.event.issue.body, 'issue-helper') == false) && (steps.checkUser.outputs.result == 'false')
|
||||
uses: actions-cool/issues-helper@v1.2
|
||||
uses: actions-cool/issues-helper@v3
|
||||
with:
|
||||
actions: 'create-comment,add-labels,close-issue'
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
name: PR Labeled
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [labeled]
|
||||
|
||||
jobs:
|
||||
reply:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Usage
|
||||
if: github.event.label.name == 'Usage'
|
||||
uses: actions-cool/issues-helper@v1.2
|
||||
with:
|
||||
actions: 'create-comment, close-issue'
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
body: |
|
||||
Hello @${{ github.event.pull_request.user.login }}, we use GitHub PR to build and perfect of Ant Design Vue. So, please don't ask usage questions here. You can try to open a new discussion in [antdv discussions](https://github.com/vueComponent/ant-design-vue/discussions), select `Q&A` to ask questions, also can ask questions on [Stack Overflow](http://stackoverflow.com/questions/) or [Segment Fault](https://segmentfault.com).
|
||||
|
||||
你好 @${{ github.event.pull_request.user.login }},Ant Design Vue PR 是用于建设、完善项目的地方。请勿询问如何使用的问题,你可以试着在 [antdv discussions](https://github.com/vueComponent/ant-design-vue/discussions) 新开一个 discussion,选择 `Q&A` 类别进行提问,也可以在 [Stack Overflow](http://stackoverflow.com/questions/) 或者 [Segment Fault](https://segmentfault.com/) 中提问。
|
|
@ -10,6 +10,159 @@
|
|||
|
||||
---
|
||||
|
||||
## 4.2.6
|
||||
|
||||
- 🐞 Fix Modal component aria-hidden error problem under chrome [#7823](https://github.com/vueComponent/ant-design-vue/issues/7823)
|
||||
- 🐞 Fix the problem that the built-in input method of Safari automatically fills in the decimal point when inputting Chinese [#7918](https://github.com/vueComponent/ant-design-vue/issues/7918)
|
||||
- 🐞 Fix InputNumber component disabled style problem [#7776](https://github.com/vueComponent/ant-design-vue/issues/7776)
|
||||
- 🐞 Fix Select cannot lose focus problem [#7819](https://github.com/vueComponent/ant-design-vue/issues/7819)
|
||||
|
||||
## 4.2.5
|
||||
|
||||
- 🐞 Fix Empty component memory leak problem
|
||||
- 🐞 Fix Image width & height property not working problem
|
||||
|
||||
## 4.2.4
|
||||
|
||||
- 🐞 Fix Wave memory leak problem
|
||||
|
||||
## 4.2.3
|
||||
|
||||
- 🌟 TourStep custom Button, support function children [#7628](https://github.com/vueComponent/ant-design-vue/pull/7628)
|
||||
- 🐞 Fix the problem that the input value is hidden in Select and Cascader search multi-select mode [#7640](https://github.com/vueComponent/ant-design-vue/issues/7640)
|
||||
|
||||
## 4.2.2
|
||||
|
||||
- 🐞 Fix TreeSelect placeholder slot invalid [#7545](https://github.com/vueComponent/ant-design-vue/issues/7545)
|
||||
- 🐞 Fix Tree slot responsive invalid issue [40ad45](https://github.com/vueComponent/ant-design-vue/commit/40ad45bc05b2bf9d0a2445d9f6ff365468ba90b7)
|
||||
- 🐞 Fix FloatButton target type error issue [#7576](https://github.com/vueComponent/ant-design-vue/issues/7576)
|
||||
- 🐞 Fix FormItem className error issue [#7582](https://github.com/vueComponent/ant-design-vue/issues/7582)
|
||||
- 🐞 Fix Input Cannot input problem under lazy [#7543](https://github.com/vueComponent/ant-design-vue/issues/7543)
|
||||
- 🐞 Fix the problem that placeholder is not hidden when inputting Chinese in Select [#7611](https://github.com/vueComponent/ant-design-vue/issues/7611)
|
||||
- 🐞 Fix the problem that the pop-up window flashes when clicking the preset option in DatePicker [#7550](https://github.com/vueComponent/ant-design-vue/issues/7550)
|
||||
|
||||
## 4.2.1
|
||||
|
||||
- 🐞 fix Input clear action error [#7523](https://github.com/vueComponent/ant-design-vue/issues/7523)
|
||||
|
||||
## 4.2.0
|
||||
|
||||
- 🌟 Optimize the textColor change when the layout component switches to dark mode [#7498](https://github.com/vueComponent/ant-design-vue/issues/7498)
|
||||
- 🌟 Tooltip added arrow hidden configuration [#7459](https://github.com/vueComponent/ant-design-vue/issues/7459)
|
||||
- 🌟 Optimize Table hover performance [#7451](https://github.com/vueComponent/ant-design-vue/issues/7451)
|
||||
- 🐞 Fixed the problem of changing the model during useForm verification, resulting in verification errors [#ffd4d8](https://github.com/vueComponent/ant-design-vue/commit/ffd4d8fe927f9ea40cbb6358ad997c447bd9a74e)
|
||||
- 🐞 Fix Tabs folding calculation error issue [#7491](https://github.com/vueComponent/ant-design-vue/issues/7491)
|
||||
- 🐞 Fix Qrcode missing type hint issue [#7502](https://github.com/vueComponent/ant-design-vue/issues/7502)
|
||||
- 🐞 Fix Menu rendering error under SSR [#7349](https://github.com/vueComponent/ant-design-vue/issues/7349)
|
||||
- 🐞 Fix Select and Cascader rendering errors under SSR [#7377](https://github.com/vueComponent/ant-design-vue/issues/7377)
|
||||
- 🐞 Fix AutoComplete missing option slot declaration issue [#7396](https://github.com/vueComponent/ant-design-vue/issues/7396)
|
||||
- 🐞 Fix Textarea autoSize not taking effect [#7478](https://github.com/vueComponent/ant-design-vue/issues/7478)
|
||||
- 🐞 Fix Pagination’s Enter key triggering two page turns [#7368](https://github.com/vueComponent/ant-design-vue/issues/7368)
|
||||
- 🐞 Fix the problem of Chinese input in the input box [#7391](https://github.com/vueComponent/ant-design-vue/issues/7391)[#7516](https://github.com/vueComponent/ant- design-vue/issues/7516)
|
||||
- 🐞 Fix Carousel beforeChange current parameter error issue [#7419](https://github.com/vueComponent/ant-design-vue/issues/7419)
|
||||
|
||||
## 4.1.2
|
||||
|
||||
- 🐞 Fix table resize error reporting under vue 3.4 [#7291](https://github.com/vueComponent/ant-design-vue/issues/7291)
|
||||
- 🐞 Fix the problem that the Segmented title attribute is not displayed [#7302](https://github.com/vueComponent/ant-design-vue/issues/7302)
|
||||
|
||||
## 4.1.1
|
||||
|
||||
- 🌟 QRcode adds scanned status [#7242](https://github.com/vueComponent/ant-design-vue/issues/7242)
|
||||
- 🐞 Fix css prefix issue in nuxt [#7256](https://github.com/vueComponent/ant-design-vue/issues/7256)
|
||||
- 🐞 Fix dropdown closing issue [#7246](https://github.com/vueComponent/ant-design-vue/issues/7246)
|
||||
- 🐞 Fix divider vertical dashed not display issue [#7218](https://github.com/vueComponent/ant-design-vue/issues/7218)
|
||||
- 🐞 Fix hook mode message console warning issue [#7281](https://github.com/vueComponent/ant-design-vue/issues/7281)
|
||||
- 🐞 Fix table expansion error reporting under vue 3.4 [#7265](https://github.com/vueComponent/ant-design-vue/issues/7265)
|
||||
- 🐞 Fix table group filter status error issue [#7233](https://github.com/vueComponent/ant-design-vue/issues/7233)
|
||||
|
||||
## 4.1.0
|
||||
|
||||
- 🐞 support vue 3.4 [#7239](https://github.com/vueComponent/ant-design-vue/issues/7239)
|
||||
|
||||
## 4.0.8
|
||||
|
||||
- 🐞 Fix theme responsiveness failure issue under Nuxt [#7180](https://github.com/vueComponent/ant-design-vue/issues/7180)
|
||||
- 🐞 Fix error reporting caused by Wave [#7108](https://github.com/vueComponent/ant-design-vue/issues/7108)
|
||||
- 🐞 Fix Upload disabled inheritance issue [#7110](https://github.com/vueComponent/ant-design-vue/issues/7110)
|
||||
- 🐞 Fix Tooltip popupAlign not taking effect [#7112](https://github.com/vueComponent/ant-design-vue/issues/7112)
|
||||
- 🐞 Fix Typography flashing problem [#7146](https://github.com/vueComponent/ant-design-vue/issues/7146)
|
||||
- 🐞 Fix the issue that RangePicker prevIcon nextIcon does not take effect [#7127](https://github.com/vueComponent/ant-design-vue/issues/7127)
|
||||
- 🐞 Fixed the issue of watermark not monitoring child element changes [#7149](https://github.com/vueComponent/ant-design-vue/issues/7149)
|
||||
- 🐞 Fix Menu animation missing issue [#7130](https://github.com/vueComponent/ant-design-vue/issues/7130)
|
||||
- 🐞 Fix the cursor change issue when TextArea autosize [#7121](https://github.com/vueComponent/ant-design-vue/issues/7121)
|
||||
|
||||
## 4.0.7
|
||||
|
||||
- 🌟 Added Flex component [#7052](https://github.com/vueComponent/ant-design-vue/issues/7052)
|
||||
- 🌟 ConfigProvider adds wave configuration [#7036](https://github.com/vueComponent/ant-design-vue/issues/7036)
|
||||
- 🌟 Watermark supports dark mode [#7067](https://github.com/vueComponent/ant-design-vue/issues/7067)
|
||||
- 🐞 Fix Space duplicate Key problem [#7048](https://github.com/vueComponent/ant-design-vue/issues/7048)
|
||||
- 🐞 Fix Upload disabled priority error issue [#7047](https://github.com/vueComponent/ant-design-vue/issues/7047)
|
||||
- 🐞 Fix Carousel rendering error in jsx [#7077](https://github.com/vueComponent/ant-design-vue/issues/7077)
|
||||
- 🐞 Fix Message offset position problem [#7093](https://github.com/vueComponent/ant-design-vue/issues/7093)
|
||||
- 🐞 Fix the problem of animation failure when using Collapse custom prefix [#7074](https://github.com/vueComponent/ant-design-vue/issues/7074)
|
||||
|
||||
## 4.0.6
|
||||
|
||||
- 🐞 Fix the Dropdown onVisibleChange failure issue introduced in 4.0.4 [#7031](https://github.com/vueComponent/ant-design-vue/issues/7031)
|
||||
|
||||
## 4.0.5
|
||||
|
||||
- 🐞 Fix cssinjs performance issue [#7023](https://github.com/vueComponent/ant-design-vue/issues/7023)
|
||||
|
||||
## 4.0.4
|
||||
|
||||
- 🌟 Added esm target file
|
||||
- 🌟 Added tooltip attribute to FormItem [#7014](https://github.com/vueComponent/ant-design-vue/issues/7014)
|
||||
- 🐞 Fix useMessage getContainer not taking effect [#6942](https://github.com/vueComponent/ant-design-vue/issues/6942)
|
||||
- 🐞 Fix the problem of Image triggering onPreviewVisibleChange event multiple times [#6945](https://github.com/vueComponent/ant-design-vue/issues/6945)
|
||||
- 🐞 Fix the problem that Checkbox global disabled does not take effect [#6970](https://github.com/vueComponent/ant-design-vue/issues/6970)
|
||||
- 🐞 Fix Drawer contentWrapperStyle not taking effect [#6983](https://github.com/vueComponent/ant-design-vue/issues/6983)
|
||||
- 🐞 Optimize Select Dropdown and other drop-down list scroll bar display hidden logic [#6987](https://github.com/vueComponent/ant-design-vue/issues/6987)
|
||||
- 🐞 Fix the problem of hiding when there are components such as input in the drop-down list such as Select Dropdown [#7020](https://github.com/vueComponent/ant-design-vue/issues/7020)
|
||||
|
||||
## 4.0.3
|
||||
|
||||
- 🐞 Fix the problem of style loss under shadow Dom [#6912](https://github.com/vueComponent/ant-design-vue/issues/6912)
|
||||
- 🐞 Upgrade Icon dependency and fix icon css missing problem under shadow Dom [#6914](https://github.com/vueComponent/ant-design-vue/issues/6914)
|
||||
|
||||
## 4.0.2
|
||||
|
||||
- 🐞 Fix useMessage causing body to be removed [#6880](https://github.com/vueComponent/ant-design-vue/issues/6880)
|
||||
- 🐞 Fix the problem that the water ripple effect does not disappear after Button loading is switched [#6895](https://github.com/vueComponent/ant-design-vue/issues/6895)
|
||||
- 🐞 Fixed the problem that flip does not reset after Image is closed [#6913](https://github.com/vueComponent/ant-design-vue/issues/6913)
|
||||
- 🐞 Fix ImageGroup animation effect loss problem [#6898](https://github.com/vueComponent/ant-design-vue/issues/6898)
|
||||
- 🐞 Fix Modal missing onUpdate:open attribute declaration [#6876](https://github.com/vueComponent/ant-design-vue/issues/6876)
|
||||
- 🐞 Fixed the issue of multiple clicks being triggered at the edge of Transfer's Checkbox [#6902](https://github.com/vueComponent/ant-design-vue/issues/6902)
|
||||
|
||||
## 4.0.1
|
||||
|
||||
- 🌟 FloatButton add Badge support [#6738](https://github.com/vueComponent/ant-design-vue/issues/6738)
|
||||
- 🌟 Image preview zoom in and out sensitivity adjustment [#6784](https://github.com/vueComponent/ant-design-vue/issues/6784)
|
||||
- 🌟 Add flip feature to Image [#6785](https://github.com/vueComponent/ant-design-vue/issues/6785)
|
||||
- 🌟 Add App component to provide context [#6735](https://github.com/vueComponent/ant-design-vue/issues/6735)
|
||||
- 🌟 Style extraction feature for SSR [#6757](https://github.com/vueComponent/ant-design-vue/issues/6757)
|
||||
- 🌟 Support px2rem [#6817](https://github.com/vueComponent/ant-design-vue/issues/6817)
|
||||
- 🌟 Tag supports borderless mode [#6819](https://github.com/vueComponent/ant-design-vue/issues/6819)
|
||||
- 🌟 Avatar group mode supports shape [#6822](https://github.com/vueComponent/ant-design-vue/issues/6822)
|
||||
- 🌟 AutoComplete supports borderless and custom clearIcon [#6829](https://github.com/vueComponent/ant-design-vue/issues/6829)
|
||||
- 🌟 InputPassword supports controlled visible [#6863](https://github.com/vueComponent/ant-design-vue/issues/6863)
|
||||
- 🐞 Fix the style misalignment problem when InputGroup is large [#6866](https://github.com/vueComponent/ant-design-vue/issues/6866)
|
||||
- 🐞 Fix the problem that Checkable Tag cannot customize class [#6854](https://github.com/vueComponent/ant-design-vue/issues/6854)
|
||||
- 🐞 Fix the rendering problem in Tabs animation mode [#6855](https://github.com/vueComponent/ant-design-vue/issues/6855)
|
||||
- 🐞 Fix the problem that the Image height attribute does not take effect [#6840](https://github.com/vueComponent/ant-design-vue/issues/6840)
|
||||
- 🐞 Fix InputNumber trigger mouseup event [#6772](https://github.com/vueComponent/ant-design-vue/issues/6772)
|
||||
- 🐞 Fix the Dropdown style problem when Tabs are collapsed [#6757](https://github.com/vueComponent/ant-design-vue/issues/6757)
|
||||
- 🐞 Fix Table expandedRowRender property does not take effect [#6783](https://github.com/vueComponent/ant-design-vue/issues/6783)
|
||||
- 🐞 Fix dayjs not packaged into dist [#6767](https://github.com/vueComponent/ant-design-vue/issues/6767)
|
||||
- 🐞 Fix clipPath browser compatibility issue [#6770](https://github.com/vueComponent/ant-design-vue/issues/6770)
|
||||
- 🐞 Fix Carousel autoplay responsive problem [#6768](https://github.com/vueComponent/ant-design-vue/issues/6768)
|
||||
- 🐞 Fix PageHeader ghost style problem [#6761](https://github.com/vueComponent/ant-design-vue/issues/6761)
|
||||
- 🐞 Fix Checkbox not triggering Form validation [#6741](https://github.com/vueComponent/ant-design-vue/issues/6741)
|
||||
- 🐞 Fix the problem that the Input prefix attribute does not take effect [#6810](https://github.com/vueComponent/ant-design-vue/issues/6810)
|
||||
- 🐞 Fix Badge style problem in Avatar [#6874](https://github.com/vueComponent/ant-design-vue/issues/6874)
|
||||
|
||||
## 4.0
|
||||
|
||||
### 🔥🔥🔥 4.0 official version released 🔥🔥🔥
|
||||
|
|
|
@ -10,6 +10,159 @@
|
|||
|
||||
---
|
||||
|
||||
## 4.2.6
|
||||
|
||||
- 🐞 修复 Modal 组件在 chrome 下,aria-hidden 报错问题 [#7823](https://github.com/vueComponent/ant-design-vue/issues/7823)
|
||||
- 🐞 修复 Safari 下自带输入法 input 组件输入中文时,自动填写小数点问题 [#7918](https://github.com/vueComponent/ant-design-vue/issues/7918)
|
||||
- 🐞 修复 InputNumber 组件 disabled 样式问题 [#7776](https://github.com/vueComponent/ant-design-vue/issues/7776)
|
||||
- 🐞 修复 Select 无法失焦问题 [#7819](https://github.com/vueComponent/ant-design-vue/issues/7819)
|
||||
|
||||
## 4.2.5
|
||||
|
||||
- 🐞 修复 Empty 组件内存泄漏问题
|
||||
- 🐞 修复 Image width & height 属性不生效问题
|
||||
|
||||
## 4.2.4
|
||||
|
||||
- 🐞 修复 Wave 内存泄漏问题
|
||||
|
||||
## 4.2.3
|
||||
|
||||
- 🌟 TourStep 自定义 Button,支持函数 children [#7628](https://github.com/vueComponent/ant-design-vue/pull/7628)
|
||||
- 🐞 修复 Select 和 Cascader 搜索多选模式下,输入值被隐藏问题 [#7640](https://github.com/vueComponent/ant-design-vue/issues/7640)
|
||||
|
||||
## 4.2.2
|
||||
|
||||
- 🐞 修复 TreeSelect placeholder 插槽无效 [#7545](https://github.com/vueComponent/ant-design-vue/issues/7545)
|
||||
- 🐞 修复 Tree 插槽响应式无效问题 [40ad45](https://github.com/vueComponent/ant-design-vue/commit/40ad45bc05b2bf9d0a2445d9f6ff365468ba90b7)
|
||||
- 🐞 修复 FloatButton target 类型错误问题 [#7576](https://github.com/vueComponent/ant-design-vue/issues/7576)
|
||||
- 🐞 修复 FormItem className 错误问题 [#7582](https://github.com/vueComponent/ant-design-vue/issues/7582)
|
||||
- 🐞 修复 Input lazy 下无法输入问题 [#7543](https://github.com/vueComponent/ant-design-vue/issues/7543)
|
||||
- 🐞 修复 Select 输入中文时,placeholder 未隐藏问题 [#7611](https://github.com/vueComponent/ant-design-vue/issues/7611)
|
||||
- 🐞 修复 DatePicker 点击预设选项时,弹窗闪动问题 [#7550](https://github.com/vueComponent/ant-design-vue/issues/7550)
|
||||
|
||||
## 4.2.1
|
||||
|
||||
- 🐞 修复 Input 清空操作才报错问题 [#7523](https://github.com/vueComponent/ant-design-vue/issues/7523)
|
||||
|
||||
## 4.2.0
|
||||
|
||||
- 🌟 优化 layout 组件切换 dark 模式时 textColor 变化 [#7498](https://github.com/vueComponent/ant-design-vue/issues/7498)
|
||||
- 🌟 Tooltip 新增 arrow 隐藏配置 [#7459](https://github.com/vueComponent/ant-design-vue/issues/7459)
|
||||
- 🌟 优化 Table hover 性能 [#7451](https://github.com/vueComponent/ant-design-vue/issues/7451)
|
||||
- 🐞 修复 useForm 校验时更改 model,导致校验错误问题 [#ffd4d8](https://github.com/vueComponent/ant-design-vue/commit/ffd4d8fe927f9ea40cbb6358ad997c447bd9a74e)
|
||||
- 🐞 修复 Tabs 折叠计算错误问题 [#7491](https://github.com/vueComponent/ant-design-vue/issues/7491)
|
||||
- 🐞 修复 Qrcode 缺少类型提示问题 [#7502](https://github.com/vueComponent/ant-design-vue/issues/7502)
|
||||
- 🐞 修复 Menu 在 SSR 下渲染错误问题 [#7349](https://github.com/vueComponent/ant-design-vue/issues/7349)
|
||||
- 🐞 修复 Select、Cascader 在 SSR 下渲染错误问题 [#7377](https://github.com/vueComponent/ant-design-vue/issues/7377)
|
||||
- 🐞 修复 AutoComplete 缺少 option slot 声明问题 [#7396](https://github.com/vueComponent/ant-design-vue/issues/7396)
|
||||
- 🐞 修复 Textarea autoSize 不生效问题 [#7478](https://github.com/vueComponent/ant-design-vue/issues/7478)
|
||||
- 🐞 修复 Pagination 回车键触发两次翻页问题 [#7368](https://github.com/vueComponent/ant-design-vue/issues/7368)
|
||||
- 🐞 修复输入框输入中文问题 [#7391](https://github.com/vueComponent/ant-design-vue/issues/7391)[#7516](https://github.com/vueComponent/ant-design-vue/issues/7516)
|
||||
- 🐞 修复 Carousel beforeChange current 参数错误问题 [#7419](https://github.com/vueComponent/ant-design-vue/issues/7419)
|
||||
|
||||
## 4.1.2
|
||||
|
||||
- 🐞 修复 table resize 在 vue 3.4 下报错问题 [#7291](https://github.com/vueComponent/ant-design-vue/issues/7291)
|
||||
- 🐞 修复 Segmented title 属性不显示问题 [#7302](https://github.com/vueComponent/ant-design-vue/issues/7302)
|
||||
|
||||
## 4.1.1
|
||||
|
||||
- 🌟 QRcode 新增 scanned 状态 [#7242](https://github.com/vueComponent/ant-design-vue/issues/7242)
|
||||
- 🐞 修复 css prefix 在 nuxt 问题 [#7256](https://github.com/vueComponent/ant-design-vue/issues/7256)
|
||||
- 🐞 修复 dropdown 关闭问题 [#7246](https://github.com/vueComponent/ant-design-vue/issues/7246)
|
||||
- 🐞 修复 divider vertical dashed 不显示问题 [#7218](https://github.com/vueComponent/ant-design-vue/issues/7218)
|
||||
- 🐞 修复 hook 模式 message 控制台 warning 问题 [#7281](https://github.com/vueComponent/ant-design-vue/issues/7281)
|
||||
- 🐞 修复 table 展开在 vue 3.4 下报错问题 [#7265](https://github.com/vueComponent/ant-design-vue/issues/7265)
|
||||
- 🐞 修复 table group 过滤状态错误问题 [#7233](https://github.com/vueComponent/ant-design-vue/issues/7233)
|
||||
|
||||
## 4.1.0
|
||||
|
||||
- 🐞 适配 vue 3.4 [#7239](https://github.com/vueComponent/ant-design-vue/issues/7239)
|
||||
|
||||
## 4.0.8
|
||||
|
||||
- 🐞 修复在 Nuxt 下 theme 响应式失效问题 [#7180](https://github.com/vueComponent/ant-design-vue/issues/7180)
|
||||
- 🐞 修复 Wave 引起的报错问题 [#7108](https://github.com/vueComponent/ant-design-vue/issues/7108)
|
||||
- 🐞 修复 Upload disabled 继承问题 [#7110](https://github.com/vueComponent/ant-design-vue/issues/7110)
|
||||
- 🐞 修复 Tooltip popupAlign 未生效问题 [#7112](https://github.com/vueComponent/ant-design-vue/issues/7112)
|
||||
- 🐞 修复 Typography 闪动问题 [#7146](https://github.com/vueComponent/ant-design-vue/issues/7146)
|
||||
- 🐞 修复 RangePicker prevIcon nextIcon 未生效问题 [#7127](https://github.com/vueComponent/ant-design-vue/issues/7127)
|
||||
- 🐞 修复 watermark 未监听子元素变动问题 [#7149](https://github.com/vueComponent/ant-design-vue/issues/7149)
|
||||
- 🐞 修复 Menu 动画丢失问题 [#7130](https://github.com/vueComponent/ant-design-vue/issues/7130)
|
||||
- 🐞 修复 TextArea autosize 时光标变化问题 [#7121](https://github.com/vueComponent/ant-design-vue/issues/7121)
|
||||
|
||||
## 4.0.7
|
||||
|
||||
- 🌟 新增 Flex 组件 [#7052](https://github.com/vueComponent/ant-design-vue/issues/7052)
|
||||
- 🌟 ConfigProvider 新增 wave 配置 [#7036](https://github.com/vueComponent/ant-design-vue/issues/7036)
|
||||
- 🌟 Watermark 支持暗黑模式 [#7067](https://github.com/vueComponent/ant-design-vue/issues/7067)
|
||||
- 🐞 修复 Space 重复 Key 问题 [#7048](https://github.com/vueComponent/ant-design-vue/issues/7048)
|
||||
- 🐞 修复 Upload disabled 优先级错误问题 [#7047](https://github.com/vueComponent/ant-design-vue/issues/7047)
|
||||
- 🐞 修复 Carousel 在 jsx 中渲染错误问题 [#7077](https://github.com/vueComponent/ant-design-vue/issues/7077)
|
||||
- 🐞 修复 Message 偏移位置问题 [#7093](https://github.com/vueComponent/ant-design-vue/issues/7093)
|
||||
- 🐞 修复 Collapse 自定义 prefix 时动画失效问题 [#7074](https://github.com/vueComponent/ant-design-vue/issues/7074)
|
||||
|
||||
## 4.0.6
|
||||
|
||||
- 🐞 修复 4.0.4 引入的 Dropdown onVisibleChange 失效问题 [#7031](https://github.com/vueComponent/ant-design-vue/issues/7031)
|
||||
|
||||
## 4.0.5
|
||||
|
||||
- 🐞 修复 cssinjs 性能问题 [#7023](https://github.com/vueComponent/ant-design-vue/issues/7023)
|
||||
|
||||
## 4.0.4
|
||||
|
||||
- 🌟 新增 esm 目标文件
|
||||
- 🌟 FormItem 新增 tooltip 属性 [#7014](https://github.com/vueComponent/ant-design-vue/issues/7014)
|
||||
- 🐞 修复 useMessage getContainer 不生效问题 [#6942](https://github.com/vueComponent/ant-design-vue/issues/6942)
|
||||
- 🐞 修复 Image 多次触发 onPreviewVisibleChange 事件问题 [#6945](https://github.com/vueComponent/ant-design-vue/issues/6945)
|
||||
- 🐞 修复 Checkbox 全局 disabled 不生效问题 [#6970](https://github.com/vueComponent/ant-design-vue/issues/6970)
|
||||
- 🐞 修复 Drawer contentWrapperStyle 不生效问题 [#6983](https://github.com/vueComponent/ant-design-vue/issues/6983)
|
||||
- 🐞 优化 Select Dropdown 等下拉列表滚动条显示隐藏逻辑 [#6987](https://github.com/vueComponent/ant-design-vue/issues/6987)
|
||||
- 🐞 修复 Select Dropdown 等下拉列表中有 input 等组件时,隐藏问题 [#7020](https://github.com/vueComponent/ant-design-vue/issues/7020)
|
||||
|
||||
## 4.0.3
|
||||
|
||||
- 🐞 修复 shadow Dom 下样式丢失问题 [#6912](https://github.com/vueComponent/ant-design-vue/issues/6912)
|
||||
- 🐞 升级 Icon 依赖,修复 shadow Dom 下 icon css 丢失问题 [#6914](https://github.com/vueComponent/ant-design-vue/issues/6914)
|
||||
|
||||
## 4.0.2
|
||||
|
||||
- 🐞 修复 useMessage 导致 body 被移除问题 [#6880](https://github.com/vueComponent/ant-design-vue/issues/6880)
|
||||
- 🐞 修复 Button loading 切换后,水波纹效果不消失问题 [#6895](https://github.com/vueComponent/ant-design-vue/issues/6895)
|
||||
- 🐞 修复 Image 关闭后 flip 没有重置问题 [#6913](https://github.com/vueComponent/ant-design-vue/issues/6913)
|
||||
- 🐞 修复 ImageGroup 动画效果丢失问题 [#6898](https://github.com/vueComponent/ant-design-vue/issues/6898)
|
||||
- 🐞 修复 Modal 缺少 onUpdate:open 属性声明 [#6876](https://github.com/vueComponent/ant-design-vue/issues/6876)
|
||||
- 🐞 修复 Transfer 的 Checkbox 边缘处会触发多次 click 问题 [#6902](https://github.com/vueComponent/ant-design-vue/issues/6902)
|
||||
|
||||
## 4.0.1
|
||||
|
||||
- 🌟 FloatButton 添加 Badge 支持 [#6738](https://github.com/vueComponent/ant-design-vue/issues/6738)
|
||||
- 🌟 Image 预览放大缩小灵敏度调整 [#6784](https://github.com/vueComponent/ant-design-vue/issues/6784)
|
||||
- 🌟 Image 新增翻转特性 [#6785](https://github.com/vueComponent/ant-design-vue/issues/6785)
|
||||
- 🌟 新增 App 组件,用于提供上下文 [#6735](https://github.com/vueComponent/ant-design-vue/issues/6735)
|
||||
- 🌟 样式抽离特性用于 SSR [#6757](https://github.com/vueComponent/ant-design-vue/issues/6757)
|
||||
- 🌟 支持 px2rem [#6817](https://github.com/vueComponent/ant-design-vue/issues/6817)
|
||||
- 🌟 Tag 支持无边框模式 [#6819](https://github.com/vueComponent/ant-design-vue/issues/6819)
|
||||
- 🌟 Avatar group 模式支持 shape [#6822](https://github.com/vueComponent/ant-design-vue/issues/6822)
|
||||
- 🌟 AutoComplete 支持无边框和自定义 clearIcon [#6829](https://github.com/vueComponent/ant-design-vue/issues/6829)
|
||||
- 🌟 InputPassword 支持受控 visible [#6863](https://github.com/vueComponent/ant-design-vue/issues/6863)
|
||||
- 🐞 修复 InputGroup 在 large 时样式错位问题 [#6866](https://github.com/vueComponent/ant-design-vue/issues/6866)
|
||||
- 🐞 修复 Checkable Tag 无法自定义 class 问题 [#6854](https://github.com/vueComponent/ant-design-vue/issues/6854)
|
||||
- 🐞 修复 Tabs 动画模式下渲染问题 [#6855](https://github.com/vueComponent/ant-design-vue/issues/6855)
|
||||
- 🐞 修复 Image height 属性不生效问题 [#6840](https://github.com/vueComponent/ant-design-vue/issues/6840)
|
||||
- 🐞 修复 InputNumber 触发 mouseup 事件问题 [#6772](https://github.com/vueComponent/ant-design-vue/issues/6772)
|
||||
- 🐞 修复 Tabs 折叠时 Dropdown 样式问题 [#6757](https://github.com/vueComponent/ant-design-vue/issues/6757)
|
||||
- 🐞 修复 Table expandedRowRender 属性不生效 [#6783](https://github.com/vueComponent/ant-design-vue/issues/6783)
|
||||
- 🐞 修复 dayjs 未打包进 dist 问题 [#6767](https://github.com/vueComponent/ant-design-vue/issues/6767)
|
||||
- 🐞 解决 clipPath 浏览器兼容问题 [#6770](https://github.com/vueComponent/ant-design-vue/issues/6770)
|
||||
- 🐞 修复 Carousel autoplay 响应式问题 [#6768](https://github.com/vueComponent/ant-design-vue/issues/6768)
|
||||
- 🐞 修复 PageHeader ghost 样式问题 [#6761](https://github.com/vueComponent/ant-design-vue/issues/6761)
|
||||
- 🐞 修复 Checkbox 没有触发 Form 校验问题 [#6741](https://github.com/vueComponent/ant-design-vue/issues/6741)
|
||||
- 🐞 修复 Input prefix 属性未生效问题 [#6810](https://github.com/vueComponent/ant-design-vue/issues/6810)
|
||||
- 🐞 修复 Badge 在 Avatar 中样式问题 [#6874](https://github.com/vueComponent/ant-design-vue/issues/6874)
|
||||
|
||||
## 4.0
|
||||
|
||||
### 🔥🔥🔥 4.0 正式版发布 🔥🔥🔥
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<p align="center">
|
||||
<a href="https://www.antdv.com/">
|
||||
<img width="200" src="https://qn.antdv.com/logo.png">
|
||||
<img width="200" src="https://aliyuncdn.antdv.com/logo.png">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
|||
|
||||
<div align="center">
|
||||
|
||||
An enterprise-class UI components based on Ant Design and Vue 3.
|
||||
基于 Ant Design 和 Vue 3 的企业级 UI 组件库。
|
||||
|
||||
 [](https://codecov.io/gh/vueComponent/ant-design-vue) [](https://www.npmjs.org/package/ant-design-vue) [](http://www.npmtrends.com/ant-design-vue) [](#backers) [](#sponsors) [](https://marketplace.visualstudio.com/items?itemName=ant-design-vue.vscode-ant-design-vue-helper) [](https://github.com/actions-cool/issues-helper)
|
||||
|
||||
|
@ -26,6 +26,12 @@ An enterprise-class UI components based on Ant Design and Vue 3.
|
|||
- 开箱即用的高质量 Vue 组件。
|
||||
- 共享 [Ant Design of React](http://ant-design.gitee.io/docs/spec/introduce-cn) 设计工具体系。
|
||||
|
||||
## 关注我们
|
||||
|
||||
收藏加关注,第一时间获取更新动态!
|
||||
|
||||

|
||||
|
||||
## 支持环境
|
||||
|
||||
- 现代浏览器。1.x 版本支持 IE 9+(需要 [polyfills](https://www.antdv.com/docs/vue/getting-started-cn/#兼容性))
|
||||
|
@ -67,6 +73,7 @@ $ yarn add ant-design-vue
|
|||
| [vue-dash-event](https://github.com/vueComponent/vue-dash-event) | 在 DOM 模板中,您可以使用 ant-design-vue 组件的自定义事件(camelCase) |
|
||||
| [@formily/antdv](https://github.com/formilyjs/antdv) | 这是一个结合了 Formily 和 ant-design-vue 的组件库 |
|
||||
| [@ant-design-vue/nuxt](https://github.com/vueComponent/ant-design-vue-nuxt) | ant-design-vue 的 nuxt 模块扩展 |
|
||||
| [ant-design-x-vue](https://github.com/wzc520pyfm/ant-design-x-vue) | 基于 Ant Design X 设计规范的 Vue AI 界面解决方案 |
|
||||
|
||||
## 问答
|
||||
|
||||
|
@ -81,24 +88,33 @@ ant-design-vue 是 MIT 协议的开源项目。为了项目能够更好的持续
|
|||
- [Patreon](https://www.patreon.com/tangjinzhou)
|
||||
- [opencollective](https://opencollective.com/ant-design-vue)
|
||||
- [paypal](https://www.paypal.me/tangjinzhou)
|
||||
- [支付宝或微信](https://qn.antdv.com/alipay-and-wechat.png)
|
||||
- [支付宝或微信](https://aliyuncdn.antdv.com/alipay-and-wechat.png)
|
||||
- ETH: 0x30cc48515d8ae9fefa20ab87226ad7e8ab9c3bc2
|
||||
|
||||
## Sponsors
|
||||
## 赞助商
|
||||
|
||||
Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/ant-design-vue#sponsor)]
|
||||
成为赞助商,并在 Github 上的自述文件上获得您的徽标,并链接到您的网站。 [[成为赞助商](https://opencollective.com/ant-design-vue#sponsor)]
|
||||
|
||||
<a href="http://www.jeecg.com/" target="_blank"><img src="https://aliyuncdn.antdv.com/jeecg-logo.png" height="64"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/0/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/1/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/2/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/3/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/4/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/5/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/6/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/7/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/8/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/9/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/10/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/10/avatar.svg"></a>
|
||||
|
||||
## Backers
|
||||
## 支持者
|
||||
|
||||
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/ant-design-vue#backer)]
|
||||
每月捐款支持我们,帮助我们继续我们的活动。 [[成为支持者](https://opencollective.com/ant-design-vue#backer)]
|
||||
|
||||
<a href="https://github.com/chuzhixin/vue-admin-beautiful" target="_blank"><img width="64" style="border-radius: 50%;" src="https://gitee.com/chu1204505056/image/raw/master/vue-admin-beautiful.png" title="vue-admin-beautiful"></a> <a href="https://opencollective.com/ant-design-vue/backer/0/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/0/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/1/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/1/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/2/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/2/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/3/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/3/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/4/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/4/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/5/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/5/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/6/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/6/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/7/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/7/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/8/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/8/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/9/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/9/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/10/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/10/avatar.svg"></a>
|
||||
|
||||
## Patreon
|
||||
|
||||
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://www.patreon.com/tangjinzhou)]
|
||||
每月捐款支持我们,帮助我们继续我们的活动。 [[成为支持者](https://www.patreon.com/tangjinzhou)]
|
||||
|
||||
<a href="https://www.mokeyjay.com" target="_blank"><img width="64" style="border-radius: 50%;" src="https://www.mokeyjay.com/headimg.png" title="donation by Patreon"></a>
|
||||
|
||||
## [更多赞助者 (通过 Patreon、支付宝、微信、paypal 等等)](https://github.com/vueComponent/ant-design-vue/blob/master/BACKERS.md)
|
||||
|
||||
## 贡献者
|
||||
|
||||
感谢所有为 ant-design-vue 做出贡献的人!
|
||||
|
||||
<a href="https://github.com/vueComponent/ant-design-vue/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=vueComponent/ant-design-vue&max=100&columns=15" />
|
||||
</a>
|
||||
|
|
24
README.md
24
README.md
|
@ -1,6 +1,6 @@
|
|||
<p align="center">
|
||||
<a href="https://www.antdv.com/">
|
||||
<img width="200" src="https://qn.antdv.com/logo.png">
|
||||
<img width="200" src="https://aliyuncdn.antdv.com/logo.png">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
@ -26,6 +26,12 @@ English | [简体中文](./README-zh_CN.md)
|
|||
- A set of high-quality Vue components out of the box.
|
||||
- Shared [Ant Design of React](https://ant.design/docs/spec/introduce) design resources.
|
||||
|
||||
## Getting started & staying tuned with us.
|
||||
|
||||
Star us, and you will receive all releases notifications from GitHub without any delay!
|
||||
|
||||

|
||||
|
||||
## Environment Support
|
||||
|
||||
- Modern browsers. v1.x support Internet Explorer 9+ (with [polyfills](https://www.antdv.com/docs/vue/getting-started/#compatibility))
|
||||
|
@ -39,7 +45,7 @@ English | [简体中文](./README-zh_CN.md)
|
|||
|
||||
## Using npm or yarn
|
||||
|
||||
**We recommend using npm or yarn to install**,it not only makes development easier,but also allow you to take advantage of the rich ecosystem of Javascript packages and tooling.
|
||||
**We recommend using npm or yarn to install**, it not only makes development easier, but also allow you to take advantage of the rich ecosystem of Javascript packages and tooling.
|
||||
|
||||
```bash
|
||||
$ npm install ant-design-vue --save
|
||||
|
@ -49,7 +55,7 @@ $ npm install ant-design-vue --save
|
|||
$ yarn add ant-design-vue
|
||||
```
|
||||
|
||||
If you are in a bad network environment,you can try other registries and tools like [cnpm](https://github.com/cnpm/cnpm).
|
||||
If you are in a bad network environment, you can try other registries and tools like [cnpm](https://github.com/cnpm/cnpm).
|
||||
|
||||
## Links
|
||||
|
||||
|
@ -67,6 +73,7 @@ If you are in a bad network environment,you can try other registries and tools
|
|||
| [vue-dash-event](https://github.com/vueComponent/vue-dash-event) | The library function, implemented in the DOM template, can use the custom event of the ant-design-vue component (camelCase) |
|
||||
| [@formily/antdv](https://github.com/formilyjs/antdv) | The Library with Formily and ant-design-vue |
|
||||
| [@ant-design-vue/nuxt](https://github.com/vueComponent/ant-design-vue-nuxt) | A nuxt module for ant-design-vue |
|
||||
| [ant-design-x-vue](https://github.com/wzc520pyfm/ant-design-x-vue) | A Vue AI interface solutions base on the Ant Design X design specification |
|
||||
|
||||
## Donation
|
||||
|
||||
|
@ -75,7 +82,8 @@ ant-design-vue is an MIT-licensed open source project. In order to achieve bette
|
|||
- [Patreon](https://www.patreon.com/tangjinzhou)
|
||||
- [opencollective](https://opencollective.com/ant-design-vue)
|
||||
- [paypal](https://www.paypal.me/tangjinzhou)
|
||||
- [支付宝或微信](https://qn.antdv.com/alipay-and-wechat.png)
|
||||
- [支付宝或微信](https://aliyuncdn.antdv.com/alipay-and-wechat.png)
|
||||
- ETH: 0x30cc48515d8ae9fefa20ab87226ad7e8ab9c3bc2
|
||||
|
||||
## Sponsors
|
||||
|
||||
|
@ -85,6 +93,14 @@ Become a sponsor and get your logo on our README on Github with a link to your s
|
|||
|
||||
## [More Sponsor (From Patreon、alipay、wechat、paypal...)](https://github.com/vueComponent/ant-design-vue/blob/master/BACKERS.md)
|
||||
|
||||
## Contributors
|
||||
|
||||
Thank you to all the people who already contributed to ant-design-vue!
|
||||
|
||||
<a href="https://github.com/vueComponent/ant-design-vue/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=vueComponent/ant-design-vue&max=100&columns=15" />
|
||||
</a>
|
||||
|
||||
[](https://issuehunt.io/repos/104172832)
|
||||
|
||||
This project is tested with BrowserStack.
|
||||
|
|
|
@ -6,7 +6,6 @@ import { genWebTypes } from './web-types';
|
|||
import { outputFileSync, readFileSync } from 'fs-extra';
|
||||
import type { Options, VueTag } from './type';
|
||||
import { getComponentName, normalizePath, toKebabCase } from './utils';
|
||||
import { genVeturAttributes, genVeturTags } from './vetur';
|
||||
import { flatMap } from 'lodash';
|
||||
|
||||
async function readMarkdown(options: Options): Promise<Map<String, VueTag>> {
|
||||
|
@ -22,13 +21,13 @@ async function readMarkdown(options: Options): Promise<Map<String, VueTag>> {
|
|||
return formatter(mdParser(fileContent), componentName, kebabComponentName, options.tagPrefix);
|
||||
})
|
||||
.filter(item => item) as VueTag[][];
|
||||
const tags: Map<String, VueTag> = new Map();
|
||||
const tags = new Map<String, VueTag>();
|
||||
flatMap(data, item => item).forEach(mergedTag => mergeTag(tags, mergedTag));
|
||||
return tags;
|
||||
}
|
||||
|
||||
function readTypings(options: Options): Map<String, VueTag> {
|
||||
const tags: Map<String, VueTag> = new Map();
|
||||
const tags = new Map<String, VueTag>();
|
||||
const fileContent = readFileSync(options.typingsPath, 'utf-8');
|
||||
fileContent
|
||||
.split('\n')
|
||||
|
@ -62,7 +61,7 @@ function mergeTag(tags: Map<String, VueTag>, mergedTag: VueTag) {
|
|||
|
||||
function mergeTags(mergedTagsArr: Map<String, VueTag>[]): VueTag[] {
|
||||
if (mergedTagsArr.length === 1) return [...mergedTagsArr[0].values()];
|
||||
const tags: Map<String, VueTag> = new Map();
|
||||
const tags = new Map<String, VueTag>();
|
||||
if (mergedTagsArr.length === 0) return [];
|
||||
mergedTagsArr.forEach(mergedTags => {
|
||||
mergedTags.forEach(mergedTag => mergeTag(tags, mergedTag));
|
||||
|
@ -78,13 +77,6 @@ export async function parseAndWrite(options: Options): Promise<Number> {
|
|||
const tagsFromTypings = await readTypings(options);
|
||||
const tags = mergeTags([tagsFromMarkdown, tagsFromTypings]);
|
||||
const webTypes = genWebTypes(tags, options);
|
||||
const veturTags = genVeturTags(tags);
|
||||
const veturAttributes = genVeturAttributes(tags);
|
||||
outputFileSync(join(options.outputDir, 'tags.json'), JSON.stringify(veturTags, null, 2));
|
||||
outputFileSync(
|
||||
join(options.outputDir, 'attributes.json'),
|
||||
JSON.stringify(veturAttributes, null, 2),
|
||||
);
|
||||
outputFileSync(join(options.outputDir, 'web-types.json'), JSON.stringify(webTypes, null, 2));
|
||||
return tags.length;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ export type Articals = Artical[];
|
|||
function readLine(input: string) {
|
||||
const end = input.indexOf('\n');
|
||||
|
||||
return input.substr(0, end !== -1 ? end : input.length);
|
||||
return input.substring(0, end !== -1 ? end : input.length);
|
||||
}
|
||||
|
||||
function splitTableLine(line: string) {
|
||||
|
@ -47,7 +47,7 @@ function tableParse(input: string) {
|
|||
};
|
||||
|
||||
while (start < end) {
|
||||
const target = input.substr(start);
|
||||
const target = input.substring(start);
|
||||
const line = readLine(target);
|
||||
|
||||
if (!/^\|/.test(target)) {
|
||||
|
@ -79,7 +79,7 @@ export function mdParser(input: string): Articals {
|
|||
const end = input.length;
|
||||
|
||||
while (start < end) {
|
||||
const target = input.substr(start);
|
||||
const target = input.substring(start);
|
||||
|
||||
let match;
|
||||
if ((match = TITLE_REG.exec(target))) {
|
||||
|
@ -91,7 +91,7 @@ export function mdParser(input: string): Articals {
|
|||
|
||||
start += match.index + match[0].length;
|
||||
} else if ((match = TABLE_REG.exec(target))) {
|
||||
const { table, usedLength } = tableParse(target.substr(match.index));
|
||||
const { table, usedLength } = tableParse(target.substring(match.index));
|
||||
artical.push({
|
||||
type: 'table',
|
||||
table,
|
||||
|
|
|
@ -34,25 +34,6 @@ export type VueTag = {
|
|||
description?: string;
|
||||
};
|
||||
|
||||
export type VeturTag = {
|
||||
description?: string;
|
||||
attributes: string[];
|
||||
};
|
||||
|
||||
export type VeturTags = Record<string, VeturTag>;
|
||||
|
||||
export type VeturAttribute = {
|
||||
type: string;
|
||||
description: string;
|
||||
};
|
||||
|
||||
export type VeturAttributes = Record<string, VeturAttribute>;
|
||||
|
||||
export type VeturResult = {
|
||||
tags: VeturTags;
|
||||
attributes: VeturAttributes;
|
||||
};
|
||||
|
||||
export type Options = {
|
||||
name: string;
|
||||
path: PathLike;
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
import type { VueTag, VeturTags, VeturAttributes } from './type';
|
||||
|
||||
export function genVeturTags(tags: VueTag[]) {
|
||||
const veturTags: VeturTags = {};
|
||||
|
||||
tags.forEach(tag => {
|
||||
veturTags[tag.name] = {
|
||||
attributes: tag.attributes ? tag.attributes.map(item => item.name) : [],
|
||||
};
|
||||
});
|
||||
|
||||
return veturTags;
|
||||
}
|
||||
|
||||
export function genVeturAttributes(tags: VueTag[]) {
|
||||
const veturAttributes: VeturAttributes = {};
|
||||
|
||||
tags.forEach(tag => {
|
||||
if (tag.attributes) {
|
||||
tag.attributes.forEach(attr => {
|
||||
veturAttributes[`${tag.name}/${attr.name}`] = {
|
||||
type: attr.value.type,
|
||||
description: `${attr.description}, Default: ${attr.default}`,
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return veturAttributes;
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const assign = require('object-assign');
|
||||
const { getProjectPath } = require('./utils/projectHelper');
|
||||
|
||||
module.exports = function () {
|
||||
|
@ -9,7 +8,7 @@ module.exports = function () {
|
|||
if (fs.existsSync(getProjectPath('tsconfig.json'))) {
|
||||
my = require(getProjectPath('tsconfig.json'));
|
||||
}
|
||||
return assign(
|
||||
return Object.assign(
|
||||
{
|
||||
noUnusedParameters: true,
|
||||
noUnusedLocals: true,
|
||||
|
|
|
@ -22,7 +22,7 @@ const imageOptions = {
|
|||
limit: 10000,
|
||||
};
|
||||
|
||||
function getWebpackConfig(modules) {
|
||||
function getWebpackConfig(modules, esm = false) {
|
||||
const pkg = require(getProjectPath('package.json'));
|
||||
const babelConfig = require('./getBabelCommonConfig')(modules || false);
|
||||
|
||||
|
@ -197,9 +197,25 @@ All rights reserved.
|
|||
},
|
||||
},
|
||||
];
|
||||
config.output.library = distFileBaseName;
|
||||
config.output.libraryTarget = 'umd';
|
||||
config.output.globalObject = 'this';
|
||||
if (esm) {
|
||||
entry = ['./index.esm'];
|
||||
config.experiments = {
|
||||
...config.experiments,
|
||||
outputModule: true,
|
||||
};
|
||||
config.output.chunkFormat = 'module';
|
||||
config.output.library = {
|
||||
type: 'module',
|
||||
};
|
||||
config.target = 'es2019';
|
||||
} else {
|
||||
config.output.libraryTarget = 'umd';
|
||||
config.output.library = distFileBaseName;
|
||||
config.output.globalObject = 'this';
|
||||
}
|
||||
|
||||
const entryName = esm ? `${distFileBaseName}.esm` : distFileBaseName;
|
||||
|
||||
config.optimization = {
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
|
@ -213,7 +229,7 @@ All rights reserved.
|
|||
// Development
|
||||
const uncompressedConfig = merge({}, config, {
|
||||
entry: {
|
||||
[distFileBaseName]: entry,
|
||||
[entryName]: entry,
|
||||
},
|
||||
mode: 'development',
|
||||
plugins: [
|
||||
|
@ -226,7 +242,7 @@ All rights reserved.
|
|||
// Production
|
||||
const prodConfig = merge({}, config, {
|
||||
entry: {
|
||||
[`${distFileBaseName}.min`]: entry,
|
||||
[`${entryName}.min`]: entry,
|
||||
},
|
||||
mode: 'production',
|
||||
plugins: [
|
||||
|
|
|
@ -368,7 +368,7 @@ function pub(done) {
|
|||
}
|
||||
}
|
||||
|
||||
let startTime = new Date();
|
||||
const startTime = new Date();
|
||||
gulp.task('compile-with-es', done => {
|
||||
console.log('start compile at ', startTime);
|
||||
console.log('[Parallel] Compile to es...');
|
||||
|
@ -452,7 +452,7 @@ gulp.task(
|
|||
newVersion.trim() === version
|
||||
) {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
runCmd('npm', ['run', 'pub'], code => {
|
||||
runCmd('npm', ['run', 'pub'], _code => {
|
||||
done();
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -1,51 +1,167 @@
|
|||
import { defineComponent, shallowRef, withDirectives } from 'vue';
|
||||
import antInput from './antInputDirective';
|
||||
import type { PropType } from 'vue';
|
||||
import { computed, defineComponent, shallowRef, ref, watch } from 'vue';
|
||||
import PropTypes from './vue-types';
|
||||
import type { BaseInputInnerExpose } from './BaseInputInner';
|
||||
import BaseInputInner from './BaseInputInner';
|
||||
import { styleObjectToString } from '../vc-util/Dom/css';
|
||||
|
||||
export interface BaseInputExpose {
|
||||
focus: () => void;
|
||||
blur: () => void;
|
||||
input: HTMLInputElement | HTMLTextAreaElement | null;
|
||||
setSelectionRange: (
|
||||
start: number,
|
||||
end: number,
|
||||
direction?: 'forward' | 'backward' | 'none',
|
||||
) => void;
|
||||
select: () => void;
|
||||
getSelectionStart: () => number | null;
|
||||
getSelectionEnd: () => number | null;
|
||||
getScrollTop: () => number | null;
|
||||
setScrollTop: (scrollTop: number) => void;
|
||||
}
|
||||
const BaseInput = defineComponent({
|
||||
compatConfig: { MODE: 3 },
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
value: PropTypes.string.def(''),
|
||||
disabled: PropTypes.looseBool,
|
||||
type: PropTypes.string,
|
||||
value: PropTypes.any,
|
||||
lazy: PropTypes.bool.def(true),
|
||||
tag: {
|
||||
type: String as PropType<'input' | 'textarea'>,
|
||||
default: 'input',
|
||||
},
|
||||
size: PropTypes.string,
|
||||
style: PropTypes.oneOfType([String, Object]),
|
||||
class: PropTypes.string,
|
||||
},
|
||||
emits: ['change', 'input'],
|
||||
setup(_p, { emit }) {
|
||||
const inputRef = shallowRef(null);
|
||||
emits: [
|
||||
'change',
|
||||
'input',
|
||||
'blur',
|
||||
'keydown',
|
||||
'focus',
|
||||
'compositionstart',
|
||||
'compositionend',
|
||||
'keyup',
|
||||
'paste',
|
||||
'mousedown',
|
||||
],
|
||||
setup(props, { emit, attrs, expose }) {
|
||||
const inputRef = shallowRef<BaseInputInnerExpose>(null);
|
||||
const renderValue = ref();
|
||||
const isComposing = ref(false);
|
||||
watch(
|
||||
[() => props.value, isComposing],
|
||||
() => {
|
||||
if (isComposing.value) return;
|
||||
renderValue.value = props.value;
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
const handleChange = (e: Event) => {
|
||||
const { composing } = e.target as any;
|
||||
if ((e as any).isComposing || composing) {
|
||||
emit('input', e);
|
||||
} else {
|
||||
emit('input', e);
|
||||
emit('change', e);
|
||||
emit('change', e);
|
||||
};
|
||||
const onCompositionstart = (e: CompositionEvent) => {
|
||||
isComposing.value = true;
|
||||
(e.target as any).composing = true;
|
||||
emit('compositionstart', e);
|
||||
};
|
||||
const onCompositionend = (e: CompositionEvent) => {
|
||||
isComposing.value = false;
|
||||
(e.target as any).composing = false;
|
||||
emit('compositionend', e);
|
||||
const event = document.createEvent('HTMLEvents');
|
||||
event.initEvent('input', true, true);
|
||||
e.target.dispatchEvent(event);
|
||||
handleChange(e);
|
||||
};
|
||||
const handleInput = (e: Event) => {
|
||||
if (isComposing.value && props.lazy) {
|
||||
renderValue.value = (e.target as HTMLInputElement).value;
|
||||
return;
|
||||
}
|
||||
emit('input', e);
|
||||
};
|
||||
|
||||
const handleBlur = (e: Event) => {
|
||||
emit('blur', e);
|
||||
};
|
||||
const handleFocus = (e: Event) => {
|
||||
emit('focus', e);
|
||||
};
|
||||
|
||||
const focus = () => {
|
||||
if (inputRef.value) {
|
||||
inputRef.value.focus();
|
||||
}
|
||||
};
|
||||
return {
|
||||
inputRef,
|
||||
focus: () => {
|
||||
if (inputRef.value) {
|
||||
inputRef.value.focus();
|
||||
}
|
||||
},
|
||||
blur: () => {
|
||||
if (inputRef.value) {
|
||||
inputRef.value.blur();
|
||||
}
|
||||
},
|
||||
handleChange,
|
||||
const blur = () => {
|
||||
if (inputRef.value) {
|
||||
inputRef.value.blur();
|
||||
}
|
||||
};
|
||||
},
|
||||
render() {
|
||||
return withDirectives(
|
||||
(
|
||||
<input
|
||||
{...this.$props}
|
||||
{...this.$attrs}
|
||||
onInput={this.handleChange}
|
||||
onChange={this.handleChange}
|
||||
ref="inputRef"
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
emit('keydown', e);
|
||||
};
|
||||
const handleKeyUp = (e: KeyboardEvent) => {
|
||||
emit('keyup', e);
|
||||
};
|
||||
const setSelectionRange = (
|
||||
start: number,
|
||||
end: number,
|
||||
direction?: 'forward' | 'backward' | 'none',
|
||||
) => {
|
||||
inputRef.value?.setSelectionRange(start, end, direction);
|
||||
};
|
||||
|
||||
const select = () => {
|
||||
inputRef.value?.select();
|
||||
};
|
||||
expose({
|
||||
focus,
|
||||
blur,
|
||||
input: computed(() => inputRef.value?.input),
|
||||
setSelectionRange,
|
||||
select,
|
||||
getSelectionStart: () => inputRef.value?.getSelectionStart(),
|
||||
getSelectionEnd: () => inputRef.value?.getSelectionEnd(),
|
||||
getScrollTop: () => inputRef.value?.getScrollTop(),
|
||||
});
|
||||
const handleMousedown = (e: MouseEvent) => {
|
||||
emit('mousedown', e);
|
||||
};
|
||||
const handlePaste = (e: ClipboardEvent) => {
|
||||
emit('paste', e);
|
||||
};
|
||||
const styleString = computed(() => {
|
||||
return props.style && typeof props.style !== 'string'
|
||||
? styleObjectToString(props.style)
|
||||
: props.style;
|
||||
});
|
||||
return () => {
|
||||
const { style, lazy, ...restProps } = props;
|
||||
return (
|
||||
<BaseInputInner
|
||||
{...restProps}
|
||||
{...attrs}
|
||||
style={styleString.value}
|
||||
onInput={handleInput}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
onFocus={handleFocus}
|
||||
ref={inputRef}
|
||||
value={renderValue.value}
|
||||
onCompositionstart={onCompositionstart}
|
||||
onCompositionend={onCompositionend}
|
||||
onKeyup={handleKeyUp}
|
||||
onKeydown={handleKeyDown}
|
||||
onPaste={handlePaste}
|
||||
onMousedown={handleMousedown}
|
||||
/>
|
||||
) as any,
|
||||
[[antInput]],
|
||||
);
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
import type { PropType } from 'vue';
|
||||
import { defineComponent, shallowRef } from 'vue';
|
||||
import PropTypes from './vue-types';
|
||||
|
||||
export interface BaseInputInnerExpose {
|
||||
focus: () => void;
|
||||
blur: () => void;
|
||||
input: HTMLInputElement | HTMLTextAreaElement | null;
|
||||
setSelectionRange: (
|
||||
start: number,
|
||||
end: number,
|
||||
direction?: 'forward' | 'backward' | 'none',
|
||||
) => void;
|
||||
select: () => void;
|
||||
getSelectionStart: () => number | null;
|
||||
getSelectionEnd: () => number | null;
|
||||
getScrollTop: () => number | null;
|
||||
setScrollTop: (scrollTop: number) => void;
|
||||
}
|
||||
const BaseInputInner = defineComponent({
|
||||
compatConfig: { MODE: 3 },
|
||||
// inheritAttrs: false,
|
||||
props: {
|
||||
disabled: PropTypes.looseBool,
|
||||
type: PropTypes.string,
|
||||
value: PropTypes.any,
|
||||
tag: {
|
||||
type: String as PropType<'input' | 'textarea'>,
|
||||
default: 'input',
|
||||
},
|
||||
size: PropTypes.string,
|
||||
onChange: Function as PropType<(e: Event) => void>,
|
||||
onInput: Function as PropType<(e: Event) => void>,
|
||||
onBlur: Function as PropType<(e: Event) => void>,
|
||||
onFocus: Function as PropType<(e: Event) => void>,
|
||||
onKeydown: Function as PropType<(e: Event) => void>,
|
||||
onCompositionstart: Function as PropType<(e: Event) => void>,
|
||||
onCompositionend: Function as PropType<(e: Event) => void>,
|
||||
onKeyup: Function as PropType<(e: Event) => void>,
|
||||
onPaste: Function as PropType<(e: Event) => void>,
|
||||
onMousedown: Function as PropType<(e: Event) => void>,
|
||||
},
|
||||
emits: [
|
||||
'change',
|
||||
'input',
|
||||
'blur',
|
||||
'keydown',
|
||||
'focus',
|
||||
'compositionstart',
|
||||
'compositionend',
|
||||
'keyup',
|
||||
'paste',
|
||||
'mousedown',
|
||||
],
|
||||
setup(props, { expose }) {
|
||||
const inputRef = shallowRef(null);
|
||||
|
||||
const focus = () => {
|
||||
if (inputRef.value) {
|
||||
inputRef.value.focus();
|
||||
}
|
||||
};
|
||||
const blur = () => {
|
||||
if (inputRef.value) {
|
||||
inputRef.value.blur();
|
||||
}
|
||||
};
|
||||
const setSelectionRange = (
|
||||
start: number,
|
||||
end: number,
|
||||
direction?: 'forward' | 'backward' | 'none',
|
||||
) => {
|
||||
inputRef.value?.setSelectionRange(start, end, direction);
|
||||
};
|
||||
|
||||
const select = () => {
|
||||
inputRef.value?.select();
|
||||
};
|
||||
expose({
|
||||
focus,
|
||||
blur,
|
||||
input: inputRef,
|
||||
setSelectionRange,
|
||||
select,
|
||||
getSelectionStart: () => inputRef.value?.selectionStart,
|
||||
getSelectionEnd: () => inputRef.value?.selectionEnd,
|
||||
getScrollTop: () => inputRef.value?.scrollTop,
|
||||
});
|
||||
return () => {
|
||||
const { tag: Tag, value, ...restProps } = props;
|
||||
return <Tag {...restProps} ref={inputRef} value={value} />;
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default BaseInputInner;
|
|
@ -3,7 +3,7 @@ import { getOptionProps } from './props-util';
|
|||
|
||||
export default {
|
||||
methods: {
|
||||
setState(state = {}, callback) {
|
||||
setState(state = {}, callback: () => any) {
|
||||
let newState = typeof state === 'function' ? state(this.$data, this.$props) : state;
|
||||
if (this.getDerivedStateFromProps) {
|
||||
const s = this.getDerivedStateFromProps(getOptionProps(this), {
|
||||
|
@ -26,6 +26,7 @@ export default {
|
|||
},
|
||||
__emit() {
|
||||
// 直接调用事件,底层组件不需要vueTool记录events
|
||||
// eslint-disable-next-line prefer-rest-params
|
||||
const args = [].slice.call(arguments, 0);
|
||||
let eventName = args[0];
|
||||
eventName = `on${eventName[0].toUpperCase()}${eventName.substring(1)}`;
|
|
@ -3,7 +3,7 @@ import {
|
|||
defineComponent,
|
||||
nextTick,
|
||||
onBeforeMount,
|
||||
onBeforeUnmount,
|
||||
onMounted,
|
||||
onUpdated,
|
||||
Teleport,
|
||||
watch,
|
||||
|
@ -23,12 +23,24 @@ export default defineComponent({
|
|||
// getContainer 不会改变,不用响应式
|
||||
let container: HTMLElement;
|
||||
const { shouldRender } = useInjectPortal();
|
||||
onBeforeMount(() => {
|
||||
isSSR = false;
|
||||
|
||||
function setContainer() {
|
||||
if (shouldRender.value) {
|
||||
container = props.getContainer();
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
isSSR = false;
|
||||
// drawer
|
||||
setContainer();
|
||||
});
|
||||
onMounted(() => {
|
||||
if (container) return;
|
||||
// https://github.com/vueComponent/ant-design-vue/issues/6937
|
||||
setContainer();
|
||||
});
|
||||
|
||||
const stopWatch = watch(shouldRender, () => {
|
||||
if (shouldRender.value && !container) {
|
||||
container = props.getContainer();
|
||||
|
@ -44,11 +56,11 @@ export default defineComponent({
|
|||
}
|
||||
});
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
if (container && container.parentNode) {
|
||||
container.parentNode.removeChild(container);
|
||||
}
|
||||
});
|
||||
// onBeforeUnmount(() => {
|
||||
// if (container && container.parentNode) {
|
||||
// container.parentNode.removeChild(container);
|
||||
// }
|
||||
// });
|
||||
return () => {
|
||||
if (!shouldRender.value) return null;
|
||||
if (isSSR) {
|
||||
|
|
|
@ -7,7 +7,6 @@ import {
|
|||
onMounted,
|
||||
onBeforeUnmount,
|
||||
onUpdated,
|
||||
getCurrentInstance,
|
||||
nextTick,
|
||||
computed,
|
||||
} from 'vue';
|
||||
|
@ -61,11 +60,14 @@ export default defineComponent({
|
|||
const container = shallowRef<HTMLElement>();
|
||||
const componentRef = shallowRef();
|
||||
const rafId = shallowRef<number>();
|
||||
|
||||
const triggerUpdate = shallowRef(1);
|
||||
const defaultContainer = canUseDom() && document.createElement('div');
|
||||
const removeCurrentContainer = () => {
|
||||
// Portal will remove from `parentNode`.
|
||||
// Let's handle this again to avoid refactor issue.
|
||||
container.value?.parentNode?.removeChild(container.value);
|
||||
if (container.value === defaultContainer) {
|
||||
container.value?.parentNode?.removeChild(container.value);
|
||||
}
|
||||
container.value = null;
|
||||
};
|
||||
let parent: HTMLElement = null;
|
||||
|
@ -82,8 +84,6 @@ export default defineComponent({
|
|||
|
||||
return true;
|
||||
};
|
||||
// attachToParent();
|
||||
const defaultContainer = document.createElement('div');
|
||||
const getContainer = () => {
|
||||
if (!supportDom) {
|
||||
return null;
|
||||
|
@ -106,8 +106,6 @@ export default defineComponent({
|
|||
attachToParent();
|
||||
});
|
||||
|
||||
const instance = getCurrentInstance();
|
||||
|
||||
useScrollLocker(
|
||||
computed(() => {
|
||||
return (
|
||||
|
@ -155,7 +153,7 @@ export default defineComponent({
|
|||
nextTick(() => {
|
||||
if (!attachToParent()) {
|
||||
rafId.value = raf(() => {
|
||||
instance.update();
|
||||
triggerUpdate.value += 1;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -177,7 +175,7 @@ export default defineComponent({
|
|||
getOpenCount: () => openCount,
|
||||
getContainer,
|
||||
};
|
||||
if (forceRender || visible || componentRef.value) {
|
||||
if (triggerUpdate.value && (forceRender || visible || componentRef.value)) {
|
||||
portal = (
|
||||
<Portal
|
||||
getContainer={getContainer}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import { defineComponent } from 'vue';
|
||||
import { customRenderSlot } from '../vnode';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'RenderSlot',
|
||||
setup(_props, { slots }) {
|
||||
return () => {
|
||||
return customRenderSlot(slots, 'default', {}, () => ['default value']);
|
||||
};
|
||||
},
|
||||
});
|
|
@ -0,0 +1,26 @@
|
|||
import RenderSlot from '../__mocks__/RenderSlot';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import { nextTick } from 'vue';
|
||||
|
||||
describe('render slot content', () => {
|
||||
it('renders slot content', () => {
|
||||
const wrapper = mount(RenderSlot, {
|
||||
slots: {
|
||||
default: () => 'This is slot content',
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.html()).toContain('This is slot content');
|
||||
});
|
||||
|
||||
it('render default value when slot is fragment', async () => {
|
||||
const wrapper = mount(RenderSlot, {
|
||||
slots: {
|
||||
default: () => <></>,
|
||||
},
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
expect(wrapper.html()).toContain('default value');
|
||||
});
|
||||
});
|
|
@ -1,35 +0,0 @@
|
|||
function onCompositionStart(e) {
|
||||
e.target.composing = true;
|
||||
}
|
||||
|
||||
function onCompositionEnd(e) {
|
||||
// prevent triggering an input event for no reason
|
||||
if (!e.target.composing) return;
|
||||
e.target.composing = false;
|
||||
trigger(e.target, 'input');
|
||||
}
|
||||
|
||||
function trigger(el, type) {
|
||||
const e = document.createEvent('HTMLEvents');
|
||||
e.initEvent(type, true, true);
|
||||
el.dispatchEvent(e);
|
||||
}
|
||||
|
||||
export function addEventListener(el, event, handler, options) {
|
||||
el.addEventListener(event, handler, options);
|
||||
}
|
||||
const antInput = {
|
||||
created(el, binding) {
|
||||
if (!binding.modifiers || !binding.modifiers.lazy) {
|
||||
addEventListener(el, 'compositionstart', onCompositionStart);
|
||||
addEventListener(el, 'compositionend', onCompositionEnd);
|
||||
// Safari < 10.2 & UIWebView doesn't fire compositionend when
|
||||
// switching focus before confirming composition choice
|
||||
// this also fixes the issue where some browsers e.g. iOS Chrome
|
||||
// fires "change" instead of "input" on autocomplete.
|
||||
addEventListener(el, 'change', onCompositionEnd);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default antInput;
|
|
@ -1,130 +0,0 @@
|
|||
const START_EVENT_NAME_MAP = {
|
||||
transitionstart: {
|
||||
transition: 'transitionstart',
|
||||
WebkitTransition: 'webkitTransitionStart',
|
||||
MozTransition: 'mozTransitionStart',
|
||||
OTransition: 'oTransitionStart',
|
||||
msTransition: 'MSTransitionStart',
|
||||
},
|
||||
|
||||
animationstart: {
|
||||
animation: 'animationstart',
|
||||
WebkitAnimation: 'webkitAnimationStart',
|
||||
MozAnimation: 'mozAnimationStart',
|
||||
OAnimation: 'oAnimationStart',
|
||||
msAnimation: 'MSAnimationStart',
|
||||
},
|
||||
};
|
||||
|
||||
const END_EVENT_NAME_MAP = {
|
||||
transitionend: {
|
||||
transition: 'transitionend',
|
||||
WebkitTransition: 'webkitTransitionEnd',
|
||||
MozTransition: 'mozTransitionEnd',
|
||||
OTransition: 'oTransitionEnd',
|
||||
msTransition: 'MSTransitionEnd',
|
||||
},
|
||||
|
||||
animationend: {
|
||||
animation: 'animationend',
|
||||
WebkitAnimation: 'webkitAnimationEnd',
|
||||
MozAnimation: 'mozAnimationEnd',
|
||||
OAnimation: 'oAnimationEnd',
|
||||
msAnimation: 'MSAnimationEnd',
|
||||
},
|
||||
};
|
||||
|
||||
const startEvents = [];
|
||||
const endEvents = [];
|
||||
|
||||
function detectEvents() {
|
||||
const testEl = document.createElement('div');
|
||||
const style = testEl.style;
|
||||
|
||||
if (!('AnimationEvent' in window)) {
|
||||
delete START_EVENT_NAME_MAP.animationstart.animation;
|
||||
delete END_EVENT_NAME_MAP.animationend.animation;
|
||||
}
|
||||
|
||||
if (!('TransitionEvent' in window)) {
|
||||
delete START_EVENT_NAME_MAP.transitionstart.transition;
|
||||
delete END_EVENT_NAME_MAP.transitionend.transition;
|
||||
}
|
||||
|
||||
function process(EVENT_NAME_MAP, events) {
|
||||
for (const baseEventName in EVENT_NAME_MAP) {
|
||||
if (EVENT_NAME_MAP.hasOwnProperty(baseEventName)) {
|
||||
const baseEvents = EVENT_NAME_MAP[baseEventName];
|
||||
for (const styleName in baseEvents) {
|
||||
if (styleName in style) {
|
||||
events.push(baseEvents[styleName]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process(START_EVENT_NAME_MAP, startEvents);
|
||||
process(END_EVENT_NAME_MAP, endEvents);
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
|
||||
detectEvents();
|
||||
}
|
||||
|
||||
function addEventListener(node, eventName, eventListener) {
|
||||
node.addEventListener(eventName, eventListener, false);
|
||||
}
|
||||
|
||||
function removeEventListener(node, eventName, eventListener) {
|
||||
node.removeEventListener(eventName, eventListener, false);
|
||||
}
|
||||
|
||||
const TransitionEvents = {
|
||||
// Start events
|
||||
startEvents,
|
||||
|
||||
addStartEventListener(node, eventListener) {
|
||||
if (startEvents.length === 0) {
|
||||
setTimeout(eventListener, 0);
|
||||
return;
|
||||
}
|
||||
startEvents.forEach(startEvent => {
|
||||
addEventListener(node, startEvent, eventListener);
|
||||
});
|
||||
},
|
||||
|
||||
removeStartEventListener(node, eventListener) {
|
||||
if (startEvents.length === 0) {
|
||||
return;
|
||||
}
|
||||
startEvents.forEach(startEvent => {
|
||||
removeEventListener(node, startEvent, eventListener);
|
||||
});
|
||||
},
|
||||
|
||||
// End events
|
||||
endEvents,
|
||||
|
||||
addEndEventListener(node, eventListener) {
|
||||
if (endEvents.length === 0) {
|
||||
setTimeout(eventListener, 0);
|
||||
return;
|
||||
}
|
||||
endEvents.forEach(endEvent => {
|
||||
addEventListener(node, endEvent, eventListener);
|
||||
});
|
||||
},
|
||||
|
||||
removeEndEventListener(node, eventListener) {
|
||||
if (endEvents.length === 0) {
|
||||
return;
|
||||
}
|
||||
endEvents.forEach(endEvent => {
|
||||
removeEventListener(node, endEvent, eventListener);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default TransitionEvents;
|
|
@ -1,186 +0,0 @@
|
|||
// https://github.com/yiminghe/css-animation 1.5.0
|
||||
|
||||
import Event from './Event';
|
||||
import classes from '../component-classes';
|
||||
import { requestAnimationTimeout, cancelAnimationTimeout } from '../requestAnimationTimeout';
|
||||
import { inBrowser } from '../env';
|
||||
|
||||
const isCssAnimationSupported = Event.endEvents.length !== 0;
|
||||
const capitalPrefixes = [
|
||||
'Webkit',
|
||||
'Moz',
|
||||
'O',
|
||||
// ms is special .... !
|
||||
'ms',
|
||||
];
|
||||
const prefixes = ['-webkit-', '-moz-', '-o-', 'ms-', ''];
|
||||
|
||||
function getStyleProperty(node, name) {
|
||||
if (inBrowser) return '';
|
||||
// old ff need null, https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle
|
||||
const style = window.getComputedStyle(node, null);
|
||||
let ret = '';
|
||||
for (let i = 0; i < prefixes.length; i++) {
|
||||
ret = style.getPropertyValue(prefixes[i] + name);
|
||||
if (ret) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function fixBrowserByTimeout(node) {
|
||||
if (isCssAnimationSupported) {
|
||||
const transitionDelay = parseFloat(getStyleProperty(node, 'transition-delay')) || 0;
|
||||
const transitionDuration = parseFloat(getStyleProperty(node, 'transition-duration')) || 0;
|
||||
const animationDelay = parseFloat(getStyleProperty(node, 'animation-delay')) || 0;
|
||||
const animationDuration = parseFloat(getStyleProperty(node, 'animation-duration')) || 0;
|
||||
const time = Math.max(transitionDuration + transitionDelay, animationDuration + animationDelay);
|
||||
// sometimes, browser bug
|
||||
node.rcEndAnimTimeout = setTimeout(() => {
|
||||
node.rcEndAnimTimeout = null;
|
||||
if (node.rcEndListener) {
|
||||
node.rcEndListener();
|
||||
}
|
||||
}, time * 1000 + 200);
|
||||
}
|
||||
}
|
||||
|
||||
function clearBrowserBugTimeout(node) {
|
||||
if (node.rcEndAnimTimeout) {
|
||||
clearTimeout(node.rcEndAnimTimeout);
|
||||
node.rcEndAnimTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
const cssAnimation = (node, transitionName, endCallback) => {
|
||||
const nameIsObj = typeof transitionName === 'object';
|
||||
const className = nameIsObj ? transitionName.name : transitionName;
|
||||
const activeClassName = nameIsObj ? transitionName.active : `${transitionName}-active`;
|
||||
let end = endCallback;
|
||||
let start;
|
||||
let active;
|
||||
const nodeClasses = classes(node);
|
||||
|
||||
if (endCallback && Object.prototype.toString.call(endCallback) === '[object Object]') {
|
||||
end = endCallback.end;
|
||||
start = endCallback.start;
|
||||
active = endCallback.active;
|
||||
}
|
||||
|
||||
if (node.rcEndListener) {
|
||||
node.rcEndListener();
|
||||
}
|
||||
|
||||
node.rcEndListener = e => {
|
||||
if (e && e.target !== node) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.rcAnimTimeout) {
|
||||
cancelAnimationTimeout(node.rcAnimTimeout);
|
||||
node.rcAnimTimeout = null;
|
||||
}
|
||||
|
||||
clearBrowserBugTimeout(node);
|
||||
|
||||
nodeClasses.remove(className);
|
||||
nodeClasses.remove(activeClassName);
|
||||
|
||||
Event.removeEndEventListener(node, node.rcEndListener);
|
||||
node.rcEndListener = null;
|
||||
|
||||
// Usually this optional end is used for informing an owner of
|
||||
// a leave animation and telling it to remove the child.
|
||||
if (end) {
|
||||
end();
|
||||
}
|
||||
};
|
||||
|
||||
Event.addEndEventListener(node, node.rcEndListener);
|
||||
|
||||
if (start) {
|
||||
start();
|
||||
}
|
||||
nodeClasses.add(className);
|
||||
|
||||
node.rcAnimTimeout = requestAnimationTimeout(() => {
|
||||
node.rcAnimTimeout = null;
|
||||
|
||||
nodeClasses.add(className);
|
||||
nodeClasses.add(activeClassName);
|
||||
|
||||
if (active) {
|
||||
requestAnimationTimeout(active, 0);
|
||||
}
|
||||
fixBrowserByTimeout(node);
|
||||
// 30ms for firefox
|
||||
}, 30);
|
||||
|
||||
return {
|
||||
stop() {
|
||||
if (node.rcEndListener) {
|
||||
node.rcEndListener();
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
cssAnimation.style = (node, style, callback) => {
|
||||
if (node.rcEndListener) {
|
||||
node.rcEndListener();
|
||||
}
|
||||
|
||||
node.rcEndListener = e => {
|
||||
if (e && e.target !== node) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.rcAnimTimeout) {
|
||||
cancelAnimationTimeout(node.rcAnimTimeout);
|
||||
node.rcAnimTimeout = null;
|
||||
}
|
||||
|
||||
clearBrowserBugTimeout(node);
|
||||
|
||||
Event.removeEndEventListener(node, node.rcEndListener);
|
||||
node.rcEndListener = null;
|
||||
|
||||
// Usually this optional callback is used for informing an owner of
|
||||
// a leave animation and telling it to remove the child.
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
Event.addEndEventListener(node, node.rcEndListener);
|
||||
|
||||
node.rcAnimTimeout = requestAnimationTimeout(() => {
|
||||
for (const s in style) {
|
||||
if (style.hasOwnProperty(s)) {
|
||||
node.style[s] = style[s];
|
||||
}
|
||||
}
|
||||
node.rcAnimTimeout = null;
|
||||
fixBrowserByTimeout(node);
|
||||
}, 0);
|
||||
};
|
||||
|
||||
cssAnimation.setTransition = (node, p, value) => {
|
||||
let property = p;
|
||||
let v = value;
|
||||
if (value === undefined) {
|
||||
v = property;
|
||||
property = '';
|
||||
}
|
||||
property = property || '';
|
||||
capitalPrefixes.forEach(prefix => {
|
||||
node.style[`${prefix}Transition${property}`] = v;
|
||||
});
|
||||
};
|
||||
|
||||
cssAnimation.isCssAnimationSupported = isCssAnimationSupported;
|
||||
|
||||
export { isCssAnimationSupported };
|
||||
|
||||
export default cssAnimation;
|
|
@ -1,16 +1,20 @@
|
|||
export type KeyType = string | number;
|
||||
type ValueType = [number, any]; // [times, realValue]
|
||||
|
||||
const SPLIT = '%';
|
||||
class Entity {
|
||||
instanceId: string;
|
||||
constructor(instanceId: string) {
|
||||
this.instanceId = instanceId;
|
||||
}
|
||||
/** @private Internal cache map. Do not access this directly */
|
||||
cache = new Map<string, ValueType>();
|
||||
|
||||
get(keys: KeyType[] | string): ValueType | null {
|
||||
return this.cache.get(Array.isArray(keys) ? keys.join('%') : keys) || null;
|
||||
return this.cache.get(Array.isArray(keys) ? keys.join(SPLIT) : keys) || null;
|
||||
}
|
||||
|
||||
update(keys: KeyType[] | string, valueFn: (origin: ValueType | null) => ValueType | null) {
|
||||
const path = Array.isArray(keys) ? keys.join('%') : keys;
|
||||
const path = Array.isArray(keys) ? keys.join(SPLIT) : keys;
|
||||
const prevValue = this.cache.get(path)!;
|
||||
const nextValue = valueFn(prevValue);
|
||||
|
||||
|
|
|
@ -1,29 +1,41 @@
|
|||
import type { ShallowRef, ExtractPropTypes, InjectionKey, Ref } from 'vue';
|
||||
import { provide, defineComponent, unref, inject, watch, shallowRef } from 'vue';
|
||||
import {
|
||||
provide,
|
||||
defineComponent,
|
||||
unref,
|
||||
inject,
|
||||
watch,
|
||||
shallowRef,
|
||||
getCurrentInstance,
|
||||
} from 'vue';
|
||||
import CacheEntity from './Cache';
|
||||
import type { Linter } from './linters/interface';
|
||||
import type { Transformer } from './transformers/interface';
|
||||
import { arrayType, booleanType, objectType, someType, stringType, withInstall } from '../type';
|
||||
import initDefaultProps from '../props-util/initDefaultProps';
|
||||
export const ATTR_TOKEN = 'data-token-hash';
|
||||
export const ATTR_MARK = 'data-css-hash';
|
||||
export const ATTR_DEV_CACHE_PATH = 'data-dev-cache-path';
|
||||
export const ATTR_CACHE_PATH = 'data-cache-path';
|
||||
|
||||
// Mark css-in-js instance in style element
|
||||
export const CSS_IN_JS_INSTANCE = '__cssinjs_instance__';
|
||||
export const CSS_IN_JS_INSTANCE_ID = Math.random().toString(12).slice(2);
|
||||
|
||||
export function createCache() {
|
||||
const cssinjsInstanceId = Math.random().toString(12).slice(2);
|
||||
|
||||
// Tricky SSR: Move all inline style to the head.
|
||||
// PS: We do not recommend tricky mode.
|
||||
if (typeof document !== 'undefined' && document.head && document.body) {
|
||||
const styles = document.body.querySelectorAll(`style[${ATTR_MARK}]`) || [];
|
||||
const { firstChild } = document.head;
|
||||
|
||||
Array.from(styles).forEach(style => {
|
||||
(style as any)[CSS_IN_JS_INSTANCE] =
|
||||
(style as any)[CSS_IN_JS_INSTANCE] || CSS_IN_JS_INSTANCE_ID;
|
||||
(style as any)[CSS_IN_JS_INSTANCE] = (style as any)[CSS_IN_JS_INSTANCE] || cssinjsInstanceId;
|
||||
|
||||
// Not force move if no head
|
||||
document.head.insertBefore(style, firstChild);
|
||||
// Not force move if no head
|
||||
if ((style as any)[CSS_IN_JS_INSTANCE] === cssinjsInstanceId) {
|
||||
document.head.insertBefore(style, firstChild);
|
||||
}
|
||||
});
|
||||
|
||||
// Deduplicate of moved styles
|
||||
|
@ -31,7 +43,7 @@ export function createCache() {
|
|||
Array.from(document.querySelectorAll(`style[${ATTR_MARK}]`)).forEach(style => {
|
||||
const hash = style.getAttribute(ATTR_MARK)!;
|
||||
if (styleHash[hash]) {
|
||||
if ((style as any)[CSS_IN_JS_INSTANCE] === CSS_IN_JS_INSTANCE_ID) {
|
||||
if ((style as any)[CSS_IN_JS_INSTANCE] === cssinjsInstanceId) {
|
||||
style.parentNode?.removeChild(style);
|
||||
}
|
||||
} else {
|
||||
|
@ -40,7 +52,7 @@ export function createCache() {
|
|||
});
|
||||
}
|
||||
|
||||
return new CacheEntity();
|
||||
return new CacheEntity(cssinjsInstanceId);
|
||||
}
|
||||
|
||||
export type HashPriority = 'low' | 'high';
|
||||
|
@ -76,19 +88,45 @@ const StyleContextKey: InjectionKey<ShallowRef<Partial<StyleContextProps>>> =
|
|||
Symbol('StyleContextKey');
|
||||
|
||||
export type UseStyleProviderProps = Partial<StyleContextProps> | Ref<Partial<StyleContextProps>>;
|
||||
|
||||
// fix: https://github.com/vueComponent/ant-design-vue/issues/7023
|
||||
const getCache = () => {
|
||||
const instance = getCurrentInstance();
|
||||
let cache: CacheEntity;
|
||||
if (instance && instance.appContext) {
|
||||
const globalCache = instance.appContext?.config?.globalProperties?.__ANTDV_CSSINJS_CACHE__;
|
||||
if (globalCache) {
|
||||
cache = globalCache;
|
||||
} else {
|
||||
cache = createCache();
|
||||
if (instance.appContext.config.globalProperties) {
|
||||
instance.appContext.config.globalProperties.__ANTDV_CSSINJS_CACHE__ = cache;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cache = createCache();
|
||||
}
|
||||
return cache;
|
||||
};
|
||||
|
||||
const defaultStyleContext: StyleContextProps = {
|
||||
cache: createCache(),
|
||||
defaultCache: true,
|
||||
hashPriority: 'low',
|
||||
};
|
||||
// fix: https://github.com/vueComponent/ant-design-vue/issues/6912
|
||||
export const useStyleInject = () => {
|
||||
return inject(StyleContextKey, shallowRef({ ...defaultStyleContext }));
|
||||
const cache = getCache();
|
||||
return inject(StyleContextKey, shallowRef({ ...defaultStyleContext, cache }));
|
||||
};
|
||||
export const useStyleProvider = (props: UseStyleProviderProps) => {
|
||||
const parentContext = useStyleInject();
|
||||
const context = shallowRef<Partial<StyleContextProps>>({ ...defaultStyleContext });
|
||||
const context = shallowRef<Partial<StyleContextProps>>({
|
||||
...defaultStyleContext,
|
||||
cache: createCache(),
|
||||
});
|
||||
watch(
|
||||
[props, parentContext],
|
||||
[() => unref(props), parentContext],
|
||||
() => {
|
||||
const mergedContext: Partial<StyleContextProps> = {
|
||||
...parentContext.value,
|
||||
|
@ -142,7 +180,7 @@ export const StyleProvider = withInstall(
|
|||
defineComponent({
|
||||
name: 'AStyleProvider',
|
||||
inheritAttrs: false,
|
||||
props: initDefaultProps(styleProviderProps(), defaultStyleContext),
|
||||
props: styleProviderProps(),
|
||||
setup(props, { slots }) {
|
||||
useStyleProvider(props);
|
||||
return () => slots.default?.();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import hash from '@emotion/hash';
|
||||
import { ATTR_TOKEN, CSS_IN_JS_INSTANCE, CSS_IN_JS_INSTANCE_ID } from '../StyleContext';
|
||||
import { ATTR_TOKEN, CSS_IN_JS_INSTANCE, useStyleInject } from '../StyleContext';
|
||||
import type Theme from '../theme/Theme';
|
||||
import useGlobalCache from './useGlobalCache';
|
||||
import { flattenToken, token2key } from '../util';
|
||||
|
@ -8,11 +8,15 @@ import { ref, computed } from 'vue';
|
|||
|
||||
const EMPTY_OVERRIDE = {};
|
||||
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
// nuxt generate when NODE_ENV is prerender
|
||||
const isPrerender = process.env.NODE_ENV === 'prerender';
|
||||
|
||||
// Generate different prefix to make user selector break in production env.
|
||||
// This helps developer not to do style override directly on the hash id.
|
||||
const hashPrefix = process.env.NODE_ENV !== 'production' ? 'css-dev-only-do-not-override' : 'css';
|
||||
const hashPrefix = !isProduction && !isPrerender ? 'css-dev-only-do-not-override' : 'css';
|
||||
|
||||
export interface Option<DerivativeToken> {
|
||||
export interface Option<DerivativeToken, DesignToken> {
|
||||
/**
|
||||
* Generate token with salt.
|
||||
* This is used to generate different hashId even same derivative token for different version.
|
||||
|
@ -30,6 +34,18 @@ export interface Option<DerivativeToken> {
|
|||
* It's ok to useMemo outside but this has better cache strategy.
|
||||
*/
|
||||
formatToken?: (mergedToken: any) => DerivativeToken;
|
||||
/**
|
||||
* Get final token with origin token, override token and theme.
|
||||
* The parameters do not contain formatToken since it's passed by user.
|
||||
* @param origin The original token.
|
||||
* @param override Extra tokens to override.
|
||||
* @param theme Theme instance. Could get derivative token by `theme.getDerivativeToken`
|
||||
*/
|
||||
getComputedToken?: (
|
||||
origin: DesignToken,
|
||||
override: object,
|
||||
theme: Theme<any, any>,
|
||||
) => DerivativeToken;
|
||||
}
|
||||
|
||||
const tokenKeys = new Map<string, number>();
|
||||
|
@ -37,20 +53,22 @@ function recordCleanToken(tokenKey: string) {
|
|||
tokenKeys.set(tokenKey, (tokenKeys.get(tokenKey) || 0) + 1);
|
||||
}
|
||||
|
||||
function removeStyleTags(key: string) {
|
||||
function removeStyleTags(key: string, instanceId: string) {
|
||||
if (typeof document !== 'undefined') {
|
||||
const styles = document.querySelectorAll(`style[${ATTR_TOKEN}="${key}"]`);
|
||||
|
||||
styles.forEach(style => {
|
||||
if ((style as any)[CSS_IN_JS_INSTANCE] === CSS_IN_JS_INSTANCE_ID) {
|
||||
if ((style as any)[CSS_IN_JS_INSTANCE] === instanceId) {
|
||||
style.parentNode?.removeChild(style);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const TOKEN_THRESHOLD = 0;
|
||||
|
||||
// Remove will check current keys first
|
||||
function cleanTokenStyle(tokenKey: string) {
|
||||
function cleanTokenStyle(tokenKey: string, instanceId: string) {
|
||||
tokenKeys.set(tokenKey, (tokenKeys.get(tokenKey) || 0) - 1);
|
||||
|
||||
const tokenKeyList = Array.from(tokenKeys.keys());
|
||||
|
@ -60,14 +78,36 @@ function cleanTokenStyle(tokenKey: string) {
|
|||
return count <= 0;
|
||||
});
|
||||
|
||||
if (cleanableKeyList.length < tokenKeyList.length) {
|
||||
// Should keep tokens under threshold for not to insert style too often
|
||||
if (tokenKeyList.length - cleanableKeyList.length > TOKEN_THRESHOLD) {
|
||||
cleanableKeyList.forEach(key => {
|
||||
removeStyleTags(key);
|
||||
removeStyleTags(key, instanceId);
|
||||
tokenKeys.delete(key);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const getComputedToken = <DerivativeToken = object, DesignToken = DerivativeToken>(
|
||||
originToken: DesignToken,
|
||||
overrideToken: object,
|
||||
theme: Theme<any, any>,
|
||||
format?: (token: DesignToken) => DerivativeToken,
|
||||
) => {
|
||||
const derivativeToken = theme.getDerivativeToken(originToken);
|
||||
// Merge with override
|
||||
let mergedDerivativeToken = {
|
||||
...derivativeToken,
|
||||
...overrideToken,
|
||||
};
|
||||
|
||||
// Format if needed
|
||||
if (format) {
|
||||
mergedDerivativeToken = format(mergedDerivativeToken);
|
||||
}
|
||||
|
||||
return mergedDerivativeToken;
|
||||
};
|
||||
|
||||
/**
|
||||
* Cache theme derivative token as global shared one
|
||||
* @param theme Theme entity
|
||||
|
@ -78,8 +118,10 @@ function cleanTokenStyle(tokenKey: string) {
|
|||
export default function useCacheToken<DerivativeToken = object, DesignToken = DerivativeToken>(
|
||||
theme: Ref<Theme<any, any>>,
|
||||
tokens: Ref<Partial<DesignToken>[]>,
|
||||
option: Ref<Option<DerivativeToken>> = ref({}),
|
||||
option: Ref<Option<DerivativeToken, DesignToken>> = ref({}),
|
||||
) {
|
||||
const style = useStyleInject();
|
||||
|
||||
// Basic - We do basic cache here
|
||||
const mergedToken = computed(() => Object.assign({}, ...tokens.value));
|
||||
const tokenStr = computed(() => flattenToken(mergedToken.value));
|
||||
|
@ -94,19 +136,15 @@ export default function useCacheToken<DerivativeToken = object, DesignToken = De
|
|||
overrideTokenStr.value,
|
||||
]),
|
||||
() => {
|
||||
const { salt = '', override = EMPTY_OVERRIDE, formatToken } = option.value;
|
||||
const derivativeToken = theme.value.getDerivativeToken(mergedToken.value);
|
||||
|
||||
// Merge with override
|
||||
let mergedDerivativeToken = {
|
||||
...derivativeToken,
|
||||
...override,
|
||||
};
|
||||
|
||||
// Format if needed
|
||||
if (formatToken) {
|
||||
mergedDerivativeToken = formatToken(mergedDerivativeToken);
|
||||
}
|
||||
const {
|
||||
salt = '',
|
||||
override = EMPTY_OVERRIDE,
|
||||
formatToken,
|
||||
getComputedToken: compute,
|
||||
} = option.value;
|
||||
const mergedDerivativeToken = compute
|
||||
? compute(mergedToken.value, override, theme.value)
|
||||
: getComputedToken(mergedToken.value, override, theme.value, formatToken);
|
||||
|
||||
// Optimize for `useStyleRegister` performance
|
||||
const tokenKey = token2key(mergedDerivativeToken, salt);
|
||||
|
@ -115,12 +153,11 @@ export default function useCacheToken<DerivativeToken = object, DesignToken = De
|
|||
|
||||
const hashId = `${hashPrefix}-${hash(tokenKey)}`;
|
||||
mergedDerivativeToken._hashId = hashId; // Not used
|
||||
|
||||
return [mergedDerivativeToken, hashId];
|
||||
},
|
||||
cache => {
|
||||
// Remove token will remove all related style
|
||||
cleanTokenStyle(cache[0]._tokenKey);
|
||||
cleanTokenStyle(cache[0]._tokenKey, style.value?.cache.instanceId);
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
@ -16,7 +16,8 @@ if (
|
|||
process.env.NODE_ENV !== 'production' &&
|
||||
typeof module !== 'undefined' &&
|
||||
module &&
|
||||
(module as any).hot
|
||||
(module as any).hot &&
|
||||
typeof window !== 'undefined'
|
||||
) {
|
||||
const win = window as any;
|
||||
if (typeof win.webpackHotUpdate === 'function') {
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
import canUseDom from '../../../../_util/canUseDom';
|
||||
import { ATTR_MARK } from '../../StyleContext';
|
||||
|
||||
export const ATTR_CACHE_MAP = 'data-ant-cssinjs-cache-path';
|
||||
|
||||
/**
|
||||
* This marks style from the css file.
|
||||
* Which means not exist in `<style />` tag.
|
||||
*/
|
||||
export const CSS_FILE_STYLE = '_FILE_STYLE__';
|
||||
|
||||
export function serialize(cachePathMap: Record<string, string>) {
|
||||
return Object.keys(cachePathMap)
|
||||
.map(path => {
|
||||
const hash = cachePathMap[path];
|
||||
return `${path}:${hash}`;
|
||||
})
|
||||
.join(';');
|
||||
}
|
||||
|
||||
let cachePathMap: Record<string, string>;
|
||||
let fromCSSFile = true;
|
||||
|
||||
/**
|
||||
* @private Test usage only. Can save remove if no need.
|
||||
*/
|
||||
export function reset(mockCache?: Record<string, string>, fromFile = true) {
|
||||
cachePathMap = mockCache!;
|
||||
fromCSSFile = fromFile;
|
||||
}
|
||||
|
||||
export function prepare() {
|
||||
if (!cachePathMap) {
|
||||
cachePathMap = {};
|
||||
|
||||
if (canUseDom()) {
|
||||
const div = document.createElement('div');
|
||||
div.className = ATTR_CACHE_MAP;
|
||||
div.style.position = 'fixed';
|
||||
div.style.visibility = 'hidden';
|
||||
div.style.top = '-9999px';
|
||||
document.body.appendChild(div);
|
||||
|
||||
let content = getComputedStyle(div).content || '';
|
||||
content = content.replace(/^"/, '').replace(/"$/, '');
|
||||
|
||||
// Fill data
|
||||
content.split(';').forEach(item => {
|
||||
const [path, hash] = item.split(':');
|
||||
cachePathMap[path] = hash;
|
||||
});
|
||||
|
||||
// Remove inline record style
|
||||
const inlineMapStyle = document.querySelector(`style[${ATTR_CACHE_MAP}]`);
|
||||
if (inlineMapStyle) {
|
||||
fromCSSFile = false;
|
||||
inlineMapStyle.parentNode?.removeChild(inlineMapStyle);
|
||||
}
|
||||
|
||||
document.body.removeChild(div);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function existPath(path: string) {
|
||||
prepare();
|
||||
|
||||
return !!cachePathMap[path];
|
||||
}
|
||||
|
||||
export function getStyleAndHash(path: string): [style: string | null, hash: string] {
|
||||
const hash = cachePathMap[path];
|
||||
let styleStr: string | null = null;
|
||||
|
||||
if (hash && canUseDom()) {
|
||||
if (fromCSSFile) {
|
||||
styleStr = CSS_FILE_STYLE;
|
||||
} else {
|
||||
const style = document.querySelector(`style[${ATTR_MARK}="${cachePathMap[path]}"]`);
|
||||
|
||||
if (style) {
|
||||
styleStr = style.innerHTML;
|
||||
} else {
|
||||
// Clean up since not exist anymore
|
||||
delete cachePathMap[path];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [styleStr, hash];
|
||||
}
|
|
@ -3,32 +3,38 @@ import type * as CSS from 'csstype';
|
|||
// @ts-ignore
|
||||
import unitless from '@emotion/unitless';
|
||||
import { compile, serialize, stringify } from 'stylis';
|
||||
import type { Theme, Transformer } from '..';
|
||||
import type Cache from '../Cache';
|
||||
import type Keyframes from '../Keyframes';
|
||||
import type { Linter } from '../linters';
|
||||
import { contentQuotesLinter, hashedAnimationLinter } from '../linters';
|
||||
import type { HashPriority } from '../StyleContext';
|
||||
import type { Theme, Transformer } from '../..';
|
||||
import type Cache from '../../Cache';
|
||||
import type Keyframes from '../../Keyframes';
|
||||
import type { Linter } from '../../linters';
|
||||
import { contentQuotesLinter, hashedAnimationLinter } from '../../linters';
|
||||
import type { HashPriority } from '../../StyleContext';
|
||||
import {
|
||||
useStyleInject,
|
||||
ATTR_DEV_CACHE_PATH,
|
||||
ATTR_CACHE_PATH,
|
||||
ATTR_MARK,
|
||||
ATTR_TOKEN,
|
||||
CSS_IN_JS_INSTANCE,
|
||||
CSS_IN_JS_INSTANCE_ID,
|
||||
} from '../StyleContext';
|
||||
import { supportLayer } from '../util';
|
||||
import useGlobalCache from './useGlobalCache';
|
||||
import canUseDom from '../../canUseDom';
|
||||
import { removeCSS, updateCSS } from '../../../vc-util/Dom/dynamicCSS';
|
||||
} from '../../StyleContext';
|
||||
import { supportLayer } from '../../util';
|
||||
import useGlobalCache from '../useGlobalCache';
|
||||
import { removeCSS, updateCSS } from '../../../../vc-util/Dom/dynamicCSS';
|
||||
import type { Ref } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
import type { VueNode } from '../../type';
|
||||
import type { VueNode } from '../../../type';
|
||||
import canUseDom from '../../../../_util/canUseDom';
|
||||
|
||||
import {
|
||||
ATTR_CACHE_MAP,
|
||||
existPath,
|
||||
getStyleAndHash,
|
||||
serialize as serializeCacheMap,
|
||||
} from './cacheMapUtil';
|
||||
|
||||
const isClientSide = canUseDom();
|
||||
|
||||
const SKIP_CHECK = '_skip_check_';
|
||||
|
||||
const MULTI_VALUE = '_multi_value_';
|
||||
export type CSSProperties = Omit<CSS.PropertiesFallback<number | string>, 'animationName'> & {
|
||||
animationName?: CSS.PropertiesFallback<number | string>['animationName'] | Keyframes;
|
||||
};
|
||||
|
@ -36,16 +42,17 @@ export type CSSProperties = Omit<CSS.PropertiesFallback<number | string>, 'anima
|
|||
export type CSSPropertiesWithMultiValues = {
|
||||
[K in keyof CSSProperties]:
|
||||
| CSSProperties[K]
|
||||
| Extract<CSSProperties[K], string>[]
|
||||
| readonly Extract<CSSProperties[K], string>[]
|
||||
| {
|
||||
[SKIP_CHECK]: boolean;
|
||||
value: CSSProperties[K] | Extract<CSSProperties[K], string>[];
|
||||
[SKIP_CHECK]?: boolean;
|
||||
[MULTI_VALUE]?: boolean;
|
||||
value: CSSProperties[K] | CSSProperties[K][];
|
||||
};
|
||||
};
|
||||
|
||||
export type CSSPseudos = { [K in CSS.Pseudos]?: CSSObject };
|
||||
|
||||
type ArrayCSSInterpolation = CSSInterpolation[];
|
||||
type ArrayCSSInterpolation = readonly CSSInterpolation[];
|
||||
|
||||
export type InterpolationPrimitive = null | undefined | boolean | number | string | CSSObject;
|
||||
|
||||
|
@ -59,13 +66,13 @@ export interface CSSObject extends CSSPropertiesWithMultiValues, CSSPseudos, CSS
|
|||
// == Parser ==
|
||||
// ============================================================================
|
||||
// Preprocessor style content to browser support one
|
||||
export function normalizeStyle(styleStr: string) {
|
||||
export function normalizeStyle(styleStr: string): string {
|
||||
const serialized = serialize(compile(styleStr), stringify);
|
||||
return serialized.replace(/\{%%%\:[^;];}/g, ';');
|
||||
}
|
||||
|
||||
function isCompoundCSSProperty(value: CSSObject[string]) {
|
||||
return typeof value === 'object' && value && SKIP_CHECK in value;
|
||||
return typeof value === 'object' && value && (SKIP_CHECK in value || MULTI_VALUE in value);
|
||||
}
|
||||
|
||||
// 注入 hash 值
|
||||
|
@ -224,32 +231,45 @@ export const parseStyle = (
|
|||
|
||||
styleStr += `${mergedKey}${parsedStr}`;
|
||||
} else {
|
||||
function appendStyle(cssKey: string, cssValue: any) {
|
||||
if (
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
(typeof value !== 'object' || !(value as any)?.[SKIP_CHECK])
|
||||
) {
|
||||
[contentQuotesLinter, hashedAnimationLinter, ...linters].forEach(linter =>
|
||||
linter(cssKey, cssValue, { path, hashId, parentSelectors }),
|
||||
);
|
||||
}
|
||||
|
||||
// 如果是样式则直接插入
|
||||
const styleName = cssKey.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`);
|
||||
|
||||
// Auto suffix with px
|
||||
let formatValue = cssValue;
|
||||
if (!unitless[cssKey] && typeof formatValue === 'number' && formatValue !== 0) {
|
||||
formatValue = `${formatValue}px`;
|
||||
}
|
||||
|
||||
// handle animationName & Keyframe value
|
||||
if (cssKey === 'animationName' && (cssValue as Keyframes)?._keyframe) {
|
||||
parseKeyframes(cssValue as Keyframes);
|
||||
formatValue = (cssValue as Keyframes).getName(hashId);
|
||||
}
|
||||
|
||||
styleStr += `${styleName}:${formatValue};`;
|
||||
}
|
||||
const actualValue = (value as any)?.value ?? value;
|
||||
if (
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
(typeof value !== 'object' || !(value as any)?.[SKIP_CHECK])
|
||||
typeof value === 'object' &&
|
||||
(value as any)?.[MULTI_VALUE] &&
|
||||
Array.isArray(actualValue)
|
||||
) {
|
||||
[contentQuotesLinter, hashedAnimationLinter, ...linters].forEach(linter =>
|
||||
linter(key, actualValue, { path, hashId, parentSelectors }),
|
||||
);
|
||||
actualValue.forEach(item => {
|
||||
appendStyle(key, item);
|
||||
});
|
||||
} else {
|
||||
appendStyle(key, actualValue);
|
||||
}
|
||||
|
||||
// 如果是样式则直接插入
|
||||
const styleName = key.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`);
|
||||
|
||||
// Auto suffix with px
|
||||
let formatValue = actualValue;
|
||||
if (!unitless[key] && typeof formatValue === 'number' && formatValue !== 0) {
|
||||
formatValue = `${formatValue}px`;
|
||||
}
|
||||
|
||||
// handle animationName & Keyframe value
|
||||
if (key === 'animationName' && (value as Keyframes)?._keyframe) {
|
||||
parseKeyframes(value as Keyframes);
|
||||
formatValue = (value as Keyframes).getName(hashId);
|
||||
}
|
||||
|
||||
styleStr += `${styleName}:${formatValue};`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -293,6 +313,14 @@ export default function useStyleRegister(
|
|||
path: string[];
|
||||
hashId?: string;
|
||||
layer?: string;
|
||||
nonce?: string | (() => string);
|
||||
clientOnly?: boolean;
|
||||
/**
|
||||
* Tell cssinjs the insert order of style.
|
||||
* It's useful when you need to insert style
|
||||
* before other style to overwrite for the same selector priority.
|
||||
*/
|
||||
order?: number;
|
||||
}>,
|
||||
styleFn: () => CSSInterpolation,
|
||||
) {
|
||||
|
@ -309,14 +337,32 @@ export default function useStyleRegister(
|
|||
}
|
||||
|
||||
// const [cacheStyle[0], cacheStyle[1], cacheStyle[2]]
|
||||
useGlobalCache(
|
||||
useGlobalCache<
|
||||
[
|
||||
styleStr: string,
|
||||
tokenKey: string,
|
||||
styleId: string,
|
||||
effectStyle: Record<string, string>,
|
||||
clientOnly: boolean | undefined,
|
||||
order: number,
|
||||
]
|
||||
>(
|
||||
'style',
|
||||
fullPath,
|
||||
// Create cache if needed
|
||||
() => {
|
||||
const { path, hashId, layer, nonce, clientOnly, order = 0 } = info.value;
|
||||
const cachePath = fullPath.value.join('|');
|
||||
// Get style from SSR inline style directly
|
||||
if (existPath(cachePath)) {
|
||||
const [inlineCacheStyleStr, styleHash] = getStyleAndHash(cachePath);
|
||||
if (inlineCacheStyleStr) {
|
||||
return [inlineCacheStyleStr, tokenKey.value, styleHash, {}, clientOnly, order];
|
||||
}
|
||||
}
|
||||
const styleObj = styleFn();
|
||||
const { hashPriority, container, transformers, linters } = styleContext.value;
|
||||
const { path, hashId, layer } = info.value;
|
||||
const { hashPriority, container, transformers, linters, cache } = styleContext.value;
|
||||
|
||||
const [parsedStyle, effectStyle] = parseStyle(styleObj, {
|
||||
hashId,
|
||||
hashPriority,
|
||||
|
@ -329,20 +375,29 @@ export default function useStyleRegister(
|
|||
const styleId = uniqueHash(fullPath.value, styleStr);
|
||||
|
||||
if (isMergedClientSide) {
|
||||
const style = updateCSS(styleStr, styleId, {
|
||||
const mergedCSSConfig: Parameters<typeof updateCSS>[2] = {
|
||||
mark: ATTR_MARK,
|
||||
prepend: 'queue',
|
||||
attachTo: container,
|
||||
});
|
||||
priority: order,
|
||||
};
|
||||
|
||||
(style as any)[CSS_IN_JS_INSTANCE] = CSS_IN_JS_INSTANCE_ID;
|
||||
const nonceStr = typeof nonce === 'function' ? nonce() : nonce;
|
||||
|
||||
if (nonceStr) {
|
||||
mergedCSSConfig.csp = { nonce: nonceStr };
|
||||
}
|
||||
|
||||
const style = updateCSS(styleStr, styleId, mergedCSSConfig);
|
||||
|
||||
(style as any)[CSS_IN_JS_INSTANCE] = cache.instanceId;
|
||||
|
||||
// Used for `useCacheToken` to remove on batch when token removed
|
||||
style.setAttribute(ATTR_TOKEN, tokenKey.value);
|
||||
|
||||
// Dev usage to find which cache path made this easily
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
style.setAttribute(ATTR_DEV_CACHE_PATH, fullPath.value.join('|'));
|
||||
style.setAttribute(ATTR_CACHE_PATH, fullPath.value.join('|'));
|
||||
}
|
||||
|
||||
// Inject client side effect style
|
||||
|
@ -360,7 +415,7 @@ export default function useStyleRegister(
|
|||
});
|
||||
}
|
||||
|
||||
return [styleStr, tokenKey.value, styleId];
|
||||
return [styleStr, tokenKey.value, styleId, effectStyle, clientOnly, order];
|
||||
},
|
||||
// Remove cache if no need
|
||||
([, , styleId], fromHMR) => {
|
||||
|
@ -399,19 +454,113 @@ export default function useStyleRegister(
|
|||
// ============================================================================
|
||||
// == SSR ==
|
||||
// ============================================================================
|
||||
export function extractStyle(cache: Cache) {
|
||||
// prefix with `style` is used for `useStyleRegister` to cache style context
|
||||
const styleKeys = Array.from(cache.cache.keys()).filter(key => key.startsWith('style%'));
|
||||
export function extractStyle(cache: Cache, plain = false) {
|
||||
const matchPrefix = `style%`;
|
||||
|
||||
// const tokenStyles: Record<string, string[]> = {};
|
||||
// prefix with `style` is used for `useStyleRegister` to cache style context
|
||||
const styleKeys = Array.from(cache.cache.keys()).filter(key => key.startsWith(matchPrefix));
|
||||
|
||||
// Common effect styles like animation
|
||||
const effectStyles: Record<string, boolean> = {};
|
||||
|
||||
// Mapping of cachePath to style hash
|
||||
const cachePathMap: Record<string, string> = {};
|
||||
|
||||
let styleText = '';
|
||||
|
||||
styleKeys.forEach(key => {
|
||||
const [styleStr, tokenKey, styleId]: [string, string, string] = cache.cache.get(key)![1];
|
||||
function toStyleStr(
|
||||
style: string,
|
||||
tokenKey?: string,
|
||||
styleId?: string,
|
||||
customizeAttrs: Record<string, string> = {},
|
||||
) {
|
||||
const attrs: Record<string, string | undefined> = {
|
||||
...customizeAttrs,
|
||||
[ATTR_TOKEN]: tokenKey,
|
||||
[ATTR_MARK]: styleId,
|
||||
};
|
||||
|
||||
styleText += `<style ${ATTR_TOKEN}="${tokenKey}" ${ATTR_MARK}="${styleId}">${styleStr}</style>`;
|
||||
});
|
||||
const attrStr = Object.keys(attrs)
|
||||
.map(attr => {
|
||||
const val = attrs[attr];
|
||||
return val ? `${attr}="${val}"` : null;
|
||||
})
|
||||
.filter(v => v)
|
||||
.join(' ');
|
||||
|
||||
return plain ? style : `<style ${attrStr}>${style}</style>`;
|
||||
}
|
||||
|
||||
// ====================== Fill Style ======================
|
||||
type OrderStyle = [order: number, style: string];
|
||||
|
||||
const orderStyles: OrderStyle[] = styleKeys
|
||||
.map(key => {
|
||||
const cachePath = key.slice(matchPrefix.length).replace(/%/g, '|');
|
||||
|
||||
const [styleStr, tokenKey, styleId, effectStyle, clientOnly, order]: [
|
||||
string,
|
||||
string,
|
||||
string,
|
||||
Record<string, string>,
|
||||
boolean,
|
||||
number,
|
||||
] = cache.cache.get(key)![1];
|
||||
|
||||
// Skip client only style
|
||||
if (clientOnly) {
|
||||
return null! as OrderStyle;
|
||||
}
|
||||
|
||||
// ====================== Style ======================
|
||||
// Used for vc-util
|
||||
const sharedAttrs = {
|
||||
'data-vc-order': 'prependQueue',
|
||||
'data-vc-priority': `${order}`,
|
||||
};
|
||||
|
||||
let keyStyleText = toStyleStr(styleStr, tokenKey, styleId, sharedAttrs);
|
||||
|
||||
// Save cache path with hash mapping
|
||||
cachePathMap[cachePath] = styleId;
|
||||
|
||||
// =============== Create effect style ===============
|
||||
if (effectStyle) {
|
||||
Object.keys(effectStyle).forEach(effectKey => {
|
||||
// Effect style can be reused
|
||||
if (!effectStyles[effectKey]) {
|
||||
effectStyles[effectKey] = true;
|
||||
keyStyleText += toStyleStr(
|
||||
normalizeStyle(effectStyle[effectKey]),
|
||||
tokenKey,
|
||||
`_effect-${effectKey}`,
|
||||
sharedAttrs,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const ret: OrderStyle = [order, keyStyleText];
|
||||
|
||||
return ret;
|
||||
})
|
||||
.filter(o => o);
|
||||
|
||||
orderStyles
|
||||
.sort((o1, o2) => o1[0] - o2[0])
|
||||
.forEach(([, style]) => {
|
||||
styleText += style;
|
||||
});
|
||||
|
||||
// ==================== Fill Cache Path ====================
|
||||
styleText += toStyleStr(
|
||||
`.${ATTR_CACHE_MAP}{content:"${serializeCacheMap(cachePathMap)}";}`,
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
[ATTR_CACHE_MAP]: ATTR_CACHE_MAP,
|
||||
},
|
||||
);
|
||||
|
||||
return styleText;
|
||||
}
|
|
@ -3,13 +3,15 @@ import type { CSSInterpolation, CSSObject } from './hooks/useStyleRegister';
|
|||
import useStyleRegister, { extractStyle } from './hooks/useStyleRegister';
|
||||
import Keyframes from './Keyframes';
|
||||
import type { Linter } from './linters';
|
||||
import { legacyNotSelectorLinter, logicalPropertiesLinter } from './linters';
|
||||
import { legacyNotSelectorLinter, logicalPropertiesLinter, parentSelectorLinter } from './linters';
|
||||
import type { StyleContextProps, StyleProviderProps } from './StyleContext';
|
||||
import { createCache, useStyleInject, useStyleProvider, StyleProvider } from './StyleContext';
|
||||
import type { DerivativeFunc, TokenType } from './theme';
|
||||
import { createTheme, Theme } from './theme';
|
||||
import type { Transformer } from './transformers/interface';
|
||||
import legacyLogicalPropertiesTransformer from './transformers/legacyLogicalProperties';
|
||||
import px2remTransformer from './transformers/px2rem';
|
||||
import { supportLogicProps, supportWhere } from './util';
|
||||
|
||||
const cssinjs = {
|
||||
Theme,
|
||||
|
@ -24,10 +26,12 @@ const cssinjs = {
|
|||
|
||||
// Transformer
|
||||
legacyLogicalPropertiesTransformer,
|
||||
px2remTransformer,
|
||||
|
||||
// Linters
|
||||
logicalPropertiesLinter,
|
||||
legacyNotSelectorLinter,
|
||||
parentSelectorLinter,
|
||||
|
||||
// cssinjs
|
||||
StyleProvider,
|
||||
|
@ -45,10 +49,12 @@ export {
|
|||
|
||||
// Transformer
|
||||
legacyLogicalPropertiesTransformer,
|
||||
px2remTransformer,
|
||||
|
||||
// Linters
|
||||
logicalPropertiesLinter,
|
||||
legacyNotSelectorLinter,
|
||||
parentSelectorLinter,
|
||||
|
||||
// cssinjs
|
||||
StyleProvider,
|
||||
|
@ -64,4 +70,8 @@ export type {
|
|||
StyleProviderProps,
|
||||
};
|
||||
|
||||
export const _experimental = {
|
||||
supportModernCSS: () => supportWhere() && supportLogicProps(),
|
||||
};
|
||||
|
||||
export default cssinjs;
|
||||
|
|
|
@ -3,3 +3,4 @@ export { default as hashedAnimationLinter } from './hashedAnimationLinter';
|
|||
export type { Linter } from './interface';
|
||||
export { default as legacyNotSelectorLinter } from './legacyNotSelectorLinter';
|
||||
export { default as logicalPropertiesLinter } from './logicalPropertiesLinter';
|
||||
export { default as parentSelectorLinter } from './parentSelectorLinter';
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import type { Linter } from '..';
|
||||
import { lintWarning } from './utils';
|
||||
|
||||
const linter: Linter = (_key, _value, info) => {
|
||||
if (
|
||||
info.parentSelectors.some(selector => {
|
||||
const selectors = selector.split(',');
|
||||
return selectors.some(item => item.split('&').length > 2);
|
||||
})
|
||||
) {
|
||||
lintWarning('Should not use more than one `&` in a selector.', info);
|
||||
}
|
||||
};
|
||||
|
||||
export default linter;
|
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
* respect https://github.com/cuth/postcss-pxtorem
|
||||
*/
|
||||
import unitless from '@emotion/unitless';
|
||||
import type { CSSObject } from '..';
|
||||
import type { Transformer } from './interface';
|
||||
|
||||
export interface Options {
|
||||
/**
|
||||
* The root font size.
|
||||
* @default 16
|
||||
*/
|
||||
rootValue?: number;
|
||||
/**
|
||||
* The decimal numbers to allow the REM units to grow to.
|
||||
* @default 5
|
||||
*/
|
||||
precision?: number;
|
||||
/**
|
||||
* Whether to allow px to be converted in media queries.
|
||||
* @default false
|
||||
*/
|
||||
mediaQuery?: boolean;
|
||||
}
|
||||
|
||||
const pxRegex = /url\([^)]+\)|var\([^)]+\)|(\d*\.?\d+)px/g;
|
||||
|
||||
function toFixed(number: number, precision: number) {
|
||||
const multiplier = Math.pow(10, precision + 1),
|
||||
wholeNumber = Math.floor(number * multiplier);
|
||||
return (Math.round(wholeNumber / 10) * 10) / multiplier;
|
||||
}
|
||||
|
||||
const transform = (options: Options = {}): Transformer => {
|
||||
const { rootValue = 16, precision = 5, mediaQuery = false } = options;
|
||||
|
||||
const pxReplace = (m: string, $1: any) => {
|
||||
if (!$1) return m;
|
||||
const pixels = parseFloat($1);
|
||||
// covenant: pixels <= 1, not transform to rem @zombieJ
|
||||
if (pixels <= 1) return m;
|
||||
const fixedVal = toFixed(pixels / rootValue, precision);
|
||||
return `${fixedVal}rem`;
|
||||
};
|
||||
|
||||
const visit = (cssObj: CSSObject): CSSObject => {
|
||||
const clone: CSSObject = { ...cssObj };
|
||||
|
||||
Object.entries(cssObj).forEach(([key, value]) => {
|
||||
if (typeof value === 'string' && value.includes('px')) {
|
||||
const newValue = value.replace(pxRegex, pxReplace);
|
||||
clone[key] = newValue;
|
||||
}
|
||||
|
||||
// no unit
|
||||
if (!unitless[key] && typeof value === 'number' && value !== 0) {
|
||||
clone[key] = `${value}px`.replace(pxRegex, pxReplace);
|
||||
}
|
||||
|
||||
// Media queries
|
||||
const mergedKey = key.trim();
|
||||
if (mergedKey.startsWith('@') && mergedKey.includes('px') && mediaQuery) {
|
||||
const newKey = key.replace(pxRegex, pxReplace);
|
||||
|
||||
clone[newKey] = clone[key];
|
||||
delete clone[key];
|
||||
}
|
||||
});
|
||||
|
||||
return clone;
|
||||
};
|
||||
|
||||
return { visit };
|
||||
};
|
||||
|
||||
export default transform;
|
|
@ -2,17 +2,30 @@ import hash from '@emotion/hash';
|
|||
import { removeCSS, updateCSS } from '../../vc-util/Dom/dynamicCSS';
|
||||
import canUseDom from '../canUseDom';
|
||||
|
||||
import { Theme } from './theme';
|
||||
|
||||
// Create a cache here to avoid always loop generate
|
||||
const flattenTokenCache = new WeakMap<any, string>();
|
||||
|
||||
export function flattenToken(token: any) {
|
||||
let str = '';
|
||||
Object.keys(token).forEach(key => {
|
||||
const value = token[key];
|
||||
str += key;
|
||||
if (value && typeof value === 'object') {
|
||||
str += flattenToken(value);
|
||||
} else {
|
||||
str += value;
|
||||
}
|
||||
});
|
||||
let str = flattenTokenCache.get(token) || '';
|
||||
|
||||
if (!str) {
|
||||
Object.keys(token).forEach(key => {
|
||||
const value = token[key];
|
||||
str += key;
|
||||
if (value instanceof Theme) {
|
||||
str += value.id;
|
||||
} else if (value && typeof value === 'object') {
|
||||
str += flattenToken(value);
|
||||
} else {
|
||||
str += value;
|
||||
}
|
||||
});
|
||||
|
||||
// Put in cache
|
||||
flattenTokenCache.set(token, str);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
@ -23,12 +36,18 @@ export function token2key(token: any, salt: string): string {
|
|||
return hash(`${salt}_${flattenToken(token)}`);
|
||||
}
|
||||
|
||||
const layerKey = `layer-${Date.now()}-${Math.random()}`.replace(/\./g, '');
|
||||
const layerWidth = '903px';
|
||||
const randomSelectorKey = `random-${Date.now()}-${Math.random()}`.replace(/\./g, '');
|
||||
|
||||
function supportSelector(styleStr: string, handleElement?: (ele: HTMLElement) => void): boolean {
|
||||
// Magic `content` for detect selector support
|
||||
const checkContent = '_bAmBoO_';
|
||||
|
||||
function supportSelector(
|
||||
styleStr: string,
|
||||
handleElement: (ele: HTMLElement) => void,
|
||||
supportCheck?: (ele: HTMLElement) => boolean,
|
||||
): boolean {
|
||||
if (canUseDom()) {
|
||||
updateCSS(styleStr, layerKey);
|
||||
updateCSS(styleStr, randomSelectorKey);
|
||||
|
||||
const ele = document.createElement('div');
|
||||
ele.style.position = 'fixed';
|
||||
|
@ -42,10 +61,12 @@ function supportSelector(styleStr: string, handleElement?: (ele: HTMLElement) =>
|
|||
ele.style.zIndex = '9999999';
|
||||
}
|
||||
|
||||
const support = getComputedStyle(ele).width === layerWidth;
|
||||
const support = supportCheck
|
||||
? supportCheck(ele)
|
||||
: getComputedStyle(ele).content?.includes(checkContent);
|
||||
|
||||
ele.parentNode?.removeChild(ele);
|
||||
removeCSS(layerKey);
|
||||
removeCSS(randomSelectorKey);
|
||||
|
||||
return support;
|
||||
}
|
||||
|
@ -57,12 +78,41 @@ let canLayer: boolean | undefined = undefined;
|
|||
export function supportLayer(): boolean {
|
||||
if (canLayer === undefined) {
|
||||
canLayer = supportSelector(
|
||||
`@layer ${layerKey} { .${layerKey} { width: ${layerWidth}!important; } }`,
|
||||
`@layer ${randomSelectorKey} { .${randomSelectorKey} { content: "${checkContent}"!important; } }`,
|
||||
ele => {
|
||||
ele.className = layerKey;
|
||||
ele.className = randomSelectorKey;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return canLayer!;
|
||||
}
|
||||
|
||||
let canWhere: boolean | undefined = undefined;
|
||||
export function supportWhere(): boolean {
|
||||
if (canWhere === undefined) {
|
||||
canWhere = supportSelector(
|
||||
`:where(.${randomSelectorKey}) { content: "${checkContent}"!important; }`,
|
||||
ele => {
|
||||
ele.className = randomSelectorKey;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return canWhere!;
|
||||
}
|
||||
|
||||
let canLogic: boolean | undefined = undefined;
|
||||
export function supportLogicProps(): boolean {
|
||||
if (canLogic === undefined) {
|
||||
canLogic = supportSelector(
|
||||
`.${randomSelectorKey} { inset-block: 93px !important; }`,
|
||||
ele => {
|
||||
ele.className = randomSelectorKey;
|
||||
},
|
||||
ele => getComputedStyle(ele).bottom === '93px',
|
||||
);
|
||||
}
|
||||
|
||||
return canLogic!;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import type { SizeType } from '../config-provider/SizeContext';
|
||||
|
||||
export function isPresetSize(size?: SizeType | string | number): size is SizeType {
|
||||
return ['small', 'middle', 'large'].includes(size as string);
|
||||
}
|
||||
|
||||
export function isValidGapNumber(size?: SizeType | string | number): size is number {
|
||||
if (!size) {
|
||||
// The case of size = 0 is deliberately excluded here, because the default value of the gap attribute in CSS is 0, so if the user passes 0 in, we can directly ignore it.
|
||||
return false;
|
||||
}
|
||||
return typeof size === 'number' && !Number.isNaN(size);
|
||||
}
|
|
@ -12,7 +12,7 @@ export default function getScroll(
|
|||
const method = top ? 'scrollTop' : 'scrollLeft';
|
||||
let result = 0;
|
||||
if (isWindow(target)) {
|
||||
result = target[top ? 'pageYOffset' : 'pageXOffset'];
|
||||
result = target[top ? 'scrollY' : 'scrollX'];
|
||||
} else if (target instanceof Document) {
|
||||
result = target.documentElement[method];
|
||||
} else if (target instanceof HTMLElement) {
|
||||
|
|
|
@ -28,7 +28,7 @@ export interface ConfigurableLocation {
|
|||
location?: Location;
|
||||
}
|
||||
|
||||
export const defaultWindow = /* #__PURE__ */ isClient ? window : undefined;
|
||||
export const defaultDocument = /* #__PURE__ */ isClient ? window.document : undefined;
|
||||
export const defaultNavigator = /* #__PURE__ */ isClient ? window.navigator : undefined;
|
||||
export const defaultLocation = /* #__PURE__ */ isClient ? window.location : undefined;
|
||||
export const defaultWindow = isClient ? window : undefined;
|
||||
export const defaultDocument = isClient ? window.document : undefined;
|
||||
export const defaultNavigator = isClient ? window.navigator : undefined;
|
||||
export const defaultLocation = isClient ? window.location : undefined;
|
||||
|
|
|
@ -21,8 +21,6 @@ export const rand = (min: number, max: number) => {
|
|||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
};
|
||||
export const isIOS =
|
||||
/* #__PURE__ */ isClient &&
|
||||
window?.navigator?.userAgent &&
|
||||
/iP(ad|hone|od)/.test(window.navigator.userAgent);
|
||||
isClient && window?.navigator?.userAgent && /iP(ad|hone|od)/.test(window.navigator.userAgent);
|
||||
export const hasOwn = <T extends object, K extends keyof T>(val: T, key: K): key is K =>
|
||||
Object.prototype.hasOwnProperty.call(val, key);
|
||||
|
|
|
@ -2,6 +2,7 @@ import type { Ref } from 'vue';
|
|||
import { computed, watchEffect } from 'vue';
|
||||
import { updateCSS, removeCSS } from '../../vc-util/Dom/dynamicCSS';
|
||||
import getScrollBarSize from '../../_util/getScrollBarSize';
|
||||
import canUseDom from '../../_util/canUseDom';
|
||||
|
||||
const UNIQUE_ID = `vc-util-locker-${Date.now()}`;
|
||||
|
||||
|
@ -24,6 +25,9 @@ export default function useScrollLocker(lock?: Ref<boolean>) {
|
|||
|
||||
watchEffect(
|
||||
onClear => {
|
||||
if (!canUseDom()) {
|
||||
return;
|
||||
}
|
||||
if (mergedLock.value) {
|
||||
const scrollbarSize = getScrollBarSize();
|
||||
const isOverflow = isBodyOverflowing();
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
let animation;
|
||||
|
||||
function isCssAnimationSupported() {
|
||||
if (animation !== undefined) {
|
||||
return animation;
|
||||
}
|
||||
const domPrefixes = 'Webkit Moz O ms Khtml'.split(' ');
|
||||
const elm = document.createElement('div');
|
||||
if (elm.style.animationName !== undefined) {
|
||||
animation = true;
|
||||
}
|
||||
if (animation !== undefined) {
|
||||
for (let i = 0; i < domPrefixes.length; i++) {
|
||||
if (elm.style[`${domPrefixes[i]}AnimationName`] !== undefined) {
|
||||
animation = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
animation = animation || false;
|
||||
return animation;
|
||||
}
|
||||
|
||||
export default isCssAnimationSupported;
|
|
@ -3,7 +3,7 @@
|
|||
* https://github.com/akiran/json2mq.git
|
||||
*/
|
||||
|
||||
const camel2hyphen = function (str) {
|
||||
const camel2hyphen = function (str: string) {
|
||||
return str
|
||||
.replace(/[A-Z]/g, function (match) {
|
||||
return '-' + match.toLowerCase();
|
||||
|
@ -11,12 +11,12 @@ const camel2hyphen = function (str) {
|
|||
.toLowerCase();
|
||||
};
|
||||
|
||||
const isDimension = function (feature) {
|
||||
const isDimension = function (feature: string) {
|
||||
const re = /[height|width]$/;
|
||||
return re.test(feature);
|
||||
};
|
||||
|
||||
const obj2mq = function (obj) {
|
||||
const obj2mq = function (obj: { [x: string]: any }) {
|
||||
let mq = '';
|
||||
const features = Object.keys(obj);
|
||||
features.forEach(function (feature, index) {
|
||||
|
@ -40,7 +40,7 @@ const obj2mq = function (obj) {
|
|||
return mq;
|
||||
};
|
||||
|
||||
export default function (query) {
|
||||
export default function (query: any[]) {
|
||||
let mq = '';
|
||||
if (typeof query === 'string') {
|
||||
return query;
|
|
@ -1,19 +1,19 @@
|
|||
import isPlainObject from 'lodash-es/isPlainObject';
|
||||
import classNames from '../classNames';
|
||||
import { isVNode, Fragment, Comment, Text, h } from 'vue';
|
||||
import { isVNode, Fragment, Comment, Text } from 'vue';
|
||||
import { camelize, hyphenate, isOn, resolvePropValue } from '../util';
|
||||
import isValid from '../isValid';
|
||||
import initDefaultProps from './initDefaultProps';
|
||||
import type { VueInstance } from '../hooks/_vueuse/unrefElement';
|
||||
// function getType(fn) {
|
||||
// const match = fn && fn.toString().match(/^\s*function (\w+)/);
|
||||
// return match ? match[1] : '';
|
||||
// }
|
||||
|
||||
const splitAttrs = attrs => {
|
||||
const splitAttrs = (attrs: any) => {
|
||||
const allAttrs = Object.keys(attrs);
|
||||
const eventAttrs = {};
|
||||
const onEvents = {};
|
||||
const extraAttrs = {};
|
||||
const eventAttrs: Record<string, any> = {};
|
||||
const onEvents: Record<string, any> = {};
|
||||
const extraAttrs: Record<string, any> = {};
|
||||
for (let i = 0, l = allAttrs.length; i < l; i++) {
|
||||
const key = allAttrs[i];
|
||||
if (isOn(key)) {
|
||||
|
@ -25,7 +25,7 @@ const splitAttrs = attrs => {
|
|||
}
|
||||
return { onEvents, events: eventAttrs, extraAttrs };
|
||||
};
|
||||
const parseStyleText = (cssText = '', camel) => {
|
||||
const parseStyleText = (cssText = '', camel = false) => {
|
||||
const res = {};
|
||||
const listDelimiter = /;(?![^(]*\))/g;
|
||||
const propertyDelimiter = /:(.+)/;
|
||||
|
@ -42,34 +42,9 @@ const parseStyleText = (cssText = '', camel) => {
|
|||
return res;
|
||||
};
|
||||
|
||||
const hasProp = (instance, prop) => {
|
||||
const hasProp = (instance: any, prop: string) => {
|
||||
return instance[prop] !== undefined;
|
||||
};
|
||||
// 重构后直接使用 hasProp 替换
|
||||
const slotHasProp = (slot, prop) => {
|
||||
return hasProp(slot, prop);
|
||||
};
|
||||
|
||||
const getScopedSlots = ele => {
|
||||
return (ele.data && ele.data.scopedSlots) || {};
|
||||
};
|
||||
|
||||
const getSlots = ele => {
|
||||
let componentOptions = ele.componentOptions || {};
|
||||
if (ele.$vnode) {
|
||||
componentOptions = ele.$vnode.componentOptions || {};
|
||||
}
|
||||
const children = ele.children || componentOptions.children || [];
|
||||
const slots = {};
|
||||
children.forEach(child => {
|
||||
if (!isEmptyElement(child)) {
|
||||
const name = (child.data && child.data.slot) || 'default';
|
||||
slots[name] = slots[name] || [];
|
||||
slots[name].push(child);
|
||||
}
|
||||
});
|
||||
return { ...slots, ...getScopedSlots(ele) };
|
||||
};
|
||||
|
||||
export const skipFlattenKey = Symbol('skipFlatten');
|
||||
const flattenChildren = (children = [], filterEmpty = true) => {
|
||||
|
@ -97,39 +72,29 @@ const flattenChildren = (children = [], filterEmpty = true) => {
|
|||
return res;
|
||||
};
|
||||
|
||||
const getSlot = (self, name = 'default', options = {}) => {
|
||||
const getSlot = (self: any, name = 'default', options = {}) => {
|
||||
if (isVNode(self)) {
|
||||
if (self.type === Fragment) {
|
||||
return name === 'default' ? flattenChildren(self.children) : [];
|
||||
return name === 'default' ? flattenChildren(self.children as any[]) : [];
|
||||
} else if (self.children && self.children[name]) {
|
||||
return flattenChildren(self.children[name](options));
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
} else {
|
||||
let res = self.$slots[name] && self.$slots[name](options);
|
||||
const res = self.$slots[name] && self.$slots[name](options);
|
||||
return flattenChildren(res);
|
||||
}
|
||||
};
|
||||
|
||||
const getAllChildren = ele => {
|
||||
let componentOptions = ele.componentOptions || {};
|
||||
if (ele.$vnode) {
|
||||
componentOptions = ele.$vnode.componentOptions || {};
|
||||
}
|
||||
return ele.children || componentOptions.children || [];
|
||||
};
|
||||
const getSlotOptions = () => {
|
||||
throw Error('使用 .type 直接取值');
|
||||
};
|
||||
const findDOMNode = instance => {
|
||||
const findDOMNode = (instance: any) => {
|
||||
let node = instance?.vnode?.el || (instance && (instance.$el || instance));
|
||||
while (node && !node.tagName) {
|
||||
node = node.nextSibling;
|
||||
}
|
||||
return node;
|
||||
};
|
||||
const getOptionProps = instance => {
|
||||
const getOptionProps = (instance: VueInstance) => {
|
||||
const res = {};
|
||||
if (instance.$ && instance.$.vnode) {
|
||||
const props = instance.$.vnode.props || {};
|
||||
|
@ -146,7 +111,7 @@ const getOptionProps = instance => {
|
|||
Object.keys(originProps).forEach(key => {
|
||||
props[camelize(key)] = originProps[key];
|
||||
});
|
||||
const options = instance.type.props || {};
|
||||
const options = (instance.type as any).props || {};
|
||||
Object.keys(options).forEach(k => {
|
||||
const v = resolvePropValue(options, props, k, props[k]);
|
||||
if (v !== undefined || k in props) {
|
||||
|
@ -156,7 +121,7 @@ const getOptionProps = instance => {
|
|||
}
|
||||
return res;
|
||||
};
|
||||
const getComponent = (instance, prop = 'default', options = instance, execute = true) => {
|
||||
const getComponent = (instance: any, prop = 'default', options = instance, execute = true) => {
|
||||
let com = undefined;
|
||||
if (instance.$) {
|
||||
const temp = instance[prop];
|
||||
|
@ -184,94 +149,13 @@ const getComponent = (instance, prop = 'default', options = instance, execute =
|
|||
}
|
||||
return com;
|
||||
};
|
||||
const getComponentFromProp = (instance, prop, options = instance, execute = true) => {
|
||||
if (instance.$createElement) {
|
||||
// const h = instance.$createElement;
|
||||
const temp = instance[prop];
|
||||
if (temp !== undefined) {
|
||||
return typeof temp === 'function' && execute ? temp(h, options) : temp;
|
||||
}
|
||||
return (
|
||||
(instance.$scopedSlots[prop] && execute && instance.$scopedSlots[prop](options)) ||
|
||||
instance.$scopedSlots[prop] ||
|
||||
instance.$slots[prop] ||
|
||||
undefined
|
||||
);
|
||||
} else {
|
||||
// const h = instance.context.$createElement;
|
||||
const temp = getPropsData(instance)[prop];
|
||||
if (temp !== undefined) {
|
||||
return typeof temp === 'function' && execute ? temp(h, options) : temp;
|
||||
}
|
||||
const slotScope = getScopedSlots(instance)[prop];
|
||||
if (slotScope !== undefined) {
|
||||
return typeof slotScope === 'function' && execute ? slotScope(h, options) : slotScope;
|
||||
}
|
||||
const slotsProp = [];
|
||||
const componentOptions = instance.componentOptions || {};
|
||||
(componentOptions.children || []).forEach(child => {
|
||||
if (child.data && child.data.slot === prop) {
|
||||
if (child.data.attrs) {
|
||||
delete child.data.attrs.slot;
|
||||
}
|
||||
if (child.tag === 'template') {
|
||||
slotsProp.push(child.children);
|
||||
} else {
|
||||
slotsProp.push(child);
|
||||
}
|
||||
}
|
||||
});
|
||||
return slotsProp.length ? slotsProp : undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const getAllProps = ele => {
|
||||
let props = getOptionProps(ele);
|
||||
if (ele.$) {
|
||||
props = { ...props, ...this.$attrs };
|
||||
} else {
|
||||
props = { ...ele.props, ...props };
|
||||
}
|
||||
return props;
|
||||
};
|
||||
|
||||
const getPropsData = ins => {
|
||||
const vnode = ins.$ ? ins.$ : ins;
|
||||
const res = {};
|
||||
const originProps = vnode.props || {};
|
||||
const props = {};
|
||||
Object.keys(originProps).forEach(key => {
|
||||
props[camelize(key)] = originProps[key];
|
||||
});
|
||||
const options = isPlainObject(vnode.type) ? vnode.type.props : {};
|
||||
options &&
|
||||
Object.keys(options).forEach(k => {
|
||||
const v = resolvePropValue(options, props, k, props[k]);
|
||||
if (k in props) {
|
||||
// 仅包含 props,不包含默认值
|
||||
res[k] = v;
|
||||
}
|
||||
});
|
||||
return { ...props, ...res }; // 合并事件、未声明属性等
|
||||
};
|
||||
const getValueByProp = (ele, prop) => {
|
||||
return getPropsData(ele)[prop];
|
||||
};
|
||||
|
||||
const getAttrs = ele => {
|
||||
let data = ele.data;
|
||||
if (ele.$vnode) {
|
||||
data = ele.$vnode.data;
|
||||
}
|
||||
return data ? data.attrs || {} : {};
|
||||
};
|
||||
|
||||
const getKey = ele => {
|
||||
let key = ele.key;
|
||||
const getKey = (ele: any) => {
|
||||
const key = ele.key;
|
||||
return key;
|
||||
};
|
||||
|
||||
export function getEvents(ele = {}, on = true) {
|
||||
export function getEvents(ele: any = {}, on = true) {
|
||||
let props = {};
|
||||
if (ele.$) {
|
||||
props = { ...props, ...ele.$attrs };
|
||||
|
@ -281,27 +165,9 @@ export function getEvents(ele = {}, on = true) {
|
|||
return splitAttrs(props)[on ? 'onEvents' : 'events'];
|
||||
}
|
||||
|
||||
export function getEvent(child, event) {
|
||||
return child.props && child.props[event];
|
||||
}
|
||||
|
||||
// 获取 xxx.native 或者 原生标签 事件
|
||||
export function getDataEvents(child) {
|
||||
let events = {};
|
||||
if (child.data && child.data.on) {
|
||||
events = child.data.on;
|
||||
}
|
||||
return { ...events };
|
||||
}
|
||||
|
||||
// use getListeners instead this.$listeners
|
||||
// https://github.com/vueComponent/ant-design-vue/issues/1705
|
||||
export function getListeners(context) {
|
||||
return (context.$vnode ? context.$vnode.componentOptions.listeners : context.$listeners) || {};
|
||||
}
|
||||
export function getClass(ele) {
|
||||
export function getClass(ele: any) {
|
||||
const props = (isVNode(ele) ? ele.props : ele.$attrs) || {};
|
||||
let tempCls = props.class || {};
|
||||
const tempCls = props.class || {};
|
||||
let cls = {};
|
||||
if (typeof tempCls === 'string') {
|
||||
tempCls.split(' ').forEach(c => {
|
||||
|
@ -318,7 +184,7 @@ export function getClass(ele) {
|
|||
}
|
||||
return cls;
|
||||
}
|
||||
export function getStyle(ele, camel) {
|
||||
export function getStyle(ele: any, camel?: boolean) {
|
||||
const props = (isVNode(ele) ? ele.props : ele.$attrs) || {};
|
||||
let style = props.style || {};
|
||||
if (typeof style === 'string') {
|
||||
|
@ -332,19 +198,19 @@ export function getStyle(ele, camel) {
|
|||
return style;
|
||||
}
|
||||
|
||||
export function getComponentName(opts) {
|
||||
export function getComponentName(opts: any) {
|
||||
return opts && (opts.Ctor.options.name || opts.tag);
|
||||
}
|
||||
|
||||
export function isFragment(c) {
|
||||
export function isFragment(c: any) {
|
||||
return c.length === 1 && c[0].type === Fragment;
|
||||
}
|
||||
|
||||
export function isEmptyContent(c) {
|
||||
export function isEmptyContent(c: any) {
|
||||
return c === undefined || c === null || c === '' || (Array.isArray(c) && c.length === 0);
|
||||
}
|
||||
|
||||
export function isEmptyElement(c) {
|
||||
export function isEmptyElement(c: any) {
|
||||
return (
|
||||
c &&
|
||||
(c.type === Comment ||
|
||||
|
@ -353,11 +219,11 @@ export function isEmptyElement(c) {
|
|||
);
|
||||
}
|
||||
|
||||
export function isEmptySlot(c) {
|
||||
export function isEmptySlot(c: any) {
|
||||
return !c || c().every(isEmptyElement);
|
||||
}
|
||||
|
||||
export function isStringElement(c) {
|
||||
export function isStringElement(c: any) {
|
||||
return c && c.type === Text;
|
||||
}
|
||||
|
||||
|
@ -375,7 +241,7 @@ export function filterEmpty(children = []) {
|
|||
return res.filter(c => !isEmptyElement(c));
|
||||
}
|
||||
|
||||
export function filterEmptyWithUndefined(children) {
|
||||
export function filterEmptyWithUndefined(children: any[]) {
|
||||
if (children) {
|
||||
const coms = filterEmpty(children);
|
||||
return coms.length ? coms : undefined;
|
||||
|
@ -384,34 +250,18 @@ export function filterEmptyWithUndefined(children) {
|
|||
}
|
||||
}
|
||||
|
||||
export function mergeProps() {
|
||||
const args = [].slice.call(arguments, 0);
|
||||
const props = {};
|
||||
args.forEach((p = {}) => {
|
||||
for (const [k, v] of Object.entries(p)) {
|
||||
props[k] = props[k] || {};
|
||||
if (isPlainObject(v)) {
|
||||
Object.assign(props[k], v);
|
||||
} else {
|
||||
props[k] = v;
|
||||
}
|
||||
}
|
||||
});
|
||||
return props;
|
||||
}
|
||||
|
||||
function isValidElement(element) {
|
||||
function isValidElement(element: any) {
|
||||
if (Array.isArray(element) && element.length === 1) {
|
||||
element = element[0];
|
||||
}
|
||||
return element && element.__v_isVNode && typeof element.type !== 'symbol'; // remove text node
|
||||
}
|
||||
|
||||
function getPropsSlot(slots, props, prop = 'default') {
|
||||
function getPropsSlot(slots: any, props: any, prop = 'default') {
|
||||
return props[prop] ?? slots[prop]?.();
|
||||
}
|
||||
|
||||
export const getTextFromElement = ele => {
|
||||
export const getTextFromElement = (ele: any) => {
|
||||
if (isValidElement(ele) && isStringElement(ele[0])) {
|
||||
return ele[0].children;
|
||||
}
|
||||
|
@ -422,21 +272,12 @@ export {
|
|||
hasProp,
|
||||
getOptionProps,
|
||||
getComponent,
|
||||
getComponentFromProp,
|
||||
getSlotOptions,
|
||||
slotHasProp,
|
||||
getPropsData,
|
||||
getKey,
|
||||
getAttrs,
|
||||
getValueByProp,
|
||||
parseStyleText,
|
||||
initDefaultProps,
|
||||
isValidElement,
|
||||
camelize,
|
||||
getSlots,
|
||||
getSlot,
|
||||
getAllProps,
|
||||
getAllChildren,
|
||||
findDOMNode,
|
||||
flattenChildren,
|
||||
getPropsSlot,
|
|
@ -22,8 +22,8 @@ export default function scrollTo(y: number, options: ScrollToOptions = {}) {
|
|||
const time = timestamp - startTime;
|
||||
const nextScrollTop = easeInOutCubic(time > duration ? duration : time, scrollTop, y, duration);
|
||||
if (isWindow(container)) {
|
||||
(container as Window).scrollTo(window.pageXOffset, nextScrollTop);
|
||||
} else if (container instanceof Document || container.constructor.name === 'HTMLDocument') {
|
||||
(container as Window).scrollTo(window.scrollX, nextScrollTop);
|
||||
} else if (container instanceof Document) {
|
||||
(container as Document).documentElement.scrollTop = nextScrollTop;
|
||||
} else {
|
||||
(container as HTMLElement).scrollTop = nextScrollTop;
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,82 @@
|
|||
// import { StyleProvider } from '../../cssinjs';
|
||||
import { extractStyle } from '../index';
|
||||
import { ConfigProvider } from '../../../components';
|
||||
import { theme } from '../../../index';
|
||||
|
||||
const testGreenColor = '#008000';
|
||||
describe('Static-Style-Extract', () => {
|
||||
it('should extract static styles', () => {
|
||||
const cssText = extractStyle();
|
||||
expect(cssText).not.toContain(testGreenColor);
|
||||
expect(cssText).toMatchSnapshot();
|
||||
});
|
||||
it('should extract static styles with customTheme', () => {
|
||||
const cssText = extractStyle(node => {
|
||||
return (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: testGreenColor,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
);
|
||||
});
|
||||
expect(cssText).toContain(testGreenColor);
|
||||
expect(cssText).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should extract static styles with customTheme and customStyle', () => {
|
||||
const cssText = extractStyle(node => {
|
||||
return (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
algorithm: theme.darkAlgorithm,
|
||||
token: {
|
||||
colorPrimary: testGreenColor,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
);
|
||||
});
|
||||
expect(cssText).toContain('#037003');
|
||||
expect(cssText).toMatchSnapshot();
|
||||
});
|
||||
// it('with custom hashPriority', () => {
|
||||
// const cssText = extractStyle(
|
||||
// (node) => (
|
||||
// <StyleProvider hashPriority='high'>
|
||||
// <ConfigProvider
|
||||
// theme={{
|
||||
// token: {
|
||||
// colorPrimary: testGreenColor,
|
||||
// },
|
||||
// }}
|
||||
// >
|
||||
// {node}
|
||||
// </ConfigProvider>
|
||||
// </StyleProvider>
|
||||
// ),
|
||||
// );
|
||||
// expect(cssText).toContain(testGreenColor);
|
||||
// expect(cssText).not.toContain(':where');
|
||||
// expect(cssText).toMatchSnapshot();
|
||||
//
|
||||
// const cssText2 = extractStyle((node) => (
|
||||
// <ConfigProvider
|
||||
// theme={{
|
||||
// token: {
|
||||
// colorPrimary: testGreenColor,
|
||||
// },
|
||||
// }}
|
||||
// >
|
||||
// {node}
|
||||
// </ConfigProvider>
|
||||
// ));
|
||||
// expect(cssText2).toContain(':where');
|
||||
// });
|
||||
});
|
|
@ -0,0 +1,90 @@
|
|||
import { createCache, extractStyle as extStyle, StyleProvider } from '../cssinjs';
|
||||
import * as antd from '../../components';
|
||||
import { renderToString } from 'vue/server-renderer';
|
||||
import type { CustomRender } from './interface';
|
||||
const blackList: string[] = [
|
||||
'ConfigProvider',
|
||||
'Grid',
|
||||
'Tour',
|
||||
'SelectOptGroup',
|
||||
'SelectOption',
|
||||
'MentionsOption',
|
||||
'TreeNode',
|
||||
'TreeSelectNode',
|
||||
'LocaleProvider',
|
||||
];
|
||||
|
||||
const pickerMap = {
|
||||
MonthPicker: 'month',
|
||||
WeekPicker: 'week',
|
||||
QuarterPicker: 'quarter',
|
||||
};
|
||||
|
||||
const compChildNameMap = {
|
||||
MenuDivider: 'Menu',
|
||||
MenuItem: 'Menu',
|
||||
MenuItemGroup: 'Menu',
|
||||
SubMenu: 'Menu',
|
||||
TableColumn: 'Table',
|
||||
TableColumnGroup: 'Table',
|
||||
TableSummary: 'Table',
|
||||
TableSummaryRow: 'Table',
|
||||
TableSummaryCell: 'Table',
|
||||
TabPane: 'Tabs',
|
||||
TimelineItem: 'Timeline',
|
||||
};
|
||||
|
||||
const defaultNode = () => (
|
||||
<>
|
||||
{Object.keys(antd)
|
||||
.filter(name => !blackList.includes(name) && name[0] === name[0].toUpperCase())
|
||||
.map(compName => {
|
||||
const Comp = antd[compName];
|
||||
if (compName === 'Dropdown') {
|
||||
return (
|
||||
<Comp key={compName} menu={{ items: [] }}>
|
||||
<div />
|
||||
</Comp>
|
||||
);
|
||||
}
|
||||
if (compName === 'Anchor') {
|
||||
return <Comp key={compName} items={[]} />;
|
||||
}
|
||||
if (compName in pickerMap) {
|
||||
const Comp = antd['DatePicker'];
|
||||
const type = pickerMap[compName];
|
||||
return <Comp key={compName} picker={type} />;
|
||||
}
|
||||
if (compName in compChildNameMap) {
|
||||
const ParentComp = antd[compChildNameMap[compName]];
|
||||
return (
|
||||
<ParentComp>
|
||||
<Comp />
|
||||
</ParentComp>
|
||||
);
|
||||
}
|
||||
if (compName === 'QRCode' || compName === 'Segmented') {
|
||||
return (
|
||||
<Comp key={compName} value={''}>
|
||||
<div />
|
||||
</Comp>
|
||||
);
|
||||
}
|
||||
return <Comp key={compName} />;
|
||||
})}
|
||||
</>
|
||||
);
|
||||
|
||||
export function extractStyle(customTheme?: CustomRender): string {
|
||||
const cache = createCache();
|
||||
renderToString(
|
||||
<StyleProvider cache={cache}>
|
||||
{customTheme ? customTheme(defaultNode()) : defaultNode()}
|
||||
</StyleProvider>,
|
||||
);
|
||||
|
||||
// Grab style from cache
|
||||
const styleText = extStyle(cache, true);
|
||||
|
||||
return styleText;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
import type { VueNode } from '../type';
|
||||
|
||||
export type CustomRender = (node: VueNode) => VueNode;
|
|
@ -1,7 +1,7 @@
|
|||
// Test via a getter in the options object to see if the passive property is accessed
|
||||
let supportsPassive = false;
|
||||
try {
|
||||
let opts = Object.defineProperty({}, 'passive', {
|
||||
const opts = Object.defineProperty({}, 'passive', {
|
||||
get() {
|
||||
supportsPassive = true;
|
||||
},
|
||||
|
|
|
@ -5,7 +5,7 @@ import type {
|
|||
TransitionGroupProps,
|
||||
TransitionProps,
|
||||
} from 'vue';
|
||||
import { nextTick, Transition, TransitionGroup } from 'vue';
|
||||
import { nextTick } from 'vue';
|
||||
import { tuple } from './type';
|
||||
|
||||
const SelectPlacements = tuple('bottomLeft', 'bottomRight', 'topLeft', 'topRight');
|
||||
|
@ -126,6 +126,4 @@ const getTransitionName = (rootPrefixCls: string, motion: string, transitionName
|
|||
return `${rootPrefixCls}-${motion}`;
|
||||
};
|
||||
|
||||
export { Transition, TransitionGroup, collapseMotion, getTransitionName, getTransitionDirection };
|
||||
|
||||
export default Transition;
|
||||
export { collapseMotion, getTransitionName, getTransitionDirection };
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
export default function triggerEvent(el: Element, type: string) {
|
||||
if ('createEvent' in document) {
|
||||
// modern browsers, IE9+
|
||||
const e = document.createEvent('HTMLEvents');
|
||||
e.initEvent(type, false, true);
|
||||
el.dispatchEvent(e);
|
||||
}
|
||||
}
|
|
@ -31,7 +31,9 @@ export interface PropOptions<T = any, D = T> {
|
|||
}
|
||||
|
||||
declare type VNodeChildAtom = VNode | string | number | boolean | null | undefined | void;
|
||||
export type VueNode = VNodeChildAtom | VNodeChildAtom[] | JSX.Element;
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
export type VueNode = VNodeChildAtom | VNodeChildAtom[] | VNode;
|
||||
|
||||
export const withInstall = <T>(comp: T) => {
|
||||
const c = comp as any;
|
||||
|
@ -90,3 +92,5 @@ export function someType<T>(types?: any[], defaultVal?: T) {
|
|||
}
|
||||
|
||||
export type CustomSlotsType<T> = SlotsType<T>;
|
||||
|
||||
export type AnyObject = Record<PropertyKey, any>;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { filterEmpty } from './props-util';
|
||||
import type { VNode, VNodeProps } from 'vue';
|
||||
import { cloneVNode } from 'vue';
|
||||
import type { Slots, VNode, VNodeArrayChildren, VNodeProps } from 'vue';
|
||||
import { cloneVNode, isVNode, Comment, Fragment, render as VueRender } from 'vue';
|
||||
import warning from './warning';
|
||||
import type { RefObject } from './createRef';
|
||||
type NodeProps = Record<string, any> &
|
||||
|
@ -40,6 +40,10 @@ export function deepCloneElement<T, U>(
|
|||
if (Array.isArray(vnode)) {
|
||||
return vnode.map(item => deepCloneElement(item, nodeProps, override, mergeRef));
|
||||
} else {
|
||||
// 需要判断是否为vnode方可进行clone操作
|
||||
if (!isVNode(vnode)) {
|
||||
return vnode;
|
||||
}
|
||||
const cloned = cloneElement(vnode, nodeProps, override, mergeRef);
|
||||
if (Array.isArray(cloned.children)) {
|
||||
cloned.children = deepCloneElement(cloned.children as VNode<T, U>[]);
|
||||
|
@ -47,3 +51,32 @@ export function deepCloneElement<T, U>(
|
|||
return cloned;
|
||||
}
|
||||
}
|
||||
|
||||
export function triggerVNodeUpdate(vm: VNode, attrs: Record<string, any>, dom: any) {
|
||||
VueRender(cloneVNode(vm, { ...attrs }), dom);
|
||||
}
|
||||
|
||||
const ensureValidVNode = (slot: VNodeArrayChildren | null) => {
|
||||
return (slot || []).some(child => {
|
||||
if (!isVNode(child)) return true;
|
||||
if (child.type === Comment) return false;
|
||||
if (child.type === Fragment && !ensureValidVNode(child.children as VNodeArrayChildren))
|
||||
return false;
|
||||
return true;
|
||||
})
|
||||
? slot
|
||||
: null;
|
||||
};
|
||||
|
||||
export function customRenderSlot(
|
||||
slots: Slots,
|
||||
name: string,
|
||||
props: Record<string, unknown>,
|
||||
fallback?: () => VNodeArrayChildren,
|
||||
) {
|
||||
const slot = slots[name]?.(props);
|
||||
if (ensureValidVNode(slot)) {
|
||||
return slot;
|
||||
}
|
||||
return fallback?.();
|
||||
}
|
||||
|
|
|
@ -159,6 +159,12 @@ function showWaveEffect(node: HTMLElement, className: string) {
|
|||
node?.insertBefore(holder, node?.firstChild);
|
||||
|
||||
render(<WaveEffect target={node} className={className} />, holder);
|
||||
return () => {
|
||||
render(null, holder);
|
||||
if (holder.parentElement) {
|
||||
holder.parentElement.removeChild(holder);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default showWaveEffect;
|
||||
|
|
|
@ -26,36 +26,35 @@ export default defineComponent({
|
|||
},
|
||||
setup(props, { slots }) {
|
||||
const instance = getCurrentInstance();
|
||||
const { prefixCls } = useConfigInject('wave', props);
|
||||
const { prefixCls, wave } = useConfigInject('wave', props);
|
||||
|
||||
// ============================== Style ===============================
|
||||
const [, hashId] = useStyle(prefixCls);
|
||||
|
||||
// =============================== Wave ===============================
|
||||
const showWave = useWave(
|
||||
instance,
|
||||
computed(() => classNames(prefixCls.value, hashId.value)),
|
||||
wave,
|
||||
);
|
||||
let onClick: (e: MouseEvent) => void;
|
||||
const clear = () => {
|
||||
const node = findDOMNode(instance);
|
||||
const node = findDOMNode(instance) as HTMLElement;
|
||||
node.removeEventListener('click', onClick, true);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
watch(
|
||||
() => props.disabled,
|
||||
() => {
|
||||
clear();
|
||||
nextTick(() => {
|
||||
const node = findDOMNode(instance);
|
||||
|
||||
const node: HTMLElement = findDOMNode(instance);
|
||||
node?.removeEventListener('click', onClick, true);
|
||||
if (!node || node.nodeType !== 1 || props.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Click handler
|
||||
const onClick = (e: MouseEvent) => {
|
||||
onClick = (e: MouseEvent) => {
|
||||
// Fix radio button click twice
|
||||
if (
|
||||
(e.target as HTMLElement).tagName === 'INPUT' ||
|
||||
|
|
|
@ -1,16 +1,25 @@
|
|||
import type { ComponentInternalInstance, Ref } from 'vue';
|
||||
import type { ComputedRef, Ref } from 'vue';
|
||||
import { onBeforeUnmount, getCurrentInstance } from 'vue';
|
||||
import { findDOMNode } from '../props-util';
|
||||
import showWaveEffect from './WaveEffect';
|
||||
|
||||
export default function useWave(
|
||||
instance: ComponentInternalInstance | null,
|
||||
className: Ref<string>,
|
||||
wave?: ComputedRef<{ disabled?: boolean }>,
|
||||
): VoidFunction {
|
||||
const instance = getCurrentInstance();
|
||||
let stopWave: () => void;
|
||||
function showWave() {
|
||||
const node = findDOMNode(instance);
|
||||
|
||||
showWaveEffect(node, className.value);
|
||||
stopWave?.();
|
||||
if (wave?.value?.disabled || !node) {
|
||||
return;
|
||||
}
|
||||
stopWave = showWaveEffect(node, className.value);
|
||||
}
|
||||
onBeforeUnmount(() => {
|
||||
stopWave?.();
|
||||
});
|
||||
|
||||
return showWave;
|
||||
}
|
||||
|
|
|
@ -176,7 +176,6 @@ const Affix = defineComponent({
|
|||
affixStyle: undefined,
|
||||
placeholderStyle: undefined,
|
||||
});
|
||||
currentInstance.update();
|
||||
// Test if `updatePosition` called
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
emit('testUpdatePosition');
|
||||
|
@ -256,7 +255,7 @@ const Affix = defineComponent({
|
|||
const { prefixCls } = useConfigInject('affix', props);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
return () => {
|
||||
const { affixStyle, placeholderStyle } = state;
|
||||
const { affixStyle, placeholderStyle, status } = state;
|
||||
const className = classNames({
|
||||
[prefixCls.value]: affixStyle,
|
||||
[hashId.value]: true,
|
||||
|
@ -271,7 +270,7 @@ const Affix = defineComponent({
|
|||
]);
|
||||
return wrapSSR(
|
||||
<ResizeObserver onResize={updatePosition}>
|
||||
<div {...restProps} {...attrs} ref={placeholderNode}>
|
||||
<div {...restProps} {...attrs} ref={placeholderNode} data-measure-status={status}>
|
||||
{affixStyle && <div style={placeholderStyle} aria-hidden="true" />}
|
||||
<div class={className} ref={fixedNode} style={affixStyle}>
|
||||
{slots.default?.()}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { CSSProperties, ExtractPropTypes, PropType } from 'vue';
|
||||
import { computed, defineComponent, shallowRef } from 'vue';
|
||||
import { computed, defineComponent, shallowRef, Transition } from 'vue';
|
||||
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
|
||||
import CheckCircleOutlined from '@ant-design/icons-vue/CheckCircleOutlined';
|
||||
import ExclamationCircleOutlined from '@ant-design/icons-vue/ExclamationCircleOutlined';
|
||||
|
@ -11,7 +11,7 @@ import InfoCircleFilled from '@ant-design/icons-vue/InfoCircleFilled';
|
|||
import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled';
|
||||
import classNames from '../_util/classNames';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import { getTransitionProps, Transition } from '../_util/transition';
|
||||
import { getTransitionProps } from '../_util/transition';
|
||||
import { isValidElement } from '../_util/props-util';
|
||||
import { tuple, withInstall } from '../_util/type';
|
||||
import { cloneElement } from '../_util/vnode';
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/app/demo/basic.vue correctly 1`] = `
|
||||
<div class="ant-app">
|
||||
<!--teleport start-->
|
||||
<!--teleport end-->
|
||||
<!--teleport start-->
|
||||
<!--teleport end-->
|
||||
<div class="ant-space ant-space-horizontal ant-space-align-center">
|
||||
<div class="ant-space-item" style="margin-right: 8px;"><button class="ant-btn ant-btn-primary" type="button">
|
||||
<!----><span>Open message</span>
|
||||
</button></div>
|
||||
<!---->
|
||||
<div class="ant-space-item" style="margin-right: 8px;"><button class="ant-btn ant-btn-primary" type="button">
|
||||
<!----><span>Open modal</span>
|
||||
</button></div>
|
||||
<!---->
|
||||
<div class="ant-space-item"><button class="ant-btn ant-btn-primary" type="button">
|
||||
<!----><span>Open notification</span>
|
||||
</button></div>
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/app/demo/myPage.vue correctly 1`] = `
|
||||
<div class="ant-space ant-space-horizontal ant-space-align-center">
|
||||
<div class="ant-space-item" style="margin-right: 8px;"><button class="ant-btn ant-btn-primary" type="button">
|
||||
<!----><span>Open message</span>
|
||||
</button></div>
|
||||
<!---->
|
||||
<div class="ant-space-item" style="margin-right: 8px;"><button class="ant-btn ant-btn-primary" type="button">
|
||||
<!----><span>Open modal</span>
|
||||
</button></div>
|
||||
<!---->
|
||||
<div class="ant-space-item"><button class="ant-btn ant-btn-primary" type="button">
|
||||
<!----><span>Open notification</span>
|
||||
</button></div>
|
||||
<!---->
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,3 @@
|
|||
import demoTest from '../../../tests/shared/demoTest';
|
||||
|
||||
demoTest('app');
|
|
@ -0,0 +1,44 @@
|
|||
import { provide, inject, reactive } from 'vue';
|
||||
import type { InjectionKey } from 'vue';
|
||||
import type { MessageInstance, ConfigOptions as MessageConfig } from '../message/interface';
|
||||
import type { NotificationInstance, NotificationConfig } from '../notification/interface';
|
||||
import type { ModalStaticFunctions } from '../modal/confirm';
|
||||
|
||||
export type AppConfig = {
|
||||
message?: MessageConfig;
|
||||
notification?: NotificationConfig;
|
||||
};
|
||||
|
||||
export const AppConfigContextKey: InjectionKey<AppConfig> = Symbol('appConfigContext');
|
||||
|
||||
export const useProvideAppConfigContext = (appConfigContext: AppConfig) => {
|
||||
return provide(AppConfigContextKey, appConfigContext);
|
||||
};
|
||||
|
||||
export const useInjectAppConfigContext = () => {
|
||||
return inject(AppConfigContextKey, {});
|
||||
};
|
||||
|
||||
type ModalType = Omit<ModalStaticFunctions, 'warn'>;
|
||||
|
||||
export interface useAppProps {
|
||||
message: MessageInstance;
|
||||
notification: NotificationInstance;
|
||||
modal: ModalType;
|
||||
}
|
||||
|
||||
export const AppContextKey: InjectionKey<useAppProps> = Symbol('appContext');
|
||||
|
||||
export const useProvideAppContext = (appContext: useAppProps) => {
|
||||
return provide(AppContextKey, appContext);
|
||||
};
|
||||
|
||||
const defaultAppContext: useAppProps = reactive({
|
||||
message: {},
|
||||
notification: {},
|
||||
modal: {},
|
||||
} as useAppProps);
|
||||
|
||||
export const useInjectAppContext = () => {
|
||||
return inject(AppContextKey, defaultAppContext);
|
||||
};
|
|
@ -0,0 +1,26 @@
|
|||
<docs>
|
||||
---
|
||||
order: 0
|
||||
title:
|
||||
zh-CN: 基本使用
|
||||
en-US: Basic Usage
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
获取 `message`、`notification`、`modal` 静态方法。
|
||||
|
||||
## en-US
|
||||
|
||||
Static method for `message`, `notification`, `modal`.
|
||||
</docs>
|
||||
|
||||
<template>
|
||||
<a-app>
|
||||
<my-page />
|
||||
</a-app>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import myPage from './myPage.vue';
|
||||
</script>
|
|
@ -0,0 +1,19 @@
|
|||
<template>
|
||||
<demo-sort :cols="1">
|
||||
<basic />
|
||||
</demo-sort>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import Basic from './basic.vue';
|
||||
import CN from '../index.zh-CN.md';
|
||||
import US from '../index.en-US.md';
|
||||
export default defineComponent({
|
||||
CN,
|
||||
US,
|
||||
components: {
|
||||
Basic,
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,32 @@
|
|||
<template>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="showMessage">Open message</a-button>
|
||||
<a-button type="primary" @click="showModal">Open modal</a-button>
|
||||
<a-button type="primary" @click="showNotification">Open notification</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { App } from 'ant-design-vue';
|
||||
|
||||
const { message, modal, notification } = App.useApp();
|
||||
|
||||
const showMessage = () => {
|
||||
message.success('Success!');
|
||||
};
|
||||
|
||||
const showModal = () => {
|
||||
modal.warning({
|
||||
title: 'This is a warning message',
|
||||
content: 'some messages...some messages...',
|
||||
});
|
||||
};
|
||||
|
||||
const showNotification = () => {
|
||||
notification.info({
|
||||
message: `Notification topLeft`,
|
||||
description: 'Hello, Ant Design Vue!!',
|
||||
placement: 'topLeft',
|
||||
});
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,130 @@
|
|||
---
|
||||
category: Components
|
||||
cols: 1
|
||||
type: Other
|
||||
title: App
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*TBTSR4PyVmkAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*JGb3RIzyOCkAAAAAAAAAAAAADrJ8AQ/original
|
||||
tag: New
|
||||
---
|
||||
|
||||
Application wrapper for some global usages.
|
||||
|
||||
## When To Use
|
||||
|
||||
- Provide reset styles based on `.ant-app` element.
|
||||
- You could use static methods of `message/notification/Modal` form `useApp` without writing `contextHolder` manually.
|
||||
|
||||
## API
|
||||
|
||||
### App
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| message | Global config for Message | [MessageConfig](/components/message/#messageconfig) | - | 4.x |
|
||||
| notification | Global config for Notification | [NotificationConfig](/components/notification/#notificationconfig) | - | 4.x |
|
||||
|
||||
## How to use
|
||||
|
||||
### Basic usage
|
||||
|
||||
App provides upstream and downstream method calls through `provide/inject`, because useApp needs to be used as a subcomponent, we recommend encapsulating App at the top level in the application.
|
||||
|
||||
```html
|
||||
/*myPage.vue*/
|
||||
<template>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="showMessage">Open message</a-button>
|
||||
<a-button type="primary" @click="showModal">Open modal</a-button>
|
||||
<a-button type="primary" @click="showNotification">Open notification</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { App } from 'ant-design-vue';
|
||||
|
||||
const { message, modal, notification } = App.useApp();
|
||||
|
||||
const showMessage = () => {
|
||||
message.success('Success!');
|
||||
};
|
||||
|
||||
const showModal = () => {
|
||||
modal.warning({
|
||||
title: 'This is a warning message',
|
||||
content: 'some messages...some messages...',
|
||||
});
|
||||
};
|
||||
|
||||
const showNotification = () => {
|
||||
notification.info({
|
||||
message: `Notification topLeft`,
|
||||
description: 'Hello, Ant Design Vue!!',
|
||||
placement: 'topLeft',
|
||||
});
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
Note: App.useApp must be available under App.
|
||||
|
||||
#### Embedded usage scenarios (if not necessary, try not to do nesting)
|
||||
|
||||
```html
|
||||
<a-app>
|
||||
<a-space>
|
||||
...
|
||||
<a-app>...</a-app>
|
||||
</a-space>
|
||||
</a-app>
|
||||
```
|
||||
|
||||
#### Sequence with ConfigProvider
|
||||
|
||||
The App component can only use the token in the `ConfigProvider`, if you need to use the Token, the ConfigProvider and the App component must appear in pairs.
|
||||
|
||||
```html
|
||||
<a-config-provider theme="{{ ... }}">
|
||||
<a-app>...</a-app>
|
||||
</a-config-provider>
|
||||
```
|
||||
|
||||
#### Global scene (pinia scene)
|
||||
|
||||
```ts
|
||||
import { App } from 'ant-design-vue';
|
||||
import type { MessageInstance } from 'ant-design-vue/es/message/interface';
|
||||
import type { ModalStaticFunctions } from 'ant-design-vue/es/modal/confirm';
|
||||
import type { NotificationInstance } from 'ant-design-vue/es/notification/interface';
|
||||
|
||||
export const useGlobalStore = defineStore('global', () => {
|
||||
const message: MessageInstance = ref();
|
||||
const notification: NotificationInstance = ref();
|
||||
const modal: Omit<ModalStaticFunctions, 'warn'> = ref();
|
||||
(() => {
|
||||
const staticFunction = App.useApp();
|
||||
message.value = staticFunction.message;
|
||||
modal.value = staticFunction.modal;
|
||||
notification.value = staticFunction.notification;
|
||||
})();
|
||||
|
||||
return { message, notification, modal };
|
||||
});
|
||||
```
|
||||
|
||||
```html
|
||||
// sub page
|
||||
<template>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="showMessage">Open message</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useGlobalStore } from '@/stores/global';
|
||||
const global = useGlobalStore();
|
||||
const showMessage = () => {
|
||||
global.message.success('Success!');
|
||||
};
|
||||
</script>
|
||||
```
|
|
@ -0,0 +1,83 @@
|
|||
import { defineComponent, computed } from 'vue';
|
||||
import type { App as TypeApp, Plugin } from 'vue';
|
||||
import { initDefaultProps } from '../_util/props-util';
|
||||
import classNames from '../_util/classNames';
|
||||
import { objectType } from '../_util/type';
|
||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
import useMessage from '../message/useMessage';
|
||||
import useModal from '../modal/useModal';
|
||||
import useNotification from '../notification/useNotification';
|
||||
import type { AppConfig } from './context';
|
||||
import {
|
||||
useProvideAppConfigContext,
|
||||
useInjectAppConfigContext,
|
||||
useProvideAppContext,
|
||||
useInjectAppContext,
|
||||
} from './context';
|
||||
import useStyle from './style';
|
||||
|
||||
export const AppProps = () => {
|
||||
return {
|
||||
rootClassName: String,
|
||||
message: objectType<AppConfig['message']>(),
|
||||
notification: objectType<AppConfig['notification']>(),
|
||||
};
|
||||
};
|
||||
|
||||
const useApp = () => {
|
||||
return useInjectAppContext();
|
||||
};
|
||||
|
||||
const App = defineComponent({
|
||||
name: 'AApp',
|
||||
props: initDefaultProps(AppProps(), {}),
|
||||
setup(props, { slots }) {
|
||||
const { prefixCls } = useConfigInject('app', props);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
const customClassName = computed(() => {
|
||||
return classNames(hashId.value, prefixCls.value, props.rootClassName);
|
||||
});
|
||||
|
||||
const appConfig = useInjectAppConfigContext();
|
||||
const mergedAppConfig = computed(() => ({
|
||||
message: { ...appConfig.message, ...props.message },
|
||||
notification: { ...appConfig.notification, ...props.notification },
|
||||
}));
|
||||
useProvideAppConfigContext(mergedAppConfig.value);
|
||||
|
||||
const [messageApi, messageContextHolder] = useMessage(mergedAppConfig.value.message);
|
||||
const [notificationApi, notificationContextHolder] = useNotification(
|
||||
mergedAppConfig.value.notification,
|
||||
);
|
||||
const [ModalApi, ModalContextHolder] = useModal();
|
||||
|
||||
const memoizedContextValue = computed(() => ({
|
||||
message: messageApi,
|
||||
notification: notificationApi,
|
||||
modal: ModalApi,
|
||||
}));
|
||||
useProvideAppContext(memoizedContextValue.value);
|
||||
|
||||
return () => {
|
||||
return wrapSSR(
|
||||
<div class={customClassName.value}>
|
||||
{ModalContextHolder()}
|
||||
{messageContextHolder()}
|
||||
{notificationContextHolder()}
|
||||
{slots.default?.()}
|
||||
</div>,
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
App.useApp = useApp;
|
||||
|
||||
App.install = function (app: TypeApp) {
|
||||
app.component(App.name, App);
|
||||
};
|
||||
|
||||
export default App as typeof App &
|
||||
Plugin & {
|
||||
readonly useApp: typeof useApp;
|
||||
};
|
|
@ -0,0 +1,131 @@
|
|||
---
|
||||
category: Components
|
||||
subtitle: 包裹组件
|
||||
cols: 1
|
||||
type: 其它
|
||||
title: App
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*TBTSR4PyVmkAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*JGb3RIzyOCkAAAAAAAAAAAAADrJ8AQ/original
|
||||
tag: New
|
||||
---
|
||||
|
||||
新的包裹组件,提供重置样式和提供消费上下文的默认环境。
|
||||
|
||||
## 何时使用
|
||||
|
||||
- 提供可消费 provide/inject 的 `message.xxx`、`Modal.xxx`、`notification.xxx` 的静态方法,可以简化 useMessage 等方法需要手动植入 `contextHolder` 的问题。
|
||||
- 提供基于 `.ant-app` 的默认重置样式,解决原生元素没有 antd 规范样式的问题。
|
||||
|
||||
## API
|
||||
|
||||
### App
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| message | App 内 Message 的全局配置 | [MessageConfig](/components/message-cn/#messageconfig) | - | 4.x |
|
||||
| notification | App 内 Notification 的全局配置 | [NotificationConfig](/components/notification-cn/#notificationconfig) | - | 4.x |
|
||||
|
||||
## 如何使用
|
||||
|
||||
### 基础用法
|
||||
|
||||
App 组件通过 `provide/inject` 提供上下文方法调用,因而 useApp 需要作为子组件才能使用,我们推荐在应用中顶层包裹 App。
|
||||
|
||||
```html
|
||||
/*myPage.vue*/
|
||||
<template>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="showMessage">Open message</a-button>
|
||||
<a-button type="primary" @click="showModal">Open modal</a-button>
|
||||
<a-button type="primary" @click="showNotification">Open notification</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { App } from 'ant-design-vue';
|
||||
|
||||
const { message, modal, notification } = App.useApp();
|
||||
|
||||
const showMessage = () => {
|
||||
message.success('Success!');
|
||||
};
|
||||
|
||||
const showModal = () => {
|
||||
modal.warning({
|
||||
title: 'This is a warning message',
|
||||
content: 'some messages...some messages...',
|
||||
});
|
||||
};
|
||||
|
||||
const showNotification = () => {
|
||||
notification.info({
|
||||
message: `Notification topLeft`,
|
||||
description: 'Hello, Ant Design Vue!!',
|
||||
placement: 'topLeft',
|
||||
});
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
注意:App.useApp 必须在 App 之下方可使用。
|
||||
|
||||
#### 内嵌使用场景(如无必要,尽量不做嵌套)
|
||||
|
||||
```html
|
||||
<a-app>
|
||||
<a-space>
|
||||
...
|
||||
<a-app>...</a-app>
|
||||
</a-space>
|
||||
</a-app>
|
||||
```
|
||||
|
||||
#### 与 ConfigProvider 先后顺序
|
||||
|
||||
App 组件只能在 `ConfigProvider` 之下才能使用 Design Token, 如果需要使用其样式重置能力,则 ConfigProvider 与 App 组件必须成对出现。
|
||||
|
||||
```html
|
||||
<a-config-provider theme="{{ ... }}">
|
||||
<a-app>...</a-app>
|
||||
</a-config-provider>
|
||||
```
|
||||
|
||||
#### 全局场景 (pinia 场景)
|
||||
|
||||
```ts
|
||||
import { App } from 'ant-design-vue';
|
||||
import type { MessageInstance } from 'ant-design-vue/es/message/interface';
|
||||
import type { ModalStaticFunctions } from 'ant-design-vue/es/modal/confirm';
|
||||
import type { NotificationInstance } from 'ant-design-vue/es/notification/interface';
|
||||
|
||||
export const useGlobalStore = defineStore('global', () => {
|
||||
const message: MessageInstance = ref();
|
||||
const notification: NotificationInstance = ref();
|
||||
const modal: Omit<ModalStaticFunctions, 'warn'> = ref();
|
||||
(() => {
|
||||
const staticFunction = App.useApp();
|
||||
message.value = staticFunction.message;
|
||||
modal.value = staticFunction.modal;
|
||||
notification.value = staticFunction.notification;
|
||||
})();
|
||||
|
||||
return { message, notification, modal };
|
||||
});
|
||||
```
|
||||
|
||||
```html
|
||||
// sub page
|
||||
<template>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="showMessage">Open message</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useGlobalStore } from '@/stores/global';
|
||||
const global = useGlobalStore();
|
||||
const showMessage = () => {
|
||||
global.message.success('Success!');
|
||||
};
|
||||
</script>
|
||||
```
|
|
@ -0,0 +1,22 @@
|
|||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook } from '../../theme/internal';
|
||||
|
||||
export type ComponentToken = {};
|
||||
|
||||
interface AppToken extends FullToken<'App'> {}
|
||||
|
||||
// =============================== Base ===============================
|
||||
const genBaseStyle: GenerateStyle<AppToken> = token => {
|
||||
const { componentCls, colorText, fontSize, lineHeight, fontFamily } = token;
|
||||
return {
|
||||
[componentCls]: {
|
||||
color: colorText,
|
||||
fontSize,
|
||||
lineHeight,
|
||||
fontFamily,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// ============================== Export ==============================
|
||||
export default genComponentStyleHook('App', token => [genBaseStyle(token)]);
|
|
@ -1,5 +1,28 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/auto-complete/demo/allow-clear.vue correctly 1`] = `
|
||||
<div style="width: 200px;" class="ant-select ant-select-show-search ant-select-auto-complete ant-select-single ant-select-allow-clear ant-select-show-search">
|
||||
<!---->
|
||||
<div class="ant-select-selector"><span class="ant-select-selection-search"><input type="search" id="rc_select_TEST_OR_SSR" autocomplete="off" class="ant-select-selection-search-input" role="combobox" aria-haspopup="listbox" aria-owns="rc_select_TEST_OR_SSR_list" aria-autocomplete="list" aria-controls="rc_select_TEST_OR_SSR_list" aria-activedescendant="rc_select_TEST_OR_SSR_list_0"></span>
|
||||
<!----><span class="ant-select-selection-placeholder">Clearable</span>
|
||||
</div>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<div style="width: 200px;" class="ant-select ant-select-show-search ant-select-auto-complete ant-select-single ant-select-allow-clear ant-select-show-search">
|
||||
<!---->
|
||||
<div class="ant-select-selector"><span class="ant-select-selection-search"><input type="search" id="rc_select_TEST_OR_SSR" autocomplete="off" class="ant-select-selection-search-input" role="combobox" aria-haspopup="listbox" aria-owns="rc_select_TEST_OR_SSR_list" aria-autocomplete="list" aria-controls="rc_select_TEST_OR_SSR_list" aria-activedescendant="rc_select_TEST_OR_SSR_list_0"></span>
|
||||
<!----><span class="ant-select-selection-placeholder">Customized clear icon</span>
|
||||
</div>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/auto-complete/demo/basic.vue correctly 1`] = `
|
||||
<div style="width: 200px;" class="ant-select ant-select-show-search ant-select-auto-complete ant-select-single ant-select-show-search">
|
||||
<!---->
|
||||
|
@ -12,6 +35,18 @@ exports[`renders ./components/auto-complete/demo/basic.vue correctly 1`] = `
|
|||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/auto-complete/demo/border-less.vue correctly 1`] = `
|
||||
<div style="width: 200px;" class="ant-select ant-select-borderless ant-select-show-search ant-select-auto-complete ant-select-single ant-select-show-search">
|
||||
<!---->
|
||||
<div class="ant-select-selector"><span class="ant-select-selection-search"><input type="search" id="rc_select_TEST_OR_SSR" autocomplete="off" class="ant-select-selection-search-input" role="combobox" aria-haspopup="listbox" aria-owns="rc_select_TEST_OR_SSR_list" aria-autocomplete="list" aria-controls="rc_select_TEST_OR_SSR_list" aria-activedescendant="rc_select_TEST_OR_SSR_list_0"></span>
|
||||
<!----><span class="ant-select-selection-placeholder">border less</span>
|
||||
</div>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/auto-complete/demo/certain-category.vue correctly 1`] = `
|
||||
<div class="certain-category-search-wrapper" style="width: 250px;">
|
||||
<div popupclassname="certain-category-search-dropdown" class="ant-select certain-category-search ant-select-show-search ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search" style="width: 250px;">
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<docs>
|
||||
---
|
||||
order: 8
|
||||
title:
|
||||
zh-CN: 自定义清除按钮
|
||||
en-US: Customize clear button
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
自定义清除按钮。
|
||||
|
||||
## en-US
|
||||
|
||||
Customize clear button.
|
||||
</docs>
|
||||
|
||||
<template>
|
||||
<a-auto-complete
|
||||
v-model:value="value"
|
||||
:options="options"
|
||||
style="width: 200px"
|
||||
placeholder="Clearable"
|
||||
:allow-clear="true"
|
||||
@select="onSelect"
|
||||
@search="onSearch"
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
<a-auto-complete
|
||||
v-model:value="value"
|
||||
:options="options"
|
||||
style="width: 200px"
|
||||
placeholder="Customized clear icon"
|
||||
:allow-clear="true"
|
||||
@select="onSelect"
|
||||
@search="onSearch"
|
||||
>
|
||||
<template #clearIcon>
|
||||
<close-outlined />
|
||||
</template>
|
||||
</a-auto-complete>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { CloseOutlined } from '@ant-design/icons-vue';
|
||||
|
||||
interface MockVal {
|
||||
value: string;
|
||||
}
|
||||
|
||||
const mockVal = (str: string, repeat = 1): MockVal => {
|
||||
return {
|
||||
value: str.repeat(repeat),
|
||||
};
|
||||
};
|
||||
const value = ref('');
|
||||
const options = ref<MockVal[]>([]);
|
||||
const onSearch = (searchText: string) => {
|
||||
console.log('searchText');
|
||||
options.value = !searchText
|
||||
? []
|
||||
: [mockVal(searchText), mockVal(searchText, 2), mockVal(searchText, 3)];
|
||||
};
|
||||
const onSelect = (value: string) => {
|
||||
console.log('onSelect', value);
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,53 @@
|
|||
<docs>
|
||||
---
|
||||
order: 7
|
||||
title:
|
||||
zh-CN: 无边框
|
||||
en-US: Border less
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
没有边框。
|
||||
|
||||
## en-US
|
||||
|
||||
border less.
|
||||
</docs>
|
||||
|
||||
<template>
|
||||
<a-auto-complete
|
||||
v-model:value="value"
|
||||
:options="options"
|
||||
style="width: 200px"
|
||||
placeholder="border less"
|
||||
:bordered="false"
|
||||
@select="onSelect"
|
||||
@search="onSearch"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
interface MockVal {
|
||||
value: string;
|
||||
}
|
||||
|
||||
const mockVal = (str: string, repeat = 1): MockVal => {
|
||||
return {
|
||||
value: str.repeat(repeat),
|
||||
};
|
||||
};
|
||||
const value = ref('');
|
||||
const options = ref<MockVal[]>([]);
|
||||
const onSearch = (searchText: string) => {
|
||||
console.log('searchText');
|
||||
options.value = !searchText
|
||||
? []
|
||||
: [mockVal(searchText), mockVal(searchText, 2), mockVal(searchText, 3)];
|
||||
};
|
||||
const onSelect = (value: string) => {
|
||||
console.log('onSelect', value);
|
||||
};
|
||||
</script>
|
|
@ -7,6 +7,8 @@
|
|||
<certain-category />
|
||||
<uncertain-category />
|
||||
<statusVue />
|
||||
<border-less />
|
||||
<allow-clear />
|
||||
</demo-sort>
|
||||
</template>
|
||||
|
||||
|
@ -18,6 +20,8 @@ import NonCaseSensitive from './non-case-sensitive.vue';
|
|||
import CertainCategory from './certain-category.vue';
|
||||
import UncertainCategory from './uncertain-category.vue';
|
||||
import statusVue from './status.vue';
|
||||
import BorderLess from './border-less.vue';
|
||||
import AllowClear from './allow-clear.vue';
|
||||
|
||||
import CN from '../index.zh-CN.md';
|
||||
import US from '../index.en-US.md';
|
||||
|
@ -34,6 +38,8 @@ export default defineComponent({
|
|||
NonCaseSensitive,
|
||||
CertainCategory,
|
||||
UncertainCategory,
|
||||
BorderLess,
|
||||
AllowClear,
|
||||
},
|
||||
setup() {
|
||||
return {};
|
||||
|
|
|
@ -30,6 +30,8 @@ The differences with Select are:
|
|||
| allowClear | Show clear button, effective in multiple mode only. | boolean | false | |
|
||||
| autofocus | get focus when component mounted | boolean | false | |
|
||||
| backfill | backfill selected item the input when using keyboard | boolean | false | |
|
||||
| bordered | Whether has border style | boolean | true | 4.0 |
|
||||
| clearIcon | Use slot custom clear icon | slot | `<CloseCircleFilled />` | 4.0 |
|
||||
| default (for customize input element) | customize input element | slot | `<Input />` | |
|
||||
| defaultActiveFirstOption | Whether active first option by default | boolean | true | |
|
||||
| defaultOpen | Initial open state of dropdown | boolean | - | |
|
||||
|
|
|
@ -50,10 +50,13 @@ const AutoComplete = defineComponent({
|
|||
props: autoCompleteProps(),
|
||||
// emits: ['change', 'select', 'focus', 'blur'],
|
||||
slots: Object as CustomSlotsType<{
|
||||
option: any;
|
||||
// deprecated, should use props `options` instead, not slot
|
||||
options: any;
|
||||
default: any;
|
||||
notFoundContent: any;
|
||||
dataSource: any;
|
||||
clearIcon: any;
|
||||
}>,
|
||||
setup(props, { slots, attrs, expose }) {
|
||||
warning(
|
||||
|
|
|
@ -31,6 +31,8 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*WERTQ6qvgEYAAA
|
|||
| allowClear | 支持清除, 单选模式有效 | boolean | false | |
|
||||
| autofocus | 自动获取焦点 | boolean | false | |
|
||||
| backfill | 使用键盘选择选项的时候把选中项回填到输入框中 | boolean | false | |
|
||||
| bordered | 是否有边框 | boolean | true | 4.0 |
|
||||
| clearIcon | 使用插槽自定义清除按钮 | slot | `<CloseCircleFilled />` | 4.0 |
|
||||
| default (自定义输入框) | 自定义输入框 | slot | `<Input />` | |
|
||||
| defaultActiveFirstOption | 是否默认高亮第一个选项。 | boolean | true | |
|
||||
| defaultOpen | 是否默认展开下拉菜单 | boolean | - | |
|
||||
|
|
|
@ -11,7 +11,7 @@ import useConfigInject from '../config-provider/hooks/useConfigInject';
|
|||
import ResizeObserver from '../vc-resize-observer';
|
||||
import eagerComputed from '../_util/eagerComputed';
|
||||
import useStyle from './style';
|
||||
import { useInjectSize } from './SizeContext';
|
||||
import { useAvatarInjectContext } from './AvatarContext';
|
||||
|
||||
export type AvatarSize = 'large' | 'small' | 'default' | number | ScreenSizeMap;
|
||||
|
||||
|
@ -56,9 +56,9 @@ const Avatar = defineComponent({
|
|||
|
||||
const { prefixCls } = useConfigInject('avatar', props);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
const groupSize = useInjectSize();
|
||||
const avatarCtx = useAvatarInjectContext();
|
||||
const size = computed(() => {
|
||||
return props.size === 'default' ? groupSize.value : props.size;
|
||||
return props.size === 'default' ? avatarCtx.size : props.size;
|
||||
});
|
||||
const screens = useBreakpoint();
|
||||
const responsiveSize = eagerComputed(() => {
|
||||
|
@ -135,6 +135,7 @@ const Avatar = defineComponent({
|
|||
|
||||
return () => {
|
||||
const { shape, src, alt, srcset, draggable, crossOrigin } = props;
|
||||
const mergeShape = avatarCtx.shape ?? shape;
|
||||
const icon = getPropsSlot(slots, props, 'icon');
|
||||
const pre = prefixCls.value;
|
||||
const classString = {
|
||||
|
@ -142,7 +143,7 @@ const Avatar = defineComponent({
|
|||
[pre]: true,
|
||||
[`${pre}-lg`]: size.value === 'large',
|
||||
[`${pre}-sm`]: size.value === 'small',
|
||||
[`${pre}-${shape}`]: shape,
|
||||
[`${pre}-${mergeShape}`]: true,
|
||||
[`${pre}-image`]: src && isImgExist.value,
|
||||
[`${pre}-icon`]: icon,
|
||||
[hashId.value]: true,
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import type { InjectionKey } from 'vue';
|
||||
import { inject, provide } from 'vue';
|
||||
import type { ScreenSizeMap } from '../_util/responsiveObserve';
|
||||
export type AvatarSize = 'large' | 'small' | 'default' | number | ScreenSizeMap;
|
||||
export interface AvatarContextType {
|
||||
size?: AvatarSize;
|
||||
shape?: 'circle' | 'square';
|
||||
}
|
||||
const AvatarContextKey: InjectionKey<AvatarContextType> = Symbol('AvatarContextKey');
|
||||
|
||||
export const useAvatarInjectContext = () => {
|
||||
return inject(AvatarContextKey, {});
|
||||
};
|
||||
export const useAvatarProviderContext = (context: AvatarContextType) => {
|
||||
return provide(AvatarContextKey, context);
|
||||
};
|
|
@ -3,11 +3,11 @@ import type { AvatarSize } from './Avatar';
|
|||
import Avatar from './Avatar';
|
||||
import Popover from '../popover';
|
||||
import type { PropType, ExtractPropTypes, CSSProperties } from 'vue';
|
||||
import { computed, defineComponent } from 'vue';
|
||||
import { computed, defineComponent, watchEffect } from 'vue';
|
||||
import { flattenChildren, getPropsSlot } from '../_util/props-util';
|
||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
import useStyle from './style';
|
||||
import { useProviderSize } from './SizeContext';
|
||||
import { useAvatarProviderContext } from './AvatarContext';
|
||||
|
||||
export const groupProps = () => ({
|
||||
prefixCls: String,
|
||||
|
@ -23,6 +23,7 @@ export const groupProps = () => ({
|
|||
type: [Number, String, Object] as PropType<AvatarSize>,
|
||||
default: 'default' as AvatarSize,
|
||||
},
|
||||
shape: { type: String as PropType<'circle' | 'square'>, default: 'circle' },
|
||||
});
|
||||
|
||||
export type AvatarGroupProps = Partial<ExtractPropTypes<ReturnType<typeof groupProps>>>;
|
||||
|
@ -36,13 +37,17 @@ const Group = defineComponent({
|
|||
const { prefixCls, direction } = useConfigInject('avatar', props);
|
||||
const groupPrefixCls = computed(() => `${prefixCls.value}-group`);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
useProviderSize(computed(() => props.size));
|
||||
watchEffect(() => {
|
||||
const context = { size: props.size, shape: props.shape };
|
||||
useAvatarProviderContext(context);
|
||||
});
|
||||
return () => {
|
||||
const {
|
||||
maxPopoverPlacement = 'top',
|
||||
maxCount,
|
||||
maxStyle,
|
||||
maxPopoverTrigger = 'hover',
|
||||
shape,
|
||||
} = props;
|
||||
|
||||
const cls = {
|
||||
|
@ -72,7 +77,7 @@ const Group = defineComponent({
|
|||
placement={maxPopoverPlacement}
|
||||
overlayClassName={`${groupPrefixCls.value}-popover`}
|
||||
>
|
||||
<Avatar style={maxStyle}>{`+${numOfChildren - maxCount}`}</Avatar>
|
||||
<Avatar style={maxStyle} shape={shape}>{`+${numOfChildren - maxCount}`}</Avatar>
|
||||
</Popover>,
|
||||
);
|
||||
return wrapSSR(
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
import type { InjectionKey, Ref } from 'vue';
|
||||
import { computed, inject, ref, provide } from 'vue';
|
||||
import type { ScreenSizeMap } from '../_util/responsiveObserve';
|
||||
export type AvatarSize = 'large' | 'small' | 'default' | number | ScreenSizeMap;
|
||||
const SizeContextKey: InjectionKey<Ref<AvatarSize>> = Symbol('SizeContextKey');
|
||||
|
||||
export const useInjectSize = () => {
|
||||
return inject(SizeContextKey, ref('default' as AvatarSize));
|
||||
};
|
||||
export const useProviderSize = (size: Ref<AvatarSize>) => {
|
||||
const parentSize = useInjectSize();
|
||||
provide(
|
||||
SizeContextKey,
|
||||
computed(() => size.value || parentSize.value),
|
||||
);
|
||||
return size;
|
||||
};
|
|
@ -16,29 +16,20 @@ Usually used for reminders and notifications.
|
|||
</docs>
|
||||
|
||||
<template>
|
||||
<span style="margin-right: 24px">
|
||||
<a-space :size="24">
|
||||
<a-badge :count="1">
|
||||
<a-avatar shape="square">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
</a-badge>
|
||||
</span>
|
||||
<span>
|
||||
<a-badge dot>
|
||||
<a-avatar shape="square">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
</a-badge>
|
||||
</span>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { UserOutlined } from '@ant-design/icons-vue';
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#components-avatar-demo-badge .ant-avatar {
|
||||
margin-top: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -16,31 +16,36 @@ Three sizes and two shapes are available.
|
|||
</docs>
|
||||
|
||||
<template>
|
||||
<a-avatar :size="64">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
<a-avatar size="large">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
<a-avatar>
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
<a-avatar size="small">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
<br />
|
||||
<a-avatar shape="square" :size="64">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
<a-avatar shape="square" size="large">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
<a-avatar shape="square">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
<a-avatar shape="square" size="small">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
<a-space direction="vertical" :size="32">
|
||||
<a-space wrap :size="16">
|
||||
<a-avatar :size="64">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
<a-avatar size="large">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
<a-avatar>
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
<a-avatar size="small">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
</a-space>
|
||||
<a-space wrap :size="16">
|
||||
<a-avatar shape="square" :size="64">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
<a-avatar shape="square" size="large">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
<a-avatar shape="square">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
<a-avatar shape="square" size="small">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
</a-space>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
|
|
@ -8,27 +8,22 @@ title:
|
|||
|
||||
## zh-CN
|
||||
|
||||
对于字符型的头像,当字符串较长时,字体大小可以根据头像宽度自动调整。
|
||||
对于字符型的头像,当字符串较长时,字体大小可以根据头像宽度自动调整。也可使用 `gap`` 来设置字符距离左右两侧边界单位像素。
|
||||
|
||||
## en-US
|
||||
|
||||
For letter type Avatar, when the letters are too long to display, the font size can be automatically adjusted according to the width of the Avatar.
|
||||
For letter type Avatar, when the letters are too long to display, the font size can be automatically adjusted according to the width of the Avatar. You can also use `gap` to set the unit distance between left and right sides.
|
||||
</docs>
|
||||
|
||||
<template>
|
||||
<a-avatar
|
||||
shape="square"
|
||||
size="large"
|
||||
:style="{ backgroundColor: color, verticalAlign: 'middle' }"
|
||||
>
|
||||
<a-avatar size="large" :style="{ backgroundColor: color, verticalAlign: 'middle' }" :gap="gap">
|
||||
{{ avatarValue }}
|
||||
</a-avatar>
|
||||
<a-button
|
||||
size="small"
|
||||
:style="{ marginLeft: '16px', verticalAlign: 'middle' }"
|
||||
@click="changeValue"
|
||||
>
|
||||
改变
|
||||
<a-button size="small" :style="{ margin: '0 16px', verticalAlign: 'middle' }" @click="changeUser">
|
||||
ChangeUser
|
||||
</a-button>
|
||||
<a-button size="small" :style="{ verticalAlign: 'middle' }" @click="changeGap">
|
||||
ChangeGap
|
||||
</a-button>
|
||||
</template>
|
||||
|
||||
|
@ -39,9 +34,16 @@ const UserList = ['U', 'Lucy', 'Tom', 'Edward'];
|
|||
const colorList = ['#f56a00', '#7265e6', '#ffbf00', '#00a2ae'];
|
||||
const avatarValue = ref(UserList[0]);
|
||||
const color = ref(colorList[0]);
|
||||
const changeValue = () => {
|
||||
const changeUser = () => {
|
||||
const index = UserList.indexOf(avatarValue.value);
|
||||
avatarValue.value = index < UserList.length - 1 ? UserList[index + 1] : UserList[0];
|
||||
color.value = index < colorList.length - 1 ? colorList[index + 1] : colorList[0];
|
||||
};
|
||||
|
||||
const GapList = [4, 3, 2, 1];
|
||||
const gap = ref(GapList[0]);
|
||||
const changeGap = () => {
|
||||
const index = GapList.indexOf(gap.value);
|
||||
gap.value = index < GapList.length - 1 ? GapList[index + 1] : GapList[0];
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -17,20 +17,22 @@ Avatar group display.
|
|||
|
||||
<template>
|
||||
<a-avatar-group>
|
||||
<a-avatar src="https://joeschmoe.io/api/v1/random" />
|
||||
<a-avatar style="background-color: #f56a00">K</a-avatar>
|
||||
<a-avatar src="https://xsgames.co/randomusers/avatar.php?g=pixel&key=1" />
|
||||
<a href="https://www.antdv.com">
|
||||
<a-avatar style="background-color: #f56a00">K</a-avatar>
|
||||
</a>
|
||||
<a-tooltip title="Ant User" placement="top">
|
||||
<a-avatar style="background-color: #87d068">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
</a-tooltip>
|
||||
<a-avatar style="background-color: #1890ff">
|
||||
<template #icon><UserOutlined /></template>
|
||||
<template #icon><AntDesignOutlined /></template>
|
||||
</a-avatar>
|
||||
</a-avatar-group>
|
||||
<a-divider />
|
||||
<a-avatar-group :max-count="2" :max-style="{ color: '#f56a00', backgroundColor: '#fde3cf' }">
|
||||
<a-avatar src="https://joeschmoe.io/api/v1/random" />
|
||||
<a-avatar src="https://xsgames.co/randomusers/avatar.php?g=pixel&key=2" />
|
||||
<a-avatar style="background-color: #1890ff">K</a-avatar>
|
||||
<a-tooltip title="Ant User" placement="top">
|
||||
<a-avatar style="background-color: #87d068">
|
||||
|
@ -38,7 +40,7 @@ Avatar group display.
|
|||
</a-avatar>
|
||||
</a-tooltip>
|
||||
<a-avatar style="background-color: #1890ff">
|
||||
<template #icon><UserOutlined /></template>
|
||||
<template #icon><AntDesignOutlined /></template>
|
||||
</a-avatar>
|
||||
</a-avatar-group>
|
||||
<a-divider />
|
||||
|
@ -50,7 +52,7 @@ Avatar group display.
|
|||
backgroundColor: '#fde3cf',
|
||||
}"
|
||||
>
|
||||
<a-avatar src="https://joeschmoe.io/api/v1/random" />
|
||||
<a-avatar src="https://xsgames.co/randomusers/avatar.php?g=pixel&key=3" />
|
||||
<a-avatar style="background-color: #1890ff">K</a-avatar>
|
||||
<a-tooltip title="Ant User" placement="top">
|
||||
<a-avatar style="background-color: #87d068">
|
||||
|
@ -58,11 +60,42 @@ Avatar group display.
|
|||
</a-avatar>
|
||||
</a-tooltip>
|
||||
<a-avatar style="background-color: #1890ff">
|
||||
<template #icon><UserOutlined /></template>
|
||||
<template #icon><AntDesignOutlined /></template>
|
||||
</a-avatar>
|
||||
</a-avatar-group>
|
||||
<a-divider />
|
||||
<a-avatar-group
|
||||
:max-count="2"
|
||||
max-popover-trigger="click"
|
||||
size="large"
|
||||
:max-style="{ color: '#f56a00', backgroundColor: '#fde3cf', cursor: 'pointer' }"
|
||||
>
|
||||
<a-avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
|
||||
<a-avatar style="background-color: #f56a00">K</a-avatar>
|
||||
<a-tooltip title="Ant User" placement="top">
|
||||
<a-avatar style="background-color: #87d068">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
</a-tooltip>
|
||||
<a-avatar style="background-color: #1890ff">
|
||||
<template #icon><AntDesignOutlined /></template>
|
||||
</a-avatar>
|
||||
</a-avatar-group>
|
||||
<a-divider />
|
||||
<a-avatar-group shape="square">
|
||||
<a-avatar style="background-color: #fde3cf">A</a-avatar>
|
||||
<a-avatar style="background-color: #f56a00">K</a-avatar>
|
||||
<a-tooltip title="Ant User" placement="top">
|
||||
<a-avatar style="background-color: #87d068">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
</a-tooltip>
|
||||
<a-avatar style="background-color: #1890ff">
|
||||
<template #icon><AntDesignOutlined /></template>
|
||||
</a-avatar>
|
||||
</a-avatar-group>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { UserOutlined } from '@ant-design/icons-vue';
|
||||
import { UserOutlined, AntDesignOutlined } from '@ant-design/icons-vue';
|
||||
</script>
|
||||
|
|
|
@ -36,10 +36,3 @@ export default defineComponent({
|
|||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
[id^='components-avatar-demo-'] .ant-avatar {
|
||||
margin-top: 16px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -16,20 +16,22 @@ Image, Icon and letter are supported, and the latter two kinds avatar can have c
|
|||
</docs>
|
||||
|
||||
<template>
|
||||
<a-avatar>
|
||||
<template #icon>
|
||||
<UserOutlined />
|
||||
</template>
|
||||
</a-avatar>
|
||||
<a-avatar>U</a-avatar>
|
||||
<a-avatar :size="40">USER</a-avatar>
|
||||
<a-avatar src="https://joeschmoe.io/api/v1/random" />
|
||||
<a-avatar style="color: #f56a00; background-color: #fde3cf">U</a-avatar>
|
||||
<a-avatar style="background-color: #87d068">
|
||||
<template #icon>
|
||||
<UserOutlined />
|
||||
</template>
|
||||
</a-avatar>
|
||||
<a-space :size="16" wrap>
|
||||
<a-avatar>
|
||||
<template #icon>
|
||||
<UserOutlined />
|
||||
</template>
|
||||
</a-avatar>
|
||||
<a-avatar>U</a-avatar>
|
||||
<a-avatar :size="40">USER</a-avatar>
|
||||
<a-avatar src="https://www.antdv.com/assets/logo.1ef800a8.svg" />
|
||||
<a-avatar style="color: #f56a00; background-color: #fde3cf">U</a-avatar>
|
||||
<a-avatar style="background-color: #87d068">
|
||||
<template #icon>
|
||||
<UserOutlined />
|
||||
</template>
|
||||
</a-avatar>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
|
|
@ -34,3 +34,4 @@ Avatars can be used to represent people or objects. It supports images, `Icon`s,
|
|||
| maxPopoverTrigger | Set the trigger of excess avatar Popover | `hover` \| `focus` \| `click` | `hover` | 3.0 |
|
||||
| maxStyle | The style of excess avatar style | CSSProperties | - | |
|
||||
| size | The size of the avatar | number \| `large` \| `small` \| `default` \| { xs: number, sm: number, ...} | `default` | |
|
||||
| shape | The shape of the avatar | `circle` \| `square` | `circle` | 4.0 |
|
||||
|
|
|
@ -39,3 +39,4 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*YbgyQaRGz-UAAA
|
|||
| maxPopoverTrigger | 设置多余头像 Popover 的触发方式 | `hover` \| `focus` \| `click` | `hover` | 3.0 |
|
||||
| maxStyle | 多余头像样式 | CSSProperties | - | |
|
||||
| size | 设置头像的大小 | number \| `large` \| `small` \| `default` \| { xs: number, sm: number, ...} | `default` | |
|
||||
| shape | 设置头像的形状 | `circle` \| `square` | `circle` | 4.0 |
|
||||
|
|
|
@ -3,20 +3,57 @@ import type { FullToken, GenerateStyle } from '../../theme/internal';
|
|||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import { resetComponent } from '../../style';
|
||||
|
||||
export interface ComponentToken {}
|
||||
export interface ComponentToken {
|
||||
/**
|
||||
* @desc 头像背景色
|
||||
* @descEN Background color of Avatar
|
||||
*/
|
||||
containerSize: number;
|
||||
/**
|
||||
* @desc 大号头像尺寸
|
||||
* @descEN Size of large Avatar
|
||||
*/
|
||||
containerSizeLG: number;
|
||||
/**
|
||||
* @desc 小号头像尺寸
|
||||
* @descEN Size of small Avatar
|
||||
*/
|
||||
containerSizeSM: number;
|
||||
/**
|
||||
* @desc 头像文字大小
|
||||
* @descEN Font size of Avatar
|
||||
*/
|
||||
textFontSize: number;
|
||||
/**
|
||||
* @desc 大号头像文字大小
|
||||
* @descEN Font size of large Avatar
|
||||
*/
|
||||
textFontSizeLG: number;
|
||||
/**
|
||||
* @desc 小号头像文字大小
|
||||
* @descEN Font size of small Avatar
|
||||
*/
|
||||
textFontSizeSM: number;
|
||||
/**
|
||||
* @desc 头像组间距
|
||||
* @descEN Spacing between avatars in a group
|
||||
*/
|
||||
groupSpace: number;
|
||||
/**
|
||||
* @desc 头像组重叠宽度
|
||||
* @descEN Overlapping of avatars in a group
|
||||
*/
|
||||
groupOverlapping: number;
|
||||
/**
|
||||
* @desc 头像组边框颜色
|
||||
* @descEN Border color of avatars in a group
|
||||
*/
|
||||
groupBorderColor: string;
|
||||
}
|
||||
|
||||
type AvatarToken = FullToken<'Avatar'> & {
|
||||
avatarBg: string;
|
||||
avatarColor: string;
|
||||
avatarSizeBase: number;
|
||||
avatarSizeLG: number;
|
||||
avatarSizeSM: number;
|
||||
avatarFontSizeBase: number;
|
||||
avatarFontSizeLG: number;
|
||||
avatarFontSizeSM: number;
|
||||
avatarGroupOverlapping: number;
|
||||
avatarGroupSpace: number;
|
||||
avatarGroupBorderColor: string;
|
||||
avatarBgColor: string;
|
||||
};
|
||||
|
||||
|
@ -27,12 +64,12 @@ const genBaseStyle: GenerateStyle<AvatarToken> = token => {
|
|||
iconCls,
|
||||
avatarBg,
|
||||
avatarColor,
|
||||
avatarSizeBase,
|
||||
avatarSizeLG,
|
||||
avatarSizeSM,
|
||||
avatarFontSizeBase,
|
||||
avatarFontSizeLG,
|
||||
avatarFontSizeSM,
|
||||
containerSize,
|
||||
containerSizeLG,
|
||||
containerSizeSM,
|
||||
textFontSize,
|
||||
textFontSizeLG,
|
||||
textFontSizeSM,
|
||||
borderRadius,
|
||||
borderRadiusLG,
|
||||
borderRadiusSM,
|
||||
|
@ -89,14 +126,14 @@ const genBaseStyle: GenerateStyle<AvatarToken> = token => {
|
|||
display: 'block',
|
||||
},
|
||||
|
||||
...avatarSizeStyle(avatarSizeBase, avatarFontSizeBase, borderRadius),
|
||||
...avatarSizeStyle(containerSize, textFontSize, borderRadius),
|
||||
|
||||
[`&-lg`]: {
|
||||
...avatarSizeStyle(avatarSizeLG, avatarFontSizeLG, borderRadiusLG),
|
||||
...avatarSizeStyle(containerSizeLG, textFontSizeLG, borderRadiusLG),
|
||||
},
|
||||
|
||||
[`&-sm`]: {
|
||||
...avatarSizeStyle(avatarSizeSM, avatarFontSizeSM, borderRadiusSM),
|
||||
...avatarSizeStyle(containerSizeSM, textFontSizeSM, borderRadiusSM),
|
||||
},
|
||||
|
||||
'> img': {
|
||||
|
@ -110,55 +147,65 @@ const genBaseStyle: GenerateStyle<AvatarToken> = token => {
|
|||
};
|
||||
|
||||
const genGroupStyle: GenerateStyle<AvatarToken> = token => {
|
||||
const { componentCls, avatarGroupBorderColor, avatarGroupSpace } = token;
|
||||
const { componentCls, groupBorderColor, groupOverlapping, groupSpace } = token;
|
||||
|
||||
return {
|
||||
[`${componentCls}-group`]: {
|
||||
display: 'inline-flex',
|
||||
|
||||
[`${componentCls}`]: {
|
||||
borderColor: avatarGroupBorderColor,
|
||||
borderColor: groupBorderColor,
|
||||
},
|
||||
|
||||
[`> *:not(:first-child)`]: {
|
||||
marginInlineStart: avatarGroupSpace,
|
||||
marginInlineStart: groupOverlapping,
|
||||
},
|
||||
},
|
||||
[`${componentCls}-group-popover`]: {
|
||||
[`${componentCls} + ${componentCls}`]: {
|
||||
marginInlineStart: groupSpace,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default genComponentStyleHook('Avatar', token => {
|
||||
const {
|
||||
colorTextLightSolid,
|
||||
export default genComponentStyleHook(
|
||||
'Avatar',
|
||||
token => {
|
||||
const { colorTextLightSolid, colorTextPlaceholder } = token;
|
||||
const avatarToken = mergeToken<AvatarToken>(token, {
|
||||
avatarBg: colorTextPlaceholder,
|
||||
avatarColor: colorTextLightSolid,
|
||||
});
|
||||
return [genBaseStyle(avatarToken), genGroupStyle(avatarToken)];
|
||||
},
|
||||
token => {
|
||||
const {
|
||||
controlHeight,
|
||||
controlHeightLG,
|
||||
controlHeightSM,
|
||||
|
||||
controlHeight,
|
||||
controlHeightLG,
|
||||
controlHeightSM,
|
||||
fontSize,
|
||||
fontSizeLG,
|
||||
fontSizeXL,
|
||||
fontSizeHeading3,
|
||||
|
||||
fontSize,
|
||||
fontSizeLG,
|
||||
fontSizeXL,
|
||||
fontSizeHeading3,
|
||||
marginXS,
|
||||
marginXXS,
|
||||
colorBorderBg,
|
||||
} = token;
|
||||
return {
|
||||
containerSize: controlHeight,
|
||||
containerSizeLG: controlHeightLG,
|
||||
containerSizeSM: controlHeightSM,
|
||||
|
||||
marginXS,
|
||||
colorBorderBg,
|
||||
colorTextPlaceholder,
|
||||
} = token;
|
||||
textFontSize: Math.round((fontSizeLG + fontSizeXL) / 2),
|
||||
textFontSizeLG: fontSizeHeading3,
|
||||
textFontSizeSM: fontSize,
|
||||
|
||||
const avatarToken = mergeToken<AvatarToken>(token, {
|
||||
avatarBg: colorTextPlaceholder,
|
||||
avatarColor: colorTextLightSolid,
|
||||
|
||||
avatarSizeBase: controlHeight,
|
||||
avatarSizeLG: controlHeightLG,
|
||||
avatarSizeSM: controlHeightSM,
|
||||
|
||||
avatarFontSizeBase: Math.round((fontSizeLG + fontSizeXL) / 2),
|
||||
avatarFontSizeLG: fontSizeHeading3,
|
||||
avatarFontSizeSM: fontSize,
|
||||
avatarGroupSpace: -marginXS,
|
||||
avatarGroupBorderColor: colorBorderBg,
|
||||
});
|
||||
|
||||
return [genBaseStyle(avatarToken), genGroupStyle(avatarToken)];
|
||||
});
|
||||
groupSpace: marginXXS,
|
||||
groupOverlapping: -marginXS,
|
||||
groupBorderColor: colorBorderBg,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
|
|
@ -3,9 +3,9 @@ import ScrollNumber from './ScrollNumber';
|
|||
import classNames from '../_util/classNames';
|
||||
import { getPropsSlot, flattenChildren } from '../_util/props-util';
|
||||
import { cloneElement } from '../_util/vnode';
|
||||
import { getTransitionProps, Transition } from '../_util/transition';
|
||||
import { getTransitionProps } from '../_util/transition';
|
||||
import type { ExtractPropTypes, CSSProperties, PropType } from 'vue';
|
||||
import { defineComponent, computed, ref, watch } from 'vue';
|
||||
import { defineComponent, computed, ref, watch, Transition } from 'vue';
|
||||
import Ribbon from './Ribbon';
|
||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
import isNumeric from '../_util/isNumeric';
|
||||
|
@ -107,7 +107,7 @@ export default defineComponent({
|
|||
const statusCls = computed(() => ({
|
||||
[`${prefixCls.value}-status-dot`]: hasStatus.value,
|
||||
[`${prefixCls.value}-status-${props.status}`]: !!props.status,
|
||||
[`${prefixCls.value}-status-${props.color}`]: isInternalColor.value,
|
||||
[`${prefixCls.value}-color-${props.color}`]: isInternalColor.value,
|
||||
}));
|
||||
|
||||
const statusStyle = computed(() => {
|
||||
|
@ -125,7 +125,7 @@ export default defineComponent({
|
|||
[`${prefixCls.value}-multiple-words`]:
|
||||
!isDotRef.value && displayCount.value && displayCount.value.toString().length > 1,
|
||||
[`${prefixCls.value}-status-${props.status}`]: !!props.status,
|
||||
[`${prefixCls.value}-status-${props.color}`]: isInternalColor.value,
|
||||
[`${prefixCls.value}-color-${props.color}`]: isInternalColor.value,
|
||||
}));
|
||||
|
||||
return () => {
|
||||
|
|
|
@ -33,19 +33,19 @@ exports[`renders ./components/badge/demo/change.vue correctly 1`] = `
|
|||
exports[`renders ./components/badge/demo/colors.vue correctly 1`] = `
|
||||
<h4 style="margin-bottom: 16px;">Presets:</h4>
|
||||
<div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-pink"></span><span class="ant-badge-status-text">pink</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-red"></span><span class="ant-badge-status-text">red</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-yellow"></span><span class="ant-badge-status-text">yellow</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-orange"></span><span class="ant-badge-status-text">orange</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-cyan"></span><span class="ant-badge-status-text">cyan</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-green"></span><span class="ant-badge-status-text">green</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-blue"></span><span class="ant-badge-status-text">blue</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-purple"></span><span class="ant-badge-status-text">purple</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-geekblue"></span><span class="ant-badge-status-text">geekblue</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-magenta"></span><span class="ant-badge-status-text">magenta</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-volcano"></span><span class="ant-badge-status-text">volcano</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-gold"></span><span class="ant-badge-status-text">gold</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-lime"></span><span class="ant-badge-status-text">lime</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-pink"></span><span class="ant-badge-status-text">pink</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-red"></span><span class="ant-badge-status-text">red</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-yellow"></span><span class="ant-badge-status-text">yellow</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-orange"></span><span class="ant-badge-status-text">orange</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-cyan"></span><span class="ant-badge-status-text">cyan</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-green"></span><span class="ant-badge-status-text">green</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-blue"></span><span class="ant-badge-status-text">blue</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-purple"></span><span class="ant-badge-status-text">purple</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-geekblue"></span><span class="ant-badge-status-text">geekblue</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-magenta"></span><span class="ant-badge-status-text">magenta</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-volcano"></span><span class="ant-badge-status-text">volcano</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-gold"></span><span class="ant-badge-status-text">gold</span></span></div>
|
||||
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-lime"></span><span class="ant-badge-status-text">lime</span></span></div>
|
||||
</div>
|
||||
<div class="ant-divider ant-divider-horizontal ant-divider-with-text ant-divider-with-text-left" role="separator"><span class="ant-divider-inner-text">Custom</span></div>
|
||||
<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot" style="background: rgb(255, 85, 0); color: rgb(255, 85, 0);"></span><span class="ant-badge-status-text">#f50</span></span>
|
||||
|
@ -89,141 +89,167 @@ exports[`renders ./components/badge/demo/overflow.vue correctly 1`] = `
|
|||
`;
|
||||
|
||||
exports[`renders ./components/badge/demo/ribbon.vue correctly 1`] = `
|
||||
<div class="ant-ribbon-wrapper ">
|
||||
<div class="ant-card ant-card-bordered ant-card-small">
|
||||
<div class="ant-card-head">
|
||||
<div class="ant-card-head-wrapper">
|
||||
<div class="ant-card-head-title">Pushes open the window</div>
|
||||
<div style="width: 100%;" class="ant-space ant-space-vertical">
|
||||
<div class="ant-space-item" style="margin-bottom: 8px;">
|
||||
<div class="ant-ribbon-wrapper ">
|
||||
<div class="ant-card ant-card-bordered ant-card-small">
|
||||
<div class="ant-card-head">
|
||||
<div class="ant-card-head-wrapper">
|
||||
<div class="ant-card-head-title">Pushes open the window</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-card-body">and raises the spyglass.</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-ribbon ant-ribbon-placement-end"><span class="ant-ribbon-text">Hippies</span>
|
||||
<div class="ant-ribbon-corner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-card-body">and raises the spyglass.</div>
|
||||
<!---->
|
||||
</div>
|
||||
<div class="ant-ribbon ant-ribbon-placement-end"><span class="ant-ribbon-text">Hippies</span>
|
||||
<div class="ant-ribbon-corner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ant-ribbon-wrapper ">
|
||||
<div class="ant-card ant-card-bordered ant-card-small">
|
||||
<div class="ant-card-head">
|
||||
<div class="ant-card-head-wrapper">
|
||||
<div class="ant-card-head-title">Pushes open the window</div>
|
||||
<!---->
|
||||
<div class="ant-space-item" style="margin-bottom: 8px;">
|
||||
<div class="ant-ribbon-wrapper ">
|
||||
<div class="ant-card ant-card-bordered ant-card-small">
|
||||
<div class="ant-card-head">
|
||||
<div class="ant-card-head-wrapper">
|
||||
<div class="ant-card-head-title">Pushes open the window</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-card-body">and raises the spyglass.</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-pink"><span class="ant-ribbon-text">Hippies</span>
|
||||
<div class="ant-ribbon-corner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-card-body">and raises the spyglass.</div>
|
||||
<!---->
|
||||
</div>
|
||||
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-pink"><span class="ant-ribbon-text">Hippies</span>
|
||||
<div class="ant-ribbon-corner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ant-ribbon-wrapper ">
|
||||
<div class="ant-card ant-card-bordered ant-card-small">
|
||||
<div class="ant-card-head">
|
||||
<div class="ant-card-head-wrapper">
|
||||
<div class="ant-card-head-title">Pushes open the window</div>
|
||||
<!---->
|
||||
<div class="ant-space-item" style="margin-bottom: 8px;">
|
||||
<div class="ant-ribbon-wrapper ">
|
||||
<div class="ant-card ant-card-bordered ant-card-small">
|
||||
<div class="ant-card-head">
|
||||
<div class="ant-card-head-wrapper">
|
||||
<div class="ant-card-head-title">Pushes open the window</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-card-body">and raises the spyglass.</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-red"><span class="ant-ribbon-text">Hippies</span>
|
||||
<div class="ant-ribbon-corner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-card-body">and raises the spyglass.</div>
|
||||
<!---->
|
||||
</div>
|
||||
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-red"><span class="ant-ribbon-text">Hippies</span>
|
||||
<div class="ant-ribbon-corner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ant-ribbon-wrapper ">
|
||||
<div class="ant-card ant-card-bordered ant-card-small">
|
||||
<div class="ant-card-head">
|
||||
<div class="ant-card-head-wrapper">
|
||||
<div class="ant-card-head-title">Pushes open the window</div>
|
||||
<!---->
|
||||
<div class="ant-space-item" style="margin-bottom: 8px;">
|
||||
<div class="ant-ribbon-wrapper ">
|
||||
<div class="ant-card ant-card-bordered ant-card-small">
|
||||
<div class="ant-card-head">
|
||||
<div class="ant-card-head-wrapper">
|
||||
<div class="ant-card-head-title">Pushes open the window</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-card-body">and raises the spyglass.</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-cyan"><span class="ant-ribbon-text">Hippies</span>
|
||||
<div class="ant-ribbon-corner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-card-body">and raises the spyglass.</div>
|
||||
<!---->
|
||||
</div>
|
||||
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-cyan"><span class="ant-ribbon-text">Hippies</span>
|
||||
<div class="ant-ribbon-corner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ant-ribbon-wrapper ">
|
||||
<div class="ant-card ant-card-bordered ant-card-small">
|
||||
<div class="ant-card-head">
|
||||
<div class="ant-card-head-wrapper">
|
||||
<div class="ant-card-head-title">Pushes open the window</div>
|
||||
<!---->
|
||||
<div class="ant-space-item" style="margin-bottom: 8px;">
|
||||
<div class="ant-ribbon-wrapper ">
|
||||
<div class="ant-card ant-card-bordered ant-card-small">
|
||||
<div class="ant-card-head">
|
||||
<div class="ant-card-head-wrapper">
|
||||
<div class="ant-card-head-title">Pushes open the window</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-card-body">and raises the spyglass.</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-green"><span class="ant-ribbon-text">Hippies</span>
|
||||
<div class="ant-ribbon-corner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-card-body">and raises the spyglass.</div>
|
||||
<!---->
|
||||
</div>
|
||||
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-green"><span class="ant-ribbon-text">Hippies</span>
|
||||
<div class="ant-ribbon-corner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ant-ribbon-wrapper ">
|
||||
<div class="ant-card ant-card-bordered ant-card-small">
|
||||
<div class="ant-card-head">
|
||||
<div class="ant-card-head-wrapper">
|
||||
<div class="ant-card-head-title">Pushes open the window</div>
|
||||
<!---->
|
||||
<div class="ant-space-item" style="margin-bottom: 8px;">
|
||||
<div class="ant-ribbon-wrapper ">
|
||||
<div class="ant-card ant-card-bordered ant-card-small">
|
||||
<div class="ant-card-head">
|
||||
<div class="ant-card-head-wrapper">
|
||||
<div class="ant-card-head-title">Pushes open the window</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-card-body">and raises the spyglass.</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-purple"><span class="ant-ribbon-text">Hippies</span>
|
||||
<div class="ant-ribbon-corner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-card-body">and raises the spyglass.</div>
|
||||
<!---->
|
||||
</div>
|
||||
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-purple"><span class="ant-ribbon-text">Hippies</span>
|
||||
<div class="ant-ribbon-corner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ant-ribbon-wrapper ">
|
||||
<div class="ant-card ant-card-bordered ant-card-small">
|
||||
<div class="ant-card-head">
|
||||
<div class="ant-card-head-wrapper">
|
||||
<div class="ant-card-head-title">Pushes open the window</div>
|
||||
<!---->
|
||||
<div class="ant-space-item" style="margin-bottom: 8px;">
|
||||
<div class="ant-ribbon-wrapper ">
|
||||
<div class="ant-card ant-card-bordered ant-card-small">
|
||||
<div class="ant-card-head">
|
||||
<div class="ant-card-head-wrapper">
|
||||
<div class="ant-card-head-title">Pushes open the window</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-card-body">and raises the spyglass.</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-volcano"><span class="ant-ribbon-text">Hippies</span>
|
||||
<div class="ant-ribbon-corner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-card-body">and raises the spyglass.</div>
|
||||
<!---->
|
||||
</div>
|
||||
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-volcano"><span class="ant-ribbon-text">Hippies</span>
|
||||
<div class="ant-ribbon-corner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ant-ribbon-wrapper ">
|
||||
<div class="ant-card ant-card-bordered ant-card-small">
|
||||
<div class="ant-card-head">
|
||||
<div class="ant-card-head-wrapper">
|
||||
<div class="ant-card-head-title">Pushes open the window</div>
|
||||
<!---->
|
||||
<div class="ant-space-item">
|
||||
<div class="ant-ribbon-wrapper ">
|
||||
<div class="ant-card ant-card-bordered ant-card-small">
|
||||
<div class="ant-card-head">
|
||||
<div class="ant-card-head-wrapper">
|
||||
<div class="ant-card-head-title">Pushes open the window</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-card-body">and raises the spyglass.</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-magenta"><span class="ant-ribbon-text">Hippies</span>
|
||||
<div class="ant-ribbon-corner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
<div class="ant-card-body">and raises the spyglass.</div>
|
||||
<!---->
|
||||
</div>
|
||||
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-magenta"><span class="ant-ribbon-text">Hippies</span>
|
||||
<div class="ant-ribbon-corner"></div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
@ -234,15 +260,18 @@ exports[`renders ./components/badge/demo/status.vue correctly 1`] = `
|
|||
<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-processing"></span><span class="ant-badge-status-text"><!----></span></span>
|
||||
<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-warning"></span><span class="ant-badge-status-text"><!----></span></span>
|
||||
<br>
|
||||
<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-success"></span><span class="ant-badge-status-text">Success</span></span>
|
||||
<br>
|
||||
<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-error"></span><span class="ant-badge-status-text">Error</span></span>
|
||||
<br>
|
||||
<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-default"></span><span class="ant-badge-status-text">Default</span></span>
|
||||
<br>
|
||||
<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-processing"></span><span class="ant-badge-status-text">Processing</span></span>
|
||||
<br>
|
||||
<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-warning"></span><span class="ant-badge-status-text">warning</span></span>
|
||||
<div class="ant-space ant-space-vertical">
|
||||
<div class="ant-space-item" style="margin-bottom: 8px;"><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-success"></span><span class="ant-badge-status-text">Success</span></span></div>
|
||||
<!---->
|
||||
<div class="ant-space-item" style="margin-bottom: 8px;"><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-error"></span><span class="ant-badge-status-text">Error</span></span></div>
|
||||
<!---->
|
||||
<div class="ant-space-item" style="margin-bottom: 8px;"><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-default"></span><span class="ant-badge-status-text">Default</span></span></div>
|
||||
<!---->
|
||||
<div class="ant-space-item" style="margin-bottom: 8px;"><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-processing"></span><span class="ant-badge-status-text">Processing</span></span></div>
|
||||
<!---->
|
||||
<div class="ant-space-item"><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-warning"></span><span class="ant-badge-status-text">warning</span></span></div>
|
||||
<!---->
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/badge/demo/title.vue correctly 1`] = `
|
||||
|
|
|
@ -16,28 +16,30 @@ Use ribbon badge.
|
|||
</docs>
|
||||
|
||||
<template>
|
||||
<a-badge-ribbon text="Hippies">
|
||||
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
|
||||
</a-badge-ribbon>
|
||||
<a-badge-ribbon text="Hippies" color="pink">
|
||||
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
|
||||
</a-badge-ribbon>
|
||||
<a-badge-ribbon text="Hippies" color="red">
|
||||
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
|
||||
</a-badge-ribbon>
|
||||
<a-badge-ribbon text="Hippies" color="cyan">
|
||||
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
|
||||
</a-badge-ribbon>
|
||||
<a-badge-ribbon text="Hippies" color="green">
|
||||
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
|
||||
</a-badge-ribbon>
|
||||
<a-badge-ribbon text="Hippies" color="purple">
|
||||
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
|
||||
</a-badge-ribbon>
|
||||
<a-badge-ribbon text="Hippies" color="volcano">
|
||||
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
|
||||
</a-badge-ribbon>
|
||||
<a-badge-ribbon text="Hippies" color="magenta">
|
||||
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
|
||||
</a-badge-ribbon>
|
||||
<a-space direction="vertical" style="width: 100%">
|
||||
<a-badge-ribbon text="Hippies">
|
||||
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
|
||||
</a-badge-ribbon>
|
||||
<a-badge-ribbon text="Hippies" color="pink">
|
||||
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
|
||||
</a-badge-ribbon>
|
||||
<a-badge-ribbon text="Hippies" color="red">
|
||||
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
|
||||
</a-badge-ribbon>
|
||||
<a-badge-ribbon text="Hippies" color="cyan">
|
||||
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
|
||||
</a-badge-ribbon>
|
||||
<a-badge-ribbon text="Hippies" color="green">
|
||||
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
|
||||
</a-badge-ribbon>
|
||||
<a-badge-ribbon text="Hippies" color="purple">
|
||||
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
|
||||
</a-badge-ribbon>
|
||||
<a-badge-ribbon text="Hippies" color="volcano">
|
||||
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
|
||||
</a-badge-ribbon>
|
||||
<a-badge-ribbon text="Hippies" color="magenta">
|
||||
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
|
||||
</a-badge-ribbon>
|
||||
</a-space>
|
||||
</template>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<docs>
|
||||
---
|
||||
order: 4
|
||||
title:
|
||||
title:
|
||||
zh-CN: 状态点
|
||||
en-US: Status
|
||||
---
|
||||
|
@ -22,13 +22,12 @@ Standalone badge with status.
|
|||
<a-badge status="processing" />
|
||||
<a-badge status="warning" />
|
||||
<br />
|
||||
<a-badge status="success" text="Success" />
|
||||
<br />
|
||||
<a-badge status="error" text="Error" />
|
||||
<br />
|
||||
<a-badge status="default" text="Default" />
|
||||
<br />
|
||||
<a-badge status="processing" text="Processing" />
|
||||
<br />
|
||||
<a-badge status="warning" text="warning" />
|
||||
|
||||
<a-space direction="vertical">
|
||||
<a-badge status="success" text="Success" />
|
||||
<a-badge status="error" text="Error" />
|
||||
<a-badge status="default" text="Default" />
|
||||
<a-badge status="processing" text="Processing" />
|
||||
<a-badge status="warning" text="warning" />
|
||||
</a-space>
|
||||
</template>
|
||||
|
|
|
@ -73,9 +73,12 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
|
|||
const ribbonPrefixCls = `${antCls}-ribbon`;
|
||||
const ribbonWrapperPrefixCls = `${antCls}-ribbon-wrapper`;
|
||||
|
||||
const statusPreset = genPresetColor(token, (colorKey, { darkColor }) => ({
|
||||
[`${componentCls}-status-${colorKey}`]: {
|
||||
const colorPreset = genPresetColor(token, (colorKey, { darkColor }) => ({
|
||||
[`&${componentCls} ${componentCls}-color-${colorKey}`]: {
|
||||
background: darkColor,
|
||||
[`&:not(${componentCls}-count)`]: {
|
||||
color: darkColor,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
|
@ -150,9 +153,9 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
|
|||
insetInlineEnd: 0,
|
||||
transform: 'translate(50%, -50%)',
|
||||
transformOrigin: '100% 0%',
|
||||
[`${iconCls}-spin`]: {
|
||||
[`&${iconCls}-spin`]: {
|
||||
animationName: antBadgeLoadingCircle,
|
||||
animationDuration: token.motionDurationMid,
|
||||
animationDuration: '1s',
|
||||
animationIterationCount: 'infinite',
|
||||
animationTimingFunction: 'linear',
|
||||
},
|
||||
|
@ -175,7 +178,7 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
|
|||
backgroundColor: token.colorSuccess,
|
||||
},
|
||||
[`${componentCls}-status-processing`]: {
|
||||
position: 'relative',
|
||||
overflow: 'visible',
|
||||
color: token.colorPrimary,
|
||||
backgroundColor: token.colorPrimary,
|
||||
|
||||
|
@ -207,13 +210,13 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
|
|||
[`${componentCls}-status-warning`]: {
|
||||
backgroundColor: token.colorWarning,
|
||||
},
|
||||
...statusPreset,
|
||||
[`${componentCls}-status-text`]: {
|
||||
marginInlineStart: marginXS,
|
||||
color: token.colorText,
|
||||
fontSize: token.fontSize,
|
||||
},
|
||||
},
|
||||
...colorPreset,
|
||||
[`${componentCls}-zoom-appear, ${componentCls}-zoom-enter`]: {
|
||||
animationName: antZoomBadgeIn,
|
||||
animationDuration: token.motionDurationSlow,
|
||||
|
@ -284,7 +287,6 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
|
|||
...resetComponent(token),
|
||||
position: 'absolute',
|
||||
top: marginXS,
|
||||
height: badgeFontHeight,
|
||||
padding: `0 ${token.paddingXS}px`,
|
||||
color: token.colorPrimary,
|
||||
lineHeight: `${badgeFontHeight}px`,
|
||||
|
|
|
@ -8,7 +8,7 @@ import DownOutlined from '@ant-design/icons-vue/DownOutlined';
|
|||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
import type { MouseEventHandler } from '../_util/EventInterface';
|
||||
import { eventType, objectType } from '../_util/type';
|
||||
import type { CustomSlotsType } from '../_util/type';
|
||||
import type { CustomSlotsType, VueNode } from '../_util/type';
|
||||
|
||||
export const breadcrumbItemProps = () => ({
|
||||
prefixCls: String,
|
||||
|
@ -38,7 +38,7 @@ export default defineComponent({
|
|||
* if overlay is have
|
||||
* Wrap a Dropdown
|
||||
*/
|
||||
const renderBreadcrumbNode = (breadcrumbItem: JSX.Element, prefixCls: string) => {
|
||||
const renderBreadcrumbNode = (breadcrumbItem: VueNode, prefixCls: string) => {
|
||||
const overlay = getPropsSlot(slots, props, 'overlay');
|
||||
if (overlay) {
|
||||
return (
|
||||
|
@ -59,7 +59,7 @@ export default defineComponent({
|
|||
const separator = getPropsSlot(slots, props, 'separator') ?? '/';
|
||||
const children = getPropsSlot(slots, props);
|
||||
const { class: cls, style, ...restAttrs } = attrs;
|
||||
let link: JSX.Element;
|
||||
let link: VueNode;
|
||||
if (props.href !== undefined) {
|
||||
link = (
|
||||
<a class={`${prefixCls.value}-link`} onClick={handleClick} {...restAttrs}>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { defineComponent, nextTick } from 'vue';
|
||||
import { defineComponent, nextTick, Transition } from 'vue';
|
||||
import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
|
||||
import Transition from '../_util/transition';
|
||||
const getCollapsedWidth = (node: HTMLSpanElement) => {
|
||||
if (node) {
|
||||
node.style.width = '0px';
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue