Compare commits
553 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b252e807be | ||
|
|
3b7b50f51f | ||
|
|
d027eca037 | ||
|
|
c96fbd43c4 | ||
|
|
2f696fb289 | ||
|
|
887ccf2534 | ||
|
|
a34c28aaf9 | ||
|
|
f428b39aa1 | ||
|
|
32b3646202 | ||
|
|
cee6c8d54b | ||
|
|
a359efcd68 | ||
|
|
84506e9473 | ||
|
|
44485824f7 | ||
|
|
2586adb41c | ||
|
|
cff02339dd | ||
|
|
a7ba8745cb | ||
|
|
4b8c8bfa7e | ||
|
|
e3dbfcd19d | ||
|
|
2cb3e9060f | ||
|
|
1daac009b3 | ||
|
|
546b9f6d59 | ||
|
|
37639a7c87 | ||
|
|
eb0967749c | ||
|
|
9d80600b63 | ||
|
|
021abead6f | ||
|
|
383128d3d0 | ||
|
|
f1ae286b15 | ||
|
|
62b34d3573 | ||
|
|
56b0878f8c | ||
|
|
eb38eace01 | ||
|
|
af98484233 | ||
|
|
cbf4858b39 | ||
|
|
4221082c8e | ||
|
|
2f89ee4cd5 | ||
|
|
c26241e8a1 | ||
|
|
d62013bfe1 | ||
|
|
c4efcecd98 | ||
|
|
d6d0a17359 | ||
|
|
b26ebafdef | ||
|
|
ea72bd2f92 | ||
|
|
e2317870f1 | ||
|
|
7dc3b723cd | ||
|
|
dfa0f402d4 | ||
|
|
c4aaff43f6 | ||
|
|
ae2fa05da5 | ||
|
|
5f47b8370c | ||
|
|
8faba4cb2f | ||
|
|
0be0c9ca72 | ||
|
|
5f0258bc04 | ||
|
|
6941c84de2 | ||
|
|
7bc32d9148 | ||
|
|
b1e6227e67 | ||
|
|
f3f308ffaf | ||
|
|
e7020c6106 | ||
|
|
dc204718f0 | ||
|
|
e4a9af594f | ||
|
|
c22c398cec | ||
|
|
8862cb0e35 | ||
|
|
4f3eb847b3 | ||
|
|
f11140a0a6 | ||
|
|
c653f07ca8 | ||
|
|
7ceb3fdff9 | ||
|
|
3e9af29f7f | ||
|
|
4eccc7696e | ||
|
|
788d9c8678 | ||
|
|
900ce3cc5f | ||
|
|
4b6a66900f | ||
|
|
651edfe54d | ||
|
|
636d515e62 | ||
|
|
a3b3125c5c | ||
|
|
d6ab9fde20 | ||
|
|
99f82d7243 | ||
|
|
3f2c6bebc0 | ||
|
|
002af59ea3 | ||
|
|
3ec1319427 | ||
|
|
2fefe1edce | ||
|
|
784e29fd65 | ||
|
|
74d10acb03 | ||
|
|
0a7d248cc5 | ||
|
|
0a095d55f4 | ||
|
|
08f6e2f603 | ||
|
|
a1457be82f | ||
|
|
724d87ea40 | ||
|
|
87384331e8 | ||
|
|
0db185e5d7 | ||
|
|
9774f127f8 | ||
|
|
53970c95be | ||
|
|
3842de7f5f | ||
|
|
a941c9928e | ||
|
|
a0924bb67a | ||
|
|
ac6c3d3eae | ||
|
|
9c7bb68d01 | ||
|
|
451cb4c623 | ||
|
|
e8ea302025 | ||
|
|
6bb7a6c60e | ||
|
|
1a60ccde97 | ||
|
|
ed3c401c9e | ||
|
|
be1d6848f0 | ||
|
|
5934242b7e | ||
|
|
e19372d5f4 | ||
|
|
58c129dff9 | ||
|
|
f5b5d9a5f3 | ||
|
|
cd443ca3da | ||
|
|
5b7af23023 | ||
|
|
2039cf87ee | ||
|
|
7149218fa4 | ||
|
|
cb8283877a | ||
|
|
107c74cd7a | ||
|
|
5cef4e9780 | ||
|
|
4aaf555d80 | ||
|
|
dc84614b0c | ||
|
|
625fc71ebb | ||
|
|
659cef8a98 | ||
|
|
6cc07e595a | ||
|
|
fec4df7150 | ||
|
|
88fbe7cc58 | ||
|
|
7eb00d77e9 | ||
|
|
6784bf841e | ||
|
|
7268e9423f | ||
|
|
309de75dc5 | ||
|
|
3dc13b49b9 | ||
|
|
96540f5afd | ||
|
|
6b504aa08b | ||
|
|
e0d718e49c | ||
|
|
01651c2f14 | ||
|
|
f647c99f0a | ||
|
|
1e4e30f9a2 | ||
|
|
139a6d9f9c | ||
|
|
742ad40cec | ||
|
|
d161c0a805 | ||
|
|
9b6bedc109 | ||
|
|
887c2a7386 | ||
|
|
86561ea4e6 | ||
|
|
760706b92b | ||
|
|
92ffaf51d5 | ||
|
|
57e56e8175 | ||
|
|
8a6f8eddde | ||
|
|
2d90a5ba61 | ||
|
|
7c78a4d0d4 | ||
|
|
d3fe28ccd0 | ||
|
|
aac960738a | ||
|
|
d3e0241469 | ||
|
|
22e6d6a6d2 | ||
|
|
1a1d339466 | ||
|
|
3ac0f9fc9a | ||
|
|
e71c772d12 | ||
|
|
00b883302c | ||
|
|
e33d5e7bb1 | ||
|
|
7217ae2671 | ||
|
|
994651f5f9 | ||
|
|
f23fd9c145 | ||
|
|
b12a61d7c6 | ||
|
|
f40e975f3f | ||
|
|
017cc60cf3 | ||
|
|
b0e883b4dc | ||
|
|
9cbc399916 | ||
|
|
ecf1fa5827 | ||
|
|
cf707bc9f7 | ||
|
|
b9cae83735 | ||
|
|
a622002aed | ||
|
|
f5b00d332a | ||
|
|
188230ed62 | ||
|
|
a5c102546b | ||
|
|
ee785cea3a | ||
|
|
e6b4020059 | ||
|
|
aa50560d83 | ||
|
|
1f48f2a157 | ||
|
|
4c213db337 | ||
|
|
7327d9fc5f | ||
|
|
c636a24ab6 | ||
|
|
064d1cf34a | ||
|
|
35ebcd3c55 | ||
|
|
1c8c0bb99e | ||
|
|
d6d06c6ecc | ||
|
|
bd8054ef05 | ||
|
|
725a0679b2 | ||
|
|
c7e6ff57f6 | ||
|
|
ea4f9ef2c6 | ||
|
|
bbc2a37ab8 | ||
|
|
d23d35d15a | ||
|
|
eef19d1a04 | ||
|
|
92ec06b65c | ||
|
|
e2d954d1e7 | ||
|
|
1d9e1aaf2d | ||
|
|
a92c60c8cc | ||
|
|
1ecf70469d | ||
|
|
73ee739d02 | ||
|
|
fadd204d35 | ||
|
|
dd653e305d | ||
|
|
13a7fc0d07 | ||
|
|
4f9905e4d3 | ||
|
|
42979fa4ff | ||
|
|
db8498e15c | ||
|
|
1b94dd8f40 | ||
|
|
181b8454b1 | ||
|
|
01ac4e13d3 | ||
|
|
bf916998f2 | ||
|
|
7ccf5eebc0 | ||
|
|
fec4d82416 | ||
|
|
6d2cc9121a | ||
|
|
853784bc3f | ||
|
|
612ab8f7bd | ||
|
|
29d9a13ffb | ||
|
|
4c2ff9ca34 | ||
|
|
63dff641cf | ||
|
|
f918eaa38c | ||
|
|
49f47947c5 | ||
|
|
bde2c2905b | ||
|
|
781cb6db90 | ||
|
|
c4c17f4f4f | ||
|
|
6aa47d0ebf | ||
|
|
81c8a0732d | ||
|
|
dfbee7f109 | ||
|
|
2714c5d6f2 | ||
|
|
2402eb5a99 | ||
|
|
d957c00dca | ||
|
|
0845e3efae | ||
|
|
3806959a6d | ||
|
|
0b18dbc001 | ||
|
|
f788099ab7 | ||
|
|
e52a41c7be | ||
|
|
45efe53fd2 | ||
|
|
7610b39759 | ||
|
|
94a04746c2 | ||
|
|
b6a74e8abe | ||
|
|
58ccca7f75 | ||
|
|
e97536deb5 | ||
|
|
6851ef63b7 | ||
|
|
e559120849 | ||
|
|
c9cf3bb0c5 | ||
|
|
b1a1e1440b | ||
|
|
89789f974b | ||
|
|
e4e3cb9125 | ||
|
|
d94efdaa96 | ||
|
|
507c52b220 | ||
|
|
330a594d4b | ||
|
|
13b86c3220 | ||
|
|
ce88118f88 | ||
|
|
e6e5795dab | ||
|
|
b12825dee9 | ||
|
|
9bd86524e2 | ||
|
|
609ba0776b | ||
|
|
31f223fc9e | ||
|
|
8b569f5573 | ||
|
|
0ea0bd7d2d | ||
|
|
83ba002377 | ||
|
|
99a02b92d7 | ||
|
|
8fd061c819 | ||
|
|
9bc9c80617 | ||
|
|
3c2848d785 | ||
|
|
c022e0f61b | ||
|
|
49711c27aa | ||
|
|
47d9b441d4 | ||
|
|
d9b99c2d6f | ||
|
|
b06a057dd4 | ||
|
|
a5ea866492 | ||
|
|
2eb3bdb7a3 | ||
|
|
19c9ec1544 | ||
|
|
3ead8e3d11 | ||
|
|
6d6208a7fa | ||
|
|
15707df9bc | ||
|
|
a0b2f21987 | ||
|
|
ea47c6c9f3 | ||
|
|
76c780f3a9 | ||
|
|
556dfa96c5 | ||
|
|
ea6b0b9e56 | ||
|
|
547c811365 | ||
|
|
d26a0ceb1a | ||
|
|
9ce9d5913b | ||
|
|
83e53e59de | ||
|
|
30dec0b6a0 | ||
|
|
fa87fc1234 | ||
|
|
3f52012b40 | ||
|
|
b0091b516c | ||
|
|
1f0e950538 | ||
|
|
a42b28ff58 | ||
|
|
fbeace0f81 | ||
|
|
7a99d421c9 | ||
|
|
5724abb1ed | ||
|
|
0898f44329 | ||
|
|
24a6ed9201 | ||
|
|
3ee0f9c321 | ||
|
|
f9b2f3f53e | ||
|
|
ed7f3299fd | ||
|
|
562937ce28 | ||
|
|
abb04d53f4 | ||
|
|
083c2fa33f | ||
|
|
eae015d0ee | ||
|
|
e46589f784 | ||
|
|
0b5cb01d2f | ||
|
|
0c788b272f | ||
|
|
9aa593096e | ||
|
|
cef5a9d791 | ||
|
|
480d599895 | ||
|
|
813a536d0f | ||
|
|
33ac4ccc76 | ||
|
|
f409f18c0f | ||
|
|
658bd6a67d | ||
|
|
d284e50900 | ||
|
|
459e68f93b | ||
|
|
5bdd8f8640 | ||
|
|
23c85e45b7 | ||
|
|
e3aea2ee0c | ||
|
|
33c1227063 | ||
|
|
0fdb244c6d | ||
|
|
fed91d4a82 | ||
|
|
7f80adf253 | ||
|
|
c24c9e602c | ||
|
|
d8cfaf830f | ||
|
|
a7c4734802 | ||
|
|
8e14fbdc0e | ||
|
|
5b5b7d100d | ||
|
|
431525248b | ||
|
|
248d304421 | ||
|
|
4ff6c8ad51 | ||
|
|
e3075c6cbc | ||
|
|
be7d5de803 | ||
|
|
bf961b2c2a | ||
|
|
c002957436 | ||
|
|
fddf68752e | ||
|
|
55c84b449e | ||
|
|
bcf765dcf3 | ||
|
|
9424d2be52 | ||
|
|
c9767eaae4 | ||
|
|
52f253cfc8 | ||
|
|
f9acc6517a | ||
|
|
75bb7f7355 | ||
|
|
0e591c19ca | ||
|
|
c9d8f02c8e | ||
|
|
0640447cb3 | ||
|
|
d4eed6320c | ||
|
|
237cdbb2fc | ||
|
|
75bdef3e45 | ||
|
|
4eee8efbae | ||
|
|
043584fc6c | ||
|
|
8e5f7ea1d1 | ||
|
|
0a779234d2 | ||
|
|
de204315c6 | ||
|
|
37d795f9bc | ||
|
|
e3ff7dfab3 | ||
|
|
18b46dbb62 | ||
|
|
88b3ce1e7d | ||
|
|
fd857723bd | ||
|
|
4c96ea3517 | ||
|
|
e3d9944ed0 | ||
|
|
d3d258ba5b | ||
|
|
e1fd23515a | ||
|
|
33f553da2c | ||
|
|
331320b80b | ||
|
|
2e578d1f64 | ||
|
|
cfb998a906 | ||
|
|
2af1bffce1 | ||
|
|
738e33cd7f | ||
|
|
0febbe14de | ||
|
|
3b45fd540f | ||
|
|
4c758f484e | ||
|
|
0a207cc1f1 | ||
|
|
6102e015c3 | ||
|
|
20700b9e67 | ||
|
|
780f01a993 | ||
|
|
3d4afaaa5d | ||
|
|
870def7781 | ||
|
|
5ab16ba05d | ||
|
|
f1b8acc7b5 | ||
|
|
dd499fdee2 | ||
|
|
2fb27e9598 | ||
|
|
1dcaad3f8e | ||
|
|
6fe2c0c425 | ||
|
|
58d3bf0352 | ||
|
|
f271ce3b03 | ||
|
|
0a9b79096b | ||
|
|
12b8de2861 | ||
|
|
de16bd5883 | ||
|
|
93572503dd | ||
|
|
23d90ff554 | ||
|
|
ffa032b146 | ||
|
|
654b347d58 | ||
|
|
868c19523d | ||
|
|
252b153e86 | ||
|
|
9220805ebf | ||
|
|
324d956969 | ||
|
|
32525e5797 | ||
|
|
76c5058590 | ||
|
|
c149e9594d | ||
|
|
023e79f085 | ||
|
|
5eca790f0a | ||
|
|
7fa746f7c8 | ||
|
|
37843c4706 | ||
|
|
f60002cd14 | ||
|
|
c031dd3b10 | ||
|
|
4bb397d6e5 | ||
|
|
118e64c400 | ||
|
|
62c4231389 | ||
|
|
741eea6c73 | ||
|
|
4ca56fea73 | ||
|
|
b63c215ac9 | ||
|
|
a99bc749cb | ||
|
|
63a6f74321 | ||
|
|
b18fb3b74d | ||
|
|
b394c5a833 | ||
|
|
910464838a | ||
|
|
f39ed9ee25 | ||
|
|
14bac3b37a | ||
|
|
e9de762c45 | ||
|
|
4ea5b1d20b | ||
|
|
2aa83f71cc | ||
|
|
4bc42dfe73 | ||
|
|
ddf7a5b5f6 | ||
|
|
f6b0e9d59b | ||
|
|
fbc70acf2d | ||
|
|
5720d80e67 | ||
|
|
08656fec3f | ||
|
|
0751a8f0a1 | ||
|
|
b189a7a9c0 | ||
|
|
88348f8c85 | ||
|
|
d4aced0b21 | ||
|
|
2b7ef84999 | ||
|
|
0d18bee5f3 | ||
|
|
6bcf1e5790 | ||
|
|
02d18739d6 | ||
|
|
a30ccf5583 | ||
|
|
7c08596f40 | ||
|
|
02ea1c044c | ||
|
|
ced25b13a4 | ||
|
|
597c4bca44 | ||
|
|
07ea77092d | ||
|
|
5613670284 | ||
|
|
59fe162fe5 | ||
|
|
eecc70cf96 | ||
|
|
431706a330 | ||
|
|
cf7532a1d6 | ||
|
|
eaa87d8b5b | ||
|
|
9c4fea0d1c | ||
|
|
69f231639d | ||
|
|
8a98319d58 | ||
|
|
7e16bb70b1 | ||
|
|
774d877518 | ||
|
|
029dd9bb77 | ||
|
|
645a32032a | ||
|
|
6cfdfa8636 | ||
|
|
4c37b3f818 | ||
|
|
c2e3735ffb | ||
|
|
24c909502d | ||
|
|
77f045ccdc | ||
|
|
36aeb76e5f | ||
|
|
300374d9a8 | ||
|
|
b6d4923fb0 | ||
|
|
4658413aea | ||
|
|
2221fe1132 | ||
|
|
07ac1ea11f | ||
|
|
f1d5e0421b | ||
|
|
8ac8f35db4 | ||
|
|
2d42e44128 | ||
|
|
f414b96c03 | ||
|
|
5af1ac1836 | ||
|
|
9afcad69d1 | ||
|
|
ee5805da65 | ||
|
|
e82227b698 | ||
|
|
bf82413930 | ||
|
|
58deb56ca1 | ||
|
|
4b90c16c15 | ||
|
|
4bd2bfef69 | ||
|
|
c4a2717796 | ||
|
|
ea32d3659c | ||
|
|
d786436367 | ||
|
|
1b7b3bd006 | ||
|
|
84a9d1821b | ||
|
|
f8c5781102 | ||
|
|
777f999db5 | ||
|
|
a276e32f51 | ||
|
|
80dc66474d | ||
|
|
0e32f3669e | ||
|
|
4cb8bc68ba | ||
|
|
65d56feeeb | ||
|
|
a4a466dd26 | ||
|
|
3323ba8f0d | ||
|
|
fb3bd7f583 | ||
|
|
1235527398 | ||
|
|
15e8c64633 | ||
|
|
b4d07a679a | ||
|
|
72296a4385 | ||
|
|
8c153e6427 | ||
|
|
97ec6b66d0 | ||
|
|
ef762b50a7 | ||
|
|
4b46fb97a8 | ||
|
|
e7c875bda8 | ||
|
|
b0305f8b7e | ||
|
|
404810aba8 | ||
|
|
fd93cfb229 | ||
|
|
6d37c780ed | ||
|
|
3ce19cdfb3 | ||
|
|
c4ed771b1f | ||
|
|
7ec2988c71 | ||
|
|
499a3324b1 | ||
|
|
cf1a728e21 | ||
|
|
a07e3ad0b5 | ||
|
|
faada22274 | ||
|
|
4c00e8f69a | ||
|
|
0ac7832631 | ||
|
|
7a8977d175 | ||
|
|
7dd0009c60 | ||
|
|
c7b896be20 | ||
|
|
97654abcaa | ||
|
|
7e99f8eec3 | ||
|
|
7938338441 | ||
|
|
fdb12c2ea3 | ||
|
|
4686b1361a | ||
|
|
d424c06a99 | ||
|
|
079a983672 | ||
|
|
ffa4af3be0 | ||
|
|
caf773d5a6 | ||
|
|
b80668577d | ||
|
|
0495462ad5 | ||
|
|
30d40aa15f | ||
|
|
bacf855ed8 | ||
|
|
33669c1390 | ||
|
|
3a3aa47d32 | ||
|
|
b6526e70d6 | ||
|
|
8af4fbb0f0 | ||
|
|
84d945f7da | ||
|
|
171d3e64a0 | ||
|
|
e1d7e0bece | ||
|
|
59ce7e4a8f | ||
|
|
9f6e8e466a | ||
|
|
9bc285b67e | ||
|
|
6ec7c79cf7 | ||
|
|
3dd6235041 | ||
|
|
3ce6c88952 | ||
|
|
688c56d79c | ||
|
|
aa7ea0637e | ||
|
|
b3aa6ba924 | ||
|
|
be61bebd92 | ||
|
|
6c74abe0ed | ||
|
|
83fe3ddaee | ||
|
|
a7b717162f | ||
|
|
7332a0fe8a | ||
|
|
4f23af6a15 | ||
|
|
30e65b2ba7 | ||
|
|
edaa7881bd | ||
|
|
ff542ff7d7 | ||
|
|
7203dcb145 | ||
|
|
4346b10363 | ||
|
|
d06a7ef606 | ||
|
|
8571e6814b | ||
|
|
1d628ef207 | ||
|
|
cff20b7a4c | ||
|
|
7a92c4bf95 | ||
|
|
8e76af2192 | ||
|
|
ddb56ac56a | ||
|
|
6c61658bba | ||
|
|
757022d229 | ||
|
|
b0e208a155 | ||
|
|
6de0ab3293 |
25
.babelrc
25
.babelrc
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"presets": ["react"],
|
||||
"ignore": ["third_party"],
|
||||
"plugins": [
|
||||
"transform-class-properties",
|
||||
"syntax-trailing-function-commas",
|
||||
["transform-object-rest-spread", { "useBuiltIns": true }],
|
||||
"transform-es2015-template-literals",
|
||||
"transform-es2015-literals",
|
||||
"transform-es2015-arrow-functions",
|
||||
"transform-es2015-block-scoped-functions",
|
||||
["transform-es2015-classes", { "loose": true }],
|
||||
"transform-es2015-object-super",
|
||||
"transform-es2015-shorthand-properties",
|
||||
"transform-es2015-computed-properties",
|
||||
"transform-es2015-for-of",
|
||||
"check-es2015-constants",
|
||||
["transform-es2015-spread", { "loose": true }],
|
||||
"transform-es2015-parameters",
|
||||
["transform-es2015-destructuring", { "loose": true }],
|
||||
["transform-es2015-block-scoping", { "throwIfClosureRequired": true }],
|
||||
"transform-es3-member-expression-literals",
|
||||
"transform-es3-property-literals"
|
||||
]
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
# http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
max_line_length = 80
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
max_line_length = 0
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[COMMIT_EDITMSG]
|
||||
max_line_length = 0
|
||||
@@ -1,14 +0,0 @@
|
||||
# Third party
|
||||
**/node_modules
|
||||
|
||||
# Not written by hand
|
||||
packages/react-art/npm/lib
|
||||
|
||||
# Build products
|
||||
build/
|
||||
coverage/
|
||||
fixtures/
|
||||
scripts/bench/benchmarks/**/*.js
|
||||
|
||||
# React repository clone
|
||||
scripts/bench/remote-repo/
|
||||
64
.eslintrc.js
64
.eslintrc.js
@@ -1,64 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const OFF = 0;
|
||||
const ERROR = 2;
|
||||
|
||||
module.exports = {
|
||||
extends: 'fbjs',
|
||||
|
||||
plugins: [
|
||||
'react',
|
||||
'react-internal',
|
||||
],
|
||||
|
||||
// We're stricter than the default config, mostly. We'll override a few rules
|
||||
// and then enable some React specific ones.
|
||||
rules: {
|
||||
'accessor-pairs': OFF,
|
||||
'brace-style': [ERROR, '1tbs'],
|
||||
'comma-dangle': [ERROR, 'always-multiline'],
|
||||
'consistent-return': OFF,
|
||||
'dot-location': [ERROR, 'property'],
|
||||
'dot-notation': ERROR,
|
||||
'eol-last': ERROR,
|
||||
'eqeqeq': [ERROR, 'allow-null'],
|
||||
'indent': OFF,
|
||||
'jsx-quotes': [ERROR, 'prefer-double'],
|
||||
'keyword-spacing': [ERROR, {after: true, before: true}],
|
||||
'no-bitwise': OFF,
|
||||
'no-inner-declarations': [ERROR, 'functions'],
|
||||
'no-multi-spaces': ERROR,
|
||||
'no-restricted-syntax': [ERROR, 'WithStatement'],
|
||||
'no-shadow': ERROR,
|
||||
'no-unused-expressions': ERROR,
|
||||
'no-unused-vars': [ERROR, {args: 'none'}],
|
||||
'no-useless-concat': OFF,
|
||||
'quotes': [ERROR, 'single', {avoidEscape: true, allowTemplateLiterals: true }],
|
||||
'space-before-blocks': ERROR,
|
||||
'space-before-function-paren': OFF,
|
||||
|
||||
// React & JSX
|
||||
// Our transforms set this automatically
|
||||
'react/jsx-boolean-value': [ERROR, 'always'],
|
||||
'react/jsx-no-undef': ERROR,
|
||||
// We don't care to do this
|
||||
'react/jsx-sort-prop-types': OFF,
|
||||
'react/jsx-space-before-closing': ERROR,
|
||||
'react/jsx-uses-react': ERROR,
|
||||
'react/no-is-mounted': OFF,
|
||||
// This isn't useful in our test code
|
||||
'react/react-in-jsx-scope': ERROR,
|
||||
'react/self-closing-comp': ERROR,
|
||||
// We don't care to do this
|
||||
'react/jsx-wrap-multilines': [ERROR, {declaration: false, assignment: false}],
|
||||
|
||||
// CUSTOM RULES
|
||||
// the second argument of warning/invariant should be a literal string
|
||||
'react-internal/warning-and-invariant-args': ERROR,
|
||||
'react-internal/no-primitive-constructors': ERROR,
|
||||
},
|
||||
|
||||
globals: {
|
||||
expectDev: true,
|
||||
},
|
||||
};
|
||||
45
.flowconfig
45
.flowconfig
@@ -1,45 +0,0 @@
|
||||
[ignore]
|
||||
|
||||
<PROJECT_ROOT>/fixtures/.*
|
||||
<PROJECT_ROOT>/build/.*
|
||||
<PROJECT_ROOT>/scripts/bench/.*
|
||||
|
||||
# These shims are copied into external projects:
|
||||
<PROJECT_ROOT>/scripts/rollup/shims/facebook-www/.*
|
||||
<PROJECT_ROOT>/scripts/rollup/shims/react-native/.*
|
||||
|
||||
# Note: intentionally *don't* ignore /scripts/rollup/shims/rollup/
|
||||
# because it is part of the build and isn't external.
|
||||
|
||||
<PROJECT_ROOT>/.*/node_modules/y18n/.*
|
||||
<PROJECT_ROOT>/node_modules/chrome-devtools-frontend/.*
|
||||
<PROJECT_ROOT>/node_modules/devtools-timeline-model/.*
|
||||
<PROJECT_ROOT>/node_modules/create-react-class/.*
|
||||
<PROJECT_ROOT>/.*/__mocks__/.*
|
||||
<PROJECT_ROOT>/.*/__tests__/.*
|
||||
|
||||
[include]
|
||||
|
||||
[libs]
|
||||
./node_modules/fbjs/flow/lib/dev.js
|
||||
./scripts/flow
|
||||
|
||||
[options]
|
||||
esproposal.class_static_fields=enable
|
||||
esproposal.class_instance_fields=enable
|
||||
unsafe.enable_getters_and_setters=true
|
||||
|
||||
munge_underscores=false
|
||||
|
||||
suppress_type=$FlowIssue
|
||||
suppress_type=$FlowFixMe
|
||||
suppress_type=$FixMe
|
||||
suppress_type=$FlowExpectedError
|
||||
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-3]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*www[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-3]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*www[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
|
||||
|
||||
[version]
|
||||
^0.53.1
|
||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1 +0,0 @@
|
||||
* text=auto
|
||||
14
.github/ISSUE_TEMPLATE.md
vendored
14
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,14 +0,0 @@
|
||||
<!--
|
||||
Note: if the issue is about documentation or the website, please file it at:
|
||||
https://github.com/reactjs/reactjs.org/issues/new
|
||||
-->
|
||||
|
||||
**Do you want to request a *feature* or report a *bug*?**
|
||||
|
||||
**What is the current behavior?**
|
||||
|
||||
**If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://jsfiddle.net or similar (template for React 16: https://jsfiddle.net/Luktwrdm/, template for React 15: https://jsfiddle.net/hmbg7e9w/).**
|
||||
|
||||
**What is the expected behavior?**
|
||||
|
||||
**Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?**
|
||||
12
.github/PULL_REQUEST_TEMPLATE.md
vendored
12
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,12 +0,0 @@
|
||||
**Before submitting a pull request,** please make sure the following is done:
|
||||
|
||||
1. Fork [the repository](https://github.com/facebook/react) and create your branch from `master`.
|
||||
2. Run `yarn` in the repository root.
|
||||
3. If you've fixed a bug or added code that should be tested, add tests!
|
||||
4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch TestName` is helpful in development.
|
||||
5. Format your code with [prettier](https://github.com/prettier/prettier) (`yarn prettier`).
|
||||
6. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only check changed files.
|
||||
7. Run the [Flow](https://flowtype.org/) typechecks (`yarn flow`).
|
||||
8. If you haven't already, complete the CLA.
|
||||
|
||||
**Learn more about contributing:** https://reactjs.org/docs/how-to-contribute.html
|
||||
23
.gitignore
vendored
23
.gitignore
vendored
@@ -1,23 +0,0 @@
|
||||
.DS_STORE
|
||||
node_modules
|
||||
*~
|
||||
*.pyc
|
||||
.grunt
|
||||
_SpecRunner.html
|
||||
__benchmarks__
|
||||
build/
|
||||
remote-repo/
|
||||
coverage/
|
||||
.module-cache
|
||||
fixtures/dom/public/react-dom.js
|
||||
fixtures/dom/public/react.js
|
||||
test/the-files-to-test.generated.js
|
||||
*.log*
|
||||
chrome-user-data
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
.idea
|
||||
*.iml
|
||||
.vscode
|
||||
*.swp
|
||||
*.swo
|
||||
164
.mailmap
164
.mailmap
@@ -1,164 +0,0 @@
|
||||
Adam Timberlake <adam.timberlake@gmail.com>
|
||||
Alex Mykyta <dancingwithcows@gmail.com>
|
||||
Alex Pien <alexpien@gmail.com>
|
||||
Alex Pien <alexpien@gmail.com> <pien@pien-mbp.dhcp.thefacebook.com>
|
||||
Alex Pien <alexpien@gmail.com> <pien@pien-mbp.local>
|
||||
Andreas Savvides <asavvides@twitter.com> <AnSavvides@users.noreply.github.com>
|
||||
Andreas Savvides <asavvides@twitter.com> <andreas@nibbli.com>
|
||||
Andreas Svensson <andreas@syranide.com>
|
||||
Andres Suarez <zertosh@gmail.com>
|
||||
Andrew Kulakov <avk@8xx8.ru>
|
||||
Andrew Sokolov <asokolov@atlassian.com>
|
||||
Anto Aravinth <anto.aravinth.cse@gmail.com>
|
||||
Baraa Hamodi <bhamodi@uwaterloo.ca> <baraa@optimizely.com>
|
||||
Ben Halpern <bendhalpern@gmail.com>
|
||||
Ben Newman <bn@cs.stanford.edu> <benjamn@fb.com>
|
||||
Benjamin Woodruff <github@benjam.info> <bgw@fb.com>
|
||||
Bill Fisher <fisherwebdev@gmail.com>
|
||||
Blaine Kasten <blainekasten@gmail.com>
|
||||
Brandon Tilley <brandon@brandontilley.com>
|
||||
Changsoon Bok <winmain@gmail.com>
|
||||
Cheng Lou <chenglou92@gmail.com> <chenglou@fb.com>
|
||||
Christian Oliff <christianoliff@yahoo.com>
|
||||
Christoph Pojer <christoph.pojer@gmail.com>
|
||||
Christoph Pojer <christoph.pojer@gmail.com> <cpojer@fb.com>
|
||||
Connor McSheffrey <c@conr.me> <connor.mcsheffrey@gmail.com>
|
||||
Conor Hastings <hastings.conorm@gmail.com> <conor@socialtables.com>
|
||||
Dan Schafer <dschafer@fb.com>
|
||||
Daniel Gasienica <daniel@gasienica.ch> <daniel@fiftythree.com>
|
||||
Daniel Gasienica <daniel@gasienica.ch> <dgasienica@zynga.com>
|
||||
Daniel Hejl <daniel.hejl@hotmail.com>
|
||||
Daniel Lo Nigro <daniel@dan.cx> <danlo@fb.com>
|
||||
Dave Galbraith <dave@jut.io>
|
||||
Dennis Johnson <songawee@gmail.com>
|
||||
Dmitry Blues <dmitri.blyus@gmail.com>
|
||||
Dongsheng Liu <bellanchor@gmail.com>
|
||||
Erik Harper <eharper@mixpo.com>
|
||||
Evan Coonrod <evan@paloalto.com>
|
||||
Fabio M. Costa <fabiomcosta@gmail.com> <fabs@fb.com>
|
||||
Felix Kling <felix.kling@gmx.net> <fkling@fb.com>
|
||||
François-Xavier Bois <fxbois@gmail.com>
|
||||
Fyodor Ivanishchev <cbrwizard@gmail.com>
|
||||
Gabe Levi <gabelevi@gmail.com> <glevi@fb.com>
|
||||
Geert Pasteels <geert.pasteels@gmail.com>
|
||||
George A Sisco III <george.sisco@gmail.com>
|
||||
Georgii Dolzhykov <thorn.mailbox@gmail.com>
|
||||
Harry Hull <harry.hull1@gmail.com>
|
||||
Hendrik Swanepoel <hendrik.swanepoel@gmail.com>
|
||||
Hyeock Kwon <doublus@gmail.com>
|
||||
Ian Obermiller <ian@obermillers.com> <iano@fb.com>
|
||||
Ilia Pavlenkov <dortonway@gmail.com>
|
||||
Ilyá Belsky <gelias.gbelsky@gmail.com>
|
||||
Ingvar Stepanyan <me@rreverser.com> <rreverser@ubuntu.rreverser.a4.internal.cloudapp.net>
|
||||
Irae Carvalho <irae@irae.pro.br>
|
||||
Ivan Vergiliev <ivan.vergiliev@gmail.com>
|
||||
JJ Weber <jj.weber@gmail.com>
|
||||
Jae Hun Ro <jhr24@duke.edu>
|
||||
Jaime Mingo <j.mingov@3boll.com>
|
||||
James Brantly <james@jbrantly.com>
|
||||
Jan Hancic <jan.hancic@gmail.com> <jan.hancic@caplin.com>
|
||||
Jan Kassens <jan@kassens.net> <jkassens@fb.com>
|
||||
Jason Bonta <jbonta@gmail.com> <jasonbonta@fb.com>
|
||||
Jason Quense <monastic.panic@gmail.com>
|
||||
Jason Trill <jason@jasontrill.com>
|
||||
Jeff Chan <jefftchan@gmail.com> <jeff@quizlet.com>
|
||||
Jeff Morrison <jeff@anafx.com> <Jeff@anafx.com>
|
||||
Jeff Morrison <jeff@anafx.com> <jeffmo@fb.com>
|
||||
Jeff Morrison <jeff@anafx.com> <lbljeffmo@gmail.com>
|
||||
Jeffrey Lin <lin.jeffrey@gmail.com> <jeffreylin@fb.com>
|
||||
Jim Sproch <jsproch@fb.com>
|
||||
Jim Sproch <jsproch@fb.com> <jsfb@github>
|
||||
Jim Sproch <jsproch@fb.com> <none@no-reply.com>
|
||||
Jinwoo Oh <arkist@gmail.com>
|
||||
Jinxiu Lee <lee.jinxiu@gmail.com>
|
||||
Jiyeon Seo <zzzeons@gmail.com>
|
||||
Jon Chester <jonchester@fb.com>
|
||||
Jon Madison <jon@tfftech.com>
|
||||
Jonathan Hsu <jhiswin@gmail.com>
|
||||
Jonathan Persson <persson.jonathan@gmail.com> <jonathan.persson@creuna.se>
|
||||
Jordan Walke <jordojw@gmail.com>
|
||||
Jordan Walke <jordojw@gmail.com> <jordanjcw@fb.com>
|
||||
Joseph Savona <joesavona@fb.com> <josephsavona@users.noreply.github.com>
|
||||
Josh Duck <josh@fb.com> <github@joshduck.com>
|
||||
Juan Serrano <germ13@users.noreply.github.com>
|
||||
Jun Wu <quark@lihdd.net>
|
||||
Justin Robison <jrobison151@gmail.com>
|
||||
Keito Uchiyama <projects@keito.me> <keito@fb.com>
|
||||
Kevin Coughlin <kevintcoughlin@gmail.com> <kevincoughlin@tumblr.com>
|
||||
Krystian Karczewski <karcz.k@gmail.com>
|
||||
Kunal Mehta <k.mehta@berkeley.edu> <kunalm@fb.com>
|
||||
Laurence Rowe <l@lrowe.co.uk> <laurence@lrowe.co.uk>
|
||||
Marcin K. <katzoo@github.mail>
|
||||
Mark Anderson <undernewmanagement@users.noreply.github.com>
|
||||
Mark Funk <mfunk86@gmail.com> <mark@boomtownroi.com>
|
||||
Martin Andert <mandert@gmail.com>
|
||||
Mathieu M-Gosselin <mathieumg@gmail.com> <mathieumg@atx33.com>
|
||||
Matsunoki <himkt@klis.tsukuba.ac.jp>
|
||||
Matt Brookes <matt@brookes.net>
|
||||
Matt Dunn-Rankin <mdunnrankin@gmail.com> <matchu1993@gmail.com>
|
||||
Matt Zabriskie <mzabriskie@gmail.com>
|
||||
Matthew Johnston <matthewjohnston4@outlook.com> <matthewjohnston4@users.noreply.github.com>
|
||||
Matthew Looi <looi.matthew@gmail.com>
|
||||
Mattijs Kneppers <mattijs@arttech.nl>
|
||||
Max Heiber <max.heiber@gmail.com>
|
||||
Max Stoiber <contact@mstoiber.com>
|
||||
Michal Srb <xixixao@seznam.cz> xixixao <xixixao@seznam.cz>
|
||||
Michelle Todd <himichelletodd@gmail.com> <michelle@khanacademy.org>
|
||||
Mihai Parparita <mihai.parparita@gmail.com> <mihai@persistent.info>
|
||||
Minwe LUO <minwe@yunshipei.com>
|
||||
Murray M. Moss <murray@mmoss.name> <MMoss@cainc.com>
|
||||
Murray M. Moss <murray@mmoss.name> <mmoss@users.noreply.github.com>
|
||||
Neri Marschik <marschik_neri@cyberagent.co.jp>
|
||||
Nick Gavalas <njg57@cornell.edu>
|
||||
Nick Thompson <ncthom91@gmail.com> <nickt@instagram.com>
|
||||
Patrick Stapleton <github@gdi2290.com>
|
||||
Paul O’Shannessy <paul@oshannessy.com> <poshannessy@fb.com>
|
||||
Paul Shen <paul@mnml0.com> <paulshen@fb.com>
|
||||
Pete Hunt <floydophone@gmail.com>
|
||||
Pete Hunt <floydophone@gmail.com> <pete.hunt@fb.com>
|
||||
Pete Hunt <floydophone@gmail.com> <pete@instagram.com>
|
||||
Pete Hunt <floydophone@gmail.com> <phunt@instagram.com>
|
||||
Petri Lievonen <plievone@cc.hut.fi>
|
||||
Petri Lievonen <plievone@cc.hut.fi> <petri.lievonen@tkk.fi>
|
||||
Pieter Vanderwerff <me@pieter.io> <pieter@heyday.co.nz>
|
||||
Pouja Nikray <poujanik@gmail.com>
|
||||
Rainer Oviir <roviir@gmail.com> <raineroviir@rainers-MacBook-Pro.local>
|
||||
Ray <ray@tomo.im>
|
||||
Richard Feldman <richard.t.feldman@gmail.com> <richard@noredink.com>
|
||||
Richard Livesey <Livesey7@hotmail.co.uk>
|
||||
Rob Arnold <robarnold@cs.cmu.edu>
|
||||
Robert Binna <rbinna@gmail.com> <speedskater@users.noreply.github.com>
|
||||
Robin Frischmann <robin@rofrischmann.de>
|
||||
Sander Spies <sandermail@gmail.com>
|
||||
Scott Feeney <scott@oceanbase.org> <smf@fb.com>
|
||||
Sebastian Markbåge <sebastian@calyptus.eu> <sema@fb.com>
|
||||
Sergey Rubanov <chi187@gmail.com>
|
||||
Shogun Sea <shogunsea08@gmail.com> <xxin@groupon.com>
|
||||
Soichiro Kawamura <mail@w-st.com>
|
||||
Sophie Alpert <git@sophiebits.com> <balpert@fb.com>
|
||||
Sophie Alpert <git@sophiebits.com> <ben@benalpert.com>
|
||||
Sophie Alpert <git@sophiebits.com> <sophiebits@fb.com>
|
||||
Sophie Alpert <git@sophiebits.com> <spicyjalapeno@gmail.com>
|
||||
Sota Ohara <ohrst.18@gmail.com>
|
||||
Steven Luscher <react@steveluscher.com> <github@steveluscher.com>
|
||||
Steven Luscher <react@steveluscher.com> <steveluscher@fb.com>
|
||||
Steven Luscher <react@steveluscher.com> <steveluscher@instagram.com>
|
||||
Steven Luscher <react@steveluscher.com> <steveluscher@users.noreply.github.com>
|
||||
Stoyan Stefanov <ssttoo@ymail.com>
|
||||
Tengfei Guo <terryr3rd@yeah.net> <tfguo369@gmail.com>
|
||||
Thomas Aylott <oblivious@subtlegradient.com> <aylott@fb.com>
|
||||
Timothy Yung <yungsters@gmail.com> <yungsters@fb.com>
|
||||
Tomoya Suzuki <tmysz.dev@gmail.com>
|
||||
Vasiliy Loginevskiy <Yeti.or@gmail.com>
|
||||
Vasiliy Loginevskiy <Yeti.or@gmail.com> <yeti-or@yandex-team.ru>
|
||||
Vjeux <vjeuxx@gmail.com>
|
||||
Vjeux <vjeuxx@gmail.com> <vjeux@fb.com>
|
||||
Volkan Unsal <spocksplanet@gmail.com>
|
||||
Wander Wang <wander.wang@ismole.com>
|
||||
Xavier Morel <xmo-odoo@users.noreply.github.com>
|
||||
YouBao Nong <noyobo@gmail.com> <nongyoubao@alibaba-inc.com>
|
||||
Yutaka Nakajima <nakazye@gmail.com>
|
||||
Zach Bruggeman <mail@bruggie.com> <zbruggeman@me.com>
|
||||
iawia002 <z2d@jifangcheng.com> <850127508@qq.com>
|
||||
元彦 <yuanyan@users.noreply.github.com>
|
||||
张敏 <cookfront@gmail.com>
|
||||
1333
CHANGELOG.md
1333
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@@ -1,5 +0,0 @@
|
||||
# Contributing to React
|
||||
|
||||
Want to contribute to React? There are a few things you need to know.
|
||||
|
||||
We wrote a **[contribution guide](https://reactjs.org/contributing/how-to-contribute.html)** to help you get started.
|
||||
21
LICENSE
21
LICENSE
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-present, Facebook, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
76
README.md
76
README.md
@@ -1,76 +0,0 @@
|
||||
# [React](https://reactjs.org/) · [](https://github.com/facebook/react/blob/master/LICENSE) [](https://www.npmjs.com/package/react) [](https://coveralls.io/github/facebook/react?branch=master) [](https://circleci.com/gh/facebook/react) [](https://reactjs.org/docs/how-to-contribute.html#your-first-pull-request)
|
||||
|
||||
React is a JavaScript library for building user interfaces.
|
||||
|
||||
* **Declarative:** React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes. Declarative views make your code more predictable, simpler to understand, and easier to debug.
|
||||
* **Component-Based:** Build encapsulated components that manage their own state, then compose them to make complex UIs. Since component logic is written in JavaScript instead of templates, you can easily pass rich data through your app and keep state out of the DOM.
|
||||
* **Learn Once, Write Anywhere:** We don't make assumptions about the rest of your technology stack, so you can develop new features in React without rewriting existing code. React can also render on the server using Node and power mobile apps using [React Native](https://facebook.github.io/react-native/).
|
||||
|
||||
[Learn how to use React in your own project](https://reactjs.org/docs/getting-started.html).
|
||||
|
||||
## Documentation
|
||||
|
||||
You can find the React documentation [on the website](https://reactjs.org/docs).
|
||||
It is divided into several sections:
|
||||
|
||||
* [Quick Start](https://reactjs.org/docs/hello-world.html)
|
||||
* [Advanced Guides](https://reactjs.org/docs/jsx-in-depth.html)
|
||||
* [API Reference](https://reactjs.org/docs/react-api.html)
|
||||
* [Tutorial](https://reactjs.org/tutorial/tutorial.html)
|
||||
* [Where to Get Support](https://reactjs.org/community/support.html)
|
||||
* [Contributing Guide](https://reactjs.org/docs/how-to-contribute.html)
|
||||
|
||||
You can improve it by sending pull requests to [this repository](https://github.com/reactjs/reactjs.org).
|
||||
|
||||
## Examples
|
||||
|
||||
We have several examples [on the website](https://reactjs.org/). Here is the first one to get you started:
|
||||
|
||||
```jsx
|
||||
class HelloMessage extends React.Component {
|
||||
render() {
|
||||
return <div>Hello {this.props.name}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<HelloMessage name="John" />,
|
||||
document.getElementById('container')
|
||||
);
|
||||
```
|
||||
|
||||
This example will render "Hello John" into a container on the page.
|
||||
|
||||
You'll notice that we used an HTML-like syntax; [we call it JSX](https://reactjs.org/docs/introducing-jsx.html). JSX is not required to use React, but it makes code more readable, and writing it feels like writing HTML. We recommend using [Babel](https://babeljs.io/) with a [React preset](https://babeljs.io/docs/plugins/preset-react/) to convert JSX into native JavaScript for browsers to digest.
|
||||
|
||||
## Installation
|
||||
|
||||
React is available as the `react` package on [npm](https://www.npmjs.com/). It is also available on a [CDN](https://reactjs.org/docs/installation.html#using-a-cdn).
|
||||
|
||||
React is flexible and can be used in a variety of projects. You can create new apps with it, but you can also gradually introduce it into an existing codebase without doing a rewrite.
|
||||
|
||||
The recommended way to install React depends on your project. Here you can find short guides for the most common scenarios:
|
||||
|
||||
* [Trying Out React](https://reactjs.org/docs/installation.html#trying-out-react)
|
||||
* [Creating a New Application](https://reactjs.org/docs/installation.html#creating-a-new-application)
|
||||
* [Adding React to an Existing Application](https://reactjs.org/docs/installation.html#adding-react-to-an-existing-application)
|
||||
|
||||
## Contributing
|
||||
|
||||
The main purpose of this repository is to continue to evolve React core, making it faster and easier to use. Development of React happens in the open on GitHub, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving React.
|
||||
|
||||
### [Code of Conduct](https://code.facebook.com/codeofconduct)
|
||||
|
||||
Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please read [the full text](https://code.facebook.com/codeofconduct) so that you can understand what actions will and will not be tolerated.
|
||||
|
||||
### [Contributing Guide](https://reactjs.org/contributing/how-to-contribute.html)
|
||||
|
||||
Read our [contributing guide](https://reactjs.org/contributing/how-to-contribute.html) to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to React.
|
||||
|
||||
### Good First Issues
|
||||
|
||||
To help you get your feet wet and get you familiar with our contribution process, we have a list of [good first issues](https://github.com/facebook/react/labels/good%20first%20issue) that contain bugs which have a relatively limited scope. This is a great place to get started.
|
||||
|
||||
### License
|
||||
|
||||
React is [MIT licensed](./LICENSE).
|
||||
40
circle.yml
40
circle.yml
@@ -1,40 +0,0 @@
|
||||
---
|
||||
machine:
|
||||
timezone: America/Los_Angeles
|
||||
node:
|
||||
version: 8
|
||||
ruby:
|
||||
version: 2.2.3
|
||||
environment:
|
||||
TRAVIS_REPO_SLUG: facebook/react
|
||||
YARN_VERSION: 1.2.1
|
||||
PATH: "${PATH}:${HOME}/.yarn/bin"
|
||||
|
||||
dependencies:
|
||||
pre:
|
||||
# This is equivalent to $TRAVIS_COMMIT_RANGE
|
||||
- echo $CIRCLE_COMPARE_URL | cut -d/ -f7
|
||||
# install yarn if it's not already installed
|
||||
- |
|
||||
if [[ ! -e ~/.yarn/bin/yarn || $(yarn --version) != "${YARN_VERSION}" ]]; then
|
||||
curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version $YARN_VERSION
|
||||
fi
|
||||
override:
|
||||
- yarn install
|
||||
- scripts/circleci/set_up_github_keys.sh
|
||||
post:
|
||||
# - npm ls --depth=0
|
||||
cache_directories:
|
||||
- ~/.yarn
|
||||
- ~/.yarn-cache
|
||||
|
||||
test:
|
||||
override:
|
||||
- ./scripts/circleci/test_entry_point.sh:
|
||||
parallel: true
|
||||
|
||||
deployment:
|
||||
staging:
|
||||
branch: /.*/
|
||||
commands:
|
||||
- ./scripts/circleci/upload_build.sh
|
||||
1
fixtures/art/.gitignore
vendored
1
fixtures/art/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
bundle.js
|
||||
@@ -1,10 +0,0 @@
|
||||
# VectorWidget example
|
||||
|
||||
To try this example, run:
|
||||
|
||||
```
|
||||
yarn
|
||||
yarn build
|
||||
```
|
||||
|
||||
in this directory, then open index.html in your browser.
|
||||
@@ -1,148 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var Circle = require('react-art/Circle');
|
||||
var React = require('react');
|
||||
var ReactART = require('react-art');
|
||||
var Group = ReactART.Group;
|
||||
var Shape = ReactART.Shape;
|
||||
var Surface = ReactART.Surface;
|
||||
var Transform = ReactART.Transform;
|
||||
|
||||
var MOUSE_UP_DRAG = 0.978;
|
||||
var MOUSE_DOWN_DRAG = 0.9;
|
||||
var MAX_VEL = 11;
|
||||
var CLICK_ACCEL = 3;
|
||||
var BASE_VEL = 0.15;
|
||||
|
||||
/**
|
||||
* An animated SVG component.
|
||||
*/
|
||||
class VectorWidget extends React.Component {
|
||||
/**
|
||||
* Initialize state members.
|
||||
*/
|
||||
state = {degrees: 0, velocity: 0, drag: MOUSE_UP_DRAG};
|
||||
|
||||
/**
|
||||
* When the component is mounted into the document - this is similar to a
|
||||
* constructor, but invoked when the instance is actually mounted into the
|
||||
* document. Here's, we'll just set up an animation loop that invokes our
|
||||
* method. Binding of `this.onTick` is not needed because all React methods
|
||||
* are automatically bound before being mounted.
|
||||
*/
|
||||
componentDidMount() {
|
||||
this._interval = window.setInterval(this.onTick, 20);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.clearInterval(this._interval);
|
||||
}
|
||||
|
||||
onTick = () => {
|
||||
var nextDegrees = this.state.degrees + BASE_VEL + this.state.velocity;
|
||||
var nextVelocity = this.state.velocity * this.state.drag;
|
||||
this.setState({degrees: nextDegrees, velocity: nextVelocity});
|
||||
};
|
||||
|
||||
/**
|
||||
* When mousing down, we increase the friction down the velocity.
|
||||
*/
|
||||
handleMouseDown = () => {
|
||||
this.setState({drag: MOUSE_DOWN_DRAG});
|
||||
};
|
||||
|
||||
/**
|
||||
* Cause the rotation to "spring".
|
||||
*/
|
||||
handleMouseUp = () => {
|
||||
var nextVelocity = Math.min(this.state.velocity + CLICK_ACCEL, MAX_VEL);
|
||||
this.setState({velocity: nextVelocity, drag: MOUSE_UP_DRAG});
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the "main" method for any component. The React API allows you to
|
||||
* describe the structure of your UI component at *any* point in time.
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<Surface width={700} height={700} style={{cursor: 'pointer'}}>
|
||||
{this.renderGraphic(this.state.degrees)}
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Better SVG support for React coming soon.
|
||||
*/
|
||||
renderGraphic = rotation => {
|
||||
return (
|
||||
<Group onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp}>
|
||||
<Group x={210} y={135}>
|
||||
<Shape fill="rgba(0,0,0,0.1)" d={BORDER_PATH} />
|
||||
<Shape fill="#7BC7BA" d={BG_PATH} />
|
||||
<Shape fill="#DCDCDC" d={BAR_PATH} />
|
||||
<Shape fill="#D97B76" d={RED_DOT_PATH} />
|
||||
<Shape fill="#DBBB79" d={YELLOW_DOT_PATH} />
|
||||
<Shape fill="#A6BD8A" d={GREEN_DOT_PATH} />
|
||||
<Group x={55} y={29}>
|
||||
<Group rotation={rotation} originX={84} originY={89}>
|
||||
<Group x={84} y={89}>
|
||||
<Circle fill="#FFFFFF" radius={16} />
|
||||
</Group>
|
||||
<Group>
|
||||
<Shape d={RING_ONE_PATH} stroke="#FFFFFF" strokeWidth={8} />
|
||||
<Shape
|
||||
d={RING_TWO_PATH}
|
||||
transform={RING_TWO_ROTATE}
|
||||
stroke="#FFFFFF"
|
||||
strokeWidth={8}
|
||||
/>
|
||||
<Shape
|
||||
d={RING_THREE_PATH}
|
||||
transform={RING_THREE_ROTATE}
|
||||
stroke="#FFFFFF"
|
||||
strokeWidth={8}
|
||||
/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
var BORDER_PATH =
|
||||
'M3.00191459,4 C1.34400294,4 0,5.34785514 0,7.00550479 L0,220.994495 C0,222.65439 1.34239483,224 3.00191459,224 L276.998085,224 C278.655997,224 280,222.652145 280,220.994495 L280,7.00550479 C280,5.34561033 278.657605,4 276.998085,4 L3.00191459,4 Z M3.00191459,4';
|
||||
var BG_PATH =
|
||||
'M3.00191459,1 C1.34400294,1 0,2.34785514 0,4.00550479 L0,217.994495 C0,219.65439 1.34239483,221 3.00191459,221 L276.998085,221 C278.655997,221 280,219.652145 280,217.994495 L280,4.00550479 C280,2.34561033 278.657605,1 276.998085,1 L3.00191459,1 Z M3.00191459,1';
|
||||
var BAR_PATH =
|
||||
'M3.00191459,0 C1.34400294,0 0,1.34559019 0,3.00878799 L0,21 C0,21 0,21 0,21 L280,21 C280,21 280,21 280,21 L280,3.00878799 C280,1.34708027 278.657605,0 276.998085,0 L3.00191459,0 Z M3.00191459,0';
|
||||
var RED_DOT_PATH =
|
||||
'M12.5,17 C16.0898511,17 19,14.0898511 19,10.5 C19,6.91014895 16.0898511,4 12.5,4 C8.91014895,4 6,6.91014895 6,10.5 C6,14.0898511 8.91014895,17 12.5,17 Z M12.5,17';
|
||||
var YELLOW_DOT_PATH =
|
||||
'M31.5,17 C35.0898511,17 38,14.0898511 38,10.5 C38,6.91014895 35.0898511,4 31.5,4 C27.9101489,4 25,6.91014895 25,10.5 C25,14.0898511 27.9101489,17 31.5,17 Z M31.5,17';
|
||||
var GREEN_DOT_PATH =
|
||||
'M50.5,17 C54.0898511,17 57,14.0898511 57,10.5 C57,6.91014895 54.0898511,4 50.5,4 C46.9101489,4 44,6.91014895 44,10.5 C44,14.0898511 46.9101489,17 50.5,17 Z M50.5,17';
|
||||
var RING_ONE_PATH =
|
||||
'M84,121 C130.391921,121 168,106.673113 168,89 C168,71.3268871 130.391921,57 84,57 C37.6080787,57 0,71.3268871 0,89 C0,106.673113 37.6080787,121 84,121 Z M84,121';
|
||||
var RING_TWO_PATH =
|
||||
'M84,121 C130.391921,121 168,106.673113 168,89 C168,71.3268871 130.391921,57 84,57 C37.6080787,57 0,71.3268871 0,89 C0,106.673113 37.6080787,121 84,121 Z M84,121';
|
||||
var RING_THREE_PATH =
|
||||
'M84,121 C130.391921,121 168,106.673113 168,89 C168,71.3268871 130.391921,57 84,57 C37.6080787,57 0,71.3268871 0,89 C0,106.673113 37.6080787,121 84,121 Z M84,121';
|
||||
var RING_TWO_ROTATE = new Transform()
|
||||
.translate(84.0, 89.0)
|
||||
.rotate(-240.0)
|
||||
.translate(-84.0, -89.0);
|
||||
var RING_THREE_ROTATE = new Transform()
|
||||
.translate(84.0, 89.0)
|
||||
.rotate(-300.0)
|
||||
.translate(-84.0, -89.0);
|
||||
|
||||
module.exports = VectorWidget;
|
||||
@@ -1,7 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var ReactDOM = require('react-dom');
|
||||
var VectorWidget = require('./VectorWidget');
|
||||
|
||||
ReactDOM.render(<VectorWidget />, document.getElementById('container'));
|
||||
@@ -1,22 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>VectorWidget</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="container">
|
||||
<p>If you're seeing this message, it means you haven't generated the bundle file for this example. Try running:</p>
|
||||
|
||||
<pre><code>
|
||||
npm install
|
||||
npm run build
|
||||
</code></pre>
|
||||
|
||||
<p>then reload the page.</p>
|
||||
</div>
|
||||
|
||||
<script src="bundle.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.24.0",
|
||||
"babel-loader": "^6.4.1",
|
||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||
"babel-preset-es2015": "^6.6.0",
|
||||
"babel-preset-react": "^6.5.0",
|
||||
"react": "file:../../build/packages/react",
|
||||
"react-art": "file:../../build/packages/react-art",
|
||||
"react-dom": "file:../../build/packages/react-dom",
|
||||
"webpack": "^1.14.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack app.js bundle.js"
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
var webpack = require('webpack');
|
||||
var path = require('path');
|
||||
|
||||
module.exports = {
|
||||
context: __dirname,
|
||||
entry: './app.js',
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
loader: require.resolve('babel-loader'),
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
query: {
|
||||
presets: [
|
||||
require.resolve('babel-preset-es2015'),
|
||||
require.resolve('babel-preset-react'),
|
||||
],
|
||||
plugins: [require.resolve('babel-plugin-transform-class-properties')],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: JSON.stringify('development'),
|
||||
},
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
react: require.resolve('react'),
|
||||
},
|
||||
},
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
24
fixtures/attribute-behavior/.gitignore
vendored
24
fixtures/attribute-behavior/.gitignore
vendored
@@ -1,24 +0,0 @@
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
/public/react.development.js
|
||||
/public/react-dom.development.js
|
||||
/public/react-dom-server.browser.development.js
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,31 +0,0 @@
|
||||
# Attribute Behavior Fixture
|
||||
|
||||
**WIP:** This is an MVP, still needs polish.
|
||||
|
||||
### Known Issues
|
||||
- There are currently two errors thrown when the page loads;
|
||||
`SyntaxError: missing ; before statement`
|
||||
|
||||
## Instructions
|
||||
|
||||
`cd fixtures/attribute-behavior && yarn install && yarn start`
|
||||
|
||||
## Interpretation
|
||||
|
||||
Each row is an attribute which could be set on some DOM component. Some of
|
||||
them are invalid or mis-capitalized or mixed up versions of real ones.
|
||||
Each column is a value which can be passed to that attribute.
|
||||
Every cell has a box on the left and a box on the right.
|
||||
The left box shows the property (or attribute) assigned by React 15.\*, and the
|
||||
right box shows the property (or attribute) assigned by the latest version of
|
||||
React 16.
|
||||
|
||||
Right now we use a purple outline to call out cases where the assigned property
|
||||
(or attribute) has changed between React 15 and 16.
|
||||
|
||||
---
|
||||
|
||||
|
||||
This project was bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app).
|
||||
|
||||
You can find the guide for how to do things in a CRA [here](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md).
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"name": "attribute-behavior",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"file-saver": "^1.3.3",
|
||||
"glamor": "^2.20.40",
|
||||
"react": "^15.6.1",
|
||||
"react-dom": "^15.6.1",
|
||||
"react-scripts": "1.0.11",
|
||||
"react-virtualized": "^9.9.0"
|
||||
},
|
||||
"scripts": {
|
||||
"prestart": "cp ../../build/dist/{react,react-dom,react-dom-server.browser}.development.js public/",
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test --env=jsdom",
|
||||
"eject": "react-scripts eject"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB |
@@ -1,40 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="#000000">
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"start_url": "./index.html",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +0,0 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './App';
|
||||
|
||||
it('renders without crashing', () => {
|
||||
const div = document.createElement('div');
|
||||
ReactDOM.render(<App />, div);
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +0,0 @@
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import './index.css';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './App';
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'));
|
||||
File diff suppressed because it is too large
Load Diff
17
fixtures/dom/.gitignore
vendored
17
fixtures/dom/.gitignore
vendored
@@ -1,17 +0,0 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
node_modules
|
||||
|
||||
# testing
|
||||
coverage
|
||||
|
||||
# production
|
||||
build
|
||||
public/react.development.js
|
||||
public/react-dom.development.js
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env
|
||||
npm-debug.log
|
||||
@@ -1,17 +0,0 @@
|
||||
# DOM Fixtures
|
||||
|
||||
A set of DOM test cases for quickly identifying browser issues.
|
||||
|
||||
## Setup
|
||||
|
||||
To reference a local build of React, first run `yarn build` at the root
|
||||
of the React project. Then:
|
||||
|
||||
```
|
||||
cd fixtures/dom
|
||||
yarn
|
||||
yarn start
|
||||
```
|
||||
|
||||
The `start` command runs a script that copies over the local build of react into
|
||||
the public directory.
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"name": "react-fixtures",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"react-scripts": "^1.0.11"
|
||||
},
|
||||
"dependencies": {
|
||||
"classnames": "^2.2.5",
|
||||
"core-js": "^2.4.1",
|
||||
"prop-types": "^15.6.0",
|
||||
"query-string": "^4.2.3",
|
||||
"react": "^15.4.1",
|
||||
"react-dom": "^15.4.1",
|
||||
"semver": "^5.3.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"prestart": "cp ../../build/dist/{react,react-dom}.development.js public/",
|
||||
"build": "react-scripts build && cp build/index.html build/200.html",
|
||||
"test": "react-scripts test --env=jsdom",
|
||||
"eject": "react-scripts eject"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB |
@@ -1,33 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tag above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
<script src="https://unpkg.com/prop-types@15.5.6/prop-types.js"></script>
|
||||
<script src="https://unpkg.com/expect@1.20.2/umd/expect.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start`.
|
||||
To create a production bundle, use `npm run build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,18 +0,0 @@
|
||||
import Header from './Header';
|
||||
import Fixtures from './fixtures';
|
||||
import '../style.css';
|
||||
|
||||
const React = window.React;
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div>
|
||||
<Header />
|
||||
<div className="container">
|
||||
<Fixtures />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -1,18 +0,0 @@
|
||||
const PropTypes = window.PropTypes;
|
||||
const React = window.React;
|
||||
|
||||
const propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
class Fixture extends React.Component {
|
||||
render() {
|
||||
const {children} = this.props;
|
||||
|
||||
return <div className="test-fixture">{children}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
Fixture.propTypes = propTypes;
|
||||
|
||||
export default Fixture;
|
||||
@@ -1,26 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const propTypes = {
|
||||
title: PropTypes.node.isRequired,
|
||||
description: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
class FixtureSet extends React.Component {
|
||||
render() {
|
||||
const {title, description, children} = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>{title}</h1>
|
||||
{description && <p>{description}</p>}
|
||||
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FixtureSet.propTypes = propTypes;
|
||||
|
||||
export default FixtureSet;
|
||||
@@ -1,87 +0,0 @@
|
||||
import {parse, stringify} from 'query-string';
|
||||
import getVersionTags from '../tags';
|
||||
const React = window.React;
|
||||
|
||||
class Header extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
const query = parse(window.location.search);
|
||||
const version = query.version || 'local';
|
||||
const versions = [version];
|
||||
this.state = {version, versions};
|
||||
}
|
||||
componentWillMount() {
|
||||
getVersionTags().then(tags => {
|
||||
let versions = tags.map(tag => tag.name.slice(1));
|
||||
versions = [`local`, ...versions];
|
||||
this.setState({versions});
|
||||
});
|
||||
}
|
||||
handleVersionChange(event) {
|
||||
const query = parse(window.location.search);
|
||||
query.version = event.target.value;
|
||||
if (query.version === 'local') {
|
||||
delete query.version;
|
||||
}
|
||||
window.location.search = stringify(query);
|
||||
}
|
||||
handleFixtureChange(event) {
|
||||
window.location.pathname = event.target.value;
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<header className="header">
|
||||
<div className="header__inner">
|
||||
<span className="header__logo">
|
||||
<img
|
||||
src="https://reactjs.org/img/logo.svg"
|
||||
alt=""
|
||||
width="32"
|
||||
height="32"
|
||||
/>
|
||||
React Sandbox (v{React.version})
|
||||
</span>
|
||||
|
||||
<div className="header-controls">
|
||||
<label htmlFor="example">
|
||||
<span className="sr-only">Select an example</span>
|
||||
<select
|
||||
value={window.location.pathname}
|
||||
onChange={this.handleFixtureChange}>
|
||||
<option value="/">Select a Fixture</option>
|
||||
<option value="/range-inputs">Range Inputs</option>
|
||||
<option value="/text-inputs">Text Inputs</option>
|
||||
<option value="/number-inputs">Number Input</option>
|
||||
<option value="/password-inputs">Password Input</option>
|
||||
<option value="/selects">Selects</option>
|
||||
<option value="/textareas">Textareas</option>
|
||||
<option value="/input-change-events">
|
||||
Input change events
|
||||
</option>
|
||||
<option value="/buttons">Buttons</option>
|
||||
<option value="/date-inputs">Date Inputs</option>
|
||||
<option value="/error-handling">Error Handling</option>
|
||||
<option value="/event-pooling">Event Pooling</option>
|
||||
<option value="/custom-elements">Custom Elements</option>
|
||||
</select>
|
||||
</label>
|
||||
<label htmlFor="react_version">
|
||||
<span className="sr-only">Select a version to test</span>
|
||||
<select
|
||||
value={this.state.version}
|
||||
onChange={this.handleVersionChange}>
|
||||
{this.state.versions.map(version => (
|
||||
<option key={version} value={version}>
|
||||
{version}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Header;
|
||||
@@ -1,26 +0,0 @@
|
||||
const React = window.React;
|
||||
|
||||
function csv(string) {
|
||||
return string.split(/\s*,\s*/);
|
||||
}
|
||||
|
||||
export default function IssueList({issues}) {
|
||||
if (!issues) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof issues === 'string') {
|
||||
issues = csv(issues);
|
||||
}
|
||||
|
||||
let links = issues.reduce((memo, issue, i) => {
|
||||
return memo.concat(
|
||||
i > 0 && i < issues.length ? ', ' : null,
|
||||
<a href={'https://github.com/facebook/react/issues/' + issue} key={issue}>
|
||||
{issue}
|
||||
</a>
|
||||
);
|
||||
}, []);
|
||||
|
||||
return <span>{links}</span>;
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
import cn from 'classnames';
|
||||
import semver from 'semver';
|
||||
import PropTypes from 'prop-types';
|
||||
import IssueList from './IssueList';
|
||||
import {parse} from 'query-string';
|
||||
import {semverString} from './propTypes';
|
||||
|
||||
const React = window.React;
|
||||
|
||||
const propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
title: PropTypes.node.isRequired,
|
||||
resolvedIn: semverString,
|
||||
introducedIn: semverString,
|
||||
resolvedBy: PropTypes.string,
|
||||
};
|
||||
|
||||
class TestCase extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
complete: false,
|
||||
};
|
||||
}
|
||||
|
||||
handleChange = e => {
|
||||
this.setState({
|
||||
complete: e.target.checked,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
title,
|
||||
description,
|
||||
introducedIn,
|
||||
resolvedIn,
|
||||
resolvedBy,
|
||||
affectedBrowsers,
|
||||
relatedIssues,
|
||||
children,
|
||||
} = this.props;
|
||||
|
||||
let {complete} = this.state;
|
||||
|
||||
const {version} = parse(window.location.search);
|
||||
const isTestFixed =
|
||||
!version || !resolvedIn || semver.gte(version, resolvedIn);
|
||||
|
||||
complete = !isTestFixed || complete;
|
||||
|
||||
return (
|
||||
<section className={cn('test-case', complete && 'test-case--complete')}>
|
||||
<h2 className="test-case__title type-subheading">
|
||||
<label>
|
||||
<input
|
||||
className="test-case__title__check"
|
||||
type="checkbox"
|
||||
checked={complete}
|
||||
onChange={this.handleChange}
|
||||
/>{' '}
|
||||
{title}
|
||||
</label>
|
||||
</h2>
|
||||
|
||||
<dl className="test-case__details">
|
||||
{introducedIn && <dt>First broken in: </dt>}
|
||||
{introducedIn && (
|
||||
<dd>
|
||||
<a
|
||||
href={'https://github.com/facebook/react/tag/v' + introducedIn}>
|
||||
<code>{introducedIn}</code>
|
||||
</a>
|
||||
</dd>
|
||||
)}
|
||||
|
||||
{resolvedIn && <dt>First supported in: </dt>}
|
||||
{resolvedIn && (
|
||||
<dd>
|
||||
<a href={'https://github.com/facebook/react/tag/v' + resolvedIn}>
|
||||
<code>{resolvedIn}</code>
|
||||
</a>
|
||||
</dd>
|
||||
)}
|
||||
|
||||
{resolvedBy && <dt>Fixed by: </dt>}
|
||||
{resolvedBy && (
|
||||
<dd>
|
||||
<a
|
||||
href={
|
||||
'https://github.com/facebook/react/pull/' +
|
||||
resolvedBy.slice(1)
|
||||
}>
|
||||
<code>{resolvedBy}</code>
|
||||
</a>
|
||||
</dd>
|
||||
)}
|
||||
|
||||
{affectedBrowsers && <dt>Affected browsers: </dt>}
|
||||
{affectedBrowsers && <dd>{affectedBrowsers}</dd>}
|
||||
|
||||
{relatedIssues && <dt>Related Issues: </dt>}
|
||||
{relatedIssues && (
|
||||
<dd>
|
||||
<IssueList issues={relatedIssues} />
|
||||
</dd>
|
||||
)}
|
||||
</dl>
|
||||
|
||||
<p className="test-case__desc">{description}</p>
|
||||
|
||||
<div className="test-case__body">
|
||||
{!isTestFixed && (
|
||||
<p className="test-case__invalid-version">
|
||||
<strong>Note:</strong> This test case was fixed in a later version
|
||||
of React. This test is not expected to pass for the selected
|
||||
version, and that's ok!
|
||||
</p>
|
||||
)}
|
||||
|
||||
{children}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TestCase.propTypes = propTypes;
|
||||
|
||||
TestCase.Steps = class extends React.Component {
|
||||
render() {
|
||||
const {children} = this.props;
|
||||
return (
|
||||
<div>
|
||||
<h3>Steps to reproduce:</h3>
|
||||
<ol>{children}</ol>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
TestCase.ExpectedResult = class extends React.Component {
|
||||
render() {
|
||||
const {children} = this.props;
|
||||
return (
|
||||
<div>
|
||||
<h3>Expected Result:</h3>
|
||||
<p>{children}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
export default TestCase;
|
||||
@@ -1,43 +0,0 @@
|
||||
import FixtureSet from '../../FixtureSet';
|
||||
import TestCase from '../../TestCase';
|
||||
|
||||
const React = window.React;
|
||||
|
||||
function onButtonClick() {
|
||||
window.alert(`This shouldn't have happened!`);
|
||||
}
|
||||
|
||||
export default class ButtonTestCases extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<FixtureSet title="Buttons" description="">
|
||||
<TestCase
|
||||
title="onClick with disabled buttons"
|
||||
description="The onClick event handler should not be invoked when clicking on a disabled buyaton">
|
||||
<TestCase.Steps>
|
||||
<li>Click on the disabled button</li>
|
||||
</TestCase.Steps>
|
||||
<TestCase.ExpectedResult>
|
||||
Nothing should happen
|
||||
</TestCase.ExpectedResult>
|
||||
<button disabled onClick={onButtonClick}>
|
||||
Click Me
|
||||
</button>
|
||||
</TestCase>
|
||||
<TestCase
|
||||
title="onClick with disabled buttons containing other elements"
|
||||
description="The onClick event handler should not be invoked when clicking on a disabled button that contains other elements">
|
||||
<TestCase.Steps>
|
||||
<li>Click on the disabled button, which contains a span</li>
|
||||
</TestCase.Steps>
|
||||
<TestCase.ExpectedResult>
|
||||
Nothing should happen
|
||||
</TestCase.ExpectedResult>
|
||||
<button disabled onClick={onButtonClick}>
|
||||
<span>Click Me</span>
|
||||
</button>
|
||||
</TestCase>
|
||||
</FixtureSet>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
import FixtureSet from '../../FixtureSet';
|
||||
import TestCase from '../../TestCase';
|
||||
|
||||
const React = window.React;
|
||||
const ReactDOM = window.ReactDOM;
|
||||
|
||||
const supportsCustomElements = typeof customElements !== 'undefined';
|
||||
|
||||
class HelloWorld extends React.Component {
|
||||
render() {
|
||||
return <h1>Hello, world!</h1>;
|
||||
}
|
||||
}
|
||||
|
||||
if (supportsCustomElements) {
|
||||
// Babel breaks web components.
|
||||
// https://github.com/w3c/webcomponents/issues/587
|
||||
// eslint-disable-next-line no-new-func
|
||||
const MyElement = new Function(
|
||||
'React',
|
||||
'ReactDOM',
|
||||
'HelloWorld',
|
||||
`
|
||||
return class MyElement extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
const shadowRoot = this.attachShadow({ mode:'open' });
|
||||
ReactDOM.render(React.createElement(HelloWorld), shadowRoot);
|
||||
}
|
||||
}`
|
||||
)(React, ReactDOM, HelloWorld);
|
||||
customElements.define('my-element', MyElement);
|
||||
}
|
||||
|
||||
export default class ButtonTestCases extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<FixtureSet
|
||||
title="Custom Elements"
|
||||
description="Support for Custom Element DOM standards.">
|
||||
<TestCase title="Rendering into shadow root">
|
||||
<TestCase.ExpectedResult>
|
||||
You should see "Hello, World" printed below.{' '}
|
||||
</TestCase.ExpectedResult>
|
||||
{supportsCustomElements ? (
|
||||
<my-element />
|
||||
) : (
|
||||
<div>This browser does not support custom elements.</div>
|
||||
)}
|
||||
</TestCase>
|
||||
</FixtureSet>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import Fixture from '../../Fixture';
|
||||
import FixtureSet from '../../FixtureSet';
|
||||
import TestCase from '../../TestCase';
|
||||
import SwitchDateTestCase from './switch-date-test-case';
|
||||
|
||||
const React = window.React;
|
||||
|
||||
class DateInputFixtures extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<FixtureSet title="Dates" description="">
|
||||
<TestCase title="Switching between date and datetime-local">
|
||||
<TestCase.Steps>
|
||||
<li>Type a date into the date picker</li>
|
||||
<li>Toggle "Switch type"</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The month, day, and year values should correctly transfer. The
|
||||
hours/minutes/seconds should not be discarded.
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<Fixture>
|
||||
<SwitchDateTestCase />
|
||||
</Fixture>
|
||||
</TestCase>
|
||||
</FixtureSet>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DateInputFixtures;
|
||||
@@ -1,67 +0,0 @@
|
||||
const React = window.React;
|
||||
|
||||
const startDate = new Date();
|
||||
/**
|
||||
* This test case was originally provided by @richsoni,
|
||||
* https://github.com/facebook/react/issues/8116
|
||||
*/
|
||||
class SwitchDateTestCase extends React.Component {
|
||||
state = {
|
||||
fullDate: false,
|
||||
date: startDate,
|
||||
};
|
||||
|
||||
render() {
|
||||
const attrs = this.inputAttrs();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
<b>{attrs.type}</b> input type ({attrs.value})
|
||||
</p>
|
||||
<p>
|
||||
<input
|
||||
type={attrs.type}
|
||||
value={attrs.value}
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={this.state.fullDate}
|
||||
onChange={this.updateFullDate}
|
||||
/>{' '}
|
||||
Switch type
|
||||
</label>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
inputAttrs() {
|
||||
if (this.state.fullDate) {
|
||||
return {
|
||||
type: 'datetime-local',
|
||||
value: this.state.date.toISOString().replace(/\..*Z/, ''),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
type: 'date',
|
||||
value: this.state.date.toISOString().replace(/T.*/, ''),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
onInputChange = ({target: {value}}) => {
|
||||
const date = value ? new Date(Date.parse(value)) : startDate;
|
||||
this.setState({date});
|
||||
};
|
||||
|
||||
updateFullDate = () => {
|
||||
this.setState({
|
||||
fullDate: !this.state.fullDate,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export default SwitchDateTestCase;
|
||||
@@ -1,165 +0,0 @@
|
||||
import FixtureSet from '../../FixtureSet';
|
||||
import TestCase from '../../TestCase';
|
||||
|
||||
const React = window.React;
|
||||
const ReactDOM = window.ReactDOM;
|
||||
|
||||
function BadRender(props) {
|
||||
props.doThrow();
|
||||
}
|
||||
class ErrorBoundary extends React.Component {
|
||||
static defaultProps = {
|
||||
buttonText: 'Trigger error',
|
||||
};
|
||||
state = {
|
||||
shouldThrow: false,
|
||||
didThrow: false,
|
||||
error: null,
|
||||
};
|
||||
componentDidCatch(error) {
|
||||
this.setState({error, didThrow: true});
|
||||
}
|
||||
triggerError = () => {
|
||||
this.setState({
|
||||
shouldThrow: true,
|
||||
});
|
||||
};
|
||||
render() {
|
||||
if (this.state.didThrow) {
|
||||
if (this.state.error) {
|
||||
return <p>Captured an error: {this.state.error.message}</p>;
|
||||
} else {
|
||||
return <p>Captured an error: {'' + this.state.error}</p>;
|
||||
}
|
||||
}
|
||||
if (this.state.shouldThrow) {
|
||||
return <BadRender doThrow={this.props.doThrow} />;
|
||||
}
|
||||
return <button onClick={this.triggerError}>{this.props.buttonText}</button>;
|
||||
}
|
||||
}
|
||||
class Example extends React.Component {
|
||||
state = {key: 0};
|
||||
restart = () => {
|
||||
this.setState(state => ({key: state.key + 1}));
|
||||
};
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<button onClick={this.restart}>Reset</button>
|
||||
<ErrorBoundary
|
||||
buttonText={this.props.buttonText}
|
||||
doThrow={this.props.doThrow}
|
||||
key={this.state.key}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TriggerErrorAndCatch extends React.Component {
|
||||
container = document.createElement('div');
|
||||
|
||||
triggerErrorAndCatch = () => {
|
||||
try {
|
||||
ReactDOM.flushSync(() => {
|
||||
ReactDOM.render(
|
||||
<BadRender
|
||||
doThrow={() => {
|
||||
throw new Error('Caught error');
|
||||
}}
|
||||
/>,
|
||||
this.container
|
||||
);
|
||||
});
|
||||
} catch (e) {}
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<button onClick={this.triggerErrorAndCatch}>
|
||||
Trigger error and catch
|
||||
</button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default class ErrorHandlingTestCases extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<FixtureSet title="Error handling" description="">
|
||||
<TestCase
|
||||
title="Break on uncaught exceptions"
|
||||
description="In DEV, errors should be treated as uncaught, even though React catches them internally">
|
||||
<TestCase.Steps>
|
||||
<li>Open the browser DevTools</li>
|
||||
<li>Make sure "Pause on exceptions" is enabled</li>
|
||||
<li>Make sure "Pause on caught exceptions" is disabled</li>
|
||||
<li>Click the "Trigger error" button</li>
|
||||
<li>Click the reset button</li>
|
||||
</TestCase.Steps>
|
||||
<TestCase.ExpectedResult>
|
||||
The DevTools should pause at the line where the error was thrown, in
|
||||
the BadRender component. After resuming, the "Trigger error" button
|
||||
should be replaced with "Captured an error: Oops!" Clicking reset
|
||||
should reset the test case.
|
||||
</TestCase.ExpectedResult>
|
||||
<Example
|
||||
doThrow={() => {
|
||||
throw new Error('Oops!');
|
||||
}}
|
||||
/>
|
||||
</TestCase>
|
||||
<TestCase title="Throwing null" description="">
|
||||
<TestCase.Steps>
|
||||
<li>Click the "Trigger error" button</li>
|
||||
<li>Click the reset button</li>
|
||||
</TestCase.Steps>
|
||||
<TestCase.ExpectedResult>
|
||||
The "Trigger error" button should be replaced with "Captured an
|
||||
error: null". Clicking reset should reset the test case.
|
||||
</TestCase.ExpectedResult>
|
||||
<Example
|
||||
doThrow={() => {
|
||||
throw null; // eslint-disable-line no-throw-literal
|
||||
}}
|
||||
/>
|
||||
</TestCase>
|
||||
<TestCase
|
||||
title="Cross-origin errors (development mode only)"
|
||||
description="">
|
||||
<TestCase.Steps>
|
||||
<li>Click the "Trigger cross-origin error" button</li>
|
||||
<li>Click the reset button</li>
|
||||
</TestCase.Steps>
|
||||
<TestCase.ExpectedResult>
|
||||
The "Trigger error" button should be replaced with "Captured an
|
||||
error: A cross-origin error was thrown [...]". The actual error
|
||||
message should be logged to the console: "Uncaught Error: Expected
|
||||
true to be false".
|
||||
</TestCase.ExpectedResult>
|
||||
<Example
|
||||
buttonText="Trigger cross-origin error"
|
||||
doThrow={() => {
|
||||
// The `expect` module is loaded via unpkg, so that this assertion
|
||||
// triggers a cross-origin error
|
||||
window.expect(true).toBe(false);
|
||||
}}
|
||||
/>
|
||||
</TestCase>
|
||||
<TestCase
|
||||
title="Errors are logged even if they're caught (development mode only)"
|
||||
description="">
|
||||
<TestCase.Steps>
|
||||
<li>Click the "Trigger render error and catch" button</li>
|
||||
</TestCase.Steps>
|
||||
<TestCase.ExpectedResult>
|
||||
Open the console. "Uncaught Error: Caught error" should have been
|
||||
logged by the browser.
|
||||
</TestCase.ExpectedResult>
|
||||
<TriggerErrorAndCatch />
|
||||
</TestCase>
|
||||
</FixtureSet>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
const React = window.React;
|
||||
|
||||
class HitBox extends React.Component {
|
||||
state = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
onMouseMove: n => n,
|
||||
};
|
||||
|
||||
onMove = event => {
|
||||
this.setState({x: event.clientX, y: event.clientY});
|
||||
this.props.onMouseMove(event);
|
||||
};
|
||||
|
||||
render() {
|
||||
const {x, y} = this.state;
|
||||
|
||||
const boxStyle = {
|
||||
padding: '10px 20px',
|
||||
border: '1px solid #d9d9d9',
|
||||
margin: '10px 0 20px',
|
||||
};
|
||||
|
||||
return (
|
||||
<div onMouseMove={this.onMove} style={boxStyle}>
|
||||
<p>Trace your mouse over this box.</p>
|
||||
<p>
|
||||
Last movement: {x},{y}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default HitBox;
|
||||
@@ -1,18 +0,0 @@
|
||||
import FixtureSet from '../../FixtureSet';
|
||||
import MouseMove from './mouse-move';
|
||||
import Persistence from './persistence';
|
||||
|
||||
const React = window.React;
|
||||
|
||||
class EventPooling extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<FixtureSet title="Event Pooling" description="">
|
||||
<MouseMove />
|
||||
<Persistence />
|
||||
</FixtureSet>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default EventPooling;
|
||||
@@ -1,47 +0,0 @@
|
||||
import TestCase from '../../TestCase';
|
||||
import HitBox from './hit-box';
|
||||
|
||||
const React = window.React;
|
||||
|
||||
class MouseMove extends React.Component {
|
||||
state = {
|
||||
events: [],
|
||||
};
|
||||
|
||||
checkEvent = event => {
|
||||
let {events} = this.state;
|
||||
|
||||
if (event.type === 'mousemove' && events.indexOf(event) === -1) {
|
||||
this.setState({events: events.concat(event)});
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {events} = this.state;
|
||||
|
||||
return (
|
||||
<TestCase title="Mouse Move" description="">
|
||||
<TestCase.Steps>
|
||||
<li>Mouse over the box below</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
Mousemove should share the same instance of the event between
|
||||
dispatches.
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<HitBox onMouseMove={this.checkEvent} />
|
||||
|
||||
<p>
|
||||
Was the event pooled?{' '}
|
||||
<b>
|
||||
{events.length ? (events.length <= 1 ? 'Yes' : 'No') : 'Unsure'} (
|
||||
{events.length} events)
|
||||
</b>
|
||||
</p>
|
||||
</TestCase>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default MouseMove;
|
||||
@@ -1,62 +0,0 @@
|
||||
import TestCase from '../../TestCase';
|
||||
import HitBox from './hit-box';
|
||||
|
||||
const React = window.React;
|
||||
|
||||
class Persistence extends React.Component {
|
||||
state = {
|
||||
persisted: 0,
|
||||
pooled: [],
|
||||
};
|
||||
|
||||
addPersisted = event => {
|
||||
let {persisted, pooled} = this.state;
|
||||
|
||||
event.persist();
|
||||
|
||||
if (event.type === 'mousemove') {
|
||||
this.setState({
|
||||
persisted: persisted + 1,
|
||||
pooled: pooled.filter(e => e !== event),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
addPooled = event => {
|
||||
let {pooled} = this.state;
|
||||
|
||||
if (event.type === 'mousemove' && pooled.indexOf(event) === -1) {
|
||||
this.setState({pooled: pooled.concat(event)});
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {pooled, persisted} = this.state;
|
||||
|
||||
return (
|
||||
<TestCase title="Persistence" description="">
|
||||
<TestCase.Steps>
|
||||
<li>Mouse over the pooled event box</li>
|
||||
<li>Mouse over the persisted event box</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The pool size should not increase above 1, but reduce to 0 when
|
||||
hovering over the persisted region.
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<h2>Add Pooled Event:</h2>
|
||||
<HitBox onMouseMove={this.addPooled} />
|
||||
|
||||
<h2>Add Persisted Event:</h2>
|
||||
<HitBox onMouseMove={this.addPersisted} />
|
||||
|
||||
<p>Pool size: {pooled.length}</p>
|
||||
|
||||
<p>Persisted size: {persisted}</p>
|
||||
</TestCase>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Persistence;
|
||||
@@ -1,51 +0,0 @@
|
||||
import RangeInputFixtures from './range-inputs';
|
||||
import TextInputFixtures from './text-inputs';
|
||||
import SelectFixtures from './selects';
|
||||
import TextAreaFixtures from './textareas';
|
||||
import InputChangeEvents from './input-change-events';
|
||||
import NumberInputFixtures from './number-inputs';
|
||||
import PasswordInputFixtures from './password-inputs';
|
||||
import ButtonFixtures from './buttons';
|
||||
import DateInputFixtures from './date-inputs';
|
||||
import ErrorHandling from './error-handling';
|
||||
import EventPooling from './event-pooling';
|
||||
import CustomElementFixtures from './custom-elements';
|
||||
|
||||
const React = window.React;
|
||||
|
||||
/**
|
||||
* A simple routing component that renders the appropriate
|
||||
* fixture based on the location pathname.
|
||||
*/
|
||||
function FixturesPage() {
|
||||
switch (window.location.pathname) {
|
||||
case '/text-inputs':
|
||||
return <TextInputFixtures />;
|
||||
case '/range-inputs':
|
||||
return <RangeInputFixtures />;
|
||||
case '/selects':
|
||||
return <SelectFixtures />;
|
||||
case '/textareas':
|
||||
return <TextAreaFixtures />;
|
||||
case '/input-change-events':
|
||||
return <InputChangeEvents />;
|
||||
case '/number-inputs':
|
||||
return <NumberInputFixtures />;
|
||||
case '/password-inputs':
|
||||
return <PasswordInputFixtures />;
|
||||
case '/buttons':
|
||||
return <ButtonFixtures />;
|
||||
case '/date-inputs':
|
||||
return <DateInputFixtures />;
|
||||
case '/error-handling':
|
||||
return <ErrorHandling />;
|
||||
case '/event-pooling':
|
||||
return <EventPooling />;
|
||||
case '/custom-elements':
|
||||
return <CustomElementFixtures />;
|
||||
default:
|
||||
return <p>Please select a test fixture.</p>;
|
||||
}
|
||||
}
|
||||
|
||||
export default FixturesPage;
|
||||
@@ -1,59 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import Fixture from '../../Fixture';
|
||||
|
||||
class InputPlaceholderFixture extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
placeholder: 'A placeholder',
|
||||
changeCount: 0,
|
||||
};
|
||||
}
|
||||
|
||||
handleChange = () => {
|
||||
this.setState(({changeCount}) => {
|
||||
return {
|
||||
changeCount: changeCount + 1,
|
||||
};
|
||||
});
|
||||
};
|
||||
handleGeneratePlaceholder = () => {
|
||||
this.setState({
|
||||
placeholder: `A placeholder: ${Math.random() * 100}`,
|
||||
});
|
||||
};
|
||||
|
||||
handleReset = () => {
|
||||
this.setState({
|
||||
changeCount: 0,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const {placeholder, changeCount} = this.state;
|
||||
const color = changeCount === 0 ? 'green' : 'red';
|
||||
|
||||
return (
|
||||
<Fixture>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={placeholder}
|
||||
onChange={this.handleChange}
|
||||
/>{' '}
|
||||
<button onClick={this.handleGeneratePlaceholder}>
|
||||
Change placeholder
|
||||
</button>
|
||||
<p style={{color}}>
|
||||
<code>onChange</code>
|
||||
{' calls: '}
|
||||
<strong>{changeCount}</strong>
|
||||
</p>
|
||||
<button onClick={this.handleReset}>Reset count</button>
|
||||
</Fixture>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default InputPlaceholderFixture;
|
||||
@@ -1,49 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import Fixture from '../../Fixture';
|
||||
|
||||
class RadioClickFixture extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
changeCount: 0,
|
||||
};
|
||||
}
|
||||
|
||||
handleChange = () => {
|
||||
this.setState(({changeCount}) => {
|
||||
return {
|
||||
changeCount: changeCount + 1,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
handleReset = () => {
|
||||
this.setState({
|
||||
changeCount: 0,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const {changeCount} = this.state;
|
||||
const color = changeCount === 0 ? 'green' : 'red';
|
||||
|
||||
return (
|
||||
<Fixture>
|
||||
<label>
|
||||
<input defaultChecked type="radio" onChange={this.handleChange} />
|
||||
Test case radio input
|
||||
</label>{' '}
|
||||
<p style={{color}}>
|
||||
<code>onChange</code>
|
||||
{' calls: '}
|
||||
<strong>{changeCount}</strong>
|
||||
</p>
|
||||
<button onClick={this.handleReset}>Reset count</button>
|
||||
</Fixture>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default RadioClickFixture;
|
||||
@@ -1,58 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import Fixture from '../../Fixture';
|
||||
|
||||
class RadioGroupFixture extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
changeCount: 0,
|
||||
};
|
||||
}
|
||||
|
||||
handleChange = () => {
|
||||
this.setState(({changeCount}) => {
|
||||
return {
|
||||
changeCount: changeCount + 1,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
handleReset = () => {
|
||||
this.setState({
|
||||
changeCount: 0,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const {changeCount} = this.state;
|
||||
const color = changeCount === 2 ? 'green' : 'red';
|
||||
|
||||
return (
|
||||
<Fixture>
|
||||
<label>
|
||||
<input
|
||||
defaultChecked
|
||||
name="foo"
|
||||
type="radio"
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
Radio 1
|
||||
</label>
|
||||
<label>
|
||||
<input name="foo" type="radio" onChange={this.handleChange} />
|
||||
Radio 2
|
||||
</label>{' '}
|
||||
<p style={{color}}>
|
||||
<code>onChange</code>
|
||||
{' calls: '}
|
||||
<strong>{changeCount}</strong>
|
||||
</p>
|
||||
<button onClick={this.handleReset}>Reset count</button>
|
||||
</Fixture>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default RadioGroupFixture;
|
||||
@@ -1,80 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import Fixture from '../../Fixture';
|
||||
|
||||
class RangeKeyboardFixture extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
keydownCount: 0,
|
||||
changeCount: 0,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.input.addEventListener('keydown', this.handleKeydown, false);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.input.removeEventListener('keydown', this.handleKeydown, false);
|
||||
}
|
||||
|
||||
handleChange = () => {
|
||||
this.setState(({changeCount}) => {
|
||||
return {
|
||||
changeCount: changeCount + 1,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
handleKeydown = e => {
|
||||
// only interesting in arrow key events
|
||||
if ([37, 38, 39, 40].indexOf(e.keyCode) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState(({keydownCount}) => {
|
||||
return {
|
||||
keydownCount: keydownCount + 1,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
handleReset = () => {
|
||||
this.setState({
|
||||
keydownCount: 0,
|
||||
changeCount: 0,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const {keydownCount, changeCount} = this.state;
|
||||
const color = keydownCount === changeCount ? 'green' : 'red';
|
||||
|
||||
return (
|
||||
<Fixture>
|
||||
<div>
|
||||
<input
|
||||
type="range"
|
||||
ref={r => (this.input = r)}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<button onClick={() => this.input.focus()}>Focus Knob</button>
|
||||
</div>{' '}
|
||||
<p style={{color}}>
|
||||
<code>onKeyDown</code>
|
||||
{' calls: '}
|
||||
<strong>{keydownCount}</strong>
|
||||
{' vs '}
|
||||
<code>onChange</code>
|
||||
{' calls: '}
|
||||
<strong>{changeCount}</strong>
|
||||
</p>
|
||||
<button onClick={this.handleReset}>Reset counts</button>
|
||||
</Fixture>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default RangeKeyboardFixture;
|
||||
@@ -1,95 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import FixtureSet from '../../FixtureSet';
|
||||
import TestCase from '../../TestCase';
|
||||
import RangeKeyboardFixture from './RangeKeyboardFixture';
|
||||
import RadioClickFixture from './RadioClickFixture';
|
||||
import RadioGroupFixture from './RadioGroupFixture';
|
||||
import InputPlaceholderFixture from './InputPlaceholderFixture';
|
||||
|
||||
class InputChangeEvents extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<FixtureSet
|
||||
title="Input change events"
|
||||
description="Tests proper behavior of the onChange event for inputs">
|
||||
<TestCase
|
||||
title="Range keyboard changes"
|
||||
description={`
|
||||
Range inputs should fire onChange events for keyboard events
|
||||
`}>
|
||||
<TestCase.Steps>
|
||||
<li>Focus range input</li>
|
||||
<li>change value via the keyboard arrow keys</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The <code>onKeyDown</code> call count should be equal to the{' '}
|
||||
<code>onChange</code> call count.
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<RangeKeyboardFixture />
|
||||
</TestCase>
|
||||
|
||||
<TestCase
|
||||
title="Radio input clicks"
|
||||
description={`
|
||||
Radio inputs should only fire change events when the checked
|
||||
state changes.
|
||||
`}
|
||||
resolvedIn="16.0.0">
|
||||
<TestCase.Steps>
|
||||
<li>Click on the Radio input (or label text)</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The <code>onChange</code> call count should remain at 0
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<RadioClickFixture />
|
||||
</TestCase>
|
||||
<TestCase
|
||||
title="Uncontrolled radio groups"
|
||||
description={`
|
||||
Radio inputs should fire change events when the value moved to
|
||||
another named input
|
||||
`}
|
||||
introducedIn="15.6.0">
|
||||
<TestCase.Steps>
|
||||
<li>Click on the "Radio 2"</li>
|
||||
<li>Click back to "Radio 1"</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The <code>onChange</code> call count should equal 2
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<RadioGroupFixture />
|
||||
</TestCase>
|
||||
|
||||
<TestCase
|
||||
title="Inputs with placeholders"
|
||||
description={`
|
||||
Text inputs with placeholders should not trigger changes
|
||||
when the placeholder is altered
|
||||
`}
|
||||
resolvedIn="15.0.0"
|
||||
resolvedBy="#5004"
|
||||
affectedBrowsers="IE9+">
|
||||
<TestCase.Steps>
|
||||
<li>Click on the Text input</li>
|
||||
<li>Click on the "Change placeholder" button</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The <code>onChange</code> call count should remain at 0
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<InputPlaceholderFixture />
|
||||
</TestCase>
|
||||
</FixtureSet>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default InputChangeEvents;
|
||||
@@ -1,33 +0,0 @@
|
||||
import Fixture from '../../Fixture';
|
||||
|
||||
const React = window.React;
|
||||
|
||||
class NumberInputDecimal extends React.Component {
|
||||
state = {value: '.98'};
|
||||
changeValue = () => {
|
||||
this.setState({
|
||||
value: '0.98',
|
||||
});
|
||||
};
|
||||
render() {
|
||||
const {value} = this.state;
|
||||
return (
|
||||
<Fixture>
|
||||
<div>{this.props.children}</div>
|
||||
|
||||
<div className="control-box">
|
||||
<input
|
||||
type="number"
|
||||
value={value}
|
||||
onChange={e => {
|
||||
this.setState({value: e.target.value});
|
||||
}}
|
||||
/>
|
||||
<button onClick={this.changeValue}>change.98 to 0.98</button>
|
||||
</div>
|
||||
</Fixture>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default NumberInputDecimal;
|
||||
@@ -1,30 +0,0 @@
|
||||
import Fixture from '../../Fixture';
|
||||
|
||||
const React = window.React;
|
||||
|
||||
class NumberInputExtraZeroes extends React.Component {
|
||||
state = {value: '3.0000'};
|
||||
changeValue = () => {
|
||||
this.setState({
|
||||
value: '3.0000',
|
||||
});
|
||||
};
|
||||
onChange = event => {
|
||||
this.setState({value: event.target.value});
|
||||
};
|
||||
render() {
|
||||
const {value} = this.state;
|
||||
return (
|
||||
<Fixture>
|
||||
<div>{this.props.children}</div>
|
||||
|
||||
<div className="control-box">
|
||||
<input type="number" value={value} onChange={this.onChange} />
|
||||
<button onClick={this.changeValue}>Reset to "3.0000"</button>
|
||||
</div>
|
||||
</Fixture>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default NumberInputExtraZeroes;
|
||||
@@ -1,42 +0,0 @@
|
||||
import Fixture from '../../Fixture';
|
||||
|
||||
const React = window.React;
|
||||
|
||||
class NumberTestCase extends React.Component {
|
||||
state = {value: ''};
|
||||
onChange = event => {
|
||||
const parsed = parseFloat(event.target.value, 10);
|
||||
const value = isNaN(parsed) ? '' : parsed;
|
||||
|
||||
this.setState({value});
|
||||
};
|
||||
render() {
|
||||
return (
|
||||
<Fixture>
|
||||
<div>{this.props.children}</div>
|
||||
|
||||
<div className="control-box">
|
||||
<fieldset>
|
||||
<legend>Controlled</legend>
|
||||
<input
|
||||
type="number"
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
<span className="hint">
|
||||
{' '}
|
||||
Value: {JSON.stringify(this.state.value)}
|
||||
</span>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>Uncontrolled</legend>
|
||||
<input type="number" defaultValue={0.5} />
|
||||
</fieldset>
|
||||
</div>
|
||||
</Fixture>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default NumberTestCase;
|
||||
@@ -1,193 +0,0 @@
|
||||
import FixtureSet from '../../FixtureSet';
|
||||
import TestCase from '../../TestCase';
|
||||
import NumberTestCase from './NumberTestCase';
|
||||
import NumberInputDecimal from './NumberInputDecimal';
|
||||
import NumberInputExtraZeroes from './NumberInputExtraZeroes';
|
||||
|
||||
const React = window.React;
|
||||
|
||||
function NumberInputs() {
|
||||
return (
|
||||
<FixtureSet
|
||||
title="Number inputs"
|
||||
description="Number inputs inconsistently assign and report the value
|
||||
property depending on the browser.">
|
||||
<TestCase
|
||||
title="Backspacing"
|
||||
description="The decimal place should not be lost">
|
||||
<TestCase.Steps>
|
||||
<li>Type "3.1"</li>
|
||||
<li>Press backspace, eliminating the "1"</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read "3.", preserving the decimal place
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<NumberTestCase />
|
||||
|
||||
<p className="footnote">
|
||||
<b>Notes:</b> Chrome and Safari clear trailing decimals on blur. React
|
||||
makes this concession so that the value attribute remains in sync with
|
||||
the value property.
|
||||
</p>
|
||||
</TestCase>
|
||||
|
||||
<TestCase
|
||||
title="Decimal precision"
|
||||
description="Supports decimal precision greater than 2 places">
|
||||
<TestCase.Steps>
|
||||
<li>Type "0.01"</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read "0.01"
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<NumberTestCase />
|
||||
</TestCase>
|
||||
|
||||
<TestCase
|
||||
title="Exponent form"
|
||||
description="Supports exponent form ('2e4')">
|
||||
<TestCase.Steps>
|
||||
<li>Type "2e"</li>
|
||||
<li>Type 4, to read "2e4"</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read "2e4". The parsed value should read "20000"
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<NumberTestCase />
|
||||
</TestCase>
|
||||
|
||||
<TestCase title="Exponent Form" description="Pressing 'e' at the end">
|
||||
<TestCase.Steps>
|
||||
<li>Type "3.14"</li>
|
||||
<li>Press "e", so that the input reads "3.14e"</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read "3.14e", the parsed value should be empty
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<NumberTestCase />
|
||||
</TestCase>
|
||||
|
||||
<TestCase
|
||||
title="Exponent Form"
|
||||
description="Supports pressing 'ee' in the middle of a number">
|
||||
<TestCase.Steps>
|
||||
<li>Type "3.14"</li>
|
||||
<li>Move the text cursor to after the decimal place</li>
|
||||
<li>Press "e" twice, so that the value reads "3.ee14"</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read "3.ee14"
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<NumberTestCase />
|
||||
</TestCase>
|
||||
|
||||
<TestCase
|
||||
title="Trailing Zeroes"
|
||||
description="Typing '3.0' preserves the trailing zero">
|
||||
<TestCase.Steps>
|
||||
<li>Type "3.0"</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read "3.0"
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<NumberTestCase />
|
||||
</TestCase>
|
||||
|
||||
<TestCase
|
||||
title="Inserting decimals precision"
|
||||
description="Inserting '.' in to '300' maintains the trailing zeroes">
|
||||
<TestCase.Steps>
|
||||
<li>Type "300"</li>
|
||||
<li>Move the cursor to after the "3"</li>
|
||||
<li>Type "."</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read "3.00", not "3"
|
||||
</TestCase.ExpectedResult>
|
||||
<NumberTestCase />
|
||||
</TestCase>
|
||||
|
||||
<TestCase
|
||||
title="Replacing numbers with -"
|
||||
description="Replacing a number with the '-' sign should not clear the value">
|
||||
<TestCase.Steps>
|
||||
<li>Type "3"</li>
|
||||
<li>Select the entire value"</li>
|
||||
<li>Type '-' to replace '3' with '-'</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read "-", not be blank.
|
||||
</TestCase.ExpectedResult>
|
||||
<NumberTestCase />
|
||||
</TestCase>
|
||||
|
||||
<TestCase
|
||||
title="Negative numbers"
|
||||
description="Typing minus when inserting a negative number should work">
|
||||
<TestCase.Steps>
|
||||
<li>Type "-"</li>
|
||||
<li>Type '3'</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read "-3".
|
||||
</TestCase.ExpectedResult>
|
||||
<NumberTestCase />
|
||||
</TestCase>
|
||||
<TestCase
|
||||
title="Decimal numbers"
|
||||
description="eg: initial value is '.98', when format to '0.98', should change to '0.98' ">
|
||||
<TestCase.Steps>
|
||||
<li>initial value is '.98'</li>
|
||||
<li>setState to '0.98'</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
the input value should be '0.98'.
|
||||
</TestCase.ExpectedResult>
|
||||
<NumberInputDecimal />
|
||||
</TestCase>
|
||||
|
||||
<TestCase
|
||||
title="Trailing zeroes"
|
||||
description="Extraneous zeroes should be retained when changing the value via setState">
|
||||
<TestCase.Steps>
|
||||
<li>Change the text to 4.0000</li>
|
||||
<li>Click "Reset to 3.0000"</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read 3.0000, not 3
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<NumberInputExtraZeroes />
|
||||
|
||||
<p className="footnote">
|
||||
<b>Notes:</b> Firefox drops extraneous zeroes when assigned. Zeroes
|
||||
are preserved when editing, however directly assigning a new value
|
||||
will drop zeroes. This{' '}
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1003896">
|
||||
is a bug in Firefox
|
||||
</a>{' '}
|
||||
that we can not control for.
|
||||
</p>
|
||||
</TestCase>
|
||||
</FixtureSet>
|
||||
);
|
||||
}
|
||||
|
||||
export default NumberInputs;
|
||||
@@ -1,39 +0,0 @@
|
||||
import Fixture from '../../Fixture';
|
||||
|
||||
const React = window.React;
|
||||
|
||||
class PasswordTestCase extends React.Component {
|
||||
state = {value: ''};
|
||||
onChange = event => {
|
||||
this.setState({value: event.target.value});
|
||||
};
|
||||
render() {
|
||||
return (
|
||||
<Fixture>
|
||||
<div>{this.props.children}</div>
|
||||
|
||||
<div className="control-box">
|
||||
<fieldset>
|
||||
<legend>Controlled</legend>
|
||||
<input
|
||||
type="password"
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
<span className="hint">
|
||||
{' '}
|
||||
Value: {JSON.stringify(this.state.value)}
|
||||
</span>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>Uncontrolled</legend>
|
||||
<input type="password" defaultValue="" />
|
||||
</fieldset>
|
||||
</div>
|
||||
</Fixture>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PasswordTestCase;
|
||||
@@ -1,31 +0,0 @@
|
||||
import FixtureSet from '../../FixtureSet';
|
||||
import TestCase from '../../TestCase';
|
||||
import PasswordTestCase from './PasswordTestCase';
|
||||
|
||||
const React = window.React;
|
||||
|
||||
function NumberInputs() {
|
||||
return (
|
||||
<FixtureSet title="Password inputs" description="">
|
||||
<TestCase
|
||||
title="The show password icon"
|
||||
description={`
|
||||
Some browsers have an unmask password icon that React accidentally
|
||||
prevents the display of.
|
||||
`}
|
||||
affectedBrowsers="IE Edge, IE 11">
|
||||
<TestCase.Steps>
|
||||
<li>Type any string (not an actual password</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should include the "unmasking password" icon.
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<PasswordTestCase />
|
||||
</TestCase>
|
||||
</FixtureSet>
|
||||
);
|
||||
}
|
||||
|
||||
export default NumberInputs;
|
||||
@@ -1,30 +0,0 @@
|
||||
const React = window.React;
|
||||
|
||||
class RangeInputs extends React.Component {
|
||||
state = {value: 0.5};
|
||||
onChange = event => {
|
||||
this.setState({value: event.target.value});
|
||||
};
|
||||
render() {
|
||||
return (
|
||||
<form>
|
||||
<fieldset>
|
||||
<legend>Controlled</legend>
|
||||
<input
|
||||
type="range"
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
<span className="hint">Value: {this.state.value}</span>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>Uncontrolled</legend>
|
||||
<input type="range" defaultValue={0.5} />
|
||||
</fieldset>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default RangeInputs;
|
||||
@@ -1,166 +0,0 @@
|
||||
import FixtureSet from '../../FixtureSet';
|
||||
import TestCase from '../../TestCase';
|
||||
|
||||
const React = window.React;
|
||||
const ReactDOM = window.ReactDOM;
|
||||
|
||||
class SelectFixture extends React.Component {
|
||||
state = {value: ''};
|
||||
_nestedDOMNode = null;
|
||||
_singleFormDOMNode = null;
|
||||
_multipleFormDOMNode = null;
|
||||
|
||||
onChange = event => {
|
||||
this.setState({value: event.target.value});
|
||||
};
|
||||
|
||||
resetSingleOptionForm = event => {
|
||||
event.preventDefault();
|
||||
this._singleFormDOMNode.reset();
|
||||
};
|
||||
|
||||
resetMultipleOptionForm = event => {
|
||||
event.preventDefault();
|
||||
this._multipleFormDOMNode.reset();
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this._renderNestedSelect();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this._renderNestedSelect();
|
||||
}
|
||||
|
||||
_renderNestedSelect() {
|
||||
ReactDOM.render(
|
||||
<select value={this.state.value} onChange={this.onChange}>
|
||||
<option value="">Select a color</option>
|
||||
<option value="red">Red</option>
|
||||
<option value="blue">Blue</option>
|
||||
<option value="green">Green</option>
|
||||
</select>,
|
||||
this._nestedDOMNode
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<FixtureSet title="Selects" description="">
|
||||
<form className="field-group">
|
||||
<fieldset>
|
||||
<legend>Controlled</legend>
|
||||
<select value={this.state.value} onChange={this.onChange}>
|
||||
<option value="">Select a color</option>
|
||||
<option value="red">Red</option>
|
||||
<option value="blue">Blue</option>
|
||||
<option value="green">Green</option>
|
||||
</select>
|
||||
<span className="hint">Value: {this.state.value}</span>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Uncontrolled</legend>
|
||||
<select defaultValue="">
|
||||
<option value="">Select a color</option>
|
||||
<option value="red">Red</option>
|
||||
<option value="blue">Blue</option>
|
||||
<option value="green">Green</option>
|
||||
</select>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Controlled in nested subtree</legend>
|
||||
<div ref={node => (this._nestedDOMNode = node)} />
|
||||
<span className="hint">
|
||||
This should synchronize in both direction with the "Controlled".
|
||||
</span>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<TestCase title="A selected disabled option" relatedIssues="2803">
|
||||
<TestCase.Steps>
|
||||
<li>Open the select</li>
|
||||
<li>Select "1"</li>
|
||||
<li>Attempt to reselect "Please select an item"</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The initial picked option should be "Please select an item", however
|
||||
it should not be a selectable option.
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<div className="test-fixture">
|
||||
<select defaultValue="">
|
||||
<option value="" disabled>
|
||||
Please select an item
|
||||
</option>
|
||||
<option>0</option>
|
||||
<option>1</option>
|
||||
<option>2</option>
|
||||
</select>
|
||||
</div>
|
||||
</TestCase>
|
||||
|
||||
<TestCase title="An unselected disabled option" relatedIssues="2803">
|
||||
<TestCase.ExpectedResult>
|
||||
The initial picked option value should "0": the first non-disabled
|
||||
option.
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<div className="test-fixture">
|
||||
<select defaultValue="">
|
||||
<option disabled>Please select an item</option>
|
||||
<option>0</option>
|
||||
<option>1</option>
|
||||
<option>2</option>
|
||||
</select>
|
||||
</div>
|
||||
</TestCase>
|
||||
|
||||
<TestCase title="A single select being reset">
|
||||
<TestCase.Steps>
|
||||
<li>Open the select</li>
|
||||
<li>Select "baz" or "foo"</li>
|
||||
<li>Click the "Reset" button</li>
|
||||
</TestCase.Steps>
|
||||
<TestCase.ExpectedResult>
|
||||
The select should be reset to the inital value, "bar"
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<div className="test-fixture">
|
||||
<form ref={n => (this._singleFormDOMNode = n)}>
|
||||
<select defaultValue="bar">
|
||||
<option value="foo">foo</option>
|
||||
<option value="bar">bar</option>
|
||||
<option value="baz">baz</option>
|
||||
</select>
|
||||
<button onClick={this.resetSingleOptionForm}>Reset</button>
|
||||
</form>
|
||||
</div>
|
||||
</TestCase>
|
||||
|
||||
<TestCase title="A multiple select being reset">
|
||||
<TestCase.Steps>
|
||||
<li>Select any combination of options</li>
|
||||
<li>Click the "Reset" button</li>
|
||||
</TestCase.Steps>
|
||||
<TestCase.ExpectedResult>
|
||||
The select should be reset to the initial values "foo" and "baz"
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<div className="test-fixture">
|
||||
<form ref={n => (this._multipleFormDOMNode = n)}>
|
||||
<select multiple defaultValue={['foo', 'baz']}>
|
||||
<option value="foo">foo</option>
|
||||
<option value="bar">bar</option>
|
||||
<option value="baz">baz</option>
|
||||
</select>
|
||||
<button onClick={this.resetMultipleOptionForm}>Reset</button>
|
||||
</form>
|
||||
</div>
|
||||
</TestCase>
|
||||
</FixtureSet>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SelectFixture;
|
||||
@@ -1,59 +0,0 @@
|
||||
import Fixture from '../../Fixture';
|
||||
const React = window.React;
|
||||
|
||||
class InputTestCase extends React.Component {
|
||||
static defaultProps = {
|
||||
type: 'text',
|
||||
defaultValue: '',
|
||||
parseAs: 'text',
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
||||
this.state = {
|
||||
value: this.props.defaultValue,
|
||||
};
|
||||
}
|
||||
|
||||
onChange = event => {
|
||||
const raw = event.target.value;
|
||||
|
||||
switch (this.props.type) {
|
||||
case 'number':
|
||||
const parsed = parseFloat(event.target.value, 10);
|
||||
|
||||
this.setState({value: isNaN(parsed) ? '' : parsed});
|
||||
|
||||
break;
|
||||
default:
|
||||
this.setState({value: raw});
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {children, type, defaultValue} = this.props;
|
||||
const {value} = this.state;
|
||||
|
||||
return (
|
||||
<Fixture>
|
||||
<div>{children}</div>
|
||||
|
||||
<div className="control-box">
|
||||
<fieldset>
|
||||
<legend>Controlled {type}</legend>
|
||||
<input type={type} value={value} onChange={this.onChange} />
|
||||
<p className="hint">Value: {JSON.stringify(this.state.value)}</p>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>Uncontrolled {type}</legend>
|
||||
<input type={type} defaultValue={defaultValue} />
|
||||
</fieldset>
|
||||
</div>
|
||||
</Fixture>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default InputTestCase;
|
||||
@@ -1,65 +0,0 @@
|
||||
# Text Inputs
|
||||
|
||||
There are a couple of important concepts to be aware of when working on text
|
||||
inputs in React.
|
||||
|
||||
## `defaultValue` vs `value`
|
||||
|
||||
An input's value is drawn from two properties: `defaultValue` and `value`.
|
||||
|
||||
The `defaultValue` property directly maps to the value _attribute_, for example:
|
||||
|
||||
```javascript
|
||||
var input = document.createElement('input')
|
||||
input.defaultValue = 'hello'
|
||||
|
||||
console.log(input.getAttribute('value')) // => "hello"
|
||||
```
|
||||
|
||||
The `value` property manipulates the _working value_ for the input. This property
|
||||
changes whenever the user interacts with an input, or it is modified with JavaScript:
|
||||
|
||||
```javascript
|
||||
var input = document.createElement('input')
|
||||
input.defaultValue = 'hello'
|
||||
input.value = 'goodbye'
|
||||
|
||||
console.log(input.getAttribute('value')) // => "hello"
|
||||
console.log(input.value) // => "goodbye"
|
||||
```
|
||||
|
||||
## value detachment
|
||||
|
||||
Until `value` is manipulated by a user or JavaScript, manipulating `defaultValue`
|
||||
will also modify the `value` property:
|
||||
|
||||
```javascript
|
||||
var input = document.createElement('input')
|
||||
// This will turn into 3
|
||||
input.defaultValue = 3
|
||||
// This will turn into 5
|
||||
input.defaultValue = 5
|
||||
// This will turn into 7
|
||||
input.value = 7
|
||||
// This will do nothing
|
||||
input.defaultValue = 1
|
||||
```
|
||||
|
||||
**React detaches all inputs**. This prevents `value` from accidentally updating if
|
||||
`defaultValue` changes.
|
||||
|
||||
## Form reset events
|
||||
|
||||
React does not support `form.reset()` for controlled inputs. This is a feature,
|
||||
not a bug. `form.reset()` works by reverting an input's `value` _property_ to
|
||||
that of the current `defaultValue`. Since React assigns the value `attribute`
|
||||
every time a controlled input's value changes, controlled inputs will never
|
||||
"revert" back to their original display value.
|
||||
|
||||
## Number inputs
|
||||
|
||||
Chrome (55) and Safari (10) attempt to "correct" the value of number inputs any
|
||||
time the value property or attribute are changed. This leads to some edge documented
|
||||
here:
|
||||
|
||||
https://github.com/facebook/react/pull/7359#issuecomment-256499693
|
||||
@@ -1,96 +0,0 @@
|
||||
import Fixture from '../../Fixture';
|
||||
import FixtureSet from '../../FixtureSet';
|
||||
import TestCase from '../../TestCase';
|
||||
import InputTestCase from './InputTestCase';
|
||||
|
||||
const React = window.React;
|
||||
|
||||
class TextInputFixtures extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<FixtureSet
|
||||
title="Inputs"
|
||||
description="Common behavior across controlled and uncontrolled inputs">
|
||||
<TestCase title="Numbers in a controlled text field with no handler">
|
||||
<TestCase.Steps>
|
||||
<li>Move the cursor to after "2" in the text field</li>
|
||||
<li>Type ".2" into the text input</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The text field's value should not update.
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<Fixture>
|
||||
<div className="control-box">
|
||||
<fieldset>
|
||||
<legend>Value as number</legend>
|
||||
<input value={2} onChange={() => {}} />
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>Value as string</legend>
|
||||
<input value={'2'} onChange={() => {}} />
|
||||
</fieldset>
|
||||
</div>
|
||||
</Fixture>
|
||||
|
||||
<p className="footnote">
|
||||
This issue was first introduced when we added extra logic to number
|
||||
inputs to prevent unexpected behavior in Chrome and Safari (see the
|
||||
number input test case).
|
||||
</p>
|
||||
</TestCase>
|
||||
|
||||
<TestCase title="Cursor when editing email inputs">
|
||||
<TestCase.Steps>
|
||||
<li>Type "user@example.com"</li>
|
||||
<li>Select "@"</li>
|
||||
<li>Type ".", to replace "@" with a period</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The text field's cursor should not jump to the end.
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<InputTestCase type="email" defaultValue="" />
|
||||
</TestCase>
|
||||
|
||||
<TestCase title="Cursor when editing url inputs">
|
||||
<TestCase.Steps>
|
||||
<li>Type "http://www.example.com"</li>
|
||||
<li>Select "www."</li>
|
||||
<li>Press backspace/delete</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The text field's cursor should not jump to the end.
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<InputTestCase type="url" defaultValue="" />
|
||||
</TestCase>
|
||||
|
||||
<TestCase title="All inputs" description="General test of all inputs">
|
||||
<InputTestCase type="text" defaultValue="Text" />
|
||||
<InputTestCase type="email" defaultValue="user@example.com" />
|
||||
<InputTestCase type="number" defaultValue={0} />
|
||||
<InputTestCase type="url" defaultValue="http://example.com" />
|
||||
<InputTestCase type="tel" defaultValue="555-555-5555" />
|
||||
<InputTestCase type="color" defaultValue="#ff0000" />
|
||||
<InputTestCase type="date" defaultValue="2017-01-01" />
|
||||
<InputTestCase
|
||||
type="datetime-local"
|
||||
defaultValue="2017-01-01T01:00"
|
||||
/>
|
||||
<InputTestCase type="time" defaultValue="01:00" />
|
||||
<InputTestCase type="month" defaultValue="2017-01" />
|
||||
<InputTestCase type="week" defaultValue="2017-W01" />
|
||||
<InputTestCase type="range" defaultValue={0.5} />
|
||||
<InputTestCase type="password" defaultValue="" />
|
||||
</TestCase>
|
||||
</FixtureSet>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TextInputFixtures;
|
||||
@@ -1,45 +0,0 @@
|
||||
import FixtureSet from '../../FixtureSet';
|
||||
import TestCase from '../../TestCase';
|
||||
|
||||
const React = window.React;
|
||||
|
||||
export default class TextAreaFixtures extends React.Component {
|
||||
state = {value: ''};
|
||||
onChange = event => {
|
||||
this.setState({value: event.target.value});
|
||||
};
|
||||
render() {
|
||||
return (
|
||||
<FixtureSet title="Textareas">
|
||||
<TestCase
|
||||
title="Kitchen Sink"
|
||||
description="Verify that the controlled textarea displays its value under 'Controlled Output', and that both textareas can be typed in">
|
||||
<div>
|
||||
<form className="container">
|
||||
<fieldset>
|
||||
<legend>Controlled</legend>
|
||||
<textarea value={this.state.value} onChange={this.onChange} />
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Uncontrolled</legend>
|
||||
<textarea defaultValue="" />
|
||||
</fieldset>
|
||||
</form>
|
||||
<div className="container">
|
||||
<h4>Controlled Output:</h4>
|
||||
<div className="output">{this.state.value}</div>
|
||||
</div>
|
||||
</div>
|
||||
</TestCase>
|
||||
<TestCase title="Placeholders">
|
||||
<TestCase.ExpectedResult>
|
||||
The textarea should be rendered with the placeholder "Hello, world"
|
||||
</TestCase.ExpectedResult>
|
||||
<div style={{margin: '10px 0px'}}>
|
||||
<textarea placeholder="Hello, world" />
|
||||
</div>
|
||||
</TestCase>
|
||||
</FixtureSet>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import semver from 'semver';
|
||||
|
||||
export function semverString(props, propName, componentName) {
|
||||
let version = props[propName];
|
||||
|
||||
let error = PropTypes.string(...arguments);
|
||||
if (!error && version != null && !semver.valid(version))
|
||||
error = new Error(
|
||||
`\`${propName}\` should be a valid "semantic version" matching ` +
|
||||
'an existing React version'
|
||||
);
|
||||
|
||||
return error || null;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import './polyfills';
|
||||
import loadReact from './react-loader';
|
||||
|
||||
loadReact()
|
||||
.then(() => import('./components/App'))
|
||||
.then(App => {
|
||||
const {React, ReactDOM} = window;
|
||||
|
||||
ReactDOM.render(
|
||||
React.createElement(App.default),
|
||||
document.getElementById('root')
|
||||
);
|
||||
});
|
||||
@@ -1,35 +0,0 @@
|
||||
import 'core-js/es6/promise';
|
||||
import 'core-js/es6/set';
|
||||
import 'core-js/es6/map';
|
||||
|
||||
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
|
||||
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
|
||||
|
||||
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
|
||||
// MIT license
|
||||
(function() {
|
||||
var lastTime = 0;
|
||||
var vendors = ['ms', 'moz', 'webkit', 'o'];
|
||||
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
|
||||
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
|
||||
window.cancelAnimationFrame =
|
||||
window[vendors[x] + 'CancelAnimationFrame'] ||
|
||||
window[vendors[x] + 'CancelRequestAnimationFrame'];
|
||||
}
|
||||
|
||||
if (!window.requestAnimationFrame)
|
||||
window.requestAnimationFrame = function(callback, element) {
|
||||
var currTime = new Date().getTime();
|
||||
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
|
||||
var id = window.setTimeout(function() {
|
||||
callback(currTime + timeToCall);
|
||||
}, timeToCall);
|
||||
lastTime = currTime + timeToCall;
|
||||
return id;
|
||||
};
|
||||
|
||||
if (!window.cancelAnimationFrame)
|
||||
window.cancelAnimationFrame = function(id) {
|
||||
clearTimeout(id);
|
||||
};
|
||||
})();
|
||||
75
fixtures/dom/src/react-loader.js
vendored
75
fixtures/dom/src/react-loader.js
vendored
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
* Take a version from the window query string and load a specific
|
||||
* version of React.
|
||||
*
|
||||
* @example
|
||||
* http://localhost:3000?version=15.4.1
|
||||
* (Loads React 15.4.1)
|
||||
*/
|
||||
|
||||
function parseQuery(qstr) {
|
||||
var query = {};
|
||||
var a = qstr.substr(1).split('&');
|
||||
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
var b = a[i].split('=');
|
||||
query[decodeURIComponent(b[0])] = decodeURIComponent(b[1] || '');
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
function loadScript(src) {
|
||||
let firstScript = document.getElementsByTagName('script')[0];
|
||||
let scriptNode;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
scriptNode = document.createElement('script');
|
||||
scriptNode.async = 1;
|
||||
scriptNode.src = src;
|
||||
|
||||
scriptNode.onload = () => resolve();
|
||||
scriptNode.onerror = () => reject(new Error(`failed to load: ${src}`));
|
||||
|
||||
firstScript.parentNode.insertBefore(scriptNode, firstScript);
|
||||
});
|
||||
}
|
||||
|
||||
export default function loadReact() {
|
||||
let REACT_PATH = 'react.development.js';
|
||||
let DOM_PATH = 'react-dom.development.js';
|
||||
|
||||
let query = parseQuery(window.location.search);
|
||||
let version = query.version || 'local';
|
||||
|
||||
if (version !== 'local') {
|
||||
// The file structure was updated in 16. This wasn't the case for alphas.
|
||||
// Load the old module location for anything less than 16 RC
|
||||
if (parseInt(version, 10) >= 16 && version.indexOf('alpha') < 0) {
|
||||
REACT_PATH =
|
||||
'https://unpkg.com/react@' + version + '/umd/react.development.js';
|
||||
DOM_PATH =
|
||||
'https://unpkg.com/react-dom@' +
|
||||
version +
|
||||
'/umd/react-dom.development.js';
|
||||
} else {
|
||||
REACT_PATH = 'https://unpkg.com/react@' + version + '/dist/react.js';
|
||||
DOM_PATH =
|
||||
'https://unpkg.com/react-dom@' + version + '/dist/react-dom.js';
|
||||
}
|
||||
}
|
||||
|
||||
const needsReactDOM = version === 'local' || parseFloat(version, 10) > 0.13;
|
||||
|
||||
let request = loadScript(REACT_PATH);
|
||||
|
||||
if (needsReactDOM) {
|
||||
request = request.then(() => loadScript(DOM_PATH));
|
||||
} else {
|
||||
// Aliasing React to ReactDOM for compatibility.
|
||||
request = request.then(() => {
|
||||
window.ReactDOM = window.React;
|
||||
});
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
@@ -1,224 +0,0 @@
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 10px;
|
||||
}
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
font-size: 1.4rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
background: white;
|
||||
border-radius: 2px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.24);
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
margin: 10px;
|
||||
padding: 6px 8px;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: #222;
|
||||
box-shadow: inset 0 -1px 3px #000;
|
||||
font-size: 1.6rem;
|
||||
line-height: 3.2rem;
|
||||
overflow: hidden;
|
||||
padding: .8rem 1.6rem;
|
||||
}
|
||||
|
||||
.header select {
|
||||
width: 12rem;
|
||||
}
|
||||
|
||||
.header__inner {
|
||||
display: table;
|
||||
margin: 0 auto;
|
||||
max-width: 1000px;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.header__logo {
|
||||
color: #efefef;
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.header__logo img {
|
||||
display: inline-block;
|
||||
margin-right: 0.8rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.header-controls {
|
||||
display: table-cell;
|
||||
text-align: right;
|
||||
vertical-align: middle;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sr-only {
|
||||
clip: rect(0, 0, 0, 0);
|
||||
height: 0;
|
||||
margin: -1px;
|
||||
position: absolute;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: 0 auto;
|
||||
max-width: 900px;
|
||||
overflow: hidden;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.control-label {
|
||||
display: block;
|
||||
font-size: 1.2rem;
|
||||
letter-spacing: 0.01em;
|
||||
margin-bottom: 0.4rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.field {
|
||||
padding: 0.8rem;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
border: 1px solid #aaa;
|
||||
float: left;
|
||||
padding: 1.6rem;
|
||||
width: 49%;
|
||||
}
|
||||
|
||||
.control-box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
margin: 0 0 2rem 0;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
.type-subheading {
|
||||
font-size: 1.8rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.5;
|
||||
margin: 0 0 1.6rem;
|
||||
}
|
||||
|
||||
.hint {
|
||||
font-style: italic;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.footnote {
|
||||
border-left: 4px solid #aaa;
|
||||
color: #444;
|
||||
font-style: italic;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 2.4rem;
|
||||
margin-left: 0.4rem;
|
||||
padding-left: 1.6rem;
|
||||
}
|
||||
|
||||
.test-case {
|
||||
border-radius: 0.2rem;
|
||||
border: 1px solid #d9d9d9;
|
||||
margin: 3.2rem 0 3.2rem;
|
||||
}
|
||||
|
||||
.test-case__title {
|
||||
padding: 10px 15px 8px;
|
||||
line-height: 16px;
|
||||
font-size: 18px;
|
||||
border-bottom: 1px dashed #d9d9d9;
|
||||
margin: 0 0 -1px;
|
||||
}
|
||||
|
||||
.test-case__title__check {
|
||||
display: inline-block;
|
||||
margin-right: 8px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.test-case__body {
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.test-case__desc {
|
||||
font-style: italic;
|
||||
margin: 15px 0;
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.test-case--complete {
|
||||
border-color: #5cb85c;
|
||||
}
|
||||
|
||||
.test-case--complete .test-case__title {
|
||||
color: #5cb85c;
|
||||
}
|
||||
|
||||
.test-case__details {
|
||||
border-bottom: 1px dashed #d9d9d9;
|
||||
font-size: 80%;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.02em;
|
||||
margin: 0;
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.test-case__details > * {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.test-case__details > dt,
|
||||
.test-case__details > dd {
|
||||
padding: 8px 0 6px;
|
||||
}
|
||||
|
||||
.test-case__details > dt {
|
||||
color: #464a4c;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.test-case__details > dd {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.test-case__details > dd + dt {
|
||||
margin-left: 1.5rem;
|
||||
}
|
||||
|
||||
.test-case__invalid-version {
|
||||
font-style: italic;
|
||||
font-size: 1.6rem;
|
||||
color: #5cb85c;
|
||||
}
|
||||
|
||||
.test-fixture {
|
||||
padding: 20px;
|
||||
margin: 0 -15px; /* opposite of .test-case padding */
|
||||
background-color: #f4f4f4;
|
||||
border-top: 1px solid #d9d9d9;
|
||||
}
|
||||
|
||||
.field-group {
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/**
|
||||
* Version tags are loaded from the GitHub API. Since the GitHub API is rate-limited
|
||||
* we attempt to save and load the tags in sessionStorage when possible. Since its unlikely
|
||||
* that versions will change during a single session this should be safe.
|
||||
*/
|
||||
|
||||
const TAGS_CACHE_KEY = '@react-dom-fixtures/tags';
|
||||
|
||||
/**
|
||||
* Its possible that users will be testing changes frequently
|
||||
* in a browser that does not support sessionStorage. If the API does
|
||||
* get rate limited this hardcoded fallback will be loaded instead.
|
||||
* This way users can still switch between ~some versions while testing.
|
||||
* If there's a specific version they need to test that is not here, they
|
||||
* can manually load it by editing the URL (`?version={whatever}`)
|
||||
*/
|
||||
const fallbackTags = [
|
||||
'15.4.2',
|
||||
'15.3.2',
|
||||
'15.2.1',
|
||||
'15.1.0',
|
||||
'15.0.2',
|
||||
'0.14.8',
|
||||
'0.13.0',
|
||||
].map(version => ({
|
||||
name: `v${version}`,
|
||||
}));
|
||||
|
||||
let canUseSessionStorage = true;
|
||||
|
||||
try {
|
||||
sessionStorage.setItem('foo', '');
|
||||
} catch (err) {
|
||||
canUseSessionStorage = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to load tags from sessionStorage. In cases where
|
||||
* sessionStorage is not available (Safari private browsing) or the
|
||||
* tags are cached a fetch request is made to the GitHub API.
|
||||
*
|
||||
* Returns a promise so that the consuming module can always assume
|
||||
* the request is async, even if its loaded from sessionStorage.
|
||||
*/
|
||||
export default function getVersionTags() {
|
||||
return new Promise(resolve => {
|
||||
let cachedTags;
|
||||
if (canUseSessionStorage) {
|
||||
cachedTags = sessionStorage.getItem(TAGS_CACHE_KEY);
|
||||
}
|
||||
if (cachedTags) {
|
||||
cachedTags = JSON.parse(cachedTags);
|
||||
resolve(cachedTags);
|
||||
} else {
|
||||
fetch('https://api.github.com/repos/facebook/react/tags', {mode: 'cors'})
|
||||
.then(res => res.json())
|
||||
.then(tags => {
|
||||
// A message property indicates an error was sent from the API
|
||||
if (tags.message) {
|
||||
return resolve(fallbackTags);
|
||||
}
|
||||
if (canUseSessionStorage) {
|
||||
sessionStorage.setItem(TAGS_CACHE_KEY, JSON.stringify(tags));
|
||||
}
|
||||
resolve(tags);
|
||||
})
|
||||
.catch(() => resolve(fallbackTags));
|
||||
}
|
||||
});
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
NODE_PATH=../../build/packages
|
||||
14
fixtures/fiber-debugger/.gitignore
vendored
14
fixtures/fiber-debugger/.gitignore
vendored
@@ -1,14 +0,0 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
node_modules
|
||||
|
||||
# testing
|
||||
coverage
|
||||
|
||||
# production
|
||||
build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
npm-debug.log
|
||||
@@ -1,25 +0,0 @@
|
||||
# Fiber Debugger
|
||||
|
||||
This is a debugger handy for visualizing how [Fiber](https://github.com/facebook/react/issues/6170) works internally.
|
||||
|
||||
**It is only meant to be used by React contributors, and not by React users.**
|
||||
|
||||
It is likely that it might get broken at some point. If it's broken, ping [Dan](https://twitter.com/dan_abramov).
|
||||
|
||||
### Running
|
||||
|
||||
First, `npm run build` in React root repo folder.
|
||||
|
||||
Then `npm install` and `npm start` in this folder.
|
||||
|
||||
Open `http://localhost:3000` in Chrome.
|
||||
|
||||
### Features
|
||||
|
||||
* Edit code that uses `ReactNoop` renderer
|
||||
* Visualize how relationships between fibers change over time
|
||||
* Current tree is displayed in green
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"name": "react-fiber-debugger",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"react-scripts": "0.9.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"dagre": "^0.7.4",
|
||||
"pretty-format": "^4.2.1",
|
||||
"react-draggable": "^2.2.6",
|
||||
"react-motion": "^0.5.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB |
@@ -1,13 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.14.0/babel.min.js"></script>
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,261 +0,0 @@
|
||||
import React, {Component} from 'react';
|
||||
import Draggable from 'react-draggable';
|
||||
import ReactNoop from 'react-noop-renderer';
|
||||
import Editor from './Editor';
|
||||
import Fibers from './Fibers';
|
||||
import describeFibers from './describeFibers';
|
||||
|
||||
// The only place where we use it.
|
||||
const ReactFiberInstrumentation =
|
||||
ReactNoop.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
|
||||
.ReactFiberInstrumentation;
|
||||
|
||||
function getFiberState(root, workInProgress) {
|
||||
if (!root) {
|
||||
return null;
|
||||
}
|
||||
return describeFibers(root.current, workInProgress);
|
||||
}
|
||||
|
||||
const defaultCode = `
|
||||
log('Render <div>Hello</div>');
|
||||
ReactNoop.render(<div>Hello</div>);
|
||||
ReactNoop.flush();
|
||||
|
||||
log('Render <h1>Goodbye</h1>');
|
||||
ReactNoop.render(<h1>Goodbye</h1>);
|
||||
ReactNoop.flush();
|
||||
`;
|
||||
|
||||
class App extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
code: localStorage.getItem('fiber-debugger-code') || defaultCode,
|
||||
isEditing: false,
|
||||
history: [],
|
||||
currentStep: 0,
|
||||
show: {
|
||||
alt: false,
|
||||
child: true,
|
||||
sibling: true,
|
||||
return: false,
|
||||
fx: false,
|
||||
},
|
||||
graphSettings: {
|
||||
rankdir: 'TB',
|
||||
trackActive: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.runCode(this.state.code);
|
||||
}
|
||||
|
||||
runCode(code) {
|
||||
let currentStage;
|
||||
let currentRoot;
|
||||
|
||||
ReactFiberInstrumentation.debugTool = null;
|
||||
ReactNoop.render(null);
|
||||
ReactNoop.flush();
|
||||
ReactFiberInstrumentation.debugTool = {
|
||||
onMountContainer: root => {
|
||||
currentRoot = root;
|
||||
},
|
||||
onUpdateContainer: root => {
|
||||
currentRoot = root;
|
||||
},
|
||||
onBeginWork: fiber => {
|
||||
const fibers = getFiberState(currentRoot, fiber);
|
||||
const stage = currentStage;
|
||||
this.setState(({history}) => ({
|
||||
history: [
|
||||
...history,
|
||||
{
|
||||
action: 'BEGIN',
|
||||
fibers,
|
||||
stage,
|
||||
},
|
||||
],
|
||||
}));
|
||||
},
|
||||
onCompleteWork: fiber => {
|
||||
const fibers = getFiberState(currentRoot, fiber);
|
||||
const stage = currentStage;
|
||||
this.setState(({history}) => ({
|
||||
history: [
|
||||
...history,
|
||||
{
|
||||
action: 'COMPLETE',
|
||||
fibers,
|
||||
stage,
|
||||
},
|
||||
],
|
||||
}));
|
||||
},
|
||||
onCommitWork: fiber => {
|
||||
const fibers = getFiberState(currentRoot, fiber);
|
||||
const stage = currentStage;
|
||||
this.setState(({history}) => ({
|
||||
history: [
|
||||
...history,
|
||||
{
|
||||
action: 'COMMIT',
|
||||
fibers,
|
||||
stage,
|
||||
},
|
||||
],
|
||||
}));
|
||||
},
|
||||
};
|
||||
window.React = React;
|
||||
window.ReactNoop = ReactNoop;
|
||||
window.expect = () => ({
|
||||
toBe() {},
|
||||
toContain() {},
|
||||
toEqual() {},
|
||||
});
|
||||
window.log = s => (currentStage = s);
|
||||
// eslint-disable-next-line
|
||||
eval(
|
||||
window.Babel.transform(code, {
|
||||
presets: ['react', 'es2015'],
|
||||
}).code
|
||||
);
|
||||
}
|
||||
|
||||
handleEdit = e => {
|
||||
e.preventDefault();
|
||||
this.setState({
|
||||
isEditing: true,
|
||||
});
|
||||
};
|
||||
|
||||
handleCloseEdit = nextCode => {
|
||||
localStorage.setItem('fiber-debugger-code', nextCode);
|
||||
this.setState({
|
||||
isEditing: false,
|
||||
history: [],
|
||||
currentStep: 0,
|
||||
code: nextCode,
|
||||
});
|
||||
this.runCode(nextCode);
|
||||
};
|
||||
|
||||
render() {
|
||||
const {history, currentStep, isEditing, code} = this.state;
|
||||
if (isEditing) {
|
||||
return <Editor code={code} onClose={this.handleCloseEdit} />;
|
||||
}
|
||||
|
||||
const {fibers, action, stage} = history[currentStep] || {};
|
||||
let friendlyAction;
|
||||
if (fibers) {
|
||||
let wipFiber = fibers.descriptions[fibers.workInProgressID];
|
||||
let friendlyFiber = wipFiber.type || wipFiber.tag + ' #' + wipFiber.id;
|
||||
friendlyAction = `After ${action} on ${friendlyFiber}`;
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{height: '100%'}}>
|
||||
{fibers && (
|
||||
<Draggable>
|
||||
<Fibers
|
||||
fibers={fibers}
|
||||
show={this.state.show}
|
||||
graphSettings={this.state.graphSettings}
|
||||
/>
|
||||
</Draggable>
|
||||
)}
|
||||
<div
|
||||
style={{
|
||||
width: '100%',
|
||||
textAlign: 'center',
|
||||
position: 'fixed',
|
||||
bottom: 0,
|
||||
padding: 10,
|
||||
zIndex: 1,
|
||||
backgroundColor: '#fafafa',
|
||||
border: '1px solid #ccc',
|
||||
}}>
|
||||
<div style={{width: '50%', float: 'left'}}>
|
||||
<input
|
||||
type="range"
|
||||
style={{width: '25%'}}
|
||||
min={0}
|
||||
max={history.length - 1}
|
||||
value={currentStep}
|
||||
onChange={e =>
|
||||
this.setState({currentStep: Number(e.target.value)})
|
||||
}
|
||||
/>
|
||||
<p>
|
||||
Step {currentStep}
|
||||
: {friendlyAction} (
|
||||
<a style={{color: 'gray'}} onClick={this.handleEdit} href="#">
|
||||
Edit
|
||||
</a>
|
||||
)
|
||||
</p>
|
||||
{stage && <p>Stage: {stage}</p>}
|
||||
{Object.keys(this.state.show).map(key => (
|
||||
<label style={{marginRight: '10px'}} key={key}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={this.state.show[key]}
|
||||
onChange={e => {
|
||||
this.setState(({show}) => ({
|
||||
show: {...show, [key]: !show[key]},
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
{key}
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
<div style={{width: '50%', float: 'right'}}>
|
||||
<h5>Graph Settings</h5>
|
||||
<p>
|
||||
<label style={{display: ''}}>
|
||||
Direction:
|
||||
<select
|
||||
onChange={e => {
|
||||
const rankdir = e.target.value;
|
||||
this.setState(({graphSettings}) => ({
|
||||
graphSettings: {...graphSettings, rankdir},
|
||||
}));
|
||||
}}>
|
||||
<option value="TB">top-down</option>
|
||||
<option value="BT">down-top</option>
|
||||
<option value="LR">left-right</option>
|
||||
<option value="RL">right-left</option>
|
||||
</select>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label style={{marginRight: '10px'}}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={this.state.graphSettings.trackActive}
|
||||
onChange={e => {
|
||||
this.setState(({graphSettings}) => ({
|
||||
graphSettings: {
|
||||
...graphSettings,
|
||||
trackActive: !graphSettings.trackActive,
|
||||
},
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
Track active fiber
|
||||
</label>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -1,39 +0,0 @@
|
||||
import React, {Component} from 'react';
|
||||
|
||||
class Editor extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
code: props.code,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
}}>
|
||||
<textarea
|
||||
value={this.state.code}
|
||||
onChange={e => this.setState({code: e.target.value})}
|
||||
style={{
|
||||
height: '80%',
|
||||
width: '100%',
|
||||
fontSize: '15px',
|
||||
}}
|
||||
/>
|
||||
<div style={{height: '20%', textAlign: 'center'}}>
|
||||
<button
|
||||
onClick={() => this.props.onClose(this.state.code)}
|
||||
style={{fontSize: 'large'}}>
|
||||
Run
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Editor;
|
||||
@@ -1,414 +0,0 @@
|
||||
import React from 'react';
|
||||
import {Motion, spring} from 'react-motion';
|
||||
import dagre from 'dagre';
|
||||
// import prettyFormat from 'pretty-format';
|
||||
// import reactElement from 'pretty-format/plugins/ReactElement';
|
||||
|
||||
function getFiberColor(fibers, id) {
|
||||
if (fibers.currentIDs.indexOf(id) > -1) {
|
||||
return 'lightgreen';
|
||||
}
|
||||
if (id === fibers.workInProgressID) {
|
||||
return 'yellow';
|
||||
}
|
||||
return 'lightyellow';
|
||||
}
|
||||
|
||||
function Graph(props) {
|
||||
const {rankdir, trackActive} = props.settings;
|
||||
var g = new dagre.graphlib.Graph();
|
||||
g.setGraph({
|
||||
width: 1000,
|
||||
height: 1000,
|
||||
nodesep: 50,
|
||||
edgesep: 150,
|
||||
ranksep: 100,
|
||||
marginx: 100,
|
||||
marginy: 100,
|
||||
rankdir,
|
||||
});
|
||||
|
||||
var edgeLabels = {};
|
||||
React.Children.forEach(props.children, function(child) {
|
||||
if (!child) {
|
||||
return;
|
||||
}
|
||||
if (child.type.isVertex) {
|
||||
g.setNode(child.key, {
|
||||
label: child,
|
||||
width: child.props.width,
|
||||
height: child.props.height,
|
||||
});
|
||||
} else if (child.type.isEdge) {
|
||||
const relationshipKey = child.props.source + ':' + child.props.target;
|
||||
if (!edgeLabels[relationshipKey]) {
|
||||
edgeLabels[relationshipKey] = [];
|
||||
}
|
||||
edgeLabels[relationshipKey].push(child);
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(edgeLabels).forEach(key => {
|
||||
const children = edgeLabels[key];
|
||||
const child = children[0];
|
||||
g.setEdge(child.props.source, child.props.target, {
|
||||
label: child,
|
||||
allChildren: children.map(c => c.props.children),
|
||||
weight: child.props.weight,
|
||||
});
|
||||
});
|
||||
|
||||
dagre.layout(g);
|
||||
|
||||
var activeNode = g
|
||||
.nodes()
|
||||
.map(v => g.node(v))
|
||||
.find(node => node.label.props.isActive);
|
||||
const [winX, winY] = [window.innerWidth / 2, window.innerHeight / 2];
|
||||
var focusDx = trackActive && activeNode ? winX - activeNode.x : 0;
|
||||
var focusDy = trackActive && activeNode ? winY - activeNode.y : 0;
|
||||
|
||||
var nodes = g.nodes().map(v => {
|
||||
var node = g.node(v);
|
||||
return (
|
||||
<Motion
|
||||
style={{
|
||||
x: props.isDragging ? node.x + focusDx : spring(node.x + focusDx),
|
||||
y: props.isDragging ? node.y + focusDy : spring(node.y + focusDy),
|
||||
}}
|
||||
key={node.label.key}>
|
||||
{interpolatingStyle =>
|
||||
React.cloneElement(node.label, {
|
||||
x: interpolatingStyle.x + props.dx,
|
||||
y: interpolatingStyle.y + props.dy,
|
||||
vanillaX: node.x,
|
||||
vanillaY: node.y,
|
||||
})
|
||||
}
|
||||
</Motion>
|
||||
);
|
||||
});
|
||||
|
||||
var edges = g.edges().map(e => {
|
||||
var edge = g.edge(e);
|
||||
let idx = 0;
|
||||
return (
|
||||
<Motion
|
||||
style={edge.points.reduce((bag, point) => {
|
||||
bag[idx + ':x'] = props.isDragging
|
||||
? point.x + focusDx
|
||||
: spring(point.x + focusDx);
|
||||
bag[idx + ':y'] = props.isDragging
|
||||
? point.y + focusDy
|
||||
: spring(point.y + focusDy);
|
||||
idx++;
|
||||
return bag;
|
||||
}, {})}
|
||||
key={edge.label.key}>
|
||||
{interpolatedStyle => {
|
||||
let points = [];
|
||||
Object.keys(interpolatedStyle).forEach(key => {
|
||||
const [idx, prop] = key.split(':');
|
||||
if (!points[idx]) {
|
||||
points[idx] = {x: props.dx, y: props.dy};
|
||||
}
|
||||
points[idx][prop] += interpolatedStyle[key];
|
||||
});
|
||||
return React.cloneElement(edge.label, {
|
||||
points,
|
||||
id: edge.label.key,
|
||||
children: edge.allChildren.join(', '),
|
||||
});
|
||||
}}
|
||||
</Motion>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: 'relative',
|
||||
height: '100%',
|
||||
}}>
|
||||
{edges}
|
||||
{nodes}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Vertex(props) {
|
||||
if (Number.isNaN(props.x) || Number.isNaN(props.y)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
border: '1px solid black',
|
||||
left: props.x - props.width / 2,
|
||||
top: props.y - props.height / 2,
|
||||
width: props.width,
|
||||
height: props.height,
|
||||
overflow: 'hidden',
|
||||
padding: '4px',
|
||||
wordWrap: 'break-word',
|
||||
}}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Vertex.isVertex = true;
|
||||
|
||||
const strokes = {
|
||||
alt: 'blue',
|
||||
child: 'green',
|
||||
sibling: 'darkgreen',
|
||||
return: 'red',
|
||||
fx: 'purple',
|
||||
};
|
||||
|
||||
function Edge(props) {
|
||||
var points = props.points;
|
||||
var path = 'M' + points[0].x + ' ' + points[0].y + ' ';
|
||||
|
||||
if (!points[0].x || !points[0].y) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (var i = 1; i < points.length; i++) {
|
||||
path += 'L' + points[i].x + ' ' + points[i].y + ' ';
|
||||
if (!points[i].x || !points[i].y) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var lineID = props.id;
|
||||
|
||||
return (
|
||||
<svg
|
||||
width="100%"
|
||||
height="100%"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
}}>
|
||||
<defs>
|
||||
<path d={path} id={lineID} />
|
||||
<marker
|
||||
id="markerCircle"
|
||||
markerWidth="8"
|
||||
markerHeight="8"
|
||||
refX="5"
|
||||
refY="5">
|
||||
<circle cx="5" cy="5" r="3" style={{stroke: 'none', fill: 'black'}} />
|
||||
</marker>
|
||||
<marker
|
||||
id="markerArrow"
|
||||
markerWidth="13"
|
||||
markerHeight="13"
|
||||
refX="2"
|
||||
refY="6"
|
||||
orient="auto">
|
||||
<path d="M2,2 L2,11 L10,6 L2,2" style={{fill: 'black'}} />
|
||||
</marker>
|
||||
</defs>
|
||||
|
||||
<use
|
||||
xlinkHref={`#${lineID}`}
|
||||
fill="none"
|
||||
stroke={strokes[props.kind]}
|
||||
style={{
|
||||
markerStart: 'url(#markerCircle)',
|
||||
markerEnd: 'url(#markerArrow)',
|
||||
}}
|
||||
/>
|
||||
<text>
|
||||
<textPath xlinkHref={`#${lineID}`}>
|
||||
{' '}
|
||||
{props.children}
|
||||
</textPath>
|
||||
</text>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
Edge.isEdge = true;
|
||||
|
||||
function formatPriority(priority) {
|
||||
switch (priority) {
|
||||
case 1:
|
||||
return 'synchronous';
|
||||
case 2:
|
||||
return 'task';
|
||||
case 3:
|
||||
return 'hi-pri work';
|
||||
case 4:
|
||||
return 'lo-pri work';
|
||||
case 5:
|
||||
return 'offscreen work';
|
||||
default:
|
||||
throw new Error('Unknown priority.');
|
||||
}
|
||||
}
|
||||
|
||||
export default function Fibers({fibers, show, graphSettings, ...rest}) {
|
||||
const items = Object.keys(fibers.descriptions).map(
|
||||
id => fibers.descriptions[id]
|
||||
);
|
||||
|
||||
const isDragging = rest.className.indexOf('dragging') > -1;
|
||||
const [_, sdx, sdy] =
|
||||
rest.style.transform.match(/translate\((-?\d+)px,(-?\d+)px\)/) || [];
|
||||
const dx = Number(sdx);
|
||||
const dy = Number(sdy);
|
||||
|
||||
return (
|
||||
<div
|
||||
{...rest}
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
...rest.style,
|
||||
transform: null,
|
||||
}}>
|
||||
<Graph
|
||||
className="graph"
|
||||
dx={dx}
|
||||
dy={dy}
|
||||
isDragging={isDragging}
|
||||
settings={graphSettings}>
|
||||
{items.map(fiber => [
|
||||
<Vertex
|
||||
key={fiber.id}
|
||||
width={150}
|
||||
height={100}
|
||||
isActive={fiber.id === fibers.workInProgressID}>
|
||||
<div
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundColor: getFiberColor(fibers, fiber.id),
|
||||
}}
|
||||
title={
|
||||
/*prettyFormat(fiber, { plugins: [reactElement ]})*/
|
||||
'todo: this was hanging last time I tried to pretty print'
|
||||
}>
|
||||
<small>
|
||||
{fiber.tag} #{fiber.id}
|
||||
</small>
|
||||
<br />
|
||||
{fiber.type}
|
||||
<br />
|
||||
{fibers.currentIDs.indexOf(fiber.id) === -1 ? (
|
||||
<small>
|
||||
{fiber.pendingWorkPriority !== 0 && [
|
||||
<span key="span">
|
||||
Needs: {formatPriority(fiber.pendingWorkPriority)}
|
||||
</span>,
|
||||
<br key="br" />,
|
||||
]}
|
||||
{fiber.memoizedProps !== null &&
|
||||
fiber.pendingProps !== null && [
|
||||
fiber.memoizedProps === fiber.pendingProps
|
||||
? 'Can reuse memoized.'
|
||||
: 'Cannot reuse memoized.',
|
||||
<br key="br" />,
|
||||
]}
|
||||
</small>
|
||||
) : (
|
||||
<small>Committed</small>
|
||||
)}
|
||||
{fiber.effectTag && [
|
||||
<br key="br" />,
|
||||
<small key="small">Effect: {fiber.effectTag}</small>,
|
||||
]}
|
||||
</div>
|
||||
</Vertex>,
|
||||
fiber.child &&
|
||||
show.child && (
|
||||
<Edge
|
||||
source={fiber.id}
|
||||
target={fiber.child}
|
||||
kind="child"
|
||||
weight={1000}
|
||||
key={`${fiber.id}-${fiber.child}-child`}>
|
||||
child
|
||||
</Edge>
|
||||
),
|
||||
fiber.sibling &&
|
||||
show.sibling && (
|
||||
<Edge
|
||||
source={fiber.id}
|
||||
target={fiber.sibling}
|
||||
kind="sibling"
|
||||
weight={2000}
|
||||
key={`${fiber.id}-${fiber.sibling}-sibling`}>
|
||||
sibling
|
||||
</Edge>
|
||||
),
|
||||
fiber.return &&
|
||||
show.return && (
|
||||
<Edge
|
||||
source={fiber.id}
|
||||
target={fiber.return}
|
||||
kind="return"
|
||||
weight={1000}
|
||||
key={`${fiber.id}-${fiber.return}-return`}>
|
||||
return
|
||||
</Edge>
|
||||
),
|
||||
fiber.nextEffect &&
|
||||
show.fx && (
|
||||
<Edge
|
||||
source={fiber.id}
|
||||
target={fiber.nextEffect}
|
||||
kind="fx"
|
||||
weight={100}
|
||||
key={`${fiber.id}-${fiber.nextEffect}-nextEffect`}>
|
||||
nextFx
|
||||
</Edge>
|
||||
),
|
||||
fiber.firstEffect &&
|
||||
show.fx && (
|
||||
<Edge
|
||||
source={fiber.id}
|
||||
target={fiber.firstEffect}
|
||||
kind="fx"
|
||||
weight={100}
|
||||
key={`${fiber.id}-${fiber.firstEffect}-firstEffect`}>
|
||||
firstFx
|
||||
</Edge>
|
||||
),
|
||||
fiber.lastEffect &&
|
||||
show.fx && (
|
||||
<Edge
|
||||
source={fiber.id}
|
||||
target={fiber.lastEffect}
|
||||
kind="fx"
|
||||
weight={100}
|
||||
key={`${fiber.id}-${fiber.lastEffect}-lastEffect`}>
|
||||
lastFx
|
||||
</Edge>
|
||||
),
|
||||
fiber.alternate &&
|
||||
show.alt && (
|
||||
<Edge
|
||||
source={fiber.id}
|
||||
target={fiber.alternate}
|
||||
kind="alt"
|
||||
weight={10}
|
||||
key={`${fiber.id}-${fiber.alternate}-alt`}>
|
||||
alt
|
||||
</Edge>
|
||||
),
|
||||
])}
|
||||
</Graph>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
let nextFiberID = 1;
|
||||
const fiberIDMap = new WeakMap();
|
||||
|
||||
function getFiberUniqueID(fiber) {
|
||||
if (!fiberIDMap.has(fiber)) {
|
||||
fiberIDMap.set(fiber, nextFiberID++);
|
||||
}
|
||||
return fiberIDMap.get(fiber);
|
||||
}
|
||||
|
||||
function getFriendlyTag(tag) {
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return '[indeterminate]';
|
||||
case 1:
|
||||
return '[fn]';
|
||||
case 2:
|
||||
return '[class]';
|
||||
case 3:
|
||||
return '[root]';
|
||||
case 4:
|
||||
return '[portal]';
|
||||
case 5:
|
||||
return '[host]';
|
||||
case 6:
|
||||
return '[text]';
|
||||
case 7:
|
||||
return '[coroutine]';
|
||||
case 8:
|
||||
return '[handler]';
|
||||
case 9:
|
||||
return '[yield]';
|
||||
case 10:
|
||||
return '[frag]';
|
||||
default:
|
||||
throw new Error('Unknown tag.');
|
||||
}
|
||||
}
|
||||
|
||||
function getFriendlyEffect(effectTag) {
|
||||
const effects = {
|
||||
1: 'Performed Work',
|
||||
2: 'Placement',
|
||||
4: 'Update',
|
||||
8: 'Deletion',
|
||||
16: 'Content reset',
|
||||
32: 'Callback',
|
||||
64: 'Err',
|
||||
128: 'Ref',
|
||||
};
|
||||
return Object.keys(effects)
|
||||
.filter(flag => flag & effectTag)
|
||||
.map(flag => effects[flag])
|
||||
.join(' & ');
|
||||
}
|
||||
|
||||
export default function describeFibers(rootFiber, workInProgress) {
|
||||
let descriptions = {};
|
||||
function acknowledgeFiber(fiber) {
|
||||
if (!fiber) {
|
||||
return null;
|
||||
}
|
||||
if (!fiber.return && fiber.tag !== 3) {
|
||||
return null;
|
||||
}
|
||||
const id = getFiberUniqueID(fiber);
|
||||
if (descriptions[id]) {
|
||||
return id;
|
||||
}
|
||||
descriptions[id] = {};
|
||||
Object.assign(descriptions[id], {
|
||||
...fiber,
|
||||
id: id,
|
||||
tag: getFriendlyTag(fiber.tag),
|
||||
effectTag: getFriendlyEffect(fiber.effectTag),
|
||||
type: fiber.type && '<' + (fiber.type.name || fiber.type) + '>',
|
||||
stateNode: `[${typeof fiber.stateNode}]`,
|
||||
return: acknowledgeFiber(fiber.return),
|
||||
child: acknowledgeFiber(fiber.child),
|
||||
sibling: acknowledgeFiber(fiber.sibling),
|
||||
nextEffect: acknowledgeFiber(fiber.nextEffect),
|
||||
firstEffect: acknowledgeFiber(fiber.firstEffect),
|
||||
lastEffect: acknowledgeFiber(fiber.lastEffect),
|
||||
alternate: acknowledgeFiber(fiber.alternate),
|
||||
});
|
||||
return id;
|
||||
}
|
||||
|
||||
const rootID = acknowledgeFiber(rootFiber);
|
||||
const workInProgressID = acknowledgeFiber(workInProgress);
|
||||
|
||||
let currentIDs = new Set();
|
||||
function markAsCurent(id) {
|
||||
currentIDs.add(id);
|
||||
const fiber = descriptions[id];
|
||||
if (fiber.sibling) {
|
||||
markAsCurent(fiber.sibling);
|
||||
}
|
||||
if (fiber.child) {
|
||||
markAsCurent(fiber.child);
|
||||
}
|
||||
}
|
||||
markAsCurent(rootID);
|
||||
|
||||
return {
|
||||
descriptions,
|
||||
rootID,
|
||||
currentIDs: Array.from(currentIDs),
|
||||
workInProgressID,
|
||||
};
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: sans-serif;
|
||||
height: 100vh;
|
||||
cursor: -webkit-grab; cursor: -moz-grab;
|
||||
}
|
||||
|
||||
#root {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './App';
|
||||
import './index.css';
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'));
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,224 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html style="width: 100%; height: 100%; overflow: hidden">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Fiber Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Fiber Example</h1>
|
||||
<div id="container">
|
||||
<p>
|
||||
To install React, follow the instructions on
|
||||
<a href="https://github.com/facebook/react/">GitHub</a>.
|
||||
</p>
|
||||
<p>
|
||||
If you can see this, React is <strong>not</strong> working right.
|
||||
If you checked out the source from GitHub make sure to run <code>npm run build</code>.
|
||||
</p>
|
||||
</div>
|
||||
<script src="../../build/dist/react.development.js"></script>
|
||||
<script src="../../build/dist/react-dom.development.js"></script>
|
||||
<script src="https://unpkg.com/babel-standalone@6/babel.js"></script>
|
||||
<script type="text/babel">
|
||||
var dotStyle = {
|
||||
position: 'absolute',
|
||||
background: '#61dafb',
|
||||
font: 'normal 15px sans-serif',
|
||||
textAlign: 'center',
|
||||
cursor: 'pointer',
|
||||
};
|
||||
|
||||
var containerStyle = {
|
||||
position: 'absolute',
|
||||
transformOrigin: '0 0',
|
||||
left: '50%',
|
||||
top: '50%',
|
||||
width: '10px',
|
||||
height: '10px',
|
||||
background: '#eee',
|
||||
};
|
||||
|
||||
var targetSize = 25;
|
||||
|
||||
class Dot extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = { hover: false };
|
||||
}
|
||||
enter() {
|
||||
this.setState({
|
||||
hover: true
|
||||
});
|
||||
}
|
||||
leave() {
|
||||
this.setState({
|
||||
hover: false
|
||||
});
|
||||
}
|
||||
render() {
|
||||
var props = this.props;
|
||||
var s = props.size * 1.3;
|
||||
var style = {
|
||||
...dotStyle,
|
||||
width: s + 'px',
|
||||
height: s + 'px',
|
||||
left: (props.x) + 'px',
|
||||
top: (props.y) + 'px',
|
||||
borderRadius: (s / 2) + 'px',
|
||||
lineHeight: (s) + 'px',
|
||||
background: this.state.hover ? '#ff0' : dotStyle.background
|
||||
};
|
||||
return (
|
||||
<div style={style} onMouseEnter={() => this.enter()} onMouseLeave={() => this.leave()}>
|
||||
{this.state.hover ? '*' + props.text + '*' : props.text}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SierpinskiTriangle extends React.Component {
|
||||
shouldComponentUpdate(nextProps) {
|
||||
var o = this.props;
|
||||
var n = nextProps;
|
||||
return !(
|
||||
o.x === n.x &&
|
||||
o.y === n.y &&
|
||||
o.s === n.s &&
|
||||
o.children === n.children
|
||||
);
|
||||
}
|
||||
render() {
|
||||
let {x, y, s, children} = this.props;
|
||||
if (s <= targetSize) {
|
||||
return (
|
||||
<Dot
|
||||
x={x - (targetSize / 2)}
|
||||
y={y - (targetSize / 2)}
|
||||
size={targetSize}
|
||||
text={children}
|
||||
/>
|
||||
);
|
||||
return r;
|
||||
}
|
||||
var newSize = s / 2;
|
||||
var slowDown = true;
|
||||
if (slowDown) {
|
||||
var e = performance.now() + 0.8;
|
||||
while (performance.now() < e) {
|
||||
// Artificially long execution time.
|
||||
}
|
||||
}
|
||||
|
||||
s /= 2;
|
||||
|
||||
return [
|
||||
<SierpinskiTriangle x={x} y={y - (s / 2)} s={s}>
|
||||
{children}
|
||||
</SierpinskiTriangle>,
|
||||
<SierpinskiTriangle x={x - s} y={y + (s / 2)} s={s}>
|
||||
{children}
|
||||
</SierpinskiTriangle>,
|
||||
<SierpinskiTriangle x={x + s} y={y + (s / 2)} s={s}>
|
||||
{children}
|
||||
</SierpinskiTriangle>,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class ExampleApplication extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
seconds: 0,
|
||||
useTimeSlicing: true,
|
||||
};
|
||||
this.tick = this.tick.bind(this);
|
||||
this.onTimeSlicingChange = this.onTimeSlicingChange.bind(this);
|
||||
}
|
||||
componentDidMount() {
|
||||
this.intervalID = setInterval(this.tick, 1000);
|
||||
}
|
||||
tick() {
|
||||
if (this.state.useTimeSlicing) {
|
||||
// Update is time-sliced.
|
||||
ReactDOM.unstable_deferredUpdates(() => {
|
||||
this.setState(state => ({ seconds: (state.seconds % 10) + 1 }));
|
||||
});
|
||||
} else {
|
||||
// Update is not time-sliced. Causes demo to stutter.
|
||||
this.setState(state => ({ seconds: (state.seconds % 10) + 1 }));
|
||||
}
|
||||
}
|
||||
onTimeSlicingChange(value) {
|
||||
this.setState(() => ({ useTimeSlicing: value }));
|
||||
}
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.intervalID);
|
||||
}
|
||||
render() {
|
||||
const seconds = this.state.seconds;
|
||||
const elapsed = this.props.elapsed;
|
||||
const t = (elapsed / 1000) % 10;
|
||||
const scale = 1 + (t > 5 ? 10 - t : t) / 10;
|
||||
const transform = 'scaleX(' + (scale / 2.1) + ') scaleY(0.7) translateZ(0.1px)';
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
<h3>Time-slicing</h3>
|
||||
<p>Toggle this and observe the effect</p>
|
||||
<Toggle
|
||||
onLabel="On"
|
||||
offLabel="Off"
|
||||
onChange={this.onTimeSlicingChange}
|
||||
value={this.state.useTimeSlicing}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ ...containerStyle, transform }}>
|
||||
<div>
|
||||
<SierpinskiTriangle x={0} y={0} s={1000}>
|
||||
{this.state.seconds}
|
||||
</SierpinskiTriangle>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Toggle extends React.Component {
|
||||
constructor(props) {
|
||||
super();
|
||||
this.onChange = this.onChange.bind(this);
|
||||
}
|
||||
onChange(event) {
|
||||
this.props.onChange(event.target.value === 'on');
|
||||
}
|
||||
render() {
|
||||
const value = this.props.value;
|
||||
return (
|
||||
<label onChange={this.onChange}>
|
||||
<label>
|
||||
{this.props.onLabel}
|
||||
<input type="radio" name="value" value="on" checked={value} />
|
||||
</label>
|
||||
<label>
|
||||
{this.props.offLabel}
|
||||
<input type="radio" name="value" value="off" checked={!value} />
|
||||
</label>
|
||||
</label>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var start = new Date().getTime();
|
||||
function update() {
|
||||
ReactDOM.render(
|
||||
<ExampleApplication elapsed={new Date().getTime() - start} />,
|
||||
document.getElementById('container')
|
||||
);
|
||||
requestAnimationFrame(update);
|
||||
}
|
||||
requestAnimationFrame(update);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,42 +0,0 @@
|
||||
# Manual Testing Fixtures
|
||||
|
||||
This folder exists for **React contributors** only.
|
||||
If you use React, you don't need to worry about it.
|
||||
|
||||
These fixtures verify that the built React distributions are usable in different environments.
|
||||
**They are not running automatically.** (At least not yet. Feel free to contribute to automate them.)
|
||||
|
||||
Run them when you make changes to how we package React and ReactDOM.
|
||||
|
||||
## How to Run
|
||||
|
||||
First, build React and the fixtures:
|
||||
|
||||
```
|
||||
cd react
|
||||
npm run build
|
||||
|
||||
cd fixtures/packaging
|
||||
node build-all.js
|
||||
```
|
||||
|
||||
Then run a local server at the root of the repo, e.g.
|
||||
|
||||
```
|
||||
npm i -g pushstate-server
|
||||
cd ../..
|
||||
pushstate-server .
|
||||
```
|
||||
|
||||
(Too complicated? Send a PR to simplify this :-)).
|
||||
|
||||
Then open the following URL in your browser:
|
||||
|
||||
```
|
||||
open http://localhost:9000/fixtures/packaging/index.html
|
||||
```
|
||||
|
||||
You should see two things:
|
||||
|
||||
* "Hello World" is rendered in each iframe.
|
||||
* No errors in the console.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user