-
Notifications
You must be signed in to change notification settings - Fork 47.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Scheduling Profiler: Redesign with DevTools styling #19707
Conversation
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit 40a5d22:
|
This is in my queue to review. I was on PTO last week though and I have a lot of catch up to do. I'll try to get to it sometime in the next couple of days. 😄 There is a Yarn lockfile conflict that might be nice to fix when you get the chance though. |
6625d09
to
5aa5eda
Compare
No problem, take your time! 😄 I've rebased on master and fixed the conflict, and made 2 tiny changes: |
Oops, conflicts! I'll rebase this on master |
Bug: suppose we have a file which causes the profiler to display an error when imported. Importing the file once causes the error to be displayed correctly. However, if the file is imported a second time, the error is not displayed again. This happens because we listen to the `input` element's `onChange` event. Selecting the same file a second time does not cause the element's value to change, so the `handleFiles` callback is not called. This commit fixes this bug by emptying the `input` element's `value` in `handleFiles`. This bug is also present in the React DevTools Profiler.
98a9c72
to
2592245
Compare
Importing seems nice!
Most of them come from Material UI: https://material-ui.com/components/material-icons/
No strong preference, but I also think using |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to sit down the review now since most of what I'm writing is "use the shared thing rather than fork" 😁 I'd be happy to make that change myself, or you could. Your call!
try { | ||
return sessionStorage.setItem(key, value); | ||
} catch (error) {} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should just use react-devtools-shared/src/storage.js
.
/* Constant values shared between JS and CSS */ | ||
--interaction-commit-size: 10px; | ||
--interaction-label-width: 200px; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does not feel good to fork these styles. Too easy for them to get out of sync.
Also feels a little weird to import react-devtools-shared/src/devtools/views/root.css
but that seems better as long as we eventually plan to merge this profiler into the main DevTools app.
@@ -19,6 +19,7 @@ import './index.css'; | |||
|
|||
const container = document.createElement('div'); | |||
container.id = 'root'; | |||
container.style.height = '100%'; // Style specified here as CSS for #root will be stripped |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Could do
import styles from './index.css';
const container = document.createElement('div');
container.className = styles.Container;
container.id = 'root';
}, []); | ||
|
||
return theme; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use react-devtools-shared/src/devtools/views/hooks.js
for all of these but useBrowserTheme
?
COMPACT_LINE_HEIGHT = 10; | ||
} | ||
|
||
export {COMFORTABLE_LINE_HEIGHT, COMPACT_LINE_HEIGHT}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we just import these from react-devtools-shared/src/constants.js
?
or e.g.
export {COMFORTABLE_LINE_HEIGHT, COMPACT_LINE_HEIGHT} from 'react-devtools-shared/src/constants.js';
|
||
try { | ||
// $FlowFixMe | ||
const rawStyleString = require('!!raw-loader!react-devtools-shared/src/devtools/views/root.css') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops, we aren't even using our own forked root CSS here 😆
}; | ||
|
||
const mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)'); | ||
mediaQueryList.addEventListener('change', handlePreferredColorSchemeChange); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this picks up on dark mode if it's already set (only if the user changes their system theme after the profiler has been opened). At least that seems to be the behavior on OSX (the "change" event won't get fired).
We could also check window.matchMedia(DARK_MODE_QUERY).matches
in the effect and update, but then we might have to render twice (once for the default "light" and then again for "dark").
I think this might be a nice opportunity to use the useMutableSource
hook! 😄 It will handle all of this for us. Here's how you'd use it:
import {
unstable_createMutableSource as createMutableSource,
unstable_useMutableSource as useMutableSource,
} from 'react';
export type BrowserTheme = 'dark' | 'light';
const DARK_MODE_QUERY = '(prefers-color-scheme: dark)';
const getSnapshot = window =>
window.matchMedia(DARK_MODE_QUERY).matches ? 'dark' : 'light';
const darkModeMutableSource = createMutableSource(
window,
() => window.matchMedia(DARK_MODE_QUERY).matches,
);
const subscribe = (window, callback) => {
const mediaQueryList = window.matchMedia(DARK_MODE_QUERY);
mediaQueryList.addEventListener('change', callback);
return () => {
mediaQueryList.removeEventListener('change', callback);
};
};
export function useBrowserTheme(): BrowserTheme {
return useMutableSource(darkModeMutableSource, getSnapshot, subscribe);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, cool! I didn't know this existed 😆
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not released yet in stable, but DevTools uses prerelease APIs 😄
https://github.com/reactjs/rfcs/blob/master/text/0147-use-mutable-source.md
@@ -0,0 +1,133 @@ | |||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use react-devtools-shared/src/devtools/views/TabBar.js
and react-devtools-shared/src/devtools/views/TabBar.css
rather than fork.
Eh, screw it 😄 I'll hop in and help since it's after hours for you. Give me a few minutes and I'll push a commit that implements my own nits. |
import ImportPage from './ImportPage'; | ||
import CanvasPage from './CanvasPage'; | ||
import {ModalDialogContextController} from './ModalDialog'; | ||
import {SettingsContextController} from './Settings/SettingsContext'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not convinced the settings dialog is worth the hassle of the forked contexts and files. For now, I'm going to just rip it out :D
Thanks! I gotta get back to my art history class readings 😆 Let me know if there's anything I can do! I'll be happy to follow up on anything tomorrow afternoon. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hope it's okay that I DRYed it up a bit.
We could still do more (with the context
package and useContextMenu
hook) but that can come later.
@@ -53,6 +52,8 @@ export function useBrowserTheme(): void { | |||
default: | |||
throw Error(`Unsupported theme value "${theme}"`); | |||
} | |||
} else { | |||
updateThemeVariables('light', documentElements); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@taneliang This should be theme
not 'light'
right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah this was outside of the feature flag conditional. My apologies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I think we want 'light'
to prevent the app from going into dark mode?
Edit: yep! Sorry, ignore this comment, your second comment didn't load until I commented
Co-authored-by: Brian Vaughn <[email protected]>
Summary
Adopt DevTools styling in the scheduling profiler and show a persistent toolbar at the top of the page.
Resolves #19676.
cc @bvaughn, @kartikcho
High-Level Goals
Design: Match React DevTools's design, so that we carry the same brand and level of professionalism.
Code: Revamp
App
code structure and CSS to resemble theDevTools
component -- this is intended to make it slightly easier to merge the scheduling profiler into DevTools when the time comes.Future expansion: Create space on the canvas page to display the React version (with a view towards #19668) and other profile metadata e.g. profile name and browser type.
Misc features:
Implementation Breakdown
This is a large PR, but a lot of the code is copied verbatim from
react-devtools-shared
.ImportPage
, mainly withImportButton
react-devtools-shared
unchanged: Button, ButtonIcon, Icon, ModalDialog, ReactLogo, TabBar, Tooltip, root.css, utils/storage.jsreact-devtools-shared
with modifications:useBrowserTheme
hook for auto dark mode 🎉DEVTOOLS_VERSION
variable similar to DevTools', but computed from the scheduling profiler's package.json instead.App.js
with the rough component hierarchy and same CSS styles asDevTools.js
SchedulingProfiler
component followingProfiler.js
.If we decide to accept this PR, we'll want to adapt #19690's help text to the new design and code structure.
Questions
react-devtools-shared
instead of forking their implementations?TODO
Test Plan
Before import (equivalent to the old
ImportPage
):After import:
Because we're using DevTools code, there's built-in support for configurable (auto!) dark mode and display density. Unfortunately, this is not very useful now because the profiler canvas doesn't have support for CSS variables yet. I'll hide it behind a feature flag, but this is what it looks like now:
Settings page:
Comfortable dark:
Compact dark:
Compact dark:
Comfortable dark:
Hidden image when viewport is shorter than 600px:
New import failure dialog:
Known Issues
It's possible to hover over the canvas content even if the settings dialog is up. I can fix that in a separate PR to prevent this PR from bloating further.