+
+
+ 30
+
+ |
+
-
-
- |
+
-
-
-
+ |
+
-
- |
+
+
- 2016
-
-
- |
+
-
-
- |
+
-
-
-
-
-
+ 5
+
+
+
+
+
-
-
-
- Su
- |
-
- Mo
- |
-
- Tu
- |
-
- We
- |
-
- Th
- |
-
- Fr
- |
-
- Sa
- |
-
-
- |
-
-
-
+ 6
+
+ |
+
+
+ 7
+
+ |
+
+
+ 8
+
+ |
+
+
+ 9
+
+ |
+
+
+ 10
+
+ |
+
+
+ 11
+
+ |
+
+
+ 12
+
+ |
+
+
+
+
+ 13
+
+ |
+
+
+ 14
+
+ |
+
+
+ 15
+
+ |
+
+
+ 16
+
+ |
+
+
+ 17
+
+ |
+
+
+ 18
+
+ |
+
+
+ 19
+
+ |
+
+
+
+
+ 20
+
+ |
+
+
+ 21
+
+ |
+
+
+ 22
+
+ |
+
+
+ 23
+
+ |
+
+
+ 24
+
+ |
+
+
+ 25
+
+ |
+
+
+ 26
+
+ |
+
+
+
+
+ 27
+
+ |
+
+
+ 28
+
+ |
+
+
+ 29
+
+ |
+
+
+ 30
+
+ |
+
+
+ 1
+
+ |
+
+
+ 2
+
+ |
+
+
+ 3
+
+ |
+
+
+
+
+ 4
+
+ |
+
+
+ 5
+
+ |
+
+
+ 6
+
+ |
+
+
+ 7
+
+ |
+
+
+ 8
+
+ |
+
+
+ 9
+
+ |
+
+
+ 10
+
+ |
+
+
+
+
+
+
+
+
+
+ ,
+ ,
+ ,
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Su
+ |
+
+ Mo
+ |
+
+ Tu
+ |
+
+ We
+ |
+
+ Th
+ |
+
+ Fr
+ |
+
+ Sa
+ |
+
+
+
+
+
+
+ 30
+
+ |
+
+
+ 31
+
+ |
+
+
+ 1
+
+ |
+
+
+ 2
+
+ |
+
+
+ 3
+
+ |
+
+
+ 4
+
+ |
+
+
+ 5
+
+ |
+
+
+
+
+ 6
+
+ |
+
+
+ 7
+
+ |
+
+
+ 8
+
+ |
+
+
+ 9
+
+ |
+
+
+ 10
+
+ |
+
+
+ 11
+
+ |
+
+
+ 12
+
+ |
+
+
+
+
+ 13
+
+ |
+
+
+ 14
+
+ |
+
+
+ 15
+
+ |
+
+
+ 16
+
+ |
+
+
+ 17
+
+ |
+
+
+ 18
+
+ |
+
+
+ 19
+
+ |
+
+
+
+
+ 20
+
+ |
+
+
+ 21
+
+ |
+
+
+ 22
+
+ |
+
+
+ 23
+
+ |
+
+
+ 24
+
+ |
+
+
+ 25
+
+ |
+
+
+ 26
+
+ |
+
+
+
+
+ 27
+
+ |
+
+
+ 28
+
+ |
+
+
+ 29
+
+ |
+
+
+ 30
+
+ |
+
+
+ 1
+
+ |
+
+
+ 2
+
+ |
+
+
+ 3
+
+ |
+
+
+
+
+ 4
+
+ |
+
+
+ 5
+
+ |
+
+
+ 6
+
+ |
+
+
+ 7
+
+ |
+
+
+ 8
+
+ |
+
+
+ 9
+
+ |
+
+
+ 10
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Su
+ |
+
+ Mo
+ |
+
+ Tu
+ |
+
+ We
+ |
+
+ Th
+ |
+
+ Fr
+ |
+
+ Sa
+ |
+
+
+
+
+
+
+ 27
+
+ |
+
+
+ 28
+
+ |
+
+
+ 29
+
+ |
+
+
+ 30
+
+ |
+
+
+ 1
+
+ |
+
+
+ 2
+
+ |
+
+
+ 3
+
+ |
+
+
+
+
+ 4
+
+ |
+
+
+ 5
+
+ |
+
+
+ 6
+
+ |
+
+
+ 7
+
+ |
+
+
+ 8
+
+ |
+
+
+ 9
+
+ |
+
+
+ 10
+
+ |
+
+
+
+
+ 11
+
+ |
+
+
+ 12
+
+ |
+
+
+ 13
+
+ |
+
+
+ 14
+
+ |
+
+
+ 15
+
+ |
+
+
+ 16
+
+ |
+
+
+ 17
+
+ |
+
+
+
+
+ 18
+
+ |
+
+
+ 19
+
+ |
+
+
+ 20
+
+ |
+
+
+ 21
+
+ |
+
+
+ 22
+
+ |
+
+
+ 23
+
+ |
+
+
+ 24
+
+ |
+
+
+
+
+ 25
+
+ |
+
+
+ 26
+
+ |
+
+
+ 27
+
+ |
+
+
+ 28
+
+ |
+
+
+ 29
+
+ |
+
+
+ 30
+
+ |
+
+
+ 31
+
+ |
+
+
+
+
+ 1
+
+ |
+
+
+ 2
+
+ |
+
+
+ 3
+
+ |
+
+
+ 4
+
+ |
+
+
+ 5
+
+ |
+
+
+ 6
+
+ |
+
+
+ 7
+
+ |
+
+
+
+
+
+
+
+
+
+
+ ,
+]
+`;
+
+exports[`renders ./components/date-picker/demo/presetted-ranges.md extend context correctly 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Su
+ |
+
+ Mo
+ |
+
+ Tu
+ |
+
+ We
+ |
+
+ Th
+ |
+
+ Fr
+ |
+
+ Sa
+ |
+
+
+
+
+
+
30
@@ -35490,7 +37351,244 @@ exports[`renders ./components/date-picker/demo/range-picker.md extend context co
- 5
+ 5
+
+ |
+
+
+
+ 46
+ |
+
+
+ 6
+
+ |
+
+
+ 7
+
+ |
+
+
+ 8
+
+ |
+
+
+ 9
+
+ |
+
+
+ 10
+
+ |
+
+
+ 11
+
+ |
+
+
+ 12
+
+ |
+
+
+
+ 47
+ |
+
+
+ 13
+
+ |
+
+
+ 14
+
+ |
+
+
+ 15
+
+ |
+
+
+ 16
+
+ |
+
+
+ 17
+
+ |
+
+
+ 18
+
+ |
+
+
+ 19
+
+ |
+
+
+
+ 48
+ |
+
+
+ 20
+
+ |
+
+
+ 21
+
+ |
+
+
+ 22
+
+ |
+
+
+ 23
+
+ |
+
+
+ 24
+
+ |
+
+
+ 25
+
+ |
+
+
+ 26
|
@@ -35500,76 +37598,76 @@ exports[`renders ./components/date-picker/demo/range-picker.md extend context co
- 46
+ 49
|
- 6
+ 27
|
- 7
+ 28
|
- 8
+ 29
|
- 9
+ 30
|
- 10
+ 1
|
- 11
+ 2
|
- 12
+ 3
|
@@ -35579,155 +37677,262 @@ exports[`renders ./components/date-picker/demo/range-picker.md extend context co
- 47
+ 50
|
- 13
+ 4
|
- 14
+ 5
|
- 15
+ 6
|
- 16
+ 7
|
- 17
+ 8
|
- 18
+ 9
|
- 19
+ 10
|
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+ Su
+ |
+
+ Mo
+ |
+
+ Tu
+ |
+
+ We
+ |
+
+ Th
+ |
+
+ Fr
+ |
+
+ Sa
+ |
+
+
+
- 48
+ 49
|
- 20
+ 27
|
- 21
+ 28
|
- 22
+ 29
|
- 23
+ 30
|
- 24
+ 1
|
- 25
+ 2
|
- 26
+ 3
|
@@ -35737,76 +37942,76 @@ exports[`renders ./components/date-picker/demo/range-picker.md extend context co
- 49
+ 50
|
- 27
+ 4
|
- 28
+ 5
|
- 29
+ 6
|
- 30
+ 7
|
- 1
+ 8
|
- 2
+ 9
|
- 3
+ 10
|
@@ -35816,262 +38021,155 @@ exports[`renders ./components/date-picker/demo/range-picker.md extend context co
- 50
+ 51
|
- 4
+ 11
|
- 5
+ 12
|
- 6
+ 13
|
- 7
+ 14
|
- 8
+ 15
|
- 9
+ 16
|
- 10
+ 17
|
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
- Su
- |
-
- Mo
- |
-
- Tu
- |
-
- We
- |
-
- Th
- |
-
- Fr
- |
-
- Sa
- |
-
-
-
- 49
+ 52
|
- 27
+ 18
|
- 28
+ 19
|
- 29
+ 20
|
- 30
+ 21
|
- 1
+ 22
|
- 2
+ 23
|
- 3
+ 24
|
@@ -36081,392 +38179,626 @@ exports[`renders ./components/date-picker/demo/range-picker.md extend context co
- 50
+ 53
|
- 4
+ 25
|
- 5
+ 26
|
- 6
+ 27
|
- 7
+ 28
|
- 8
+ 29
|
+
+ 30
+
+ |
+
+
+ 31
+
+ |
+
+
+
+ 1
+ |
+
- 9
+ 1
|
- 10
+ 2
|
-
-
-
- 51
- |
- 11
+ 3
|
- 12
+ 4
|
- 13
+ 5
|
- 14
+ 6
|
- 15
+ 7
|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- 16
+ Jan
|
- 17
+ Feb
|
-
-
-
- 52
- |
- 18
+ Mar
|
+
+
- 19
+ Apr
|
- 20
+ May
|
- 21
+ Jun
|
+
+
- 22
+ Jul
|
- 23
+ Aug
|
- 24
+ Sep
|
-
-
- 53
- |
+
- 25
+ Oct
|
- 26
+ Nov
|
- 27
+ Dec
|
+
+
+
+
+
+
+
+
+
+
+
+
+
- 28
+ Jan
|
- 29
+ Feb
|
- 30
+ Mar
|
+
+
- 31
+ Apr
|
-
-
- 1
+
+ May
+
|
- 1
+ Jun
|
+
+
- 2
+ Jul
|
- 3
+ Aug
|
- 4
+ Sep
|
+
+
- 5
+ Oct
|
- 6
+ Nov
|
- 7
+ Dec
|
@@ -36493,7 +38825,7 @@ exports[`renders ./components/date-picker/demo/range-picker.md extend context co
>
-
-
-
-
-
-
- Jan
-
- |
-
-
- Feb
-
- |
-
-
- Mar
-
- |
-
-
-
-
- Apr
-
- |
-
-
- May
-
- |
-
-
- Jun
-
- |
-
-
-
-
- Jul
-
- |
-
-
- Aug
-
- |
+
+
+
+
- Sep
+ Q1
|
-
-
- Oct
+ Q2
|
- Nov
+ Q3
|
- Dec
+ Q4
|
@@ -36771,7 +39017,7 @@ exports[`renders ./components/date-picker/demo/range-picker.md extend context co
tabindex="-1"
>
+
+
+ -
+
+ 00
+
+
+ -
+
+ 01
+
+
+ -
+
+ 02
+
+
+ -
+
+ 03
+
+
+ -
+
+ 04
+
+
+ -
+
+ 05
+
+
+ -
+
+ 06
+
+
+ -
+
+ 07
+
+
+ -
+
+ 08
+
+
+ -
+
+ 09
+
+
+ -
+
+ 10
+
+
+ -
+
+ 11
+
+
+ -
+
+ 12
+
+
+ -
+
+ 13
+
+
+ -
+
+ 14
+
+
+ -
+
+ 15
+
+
+ -
+
+ 16
+
+
+ -
+
+ 17
+
+
+ -
+
+ 18
+
+
+ -
+
+ 19
+
+
+ -
+
+ 20
+
+
+ -
+
+ 21
+
+
+ -
+
+ 22
+
+
+ -
+
+ 23
+
+
+
+
+ -
+
+ 00
+
+
+ -
+
+ 01
+
+
+ -
+
+ 02
+
+
+ -
+
+ 03
+
+
+ -
+
+ 04
+
+
+ -
+
+ 05
+
+
+ -
+
+ 06
+
+
+ -
+
+ 07
+
+
+ -
+
+ 08
+
+
+ -
+
+ 09
+
+
+ -
+
+ 10
+
+
+ -
+
+ 11
+
+
+ -
+
+ 12
+
+
+ -
+
+ 13
+
+
+ -
+
+ 14
+
+
+ -
+
+ 15
+
+
+ -
+
+ 16
+
+
+ -
+
+ 17
+
+
+ -
+
+ 18
+
+
+ -
+
+ 19
+
+
+ -
+
+ 20
+
+
+ -
+
+ 21
+
+
+ -
+
+ 22
+
+
+ -
+
+ 23
+
+
+ -
+
+ 24
+
+
+ -
+
+ 25
+
+
+ -
+
+ 26
+
+
+ -
+
+ 27
+
+
+ -
+
+ 28
+
+
+ -
+
+ 29
+
+
+ -
+
+ 30
+
+
+ -
+
+ 31
+
+
+ -
+
+ 32
+
+
+ -
+
+ 33
+
+
+ -
+
+ 34
+
+
+ -
+
+ 35
+
+
+ -
+
+ 36
+
+
+ -
+
+ 37
+
+
+ -
+
+ 38
+
+
+ -
+
+ 39
+
+
+ -
+
+ 40
+
+
+ -
+
+ 41
+
+
+ -
+
+ 42
+
+
+ -
+
+ 43
+
+
+ -
+
+ 44
+
+
+ -
+
+ 45
+
+
+ -
+
+ 46
+
+
+ -
+
+ 47
+
+
+ -
+
+ 48
+
+
+ -
+
+ 49
+
+
+ -
+
+ 50
+
+
+ -
+
+ 51
+
+
+ -
+
+ 52
+
+
+ -
+
+ 53
+
+
+ -
+
+ 54
+
+
+ -
+
+ 55
+
+
+ -
+
+ 56
+
+
+ -
+
+ 57
+
+
+ -
+
+ 58
+
+
+ -
+
+ 59
+
+
+
-
- -
-
- 00
-
-
-
- 01
+ 24
-
- 02
+ 25
- 03
+ 26
- 04
+ 27
- 05
+ 28
- 06
+ 29
- 07
+ 30
- 08
+ 31
- 09
+ 32
- 10
+ 33
- 11
+ 34
- 12
+ 35
- 13
+ 36
- 14
+ 37
- 15
+ 38
- 16
+ 39
- 17
+ 40
- 18
+ 41
- 19
+ 42
- 20
+ 43
- 21
+ 44
- 22
+ 45
- 23
+ 46
- 24
+ 47
- 25
+ 48
- 26
+ 49
- 27
+ 50
- 28
+ 51
- 29
+ 52
- 30
+ 53
- 31
+ 54
- 32
+ 55
- 33
+ 56
- 34
+ 57
- 35
+ 58
- 36
+ 59
-
-
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`renders ./components/date-picker/demo/status.md extend context correctly 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Su
+ |
+
+ Mo
+ |
+
+ Tu
+ |
+
+ We
+ |
+
+ Th
+ |
+
+ Fr
+ |
+
+ Sa
+ |
+
+
+
+
+
- 37
-
-
-
-
+ 30
+
+ |
+
- 38
-
-
-
-
+ 31
+
+ |
+
- 39
-
-
-
-
+ 1
+
+ |
+
- 40
-
-
-
-
+ 2
+
+ |
+
- 41
-
-
-
-
+ 3
+
+ |
+
- 42
-
-
-
-
+ 4
+
+ |
+
- 43
-
-
-
-
+ 5
+
+ |
+
+
+
- 44
-
-
-
-
+ 6
+
+ |
+
- 45
-
-
-
-
+ 7
+
+ |
+
- 46
-
-
-
-
+ 8
+
+ |
+
- 47
-
-
-
-
+ 9
+
+ |
+
- 48
-
-
-
-
+ 10
+
+ |
+
- 49
-
-
-
-
+ 11
+
+ |
+
- 50
-
-
-
-
+ 12
+
+ |
+
+
+
- 51
-
-
-
-
+ 13
+
+ |
+
- 52
-
-
-
-
+ 14
+
+ |
+
- 53
-
-
-
-
+ 15
+
+ |
+
- 54
-
-
-
-
+ 16
+
+ |
+
- 55
-
-
-
-
+ 17
+
+ |
+
- 56
-
-
-
-
+ 18
+
+ |
+
- 57
-
-
-
-
+ 19
+
+ |
+
+
+
- 58
-
-
-
-
+ 20
+
+ |
+
- 59
-
-
-
- |
+
- 00
-
-
-
-
+ 22
+
+ |
+
- 01
-
-
-
-
+ 23
+
+ |
+
- 02
-
-
-
-
+ 24
+
+ |
+
- 03
-
-
-
-
+ 25
+
+ |
+
- 04
-
-
-
-
+ 26
+
+ |
+
+
+
- 05
-
-
-
-
+ 27
+
+ |
+
- 06
-
-
-
-
+ 28
+
+ |
+
- 07
-
-
-
-
+ 29
+
+ |
+
- 08
-
-
-
-
+ 30
+
+ |
+
- 09
-
-
-
-
+ 1
+
+ |
+
- 10
-
-
-
-
+ 2
+
+ |
+
- 11
-
-
-
-
+ 3
+
+ |
+
+
+
+
+ 4
+
+ |
+
- 12
-
-
-
-
+ 5
+
+ |
+
- 13
-
-
-
-
+ 6
+
+ |
+
- 14
-
-
-
-
+ 7
+
+ |
+
- 15
-
-
-
-
+ 8
+
+ |
+
- 16
-
-
-
-
+ 9
+
+ |
+
- 17
-
-
-
-
+ 10
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Su
+ |
+
+ Mo
+ |
+
+ Tu
+ |
+
+ We
+ |
+
+ Th
+ |
+
+ Fr
+ |
+
+ Sa
+ |
+
+
+
+
+
- 18
-
-
-
-
+ 30
+
+ |
+
- 19
-
-
-
-
+ 31
+
+ |
+
- 20
-
-
-
-
+ 1
+
+ |
+
- 21
-
-
-
-
+ 2
+
+ |
+
- 22
-
-
-
-
+ 3
+
+ |
+
- 23
-
-
-
-
+ 4
+
+ |
+
- 24
-
-
-
-
+ 5
+
+ |
+
+
+
- 25
-
-
-
-
+ 6
+
+ |
+
- 26
-
-
-
-
+ 7
+
+ |
+
- 27
-
-
-
-
+ 8
+
+ |
+
- 28
-
-
-
-
+ 9
+
+ |
+
- 29
-
-
-
-
+ 10
+
+ |
+
- 30
-
-
-
-
+ 11
+
+ |
+
- 31
-
-
-
-
+ 12
+
+ |
+
+
+
- 32
-
-
-
-
+ 13
+
+ |
+
- 33
-
-
-
-
+ 14
+
+ |
+
- 34
-
-
-
-
+ 15
+
+ |
+
- 35
-
-
-
-
+ 16
+
+ |
+
- 36
-
-
-
-
+ 17
+
+ |
+
- 37
-
-
-
-
+ 18
+
+ |
+
- 38
-
-
-
-
+ 19
+
+ |
+
+
+
- 39
-
-
-
-
+ 20
+
+ |
+
- 40
-
-
-
-
+ 21
+
+ |
+
- 41
-
-
-
-
+ 22
+
+ |
+
- 42
-
-
-
-
+ 23
+
+ |
+
- 43
-
-
-
-
+ 24
+
+ |
+
- 44
-
-
-
-
+ 25
+
+ |
+
- 45
-
-
-
-
+ 26
+
+ |
+
+
+
- 46
-
-
-
-
+ 27
+
+ |
+
- 47
-
-
-
-
+ 28
+
+ |
+
- 48
-
-
-
-
+ 29
+
+ |
+
- 49
-
-
-
-
+ 30
+
+ |
+
- 50
-
-
-
-
+ 1
+
+ |
+
- 51
-
-
-
-
+ 2
+
+ |
+
- 52
-
-
-
-
+ 3
+
+ |
+
+
+
- 53
-
-
-
-
+ 4
+
+ |
+
- 54
-
-
-
-
+ 5
+
+ |
+
- 55
-
-
-
-
+ 6
+
+ |
+
- 56
-
-
-
-
+ 7
+
+ |
+
- 57
-
-
-
-
+ 8
+
+ |
+
- 58
-
-
-
-
+ 9
+
+ |
+
- 59
-
-
-
-
+
+ 10
+
+ |
+
+
+
diff --git a/components/date-picker/__tests__/__snapshots__/demo.test.js.snap b/components/date-picker/__tests__/__snapshots__/demo.test.js.snap
index a8c220b6cb43..6e0dc91b0fc2 100644
--- a/components/date-picker/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/date-picker/__tests__/__snapshots__/demo.test.js.snap
@@ -2349,6 +2349,216 @@ exports[`renders ./components/date-picker/demo/mode.md correctly 1`] = `
`;
+exports[`renders ./components/date-picker/demo/placement.md correctly 1`] = `
+Array [
+
+
+
+
+
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+]
+`;
+
exports[`renders ./components/date-picker/demo/presetted-ranges.md correctly 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -3432,6 +3728,103 @@ exports[`renders ./components/date-picker/demo/start-end.md correctly 1`] = `
`;
+exports[`renders ./components/date-picker/demo/status.md correctly 1`] = `
+
+`;
+
exports[`renders ./components/date-picker/demo/suffix.md correctly 1`] = `
{
it('DatePicker ref methods', () => {
@@ -13,6 +15,23 @@ describe('DatePicker.typescript', () => {
);
expect(datePicker).toBeTruthy();
});
+
+ // https://github.com/ant-design/ant-design/issues/33417
+ it('DatePicker ref methods with forwardRef', () => {
+ const MyDatePicker = React.forwardRef((props, ref: DatePickRef ) => (
+
+ ));
+ const datePicker = (
+ {
+ picker?.focus();
+ picker?.blur();
+ }}
+ />
+ );
+ expect(datePicker).toBeTruthy();
+ });
+
it('RangePicker ref methods', () => {
const rangePicker = (
{
);
expect(rangePicker).toBeTruthy();
});
+
+ it('RangePicker ref methods with forwardRef', () => {
+ const MyRangePicker = React.forwardRef((props, ref: RangePickerRef) => (
+
+ ));
+ const datePicker = (
+ {
+ picker?.focus();
+ picker?.blur();
+ }}
+ />
+ );
+ expect(datePicker).toBeTruthy();
+ });
});
diff --git a/components/date-picker/demo/placement.md b/components/date-picker/demo/placement.md
new file mode 100644
index 000000000000..b878b80cf830
--- /dev/null
+++ b/components/date-picker/demo/placement.md
@@ -0,0 +1,47 @@
+---
+order: 28
+title:
+ zh-CN: 基本
+ en-US: Basic
+---
+
+## zh-CN
+
+可以通过 `placement` 手动指定弹出的位置。
+
+## en-US
+
+You can manually specify the position of the popup via `placement`.
+
+```jsx
+import { DatePicker, Space, Radio } from 'infrad';
+
+const { RangePicker } = DatePicker;
+
+const SetPlacementDemo = () => {
+ const [placement, SetPlacement] = React.useState('topLeft');
+
+ const placementChange = e => {
+ SetPlacement(e.target.value);
+ };
+
+ return (
+ <>
+
+ topLeft
+ topRight
+ bottomLeft
+ bottomRight
+
+
+
+
+
+
+
+ >
+ );
+};
+
+ReactDOM.render(, mountNode);
+```
diff --git a/components/date-picker/demo/range-picker.md b/components/date-picker/demo/range-picker.md
index 67ea108c6c88..7e7f09f6141a 100644
--- a/components/date-picker/demo/range-picker.md
+++ b/components/date-picker/demo/range-picker.md
@@ -24,6 +24,7 @@ ReactDOM.render(
+
,
mountNode,
diff --git a/components/date-picker/demo/status.md b/components/date-picker/demo/status.md
new file mode 100644
index 000000000000..7a75ecd7bafa
--- /dev/null
+++ b/components/date-picker/demo/status.md
@@ -0,0 +1,28 @@
+---
+order: 19
+version: 4.19.0
+title:
+ zh-CN: 自定义状态
+ en-US: Status
+---
+
+## zh-CN
+
+使用 `status` 为 DatePicker 添加状态,可选 `error` 或者 `warning`。
+
+## en-US
+
+Add status to DatePicker with `status`, which could be `error` or `warning`.
+
+```tsx
+import { DatePicker, Space } from 'infrad';
+
+const Status: React.FC = () => (
+
+
+
+
+);
+
+ReactDOM.render(, mountNode);
+```
diff --git a/components/date-picker/generatePicker/generateRangePicker.tsx b/components/date-picker/generatePicker/generateRangePicker.tsx
index ad3cb8e25b0d..b22466ffa80a 100644
--- a/components/date-picker/generatePicker/generateRangePicker.tsx
+++ b/components/date-picker/generatePicker/generateRangePicker.tsx
@@ -12,7 +12,7 @@ import enUS from '../locale/en_US';
import { ConfigContext, ConfigConsumerProps } from '../../config-provider';
import SizeContext from '../../config-provider/SizeContext';
import LocaleReceiver from '../../locale-provider/LocaleReceiver';
-import { getRangePlaceholder } from '../util';
+import { getRangePlaceholder, transPlacement2DropdownAlign } from '../util';
import { RangePickerProps, PickerLocale, getTimeProps, Components } from '.';
import { PickerComponentClass } from './interface';
@@ -45,6 +45,7 @@ export default function generateRangePicker(
prefixCls: customizePrefixCls,
getPopupContainer: customGetPopupContainer,
className,
+ placement,
size: customizeSize,
bordered = true,
placeholder,
@@ -75,6 +76,7 @@ export default function generateRangePicker(
}
ref={this.pickerRef}
+ dropdownAlign={transPlacement2DropdownAlign(direction, placement)}
placeholder={getRangePlaceholder(picker, locale, placeholder)}
suffixIcon={picker === 'time' ? : }
clearIcon={}
diff --git a/components/date-picker/generatePicker/generateSinglePicker.tsx b/components/date-picker/generatePicker/generateSinglePicker.tsx
index d86f254201c6..2a8e13e2a4d7 100644
--- a/components/date-picker/generatePicker/generateSinglePicker.tsx
+++ b/components/date-picker/generatePicker/generateSinglePicker.tsx
@@ -5,7 +5,7 @@ import RCPicker from 'rc-picker';
import { PickerMode } from 'rc-picker/lib/interface';
import { GenerateConfig } from 'rc-picker/lib/generate/index';
import enUS from '../locale/en_US';
-import { getPlaceholder } from '../util';
+import { getPlaceholder, transPlacement2DropdownAlign } from '../util';
import devWarning from '../../_util/devWarning';
import { ConfigContext, ConfigConsumerProps } from '../../config-provider';
import LocaleReceiver from '../../locale-provider/LocaleReceiver';
@@ -19,9 +19,18 @@ import {
Components,
} from '.';
import { PickerComponentClass } from './interface';
+import { FormItemStatusContext } from '../../form/context';
+import {
+ getFeedbackIcon,
+ getMergedStatus,
+ getStatusClassNames,
+ InputStatus,
+} from '../../_util/statusUtils';
export default function generatePicker(generateConfig: GenerateConfig) {
- type DatePickerProps = PickerProps;
+ type DatePickerProps = PickerProps & {
+ status?: InputStatus;
+ };
function getPicker(
picker?: PickerMode,
@@ -57,6 +66,23 @@ export default function generatePicker(generateConfig: GenerateConfig<
}
};
+ renderFeedback = (prefixCls: string) => (
+
+ {({ hasFeedback, status: contextStatus }) => {
+ const { status: customStatus } = this.props;
+ const status = getMergedStatus(contextStatus, customStatus);
+ return hasFeedback && getFeedbackIcon(prefixCls, status);
+ }}
+
+ );
+
+ renderSuffix = (prefixCls: string, mergedPicker?: PickerMode) => (
+ <>
+ {mergedPicker === 'time' ? : }
+ {this.renderFeedback(prefixCls)}
+ >
+ );
+
renderPicker = (contextLocale: PickerLocale) => {
const locale = { ...contextLocale, ...this.props.locale };
const { getPrefixCls, direction, getPopupContainer } = this.context;
@@ -66,7 +92,9 @@ export default function generatePicker(generateConfig: GenerateConfig<
className,
size: customizeSize,
bordered = true,
+ placement,
placeholder,
+ status: customStatus,
...restProps
} = this.props;
const { format, showTime } = this.props as any;
@@ -97,36 +125,44 @@ export default function generatePicker(generateConfig: GenerateConfig<
const mergedSize = customizeSize || size;
return (
-
- ref={this.pickerRef}
- placeholder={getPlaceholder(mergedPicker, locale, placeholder)}
- suffixIcon={
- mergedPicker === 'time' ? :
- }
- clearIcon={}
- prevIcon={}
- nextIcon={}
- superPrevIcon={}
- superNextIcon={}
- allowClear
- transitionName={`${rootPrefixCls}-slide-up`}
- {...additionalProps}
- {...restProps}
- {...additionalOverrideProps}
- locale={locale!.lang}
- className={classNames(
- {
- [`${prefixCls}-${mergedSize}`]: mergedSize,
- [`${prefixCls}-borderless`]: !bordered,
- },
- className,
+
+ {({ hasFeedback, status: contextStatus }) => (
+
+ ref={this.pickerRef}
+ placeholder={getPlaceholder(mergedPicker, locale, placeholder)}
+ suffixIcon={this.renderSuffix(prefixCls, mergedPicker)}
+ dropdownAlign={transPlacement2DropdownAlign(direction, placement)}
+ clearIcon={}
+ prevIcon={}
+ nextIcon={}
+ superPrevIcon={}
+ superNextIcon={}
+ allowClear
+ transitionName={`${rootPrefixCls}-slide-up`}
+ {...additionalProps}
+ {...restProps}
+ {...additionalOverrideProps}
+ locale={locale!.lang}
+ className={classNames(
+ {
+ [`${prefixCls}-${mergedSize}`]: mergedSize,
+ [`${prefixCls}-borderless`]: !bordered,
+ },
+ getStatusClassNames(
+ prefixCls,
+ getMergedStatus(contextStatus, customStatus),
+ hasFeedback,
+ ),
+ className,
+ )}
+ prefixCls={prefixCls}
+ getPopupContainer={customizeGetPopupContainer || getPopupContainer}
+ generateConfig={generateConfig}
+ components={Components}
+ direction={direction}
+ />
)}
- prefixCls={prefixCls}
- getPopupContainer={customizeGetPopupContainer || getPopupContainer}
- generateConfig={generateConfig}
- components={Components}
- direction={direction}
- />
+
);
}}
diff --git a/components/date-picker/generatePicker/index.tsx b/components/date-picker/generatePicker/index.tsx
index adf7476f5b10..f6341c972408 100644
--- a/components/date-picker/generatePicker/index.tsx
+++ b/components/date-picker/generatePicker/index.tsx
@@ -19,6 +19,7 @@ import { TimePickerLocale } from '../../time-picker';
import generateSinglePicker from './generateSinglePicker';
import generateRangePicker from './generateRangePicker';
import { QuickPicker, IQuickDatePicker } from './QuickPicker';
+import { tuple } from '../../_util/type';
export const Components = { button: PickerButton, rangeItem: PickerTag };
@@ -29,13 +30,18 @@ function toArray(list: T | T[]): T[] {
return Array.isArray(list) ? list : [list];
}
-export function getTimeProps(
- props: { format?: string; picker?: PickerMode } & SharedTimeProps,
+export function getTimeProps(
+ props: { format?: string; picker?: PickerMode } & Omit<
+ SharedTimeProps,
+ 'disabledTime'
+ > & {
+ disabledTime?: DisabledTime;
+ },
) {
const { format, picker, showHour, showMinute, showSecond, use12Hours } = props;
const firstFormat = toArray(format)[0];
- const showTimeObj: SharedTimeProps = { ...props };
+ const showTimeObj = { ...props };
if (firstFormat && typeof firstFormat === 'string') {
if (!firstFormat.includes('s') && showSecond === undefined) {
@@ -66,6 +72,8 @@ export function getTimeProps(
showTime: showTimeObj,
};
}
+const DataPickerPlacements = tuple('bottomLeft', 'bottomRight', 'topLeft', 'topRight');
+type DataPickerPlacement = typeof DataPickerPlacements[number];
type InjectDefaultProps = Omit<
Props,
@@ -73,6 +81,7 @@ type InjectDefaultProps = Omit<
> & {
locale?: PickerLocale;
size?: SizeType;
+ placement?: DataPickerPlacement;
bordered?: boolean;
};
@@ -95,6 +104,7 @@ export type AdditionalPickerLocaleLangProps = {
monthPlaceholder?: string;
weekPlaceholder?: string;
rangeYearPlaceholder?: [string, string];
+ rangeQuarterPlaceholder?: [string, string];
rangeMonthPlaceholder?: [string, string];
rangeWeekPlaceholder?: [string, string];
rangePlaceholder?: [string, string];
diff --git a/components/date-picker/generatePicker/interface.tsx b/components/date-picker/generatePicker/interface.tsx
index 2daf343d66a0..c0771f2e0cac 100644
--- a/components/date-picker/generatePicker/interface.tsx
+++ b/components/date-picker/generatePicker/interface.tsx
@@ -1,4 +1,5 @@
-import { ComponentClass } from 'react';
+import type { ComponentClass, ForwardedRef, Component } from 'react';
+import { PickerProps, RangePickerProps } from '.';
export interface CommonPickerMethods {
focus: () => void;
@@ -9,3 +10,9 @@ export interface PickerComponentClass extends ComponentClas
new (...args: ConstructorParameters>): InstanceType> &
CommonPickerMethods;
}
+
+export type PickerRef = ForwardedRef & CommonPickerMethods>;
+
+export type DatePickRef = PickerRef>;
+
+export type RangePickerRef = PickerRef>;
diff --git a/components/date-picker/index.en-US.md b/components/date-picker/index.en-US.md
index 0a93414b4797..648ef673f1c0 100644
--- a/components/date-picker/index.en-US.md
+++ b/components/date-picker/index.en-US.md
@@ -69,9 +69,11 @@ The following APIs are shared by DatePicker, RangePicker.
| panelRender | Customize panel render | (panelNode) => ReactNode | - | 4.5.0 |
| picker | Set picker type | `date` \| `week` \| `month` \| `quarter` \| `year` | `date` | `quarter`: 4.1.0 |
| placeholder | The placeholder of date input | string \| \[string,string] | - | |
+| placement | The position where the selection box pops up | `bottomLeft` `bottomRight` `topLeft` `topRight` | bottomLeft | |
| popupStyle | To customize the style of the popup calendar | CSSProperties | {} | |
| prevIcon | The custom prev icon | ReactNode | - | 4.17.0 |
| size | To determine the size of the input box, the height of `large` and `small`, are 40px and 24px respectively, while default size is 32px | `large` \| `middle` \| `small` | - | |
+| status | Set validation status | 'error' \| 'warning' | - | 4.19.0 |
| style | To customize the style of the input box | CSSProperties | {} | |
| suffixIcon | The custom suffix icon | ReactNode | - | |
| superNextIcon | The custom super next icon | ReactNode | - | 4.17.0 |
diff --git a/components/date-picker/index.zh-CN.md b/components/date-picker/index.zh-CN.md
index a65f3d4431e5..e2780b3e5ee3 100644
--- a/components/date-picker/index.zh-CN.md
+++ b/components/date-picker/index.zh-CN.md
@@ -71,9 +71,11 @@ import locale from 'infrad/lib/locale/zh_CN';
| panelRender | 自定义渲染面板 | (panelNode) => ReactNode | - | 4.5.0 |
| picker | 设置选择器类型 | `date` \| `week` \| `month` \| `quarter` \| `year` | `date` | `quarter`: 4.1.0 |
| placeholder | 输入框提示文字 | string \| \[string, string] | - | |
+| placement | 选择框弹出的位置 | `bottomLeft` `bottomRight` `topLeft` `topRight` | bottomLeft | |
| popupStyle | 额外的弹出日历样式 | CSSProperties | {} | |
| prevIcon | 自定义上一个图标 | ReactNode | - | 4.17.0 |
| size | 输入框大小,`large` 高度为 40px,`small` 为 24px,默认是 32px | `large` \| `middle` \| `small` | - | |
+| status | 设置校验状态 | 'error' \| 'warning' | - | 4.19.0 |
| style | 自定义输入框样式 | CSSProperties | {} | |
| suffixIcon | 自定义的选择框后缀图标 | ReactNode | - | |
| superNextIcon | 自定义 `<<` 切换图标 | ReactNode | - | 4.17.0 |
diff --git a/components/date-picker/locale/en_GB.tsx b/components/date-picker/locale/en_GB.tsx
index 15cb6161b257..5e278f58c032 100644
--- a/components/date-picker/locale/en_GB.tsx
+++ b/components/date-picker/locale/en_GB.tsx
@@ -12,6 +12,7 @@ const locale: PickerLocale = {
weekPlaceholder: 'Select week',
rangePlaceholder: ['Start date', 'End date'],
rangeYearPlaceholder: ['Start year', 'End year'],
+ rangeQuarterPlaceholder: ['Start quarter', 'End quarter'],
rangeMonthPlaceholder: ['Start month', 'End month'],
rangeWeekPlaceholder: ['Start week', 'End week'],
...CalendarLocale,
diff --git a/components/date-picker/locale/en_US.tsx b/components/date-picker/locale/en_US.tsx
index 47b57b9eeb24..358216edd786 100644
--- a/components/date-picker/locale/en_US.tsx
+++ b/components/date-picker/locale/en_US.tsx
@@ -12,6 +12,7 @@ const locale: PickerLocale = {
weekPlaceholder: 'Select week',
rangePlaceholder: ['Start date', 'End date'],
rangeYearPlaceholder: ['Start year', 'End year'],
+ rangeQuarterPlaceholder: ['Start quarter', 'End quarter'],
rangeMonthPlaceholder: ['Start month', 'End month'],
rangeWeekPlaceholder: ['Start week', 'End week'],
...CalendarLocale,
diff --git a/components/date-picker/locale/zh_CN.tsx b/components/date-picker/locale/zh_CN.tsx
index bb3181123d8b..41df329de639 100644
--- a/components/date-picker/locale/zh_CN.tsx
+++ b/components/date-picker/locale/zh_CN.tsx
@@ -13,6 +13,7 @@ const locale: PickerLocale = {
rangePlaceholder: ['开始日期', '结束日期'],
rangeYearPlaceholder: ['开始年份', '结束年份'],
rangeMonthPlaceholder: ['开始月份', '结束月份'],
+ rangeQuarterPlaceholder: ['开始季度', '结束季度'],
rangeWeekPlaceholder: ['开始周', '结束周'],
...CalendarLocale,
},
diff --git a/components/date-picker/locale/zh_TW.tsx b/components/date-picker/locale/zh_TW.tsx
index 663e94380282..f0bcf20c1e34 100644
--- a/components/date-picker/locale/zh_TW.tsx
+++ b/components/date-picker/locale/zh_TW.tsx
@@ -13,6 +13,7 @@ const locale: PickerLocale = {
rangePlaceholder: ['開始日期', '結束日期'],
rangeYearPlaceholder: ['開始年份', '結束年份'],
rangeMonthPlaceholder: ['開始月份', '結束月份'],
+ rangeQuarterPlaceholder: ['開始季度', '結束季度'],
rangeWeekPlaceholder: ['開始周', '結束周'],
...CalendarLocale,
},
diff --git a/components/date-picker/style/index.less b/components/date-picker/style/index.less
index fe07cffcaf71..c0f0a2d88bb3 100644
--- a/components/date-picker/style/index.less
+++ b/components/date-picker/style/index.less
@@ -1,6 +1,7 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import '../../input/style/mixin';
+@import './status';
@picker-prefix-cls: ~'@{ant-prefix}-picker';
@@ -13,7 +14,7 @@
}
.@{picker-prefix-cls} {
- @arrow-size: 10px;
+ @arrow-size: @popover-arrow-width;
.reset-component();
.picker-padding(@input-height-base, @font-size-base, @input-padding-horizontal-base);
@@ -106,6 +107,8 @@
}
&-suffix {
+ display: flex;
+ flex: none;
align-self: center;
margin-left: (@padding-xs / 2);
color: @disabled-color;
@@ -114,6 +117,10 @@
> * {
vertical-align: top;
+
+ &:not(:last-child) {
+ margin-right: 8px;
+ }
}
}
@@ -221,17 +228,17 @@
&-placement-bottomLeft {
.@{picker-prefix-cls}-range-arrow {
- top: (@arrow-size / 2) - (@arrow-size / 3);
+ top: (@arrow-size / 2) - (@arrow-size / 3) + 0.7px;
display: block;
- transform: rotate(-45deg);
+ transform: rotate(-135deg) translateY(1px);
}
}
&-placement-topLeft {
.@{picker-prefix-cls}-range-arrow {
- bottom: (@arrow-size / 2) - (@arrow-size / 3);
+ bottom: (@arrow-size / 2) - (@arrow-size / 3) + 0.7px;
display: block;
- transform: rotate(135deg);
+ transform: rotate(45deg);
}
}
@@ -311,19 +318,14 @@
width: @arrow-size;
height: @arrow-size;
margin-left: @input-padding-horizontal-base * 1.5;
- box-shadow: 2px -2px 6px fade(@black, 6%);
+ background: linear-gradient(
+ 135deg,
+ transparent 40%,
+ @calendar-bg 40%
+ ); // Use linear-gradient to prevent arrow from covering text
+ box-shadow: 2px 2px 6px -2px fade(@black, 10%); // use spread radius to hide shadow over popover
transition: left @animation-duration-slow ease-out;
-
- &::after {
- position: absolute;
- top: @border-width-base;
- right: @border-width-base;
- width: @arrow-size;
- height: @arrow-size;
- border: (@arrow-size / 2) solid @border-color-split;
- border-color: @calendar-bg @calendar-bg transparent transparent;
- content: '';
- }
+ .roundedArrow(@arrow-size, 5px, @calendar-bg);
}
&-panel-container {
diff --git a/components/date-picker/style/index.tsx b/components/date-picker/style/index.tsx
index cc4424295a44..18447e360f85 100644
--- a/components/date-picker/style/index.tsx
+++ b/components/date-picker/style/index.tsx
@@ -3,3 +3,5 @@ import './index.less';
// style dependencies
import '../../tag/style';
import '../../button/style';
+
+// deps-lint-skip: form
diff --git a/components/date-picker/style/panel.less b/components/date-picker/style/panel.less
index 5c6ee0a4f0e8..fec6899f38c7 100644
--- a/components/date-picker/style/panel.less
+++ b/components/date-picker/style/panel.less
@@ -101,7 +101,7 @@
display: inline-block;
width: @picker-arrow-size;
height: @picker-arrow-size;
- border: 0 solid currentColor;
+ border: 0 solid currentcolor;
border-width: 1.5px 0 0 1.5px;
content: '';
}
@@ -116,7 +116,7 @@
display: inline-block;
width: @picker-arrow-size;
height: @picker-arrow-size;
- border: 0 solid currentColor;
+ border: 0 solid currentcolor;
border-width: 1.5px 0 0 1.5px;
content: '';
}
diff --git a/components/date-picker/style/status.less b/components/date-picker/style/status.less
new file mode 100644
index 000000000000..be3adba330e3
--- /dev/null
+++ b/components/date-picker/style/status.less
@@ -0,0 +1,52 @@
+@import '../../input/style/mixin';
+
+@picker-prefix-cls: ~'@{ant-prefix}-picker';
+
+.picker-status-color(
+ @text-color: @input-color;
+ @border-color: @input-border-color;
+ @background-color: @input-bg;
+ @hoverBorderColor: @primary-color-hover;
+ @outlineColor: @primary-color-outline;
+) {
+ &.@{picker-prefix-cls} {
+ &,
+ &:not([disabled]):hover {
+ background-color: @background-color;
+ border-color: @border-color;
+ }
+
+ &-focused,
+ &:focus {
+ .active(@text-color, @hoverBorderColor, @outlineColor);
+ }
+ }
+
+ .@{picker-prefix-cls}-feedback-icon {
+ color: @text-color;
+ }
+}
+
+.@{picker-prefix-cls} {
+ &-status-error {
+ .picker-status-color(@error-color, @error-color, @input-bg, @error-color-hover, @error-color-outline);
+ }
+
+ &-status-warning {
+ .picker-status-color(@warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);
+ }
+
+ &-status-validating {
+ .@{picker-prefix-cls}-feedback-icon {
+ display: inline-block;
+ color: @primary-color;
+ }
+ }
+
+ &-status-success {
+ .@{picker-prefix-cls}-feedback-icon {
+ color: @success-color;
+ animation-name: diffZoomIn1 !important;
+ }
+ }
+}
diff --git a/components/date-picker/util.ts b/components/date-picker/util.ts
index 0643a0842a16..c2dbc6c50132 100644
--- a/components/date-picker/util.ts
+++ b/components/date-picker/util.ts
@@ -1,4 +1,6 @@
import { PickerMode } from 'rc-picker/lib/interface';
+import { DirectionType } from '../config-provider';
+import { SelectCommonPlacement } from '../_util/motion';
import { PickerLocale } from './generatePicker';
export function getPlaceholder(
@@ -40,6 +42,9 @@ export function getRangePlaceholder(
if (picker === 'year' && locale.lang.yearPlaceholder) {
return locale.lang.rangeYearPlaceholder;
}
+ if (picker === 'quarter' && locale.lang.quarterPlaceholder) {
+ return locale.lang.rangeQuarterPlaceholder;
+ }
if (picker === 'month' && locale.lang.monthPlaceholder) {
return locale.lang.rangeMonthPlaceholder;
}
@@ -51,3 +56,56 @@ export function getRangePlaceholder(
}
return locale.lang.rangePlaceholder;
}
+
+export function transPlacement2DropdownAlign(
+ direction: DirectionType,
+ placement?: SelectCommonPlacement,
+) {
+ const overflow = {
+ adjustX: 1,
+ adjustY: 1,
+ };
+ switch (placement) {
+ case 'bottomLeft': {
+ return {
+ points: ['tl', 'bl'],
+ offset: [0, 4],
+ overflow,
+ };
+ }
+ case 'bottomRight': {
+ return {
+ points: ['tr', 'br'],
+ offset: [0, 4],
+ overflow,
+ };
+ }
+ case 'topLeft': {
+ return {
+ points: ['bl', 'tl'],
+ offset: [0, -4],
+ overflow,
+ };
+ }
+ case 'topRight': {
+ return {
+ points: ['br', 'tr'],
+ offset: [0, -4],
+ overflow,
+ };
+ }
+ default: {
+ return direction === 'rtl'
+ ? {
+ points: ['tr', 'br'],
+ offset: [0, 4],
+ overflow,
+ }
+ : {
+ points: ['tl', 'bl'],
+ offset: [0, 4],
+ overflow,
+ };
+ }
+ }
+}
diff --git a/components/divider/index.tsx b/components/divider/index.tsx
index e45e8a9e60ea..aa52bdd74d74 100644
--- a/components/divider/index.tsx
+++ b/components/divider/index.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
import classNames from 'classnames';
-import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
+import { ConfigContext } from '../config-provider';
export interface DividerProps {
prefixCls?: string;
@@ -14,56 +14,54 @@ export interface DividerProps {
plain?: boolean;
}
-const Divider: React.FC = props => (
-
- {({ getPrefixCls, direction }: ConfigConsumerProps) => {
- const {
- prefixCls: customizePrefixCls,
- type = 'horizontal',
- orientation = 'center',
- orientationMargin,
- className,
- children,
- dashed,
- plain,
- ...restProps
- } = props;
- const prefixCls = getPrefixCls('divider', customizePrefixCls);
- const orientationPrefix = orientation.length > 0 ? `-${orientation}` : orientation;
- const hasChildren = !!children;
- const hasCustomMarginLeft = orientation === 'left' && orientationMargin != null;
- const hasCustomMarginRight = orientation === 'right' && orientationMargin != null;
- const classString = classNames(
- prefixCls,
- `${prefixCls}-${type}`,
- {
- [`${prefixCls}-with-text`]: hasChildren,
- [`${prefixCls}-with-text${orientationPrefix}`]: hasChildren,
- [`${prefixCls}-dashed`]: !!dashed,
- [`${prefixCls}-plain`]: !!plain,
- [`${prefixCls}-rtl`]: direction === 'rtl',
- [`${prefixCls}-no-default-orientation-margin-left`]: hasCustomMarginLeft,
- [`${prefixCls}-no-default-orientation-margin-right`]: hasCustomMarginRight,
- },
- className,
- );
+const Divider: React.FC = props => {
+ const { getPrefixCls, direction } = React.useContext(ConfigContext);
- const innerStyle = {
- ...(hasCustomMarginLeft && { marginLeft: orientationMargin }),
- ...(hasCustomMarginRight && { marginRight: orientationMargin }),
- };
+ const {
+ prefixCls: customizePrefixCls,
+ type = 'horizontal',
+ orientation = 'center',
+ orientationMargin,
+ className,
+ children,
+ dashed,
+ plain,
+ ...restProps
+ } = props;
+ const prefixCls = getPrefixCls('divider', customizePrefixCls);
+ const orientationPrefix = orientation.length > 0 ? `-${orientation}` : orientation;
+ const hasChildren = !!children;
+ const hasCustomMarginLeft = orientation === 'left' && orientationMargin != null;
+ const hasCustomMarginRight = orientation === 'right' && orientationMargin != null;
+ const classString = classNames(
+ prefixCls,
+ `${prefixCls}-${type}`,
+ {
+ [`${prefixCls}-with-text`]: hasChildren,
+ [`${prefixCls}-with-text${orientationPrefix}`]: hasChildren,
+ [`${prefixCls}-dashed`]: !!dashed,
+ [`${prefixCls}-plain`]: !!plain,
+ [`${prefixCls}-rtl`]: direction === 'rtl',
+ [`${prefixCls}-no-default-orientation-margin-left`]: hasCustomMarginLeft,
+ [`${prefixCls}-no-default-orientation-margin-right`]: hasCustomMarginRight,
+ },
+ className,
+ );
- return (
-
- {children && (
-
- {children}
-
- )}
-
- );
- }}
-
-);
+ const innerStyle = {
+ ...(hasCustomMarginLeft && { marginLeft: orientationMargin }),
+ ...(hasCustomMarginRight && { marginRight: orientationMargin }),
+ };
+
+ return (
+
+ {children && (
+
+ {children}
+
+ )}
+
+ );
+};
export default Divider;
diff --git a/components/divider/style/index.less b/components/divider/style/index.less
index ba271e05397e..ff7e932ef09d 100644
--- a/components/divider/style/index.less
+++ b/components/divider/style/index.less
@@ -13,7 +13,7 @@
top: -0.06em;
display: inline-block;
height: 0.9em;
- margin: 0 8px;
+ margin: 0 @divider-vertical-gutter;
vertical-align: middle;
border-top: 0;
border-left: @border-width-base solid @divider-color;
diff --git a/components/drawer/__tests__/__snapshots__/DrawerEvent.test.js.snap b/components/drawer/__tests__/__snapshots__/DrawerEvent.test.js.snap
index 944ad8b1aa4b..5b0680e6b11c 100644
--- a/components/drawer/__tests__/__snapshots__/DrawerEvent.test.js.snap
+++ b/components/drawer/__tests__/__snapshots__/DrawerEvent.test.js.snap
@@ -3,7 +3,7 @@
exports[`Drawer render correctly 1`] = `
,
- bottomCenter
+ bottom
,
@@ -429,7 +429,7 @@ Array [
,
@@ -643,7 +643,7 @@ Array [
,
,
@@ -856,11 +856,11 @@ Array [
,
- topCenter
+ top
,
@@ -1069,7 +1069,1291 @@ Array [
,
+
+ topRight
+
+ ,
+ ,
+]
+`;
+
+exports[`renders ./components/dropdown/demo/arrow-center.md extend context correctly 1`] = `
+Array [
+
+
+ bottomLeft
+
+ ,
+ ,
+
+
+ bottom
+
+ ,
+ ,
+
+
+ bottomRight
+
+ ,
+ ,
+ ,
+
+
+ topLeft
+
+ ,
+ ,
+
+
+ top
+
+ ,
+ ,
+
@@ -1797,7 +3081,7 @@ exports[`renders ./components/dropdown/demo/dropdown-button.md extend context co
class="ant-btn-group ant-dropdown-button"
>
@@ -1805,7 +3089,7 @@ exports[`renders ./components/dropdown/demo/dropdown-button.md extend context co
@@ -2087,7 +3371,7 @@ exports[`renders ./components/dropdown/demo/dropdown-button.md extend context co
@@ -2370,7 +3654,7 @@ exports[`renders ./components/dropdown/demo/dropdown-button.md extend context co
@@ -2645,7 +3929,7 @@ exports[`renders ./components/dropdown/demo/dropdown-button.md extend context co
class="ant-btn-group ant-dropdown-button"
>
@@ -2677,7 +3961,7 @@ exports[`renders ./components/dropdown/demo/dropdown-button.md extend context co
@@ -4066,7 +5350,7 @@ exports[`renders ./components/dropdown/demo/loading.md extend context correctly
class="ant-btn-group ant-dropdown-button"
>
@@ -4074,7 +5358,7 @@ exports[`renders ./components/dropdown/demo/loading.md extend context correctly
@@ -5750,11 +7034,11 @@ exports[`renders ./components/dropdown/demo/placement.md extend context correctl
style="margin-right:16px;padding-bottom:16px"
>
- bottomCenter
+ bottom
@@ -5965,7 +7249,7 @@ exports[`renders ./components/dropdown/demo/placement.md extend context correctl
style="padding-bottom:16px"
>
@@ -6189,7 +7473,7 @@ exports[`renders ./components/dropdown/demo/placement.md extend context correctl
style="margin-right:16px;padding-bottom:16px"
>
@@ -6404,11 +7688,11 @@ exports[`renders ./components/dropdown/demo/placement.md extend context correctl
style="margin-right:16px;padding-bottom:16px"
>
- topCenter
+ top
@@ -6619,7 +7903,7 @@ exports[`renders ./components/dropdown/demo/placement.md extend context correctl
style="padding-bottom:16px"
>
diff --git a/components/dropdown/__tests__/__snapshots__/demo.test.js.snap b/components/dropdown/__tests__/__snapshots__/demo.test.js.snap
index 91b454afb3db..9ad5849c4273 100644
--- a/components/dropdown/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/dropdown/__tests__/__snapshots__/demo.test.js.snap
@@ -3,7 +3,7 @@
exports[`renders ./components/dropdown/demo/arrow.md correctly 1`] = `
Array [
@@ -11,15 +11,15 @@ Array [
,
- bottomCenter
+ bottom
,
@@ -28,7 +28,7 @@ Array [
,
,
@@ -36,15 +36,69 @@ Array [
,
- topCenter
+ top
,
+
+ topRight
+
+ ,
+]
+`;
+
+exports[`renders ./components/dropdown/demo/arrow-center.md correctly 1`] = `
+Array [
+
+
+ bottomLeft
+
+ ,
+
+
+ bottom
+
+ ,
+
+
+ bottomRight
+
+ ,
+ ,
+
+
+ topLeft
+
+ ,
+
+
+ top
+
+ ,
+
@@ -103,7 +157,7 @@ exports[`renders ./components/dropdown/demo/dropdown-button.md correctly 1`] = `
class="ant-btn-group ant-dropdown-button"
>
@@ -111,7 +165,7 @@ exports[`renders ./components/dropdown/demo/dropdown-button.md correctly 1`] = `
@@ -152,7 +206,7 @@ exports[`renders ./components/dropdown/demo/dropdown-button.md correctly 1`] = `
@@ -194,7 +248,7 @@ exports[`renders ./components/dropdown/demo/dropdown-button.md correctly 1`] = `
@@ -228,7 +282,7 @@ exports[`renders ./components/dropdown/demo/dropdown-button.md correctly 1`] = `
class="ant-btn-group ant-dropdown-button"
>
@@ -236,7 +290,7 @@ exports[`renders ./components/dropdown/demo/dropdown-button.md correctly 1`] = `
@@ -534,7 +588,7 @@ exports[`renders ./components/dropdown/demo/loading.md correctly 1`] = `
class="ant-btn-group ant-dropdown-button"
>
@@ -542,7 +596,7 @@ exports[`renders ./components/dropdown/demo/loading.md correctly 1`] = `
@@ -654,11 +708,11 @@ exports[`renders ./components/dropdown/demo/placement.md correctly 1`] = `
style="margin-right:16px;padding-bottom:16px"
>
- bottomCenter
+ bottom
@@ -667,7 +721,7 @@ exports[`renders ./components/dropdown/demo/placement.md correctly 1`] = `
style="padding-bottom:16px"
>
@@ -689,7 +743,7 @@ exports[`renders ./components/dropdown/demo/placement.md correctly 1`] = `
style="margin-right:16px;padding-bottom:16px"
>
@@ -702,11 +756,11 @@ exports[`renders ./components/dropdown/demo/placement.md correctly 1`] = `
style="margin-right:16px;padding-bottom:16px"
>
- topCenter
+ top
@@ -715,7 +769,7 @@ exports[`renders ./components/dropdown/demo/placement.md correctly 1`] = `
style="padding-bottom:16px"
>
diff --git a/components/dropdown/__tests__/__snapshots__/dropdown-button.test.js.snap b/components/dropdown/__tests__/__snapshots__/dropdown-button.test.js.snap
index 36c779c63a8c..5d60222278ca 100644
--- a/components/dropdown/__tests__/__snapshots__/dropdown-button.test.js.snap
+++ b/components/dropdown/__tests__/__snapshots__/dropdown-button.test.js.snap
@@ -5,11 +5,11 @@ exports[`DropdownButton rtl render component should be rendered correctly in RTL
class="ant-btn-group ant-btn-group-rtl ant-dropdown-button"
>
button
@@ -24,7 +24,7 @@ Array [
exports[`Dropdown overlay is string 1`] = `
Array [
button
diff --git a/components/dropdown/__tests__/index.test.js b/components/dropdown/__tests__/index.test.js
index 06631ea92ac3..dc97a9bb8f82 100644
--- a/components/dropdown/__tests__/index.test.js
+++ b/components/dropdown/__tests__/index.test.js
@@ -59,4 +59,24 @@ describe('Dropdown', () => {
await sleep(500);
expect(wrapper.find(Dropdown).find('#customExpandIcon').length).toBe(1);
});
+
+ it('should warn if use topCenter or bottomCenter', () => {
+ const error = jest.spyOn(console, 'error');
+ mount(
+
+
+ bottomCenter
+
+
+ topCenter
+
+ ,
+ );
+ expect(error).toHaveBeenCalledWith(
+ expect.stringContaining("[antd: Dropdown] You are using 'bottomCenter'"),
+ );
+ expect(error).toHaveBeenCalledWith(
+ expect.stringContaining("[antd: Dropdown] You are using 'topCenter'"),
+ );
+ });
});
diff --git a/components/dropdown/demo/arrow-center.md b/components/dropdown/demo/arrow-center.md
new file mode 100644
index 000000000000..d1680ba8f319
--- /dev/null
+++ b/components/dropdown/demo/arrow-center.md
@@ -0,0 +1,75 @@
+---
+order: 3
+title:
+ zh-CN: 箭头指向
+ en-US: Arrow pointing at the center
+---
+
+## zh-CN
+
+设置 `arrow` 为 `{ pointAtCenter: true }` 后,箭头将指向目标元素的中心。
+
+## en-US
+
+By specifying `arrow` prop with `{ pointAtCenter: true }`, the arrow will point to the center of the target element.
+
+```jsx
+import { Menu, Dropdown, Button } from 'infrad';
+
+const menu = (
+
+);
+
+ReactDOM.render(
+ <>
+
+ bottomLeft
+
+
+ bottom
+
+
+ bottomRight
+
+
+
+ topLeft
+
+
+ top
+
+
+ topRight
+
+ >,
+ mountNode,
+);
+```
+
+```css
+#components-dropdown-demo-arrow-center .ant-btn {
+ margin-right: 8px;
+ margin-bottom: 8px;
+}
+.ant-row-rtl #components-dropdown-demo-arrow-center .ant-btn {
+ margin-right: 0;
+ margin-bottom: 8px;
+ margin-left: 8px;
+}
+```
diff --git a/components/dropdown/demo/arrow.md b/components/dropdown/demo/arrow.md
index 25349cc675e2..6808bc1dd77f 100644
--- a/components/dropdown/demo/arrow.md
+++ b/components/dropdown/demo/arrow.md
@@ -41,8 +41,8 @@ ReactDOM.render(
bottomLeft
-
- bottomCenter
+
+ bottom
bottomRight
@@ -51,8 +51,8 @@ ReactDOM.render(
topLeft
-
- topCenter
+
+ top
topRight
diff --git a/components/dropdown/demo/dropdown-button.md b/components/dropdown/demo/dropdown-button.md
index e4bd6ef2ef9b..c2817dac4319 100644
--- a/components/dropdown/demo/dropdown-button.md
+++ b/components/dropdown/demo/dropdown-button.md
@@ -46,7 +46,7 @@ ReactDOM.render(
Dropdown
- }>
+ }>
Dropdown
diff --git a/components/dropdown/demo/placement.md b/components/dropdown/demo/placement.md
index a320707263f4..42bf616c5538 100644
--- a/components/dropdown/demo/placement.md
+++ b/components/dropdown/demo/placement.md
@@ -42,8 +42,8 @@ ReactDOM.render(
bottomLeft
-
- bottomCenter
+
+ bottom
bottomRight
@@ -53,8 +53,8 @@ ReactDOM.render(
topLeft
-
- topCenter
+
+ top
topRight
diff --git a/components/dropdown/dropdown.tsx b/components/dropdown/dropdown.tsx
index 1e15d97b005f..5293ffaeef56 100644
--- a/components/dropdown/dropdown.tsx
+++ b/components/dropdown/dropdown.tsx
@@ -7,6 +7,7 @@ import { ConfigContext } from '../config-provider';
import devWarning from '../_util/devWarning';
import { tuple } from '../_util/type';
import { cloneElement } from '../_util/reactNode';
+import getPlacements from '../_util/placements';
const Placements = tuple(
'topLeft',
@@ -15,6 +16,8 @@ const Placements = tuple(
'bottomLeft',
'bottomCenter',
'bottomRight',
+ 'top',
+ 'bottom',
);
type Placement = typeof Placements[number];
@@ -34,8 +37,12 @@ type Align = {
useCssTransform?: boolean;
};
+export type DropdownArrowOptions = {
+ pointAtCenter?: boolean;
+};
+
export interface DropDownProps {
- arrow?: boolean;
+ arrow?: boolean | DropdownArrowOptions;
trigger?: ('click' | 'hover' | 'contextMenu')[];
overlay: React.ReactElement | OverlayFunc;
onVisibleChange?: (visible: boolean) => void;
@@ -129,10 +136,21 @@ const Dropdown: DropdownInterface = props => {
const getPlacement = () => {
const { placement } = props;
- if (placement !== undefined) {
- return placement;
+ if (!placement) {
+ return direction === 'rtl' ? ('bottomRight' as Placement) : ('bottomLeft' as Placement);
+ }
+
+ if (placement.includes('Center')) {
+ const newPlacement = placement.slice(0, placement.indexOf('Center'));
+ devWarning(
+ !placement.includes('Center'),
+ 'Dropdown',
+ `You are using '${placement}' placement in Dropdown, which is deprecated. Try to use '${newPlacement}' instead.`,
+ );
+ return newPlacement;
}
- return direction === 'rtl' ? ('bottomRight' as Placement) : ('bottomLeft' as Placement);
+
+ return placement;
};
const {
@@ -169,11 +187,16 @@ const Dropdown: DropdownInterface = props => {
alignPoint = true;
}
+ const builtinPlacements = getPlacements({
+ arrowPointAtCenter: typeof arrow === 'object' && arrow.pointAtCenter,
+ });
+
return (
HTMLElement | () => document.body | |
| overlay | The dropdown menu | [Menu](/components/menu) \| () => Menu | - | |
| overlayClassName | The class name of the dropdown root element | string | - | |
| overlayStyle | The style of the dropdown root element | CSSProperties | - | |
-| placement | Placement of popup menu: `bottomLeft`, `bottomCenter`, `bottomRight`, `topLeft`, `topCenter` or `topRight` | string | `bottomLeft` | |
+| placement | Placement of popup menu: `bottom` `bottomLeft` `bottomRight` `top` `topLeft` `topRight` | string | `bottomLeft` | |
| trigger | The trigger mode which executes the dropdown action. Note that hover can't be used on touchscreens | Array<`click`\|`hover`\|`contextMenu`> | \[`hover`] | |
| visible | Whether the dropdown menu is currently visible | boolean | - | |
| onVisibleChange | Called when the visible state is changed. Not trigger when hidden by click item | (visible: boolean) => void | - | |
@@ -44,7 +44,7 @@ You should use [Menu](/components/menu/) as `overlay`. The menu items and divide
| disabled | Whether the dropdown menu is disabled | boolean | - | |
| icon | Icon (appears on the right) | ReactNode | - | |
| overlay | The dropdown menu | [Menu](/components/menu) | - | |
-| placement | Placement of popup menu: `bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | string | `bottomLeft` | |
+| placement | Placement of popup menu: `bottom` `bottomLeft` `bottomRight` `top` `topLeft` `topRight` | string | `bottomLeft` | |
| size | Size of the button, the same as [Button](/components/button/#API) | string | `default` | |
| trigger | The trigger mode which executes the dropdown action | Array<`click`\|`hover`\|`contextMenu`> | \[`hover`] | |
| type | Type of the button, the same as [Button](/components/button/#API) | string | `default` | |
diff --git a/components/dropdown/index.zh-CN.md b/components/dropdown/index.zh-CN.md
index 15eccfea50b5..3ff8a060bdda 100644
--- a/components/dropdown/index.zh-CN.md
+++ b/components/dropdown/index.zh-CN.md
@@ -21,14 +21,14 @@ cover: https://gw.alipayobjects.com/zos/alicdn/eedWN59yJ/Dropdown.svg
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
-| arrow | 下拉框箭头是否显示 | boolean | false | |
+| arrow | 下拉框箭头是否显示 | boolean \| { pointAtCenter: boolean } | false | |
| disabled | 菜单是否禁用 | boolean | - | |
| destroyPopupOnHide | 关闭后是否销毁 Dropdown | boolean | false | |
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。[示例](https://codepen.io/afc163/pen/zEjNOy?editors=0010) | (triggerNode: HTMLElement) => HTMLElement | () => document.body | |
| overlay | 菜单 | [Menu](/components/menu) \| () => Menu | - | |
| overlayClassName | 下拉根元素的类名称 | string | - | |
| overlayStyle | 下拉根元素的样式 | CSSProperties | - | |
-| placement | 菜单弹出位置:`bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | string | `bottomLeft` | |
+| placement | 菜单弹出位置:`bottom` `bottomLeft` `bottomRight` `top` `topLeft` `topRight` | string | `bottomLeft` | |
| trigger | 触发下拉的行为, 移动端不支持 hover | Array<`click`\|`hover`\|`contextMenu`> | \[`hover`] | |
| visible | 菜单是否显示 | boolean | - | |
| onVisibleChange | 菜单显示状态改变时调用,参数为 `visible`。点击菜单按钮导致的消失不会触发 | (visible: boolean) => void | - | |
@@ -48,7 +48,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/eedWN59yJ/Dropdown.svg
| disabled | 菜单是否禁用 | boolean | - | |
| icon | 右侧的 icon | ReactNode | - | |
| overlay | 菜单 | [Menu](/components/menu/) | - | |
-| placement | 菜单弹出位置:`bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | string | `bottomLeft` | |
+| placement | 菜单弹出位置:`bottom` `bottomLeft` `bottomRight` `top` `topLeft` `topRight` | string | `bottomLeft` | |
| size | 按钮大小,和 [Button](/components/button/#API) 一致 | string | `default` | |
| trigger | 触发下拉的行为 | Array<`click`\|`hover`\|`contextMenu`> | \[`hover`] | |
| type | 按钮类型,和 [Button](/components/button/#API) 一致 | string | `default` | |
diff --git a/components/dropdown/style/index.less b/components/dropdown/style/index.less
index 2633d894177f..aa87f7ba4491 100644
--- a/components/dropdown/style/index.less
+++ b/components/dropdown/style/index.less
@@ -49,14 +49,14 @@
}
// Offset the popover to account for the dropdown arrow
- &-show-arrow&-placement-topCenter,
&-show-arrow&-placement-topLeft,
+ &-show-arrow&-placement-top,
&-show-arrow&-placement-topRight {
padding-bottom: @popover-distance;
}
- &-show-arrow&-placement-bottomCenter,
&-show-arrow&-placement-bottomLeft,
+ &-show-arrow&-placement-bottom,
&-show-arrow&-placement-bottomRight {
padding-top: @popover-distance;
}
@@ -68,23 +68,26 @@
position: absolute;
z-index: 1; // lift it up so the menu wouldn't cask shadow on it
display: block;
- width: sqrt(@popover-arrow-width * @popover-arrow-width * 2);
- height: sqrt(@popover-arrow-width * @popover-arrow-width * 2);
- background: transparent;
- border-style: solid;
- border-width: (sqrt(@popover-arrow-width * @popover-arrow-width * 2) / 2);
- transform: rotate(45deg);
+ width: @popover-arrow-width;
+ height: @popover-arrow-width;
+ background: linear-gradient(
+ 135deg,
+ transparent 40%,
+ @popover-bg 40%
+ ); // Use linear-gradient to prevent arrow from covering text
+ .roundedArrow(@popover-arrow-width, 5px, @popover-bg);
}
- &-placement-topCenter > &-arrow,
+ &-placement-top > &-arrow,
&-placement-topLeft > &-arrow,
&-placement-topRight > &-arrow {
- bottom: @popover-distance - @popover-arrow-width + 2.2px;
+ bottom: @popover-arrow-width * sqrt((1 / 2)) + 2px;
border-color: transparent @popover-bg @popover-bg transparent;
- box-shadow: 3px 3px 7px fade(@black, 7%);
+ box-shadow: 3px 3px 7px -3px fade(@black, 10%);
+ transform: rotate(45deg);
}
- &-placement-topCenter > &-arrow {
+ &-placement-top > &-arrow {
left: 50%;
transform: translateX(-50%) rotate(45deg);
}
@@ -97,17 +100,18 @@
right: 16px;
}
- &-placement-bottomCenter > &-arrow,
+ &-placement-bottom > &-arrow,
&-placement-bottomLeft > &-arrow,
&-placement-bottomRight > &-arrow {
- top: @popover-distance - @popover-arrow-width + 2px;
+ top: (@popover-arrow-width + 2px) * sqrt((1 / 2));
border-color: @popover-bg transparent transparent @popover-bg;
- box-shadow: -2px -2px 5px fade(@black, 6%);
+ box-shadow: 2px 2px 5px -2px fade(@black, 10%);
+ transform: rotate(-135deg) translateY(-0.5px);
}
- &-placement-bottomCenter > &-arrow {
+ &-placement-bottom > &-arrow {
left: 50%;
- transform: translateX(-50%) rotate(45deg);
+ transform: translateX(-50%) rotate(-135deg) translateY(-0.5px);
}
&-placement-bottomLeft > &-arrow {
@@ -199,7 +203,6 @@
font-weight: normal;
font-size: @dropdown-font-size;
line-height: @dropdown-line-height;
- white-space: nowrap;
cursor: pointer;
transition: all @animation-duration-slow;
@@ -217,7 +220,7 @@
&-selected {
color: @dropdown-selected-color;
- background-color: @item-active-bg;
+ background-color: @dropdown-selected-bg;
}
&:hover {
@@ -300,8 +303,8 @@
&.@{ant-prefix}-slide-down-enter.@{ant-prefix}-slide-down-enter-active&-placement-bottomLeft,
&.@{ant-prefix}-slide-down-appear.@{ant-prefix}-slide-down-appear-active&-placement-bottomLeft,
- &.@{ant-prefix}-slide-down-enter.@{ant-prefix}-slide-down-enter-active&-placement-bottomCenter,
- &.@{ant-prefix}-slide-down-appear.@{ant-prefix}-slide-down-appear-active&-placement-bottomCenter,
+ &.@{ant-prefix}-slide-down-enter.@{ant-prefix}-slide-down-enter-active&-placement-bottom,
+ &.@{ant-prefix}-slide-down-appear.@{ant-prefix}-slide-down-appear-active&-placement-bottom,
&.@{ant-prefix}-slide-down-enter.@{ant-prefix}-slide-down-enter-active&-placement-bottomRight,
&.@{ant-prefix}-slide-down-appear.@{ant-prefix}-slide-down-appear-active&-placement-bottomRight {
animation-name: antSlideUpIn;
@@ -309,21 +312,21 @@
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topLeft,
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topLeft,
- &.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topCenter,
- &.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topCenter,
+ &.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-top,
+ &.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-top,
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topRight,
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topRight {
animation-name: antSlideDownIn;
}
&.@{ant-prefix}-slide-down-leave.@{ant-prefix}-slide-down-leave-active&-placement-bottomLeft,
- &.@{ant-prefix}-slide-down-leave.@{ant-prefix}-slide-down-leave-active&-placement-bottomCenter,
+ &.@{ant-prefix}-slide-down-leave.@{ant-prefix}-slide-down-leave-active&-placement-bottom,
&.@{ant-prefix}-slide-down-leave.@{ant-prefix}-slide-down-leave-active&-placement-bottomRight {
animation-name: antSlideUpOut;
}
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topLeft,
- &.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topCenter,
+ &.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-top,
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topRight {
animation-name: antSlideDownOut;
}
diff --git a/components/form/FormItem.tsx b/components/form/FormItem.tsx
index d04a33850fdf..d879c2cab03b 100644
--- a/components/form/FormItem.tsx
+++ b/components/form/FormItem.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { useContext } from 'react';
+import { useContext, useMemo } from 'react';
import classNames from 'classnames';
import { Field, FormInstance, FieldContext, ListContext } from 'rc-field-form';
import { FieldProps } from 'rc-field-form/lib/Field';
@@ -12,7 +12,12 @@ import { tuple } from '../_util/type';
import devWarning from '../_util/devWarning';
import FormItemLabel, { FormItemLabelProps, LabelTooltipType } from './FormItemLabel';
import FormItemInput, { FormItemInputProps } from './FormItemInput';
-import { FormContext, NoStyleItemContext } from './context';
+import {
+ FormContext,
+ FormItemStatusContext,
+ NoStyleItemContext,
+ FormItemStatusContextProps,
+} from './context';
import { toArray, getFieldId } from './util';
import { cloneElement, isValidElement } from '../_util/reactNode';
import useFrameState from './hooks/useFrameState';
@@ -199,6 +204,28 @@ function FormItem(props: FormItemProps): React.ReactElemen
// ===================== Children Ref =====================
const getItemRef = useItemRef();
+ // ======================== Status ========================
+ let mergedValidateStatus: ValidateStatus = '';
+ if (validateStatus !== undefined) {
+ mergedValidateStatus = validateStatus;
+ } else if (meta?.validating) {
+ mergedValidateStatus = 'validating';
+ } else if (debounceErrors.length) {
+ mergedValidateStatus = 'error';
+ } else if (debounceWarnings.length) {
+ mergedValidateStatus = 'warning';
+ } else if (meta?.touched) {
+ mergedValidateStatus = 'success';
+ }
+
+ const formItemStatusContext = useMemo(
+ () => ({
+ status: mergedValidateStatus,
+ hasFeedback,
+ }),
+ [mergedValidateStatus, hasFeedback],
+ );
+
// ======================== Render ========================
function renderLayout(
baseChildren: React.ReactNode,
@@ -208,19 +235,6 @@ function FormItem(props: FormItemProps): React.ReactElemen
if (noStyle && !hidden) {
return baseChildren;
}
- // ======================== Status ========================
- let mergedValidateStatus: ValidateStatus = '';
- if (validateStatus !== undefined) {
- mergedValidateStatus = validateStatus;
- } else if (meta?.validating) {
- mergedValidateStatus = 'validating';
- } else if (debounceErrors.length) {
- mergedValidateStatus = 'error';
- } else if (debounceWarnings.length) {
- mergedValidateStatus = 'warning';
- } else if (meta?.touched) {
- mergedValidateStatus = 'success';
- }
const itemClassName = {
[`${prefixCls}-item`]: true,
@@ -281,11 +295,12 @@ function FormItem(props: FormItemProps): React.ReactElemen
warnings={debounceWarnings}
prefixCls={prefixCls}
status={mergedValidateStatus}
- validateStatus={mergedValidateStatus}
help={help}
>
- {baseChildren}
+
+ {baseChildren}
+
diff --git a/components/form/FormItemInput.tsx b/components/form/FormItemInput.tsx
index f327707f1b35..4b4c2c86415c 100644
--- a/components/form/FormItemInput.tsx
+++ b/components/form/FormItemInput.tsx
@@ -1,12 +1,5 @@
import * as React from 'react';
import classNames from 'classnames';
-import {
- LoadingOutlined,
- CloseCircleFilled,
- CheckCircleFilled,
- ExclamationCircleFilled,
-} from 'infra-design-icons';
-
import Col, { ColProps } from '../grid/col';
import { ValidateStatus } from './FormItem';
import { FormContext, FormItemPrefixContext } from './context';
@@ -17,8 +10,6 @@ interface FormItemInputMiscProps {
children: React.ReactNode;
errors: React.ReactNode[];
warnings: React.ReactNode[];
- hasFeedback?: boolean;
- validateStatus?: ValidateStatus;
/** @private Internal Usage, do not use in any of your production. */
_internalItemRender?: {
mark: string;
@@ -40,13 +31,6 @@ export interface FormItemInputProps {
help?: React.ReactNode;
}
-const iconMap: { [key: string]: any } = {
- success: CheckCircleFilled,
- warning: ExclamationCircleFilled,
- error: CloseCircleFilled,
- validating: LoadingOutlined,
-};
-
const FormItemInput: React.FC = props => {
const {
prefixCls,
@@ -55,9 +39,7 @@ const FormItemInput: React.FC = pro
children,
errors,
warnings,
- hasFeedback,
_internalItemRender: formItemRender,
- validateStatus,
extra,
help,
} = props;
@@ -69,15 +51,6 @@ const FormItemInput: React.FC = pro
const className = classNames(`${baseClassName}-control`, mergedWrapperCol.className);
- // Should provides additional icon if `hasFeedback`
- const IconNode = validateStatus && iconMap[validateStatus];
- const icon =
- hasFeedback && IconNode ? (
-
-
-
- ) : null;
-
// Pass to sub FormItem should not with col info
const subFormContext = React.useMemo(() => ({ ...formContext }), [formContext]);
delete subFormContext.labelCol;
@@ -86,7 +59,6 @@ const FormItemInput: React.FC = pro
const inputDom = (
);
const formItemContext = React.useMemo(() => ({ prefixCls, status }), [prefixCls, status]);
diff --git a/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap b/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap
index 3e046b1e049e..2f47644a7115 100644
--- a/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap
+++ b/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap
@@ -76,13 +76,148 @@ exports[`renders ./components/form/demo/advanced-search.md extend context correc
-
+
+
+
+
+
+
+ longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
+
+
+
+
+
+
+
+
+
+
+
+
+
+ longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -193,13 +328,148 @@ exports[`renders ./components/form/demo/advanced-search.md extend context correc
-
+
+
+
+
+
+
+ longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
+
+
+
+
+
+
+
+
+
+
+
+
+
+ longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -261,7 +531,7 @@ exports[`renders ./components/form/demo/advanced-search.md extend context correc
@@ -846,7 +1116,7 @@ exports[`renders ./components/form/demo/control-hooks.md extend context correctl
@@ -1112,7 +1382,7 @@ exports[`renders ./components/form/demo/control-ref.md extend context correctly
@@ -1477,7 +1747,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md extend context c
class="ant-form-item-control-input-content"
>
@@ -2979,9 +3249,26 @@ exports[`renders ./components/form/demo/label-debug.md extend context correctly
title=""
>
longtextlongtextlongtextlongtextlongtextlongtextlongtext
+
+ lg
+
+
+
+ ...
+
+
@@ -3016,9 +3303,26 @@ exports[`renders ./components/form/demo/label-debug.md extend context correctly
title=""
>
longtext longtext longtext longtext longtext longtext longtext
+
+ lg
+
+
+
+ ...
+
+
@@ -3886,7 +4190,7 @@ exports[`renders ./components/form/demo/ref-item.md extend context correctly 1`]
@@ -3958,7 +4262,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
class="ant-form-item-control-input-content"
>
@@ -6856,7 +7160,7 @@ exports[`renders ./components/form/demo/size.md extend context correctly 1`] = `
class="ant-form-item-control-input-content"
>
@@ -14476,7 +14780,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
class="ant-form-item-control-input-content"
>
@@ -16193,38 +16513,46 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
>
-
-
-
-
+
-
-
+
+
+
+
+
+
-
+
@@ -16246,41 +16574,49 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
>
@@ -16911,29 +17270,6 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
-
-
-
-
-
@@ -16960,7 +17296,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
class="ant-form-item-control-input-content"
>
@@ -18368,29 +18727,6 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
-
-
-
-
-
@@ -18417,7 +18753,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
class="ant-form-item-control-input-content"
>
+
+
+
@@ -18780,7 +19244,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
class="ant-form-item-control-input-content"
>
+
+
+
@@ -20306,9 +20895,9 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
>
-
-
+
+
+
-
-
-
-
+
-
-
-
-
-
+
@@ -20513,7 +21113,7 @@ exports[`renders ./components/form/demo/warning-only.md extend context correctly
class="ant-space-item"
>
diff --git a/components/form/__tests__/__snapshots__/demo.test.js.snap b/components/form/__tests__/__snapshots__/demo.test.js.snap
index 48a73ce5f347..81ad892d2ebc 100644
--- a/components/form/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/form/__tests__/__snapshots__/demo.test.js.snap
@@ -76,13 +76,66 @@ exports[`renders ./components/form/demo/advanced-search.md correctly 1`] = `
-
+
+
+
+
+
+
+ longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
+
+
+
+
+
+
+
+
@@ -193,13 +246,66 @@ exports[`renders ./components/form/demo/advanced-search.md correctly 1`] = `
-
+
+
+
+
+
+
+ longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
+
+
+
+
+
+
+
+
@@ -261,7 +367,7 @@ exports[`renders ./components/form/demo/advanced-search.md correctly 1`] = `
@@ -747,7 +853,7 @@ exports[`renders ./components/form/demo/control-hooks.md correctly 1`] = `
@@ -914,7 +1020,7 @@ exports[`renders ./components/form/demo/control-ref.md correctly 1`] = `
@@ -1197,7 +1303,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
class="ant-form-item-control-input-content"
>
@@ -2617,9 +2723,26 @@ exports[`renders ./components/form/demo/label-debug.md correctly 1`] = `
title=""
>
longtextlongtextlongtextlongtextlongtextlongtextlongtext
+
+ lg
+
+
+
+ ...
+
+
@@ -2654,9 +2777,26 @@ exports[`renders ./components/form/demo/label-debug.md correctly 1`] = `
title=""
>
longtext longtext longtext longtext longtext longtext longtext
+
+ lg
+
+
+
+ ...
+
+
@@ -3524,7 +3664,7 @@ exports[`renders ./components/form/demo/ref-item.md correctly 1`] = `
@@ -3596,7 +3736,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
@@ -5293,7 +5433,7 @@ exports[`renders ./components/form/demo/size.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
@@ -5888,7 +6028,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
@@ -7418,38 +7574,46 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
>
-
-
-
-
+
-
-
+
+
+
+
+
+
-
+
@@ -7474,38 +7638,46 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
>
-
-
-
-
+
-
-
+
+
+
+
+
+
-
+
-
-
-
-
-
@@ -7631,7 +7803,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
-
-
-
-
-
@@ -7723,7 +7895,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
-
-
-
-
-
@@ -8389,7 +8625,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
-
+
+
+
+
+
+
+
-
+
+
+
+
@@ -8581,7 +8940,7 @@ exports[`renders ./components/form/demo/warning-only.md correctly 1`] = `
class="ant-space-item"
>
diff --git a/components/form/context.tsx b/components/form/context.tsx
index 73801a8b1bbd..8ba6d2ac6b90 100644
--- a/components/form/context.tsx
+++ b/components/form/context.tsx
@@ -50,3 +50,10 @@ export interface FormItemPrefixContextProps {
export const FormItemPrefixContext = React.createContext({
prefixCls: '',
});
+
+export interface FormItemStatusContextProps {
+ status?: ValidateStatus;
+ hasFeedback?: boolean;
+}
+
+export const FormItemStatusContext = React.createContext({});
diff --git a/components/form/demo/advanced-search.md b/components/form/demo/advanced-search.md
index 9ea3e622e9d3..0df9ae20f0e6 100644
--- a/components/form/demo/advanced-search.md
+++ b/components/form/demo/advanced-search.md
@@ -21,9 +21,11 @@ Because the width of label is not fixed, you may need to adjust it by customizin
```tsx
import React, { useState } from 'react';
-import { Form, Row, Col, Input, Button } from 'infrad';
+import { Form, Row, Col, Input, Button, Select } from 'infrad';
import { DownOutlined, UpOutlined } from 'infra-design-icons';
+const { Option } = Select;
+
const AdvancedSearchForm = () => {
const [expand, setExpand] = useState(false);
const [form] = Form.useForm();
@@ -44,7 +46,16 @@ const AdvancedSearchForm = () => {
},
]}
>
-
+ {i % 3 !== 1 ? (
+
+ ) : (
+
+ )}
,
);
diff --git a/components/form/demo/validate-static.md b/components/form/demo/validate-static.md
index 70c29c16778d..1b9ed65b378d 100644
--- a/components/form/demo/validate-static.md
+++ b/components/form/demo/validate-static.md
@@ -32,6 +32,7 @@ import {
Cascader,
InputNumber,
Mentions,
+ TreeSelect,
} from 'infrad';
const { Option } = Select;
@@ -96,7 +97,7 @@ ReactDOM.render(
- |