Yoga Docs: Rename website-next
to website
(#1613)
Summary: Pull Request resolved: https://github.com/facebook/yoga/pull/1613 So that GitHub links to edit a page point to the right place. This will fail in OSS build until I switch the directory used by Vercel instance, but I am waiting to do that until ready to land, since that would cause other in progress changes to fail when exported. Reviewed By: joevilches Differential Revision: D54837857 fbshipit-source-id: 9bec90232dbe3ec8638568685671185d597fcf2d
This commit is contained in:
committed by
Facebook GitHub Bot
parent
108c2f30a2
commit
206b95aba5
187
website/src/components/Playground.tsx
Normal file
187
website/src/components/Playground.tsx
Normal file
@@ -0,0 +1,187 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import React, {
|
||||
CSSProperties,
|
||||
Suspense,
|
||||
lazy,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import {usePrismTheme} from '@docusaurus/theme-common';
|
||||
import clsx from 'clsx';
|
||||
import {LiveProvider, LiveEditor, LivePreview, LiveError} from 'react-live';
|
||||
import EditorToolbar from './EditorToolbar';
|
||||
|
||||
import type {FlexStyle} from './FlexStyle';
|
||||
import type {StyleNode} from './YogaViewer';
|
||||
|
||||
import styles from './Playground.module.css';
|
||||
import useIsBrowser from '@docusaurus/useIsBrowser';
|
||||
|
||||
export type Props = Readonly<{
|
||||
code: string;
|
||||
height?: CSSProperties['height'];
|
||||
autoFocus?: boolean;
|
||||
}>;
|
||||
|
||||
export default function Playground({code, height, autoFocus}: Props) {
|
||||
const prismTheme = usePrismTheme();
|
||||
const editorScrollRef = useRef<HTMLDivElement>(null);
|
||||
const isBrowser = useIsBrowser();
|
||||
|
||||
const [liveCode, setLiveCode] = useState(code);
|
||||
const [hasCodeChanged, setHasCodeChanged] = useState(false);
|
||||
const [scrollbarWidth, setScrollbarWidth] = useState(0);
|
||||
|
||||
// Once react-live has hydrated the content-editable area, set focus to it
|
||||
// if requested
|
||||
useEffect(() => {
|
||||
if (autoFocus && hasCodeChanged) {
|
||||
const codeElem = editorScrollRef?.current?.querySelector('.prism-code');
|
||||
const sel = window.getSelection();
|
||||
if (codeElem?.clientHeight && sel != null) {
|
||||
sel.selectAllChildren(codeElem);
|
||||
sel.collapseToStart();
|
||||
}
|
||||
}
|
||||
}, [autoFocus, hasCodeChanged]);
|
||||
|
||||
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 code change
|
||||
// causes overflow/scrollbar, adjust its position based on its width progrmatically.
|
||||
if (editorScrollRef.current) {
|
||||
setScrollbarWidth(
|
||||
editorScrollRef.current.offsetWidth -
|
||||
editorScrollRef.current.clientWidth,
|
||||
);
|
||||
}
|
||||
}, [editorScrollRef, code]);
|
||||
|
||||
const heightStyle = height
|
||||
? ({'--yg-playground-height': height} as React.CSSProperties)
|
||||
: undefined;
|
||||
|
||||
const handleCodeChange = useCallback((code: string) => {
|
||||
setHasCodeChanged(true);
|
||||
setLiveCode(code);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<LiveProvider
|
||||
code={liveCode}
|
||||
theme={prismTheme}
|
||||
scope={{Node: LiveNode, Layout: RootLiveNode}}>
|
||||
<div className={styles.wrapper} style={heightStyle}>
|
||||
<div className={clsx(styles.playgroundRow)}>
|
||||
<div className={clsx(styles.editorColumn, 'playground-editor')}>
|
||||
<div className={styles.editorScroll} ref={editorScrollRef}>
|
||||
<EditorToolbar
|
||||
code={liveCode}
|
||||
className={styles.editorToolbar}
|
||||
style={{paddingRight: scrollbarWidth + 'px'}}
|
||||
/>
|
||||
|
||||
{isBrowser ? (
|
||||
<LiveEditor
|
||||
className={clsx(styles.playgroundEditor)}
|
||||
onChange={handleCodeChange}
|
||||
/>
|
||||
) : (
|
||||
<LiveEditorFallback code={liveCode} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={clsx(styles.previewColumn)}>
|
||||
<LivePreview className={clsx(styles.livePreview)} />
|
||||
<LiveError className={clsx(styles.liveError)} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</LiveProvider>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a non-editable approximation of the LiveEditor result, without
|
||||
* relying on prism rendering, for use during SSR.
|
||||
* See https://github.com/facebook/docusaurus/issues/9629
|
||||
*/
|
||||
function LiveEditorFallback({code}: Readonly<{code: string}>) {
|
||||
return (
|
||||
<div className={clsx(styles.playgroundEditor)}>
|
||||
<pre className={clsx('prism-code', styles.liveEditorFallback)}>
|
||||
{code}
|
||||
</pre>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
type RootLiveNodeProps = Readonly<{
|
||||
children: React.ReactNode;
|
||||
config?: {useWebDefaults?: boolean};
|
||||
}>;
|
||||
|
||||
function RootLiveNode({children, config}: RootLiveNodeProps) {
|
||||
if (React.Children.count(children) !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const child = React.Children.only(children);
|
||||
if (!React.isValidElement(child) || child.type !== LiveNode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const styleNode = styleNodeFromLiveNode(child as unknown as LiveNode);
|
||||
|
||||
return (
|
||||
<Suspense fallback={null}>
|
||||
<LazyYogaViewer
|
||||
rootNode={styleNode}
|
||||
useWebDefaults={config?.useWebDefaults}
|
||||
/>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
type LiveNodeProps = Readonly<{
|
||||
children: React.ReactNode;
|
||||
style: FlexStyle;
|
||||
}>;
|
||||
|
||||
class LiveNode extends React.PureComponent<LiveNodeProps> {}
|
||||
|
||||
function styleNodeFromLiveNode(
|
||||
liveNode: React.ElementRef<typeof LiveNode>,
|
||||
): StyleNode {
|
||||
const children: StyleNode[] = [];
|
||||
|
||||
React.Children.forEach(liveNode.props.children, child => {
|
||||
if (React.isValidElement(child) && child.type === LiveNode) {
|
||||
children.push(styleNodeFromLiveNode(child as unknown as LiveNode));
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
style: liveNode.props.style,
|
||||
children,
|
||||
};
|
||||
}
|
||||
|
||||
// Docusaurus SSR does not correctly support top-level await in the import
|
||||
// chain
|
||||
// 1. https://github.com/facebook/docusaurus/issues/7238
|
||||
// 2. https://github.com/facebook/docusaurus/issues/9468
|
||||
const LazyYogaViewer = lazy(() => import('./YogaViewer'));
|
Reference in New Issue
Block a user