A tool for people curious about the React Server Components protocol rscexplorer.dev/
rsc react
35
fork

Configure Feed

Select the types of activity you want to include in your feed.

a11y tweaks

+107 -7
+27 -1
src/client/ui/App.css
··· 47 47 color: var(--text-bright); 48 48 } 49 49 50 + .App-headerLink:focus-visible { 51 + outline: 2px solid #ffd54f; 52 + outline-offset: 2px; 53 + } 54 + 50 55 /* App-exampleSelect */ 51 56 52 57 .App-exampleSelect { ··· 91 96 .App-exampleSelect-embedBtn:disabled { 92 97 opacity: 0.4; 93 98 cursor: not-allowed; 99 + } 100 + 101 + .App-exampleSelect-saveBtn:focus-visible, 102 + .App-exampleSelect-embedBtn:focus-visible { 103 + outline: none; 104 + border-color: #ffd54f; 94 105 } 95 106 96 107 /* App-buildSwitcher */ ··· 168 179 color: var(--text-bright); 169 180 } 170 181 182 + .App-embedModal-closeBtn:focus-visible { 183 + outline: 2px solid #ffd54f; 184 + outline-offset: 2px; 185 + } 186 + 171 187 .App-embedModal-body { 172 188 padding: 16px; 173 189 overflow: auto; ··· 194 210 195 211 .App-embedModal-textarea:focus { 196 212 outline: none; 197 - border-color: #555; 213 + border-color: #ffd54f; 198 214 } 199 215 200 216 .App-embedModal-textarea::selection { ··· 232 248 color: var(--text-bright); 233 249 } 234 250 251 + .App-embedModal-tab:focus-visible { 252 + outline: 2px solid #ffd54f; 253 + outline-offset: -2px; 254 + } 255 + 235 256 .App-embedModal-footer { 236 257 padding: 16px; 237 258 border-top: 1px solid var(--border); ··· 252 273 253 274 .App-embedModal-copyBtn:hover { 254 275 background: #ffe566; 276 + } 277 + 278 + .App-embedModal-copyBtn:focus-visible { 279 + outline: 2px solid #fff; 280 + outline-offset: 2px; 255 281 } 256 282 257 283 /* Responsive */
+28 -4
src/client/ui/App.tsx
··· 144 144 setTimeout(() => setCopied(false), 2000); 145 145 }; 146 146 147 + useEffect(() => { 148 + const handleKeyDown = (e: KeyboardEvent): void => { 149 + if (e.key === "Escape") { 150 + onClose(); 151 + } 152 + }; 153 + document.addEventListener("keydown", handleKeyDown); 154 + return () => document.removeEventListener("keydown", handleKeyDown); 155 + }, [onClose]); 156 + 147 157 return ( 148 158 <div className="App-embedModal-overlay" onClick={onClose}> 149 - <div className="App-embedModal" onClick={(e: MouseEvent) => e.stopPropagation()}> 159 + <div 160 + className="App-embedModal" 161 + role="dialog" 162 + aria-modal="true" 163 + aria-label="Embed this example" 164 + onClick={(e: MouseEvent) => e.stopPropagation()} 165 + > 150 166 <div className="App-embedModal-header"> 151 167 <h2 className="App-embedModal-title">Embed this example</h2> 152 - <button className="App-embedModal-closeBtn" onClick={onClose}> 168 + <button className="App-embedModal-closeBtn" onClick={onClose} aria-label="Close"> 153 169 &times; 154 170 </button> 155 171 </div> ··· 172 188 className="App-embedModal-textarea" 173 189 readOnly 174 190 value={embedCode} 191 + autoFocus 192 + onFocus={(e) => e.target.select()} 175 193 onClick={(e) => (e.target as HTMLTextAreaElement).select()} 176 194 /> 177 195 </div> ··· 276 294 onClick={handleSave} 277 295 disabled={!isDirty} 278 296 title="Save to URL" 297 + aria-label="Save to URL" 279 298 > 280 299 <svg 281 300 width="16" ··· 284 303 fill="none" 285 304 stroke="currentColor" 286 305 strokeWidth="2" 306 + aria-hidden="true" 287 307 > 288 308 <path d="M19 21H5a2 2 0 01-2-2V5a2 2 0 012-2h11l5 5v11a2 2 0 01-2 2z" /> 289 309 <polyline points="17 21 17 13 7 13 7 21" /> ··· 294 314 className="App-exampleSelect-embedBtn" 295 315 onClick={() => setShowEmbedModal(true)} 296 316 title="Embed" 317 + aria-label="Embed" 297 318 > 298 319 <svg 299 320 width="16" ··· 302 323 fill="none" 303 324 stroke="currentColor" 304 325 strokeWidth="2" 326 + aria-hidden="true" 305 327 > 306 328 <polyline points="16 18 22 12 16 6" /> 307 329 <polyline points="8 6 2 12 8 18" /> ··· 316 338 rel="noopener noreferrer" 317 339 className="App-headerLink" 318 340 title="View on GitHub" 341 + aria-label="View on GitHub" 319 342 > 320 - <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"> 343 + <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"> 321 344 <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" /> 322 345 </svg> 323 346 </a> ··· 327 350 rel="noopener noreferrer" 328 351 className="App-headerLink App-headerLink--tangled" 329 352 title="View on Tangled" 353 + aria-label="View on Tangled" 330 354 > 331 - <svg width="20" height="20" viewBox="0 0 26 26" fill="currentColor"> 355 + <svg width="20" height="20" viewBox="0 0 26 26" fill="currentColor" aria-hidden="true"> 332 356 <path d="m 16.775491,24.987061 c -0.78517,-0.0064 -1.384202,-0.234614 -2.033994,-0.631295 -0.931792,-0.490188 -1.643475,-1.31368 -2.152014,-2.221647 C 11.781409,23.136647 10.701392,23.744942 9.4922931,24.0886 8.9774725,24.238111 8.0757679,24.389777 6.5811304,23.84827 4.4270703,23.124679 2.8580086,20.883331 3.0363279,18.599583 3.0037061,17.652919 3.3488675,16.723769 3.8381157,15.925061 2.5329485,15.224503 1.4686756,14.048584 1.0611184,12.606459 0.81344502,11.816973 0.82385989,10.966486 0.91519098,10.154906 1.2422711,8.2387903 2.6795811,6.5725716 4.5299585,5.9732484 5.2685364,4.290122 6.8802592,3.0349975 8.706276,2.7794663 c 1.2124148,-0.1688264 2.46744,0.084987 3.52811,0.7011837 1.545426,-1.7139736 4.237779,-2.2205077 6.293579,-1.1676231 1.568222,0.7488935 2.689625,2.3113526 2.961888,4.0151464 1.492195,0.5977882 2.749007,1.8168898 3.242225,3.3644951 0.329805,0.9581836 0.340709,2.0135956 0.127128,2.9974286 -0.381606,1.535184 -1.465322,2.842146 -2.868035,3.556463 0.0034,0.273204 0.901506,2.243045 0.751284,3.729647 -0.03281,1.858525 -1.211631,3.619894 -2.846433,4.475452 -0.953967,0.556812 -2.084452,0.546309 -3.120531,0.535398 z m -4.470079,-5.349839 c 1.322246,-0.147248 2.189053,-1.300106 2.862307,-2.338363 0.318287,-0.472954 0.561404,-1.002348 0.803,-1.505815 0.313265,0.287151 0.578698,0.828085 1.074141,0.956909 0.521892,0.162542 1.133743,0.03052 1.45325,-0.443554 0.611414,-1.140449 0.31004,-2.516537 -0.04602,-3.698347 C 18.232844,11.92927 17.945151,11.232927 17.397785,10.751793 17.514522,9.9283111 17.026575,9.0919791 16.332883,8.6609491 15.741721,9.1323278 14.842258,9.1294949 14.271975,8.6252369 13.178927,9.7400102 12.177239,9.7029996 11.209704,8.8195135 10.992255,8.6209543 10.577326,10.031484 9.1211947,9.2324497 8.2846288,9.9333947 7.6359672,10.607693 7.0611981,11.578553 6.5026891,12.62523 5.9177873,13.554793 5.867393,14.69141 c -0.024234,0.66432 0.4948601,1.360337 1.1982269,1.306329 0.702996,0.06277 1.1815208,-0.629091 1.7138087,-0.916491 0.079382,0.927141 0.1688108,1.923227 0.4821259,2.828358 0.3596254,1.171275 1.6262605,1.915695 2.8251855,1.745211 0.08481,-0.0066 0.218672,-0.01769 0.218672,-0.0176 z m 0.686342,-3.497495 c -0.643126,-0.394168 -0.33365,-1.249599 -0.359402,-1.870938 0.064,-0.749774 0.115321,-1.538054 0.452402,-2.221125 0.356724,-0.487008 1.226721,-0.299139 1.265134,0.325689 -0.02558,0.628509 -0.314101,1.25416 -0.279646,1.9057 -0.07482,0.544043 0.05418,1.155133 -0.186476,1.652391 -0.197455,0.275121 -0.599638,0.355105 -0.892012,0.208283 z m -2.808766,-0.358124 c -0.605767,-0.328664 -0.4133176,-1.155655 -0.5083256,-1.73063 0.078762,-0.66567 0.013203,-1.510085 0.5705316,-1.976886 0.545037,-0.380109 1.286917,0.270803 1.029164,0.868384 -0.274913,0.755214 -0.09475,1.580345 -0.08893,2.34609 -0.104009,0.451702 -0.587146,0.691508 -1.002445,0.493042 z" /> 333 357 </svg> 334 358 </a>
+2
src/client/ui/EmbedApp.tsx
··· 94 94 rel="noopener noreferrer" 95 95 className="EmbedApp-fullscreenLink" 96 96 title="Open in RSC Explorer" 97 + aria-label="Open in RSC Explorer" 97 98 > 98 99 <svg 99 100 width="14" ··· 102 103 fill="none" 103 104 stroke="currentColor" 104 105 strokeWidth="2" 106 + aria-hidden="true" 105 107 > 106 108 <path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6M15 3h6v6M10 14L21 3" /> 107 109 </svg>
+27 -1
src/client/ui/FlightLog.css
··· 48 48 } 49 49 } 50 50 51 + @media (prefers-reduced-motion: reduce) { 52 + .FlightLog-empty--waiting::after { 53 + animation: none; 54 + } 55 + } 56 + 51 57 /* FlightLog-entry */ 52 58 53 59 .FlightLog-entry { ··· 116 122 .FlightLog-entry-deleteBtn:hover { 117 123 opacity: 1; 118 124 color: #e57373; 125 + } 126 + 127 + .FlightLog-entry-deleteBtn:focus-visible { 128 + outline: 2px solid #ffd54f; 129 + outline-offset: 2px; 119 130 } 120 131 121 132 .FlightLog-entry-request { ··· 248 259 249 260 .FlightLog-rawForm-textarea:focus { 250 261 outline: none; 251 - border-color: #555; 262 + border-color: #ffd54f; 252 263 } 253 264 254 265 .FlightLog-rawForm-buttons { ··· 272 283 cursor: not-allowed; 273 284 } 274 285 286 + .FlightLog-rawForm-submitBtn:focus-visible { 287 + outline: 2px solid #fff; 288 + outline-offset: 2px; 289 + } 290 + 275 291 .FlightLog-rawForm-cancelBtn { 276 292 padding: 5px 12px; 277 293 border-radius: 3px; ··· 285 301 .FlightLog-rawForm-cancelBtn:hover { 286 302 border-color: #555; 287 303 color: var(--text); 304 + } 305 + 306 + .FlightLog-rawForm-cancelBtn:focus-visible { 307 + outline: 2px solid #ffd54f; 308 + outline-offset: 2px; 288 309 } 289 310 290 311 /* FlightLog-addButton */ ··· 316 337 background: #3a3a3a; 317 338 border-color: #666; 318 339 color: var(--text); 340 + } 341 + 342 + .FlightLog-addButton:focus-visible { 343 + outline: 2px solid #ffd54f; 344 + outline-offset: 2px; 319 345 } 320 346 321 347 /* Responsive */
+7 -1
src/client/ui/FlightLog.tsx
··· 97 97 className="FlightLog-entry-deleteBtn" 98 98 onClick={() => onDelete(index)} 99 99 title="Delete" 100 + aria-label="Delete entry" 100 101 > 101 102 × 102 103 </button> ··· 195 196 </div> 196 197 ) : ( 197 198 <div className="FlightLog-addButton-wrapper"> 198 - <button className="FlightLog-addButton" onClick={handleShowRawInput} title="Add action"> 199 + <button 200 + className="FlightLog-addButton" 201 + onClick={handleShowRawInput} 202 + title="Add action" 203 + aria-label="Add action" 204 + > 199 205 + 200 206 </button> 201 207 </div>
+16
src/client/ui/LivePreview.css
··· 46 46 cursor: not-allowed; 47 47 } 48 48 49 + .LivePreview-controlBtn:focus-visible { 50 + outline: 2px solid #ffd54f; 51 + outline-offset: -2px; 52 + } 53 + 49 54 .LivePreview-controlBtn--playing { 50 55 color: #ffd54f; 51 56 } ··· 62 67 animation: none; 63 68 } 64 69 70 + .LivePreview-controlBtn--step:focus-visible { 71 + outline: 2px solid #fff; 72 + outline-offset: 2px; 73 + } 74 + 65 75 .LivePreview-controlBtn--step:disabled { 66 76 background: transparent; 67 77 color: var(--text); ··· 75 85 } 76 86 50% { 77 87 opacity: 0.7; 88 + } 89 + } 90 + 91 + @media (prefers-reduced-motion: reduce) { 92 + .LivePreview-controlBtn--step { 93 + animation: none; 78 94 } 79 95 } 80 96