Fix playground handling of visible scrollbars (#1514)
Summary: Pull Request resolved: https://github.com/facebook/yoga/pull/1514 On machines with scrollbars, we shouldn't show them unconditionally, and the toolbar should be in the area within them. This also fixes a couple bugs: 1. Preview not rendering based on correct code when light/dark mode changes 2. Crash on start on mobile safari 3. Incorrect rendering of preview on mobile safari This also fixes a bug where the playground re-rendering (e.g. on theme change) makes the preview snap back to the initial code passes. https://yoga-website-next-git-fork-nickgerleman-exp-194d90-fbopensource.vercel.app/ Reviewed By: shwanton Differential Revision: D52145666 fbshipit-source-id: 50184305987aab4cbcd066f37582997dfdc78c02
This commit is contained in:
committed by
Facebook GitHub Bot
parent
738d04fcb0
commit
43cb24fdce
@@ -13,6 +13,7 @@ import React, {
|
||||
lazy,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
@@ -45,7 +46,11 @@ export type Props = Readonly<{
|
||||
export default function Playground({code, height, autoFocus}: Props) {
|
||||
const prismTheme = usePrismTheme();
|
||||
const playgroundRef = useRef<HTMLDivElement>(null);
|
||||
const editorScrollRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [isLoaded, setIsLoaded] = useState(false);
|
||||
const [liveCode, setLiveCode] = useState(code ?? defaultCode);
|
||||
const [scrollbarWidth, setScrollbarWidth] = useState(0);
|
||||
|
||||
const LivePreviewWrapper = useCallback(
|
||||
(props: React.ComponentProps<'div'>) => {
|
||||
@@ -64,35 +69,52 @@ export default function Playground({code, height, autoFocus}: Props) {
|
||||
if (isLoaded && autoFocus) {
|
||||
const codeElem = playgroundRef?.current?.querySelector('.prism-code');
|
||||
const sel = window.getSelection();
|
||||
if (codeElem != null && sel != null) {
|
||||
if (codeElem?.clientHeight && sel != null) {
|
||||
sel.selectAllChildren(codeElem);
|
||||
sel.collapseToStart();
|
||||
}
|
||||
}
|
||||
}, [isLoaded, autoFocus]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
// The toolbar is positioned relative to the outside of the scrolling
|
||||
// container so it stays in the same place when scrolling, but this means
|
||||
// it isn't automatically adjusted for scrollbar width
|
||||
if (editorScrollRef.current) {
|
||||
setScrollbarWidth(
|
||||
editorScrollRef.current.offsetWidth -
|
||||
editorScrollRef.current.clientWidth,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const heightStyle = height
|
||||
? ({'--yg-playground-height': height} as React.CSSProperties)
|
||||
: undefined;
|
||||
|
||||
const resolvedCode = code ?? defaultCode;
|
||||
|
||||
return (
|
||||
<LiveProvider code={resolvedCode} theme={prismTheme} scope={{Layout, Node}}>
|
||||
<LiveProvider code={liveCode} theme={prismTheme} scope={{Layout, Node}}>
|
||||
<div className={styles.wrapper} ref={playgroundRef} style={heightStyle}>
|
||||
<div className={clsx(styles.playgroundRow, 'container')}>
|
||||
<div className={clsx(styles.editorColumn)}>
|
||||
<EditorToolbar
|
||||
getCode={useCallback(
|
||||
() =>
|
||||
nullthrows(
|
||||
playgroundRef.current?.querySelector('.prism-code')
|
||||
?.textContent,
|
||||
),
|
||||
[],
|
||||
)}
|
||||
/>
|
||||
<LiveEditor className={clsx(styles.playgroundEditor)} />
|
||||
<div className={clsx(styles.editorColumn, 'playground-editor')}>
|
||||
<div className={styles.editorScroll} ref={editorScrollRef}>
|
||||
<EditorToolbar
|
||||
className={styles.editorToolbar}
|
||||
style={{paddingRight: scrollbarWidth + 'px'}}
|
||||
getCode={useCallback(
|
||||
() =>
|
||||
nullthrows(
|
||||
playgroundRef.current?.querySelector('.prism-code')
|
||||
?.textContent,
|
||||
),
|
||||
[],
|
||||
)}
|
||||
/>
|
||||
<LiveEditor
|
||||
className={clsx(styles.playgroundEditor)}
|
||||
onChange={setLiveCode}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={clsx(styles.previewColumn)}>
|
||||
<LivePreview
|
||||
|
Reference in New Issue
Block a user