diff --git a/www/src/theme/Playground/EditorInfoMessage.tsx b/www/src/theme/Playground/EditorInfoMessage.tsx new file mode 100644 index 0000000000..af161bed35 --- /dev/null +++ b/www/src/theme/Playground/EditorInfoMessage.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import clsx from 'clsx'; +import styles from './styles.module.css'; + +const EditorInfoMessage: React.FC> = ( + props, +) => ( +
+); + +EditorInfoMessage.displayName = 'EditorInfoMessage'; + +export default EditorInfoMessage; diff --git a/www/src/theme/Playground/index.tsx b/www/src/theme/Playground/index.tsx index f5e81e6477..a7e95664b2 100644 --- a/www/src/theme/Playground/index.tsx +++ b/www/src/theme/Playground/index.tsx @@ -1,14 +1,16 @@ -import React from 'react'; +import React, { useCallback, useContext, useRef, useState } from 'react'; import clsx from 'clsx'; import useIsBrowser from '@docusaurus/useIsBrowser'; -import { LiveProvider, LiveEditor, LiveError } from 'react-live'; +import { LiveContext, LiveProvider, LiveEditor, LiveError } from 'react-live'; import Translate from '@docusaurus/Translate'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import BrowserOnly from '@docusaurus/BrowserOnly'; import { usePrismTheme } from '@docusaurus/theme-common'; import type { Props } from '@theme/Playground'; import type { ThemeConfig } from '@docusaurus/theme-live-codeblock'; +import CopyButton from '@theme-original/CodeBlock/CopyButton'; import Preview from './Preview'; +import EditorInfoMessage from './EditorInfoMessage'; import styles from './styles.module.css'; @@ -47,15 +49,91 @@ function ResultWithHeader({ className }: any) { ); } +let uid = 0; + function ThemedLiveEditor() { + const { code } = useContext(LiveContext); const isBrowser = useIsBrowser(); + const [focused, setFocused] = useState(false); + const [ignoreTab, setIgnoreTab] = useState(false); + const [keyboardFocused, setKeyboardFocused] = useState(false); + const mouseDownRef = useRef(false); + const idRef = useRef(null); + + if (idRef.current === null) idRef.current = `described-by-${++uid}`; + const id = idRef.current; + + const handleKeyDown = useCallback( + (e) => { + if (ignoreTab) { + if (e.key !== 'Tab' && e.key !== 'Shift') { + if (e.key === 'Enter') e.preventDefault(); + setIgnoreTab(false); + } + } else if (e.key === 'Escape') { + setIgnoreTab(true); + } + }, + [ignoreTab], + ); + + const handleFocus = useCallback(() => { + setFocused(true); + setIgnoreTab(!mouseDownRef.current); + setKeyboardFocused(!mouseDownRef.current); + }, []); + + const handleBlur = useCallback(() => { + setFocused(false); + }, []); + + const handleMouseDown = useCallback(() => { + mouseDownRef.current = true; + window.setTimeout(() => { + mouseDownRef.current = false; + }); + }, []); + + // Hack because LiveEditor doesn't define this type + const props = { + ignoreTabKey: ignoreTab, + }; + + const showMessage = keyboardFocused || (focused && !ignoreTab); + return ( - +
+ +
+ {showMessage && ( + + {ignoreTab ? ( + <> + Press enter or type a key to enable tab-to-indent + + ) : ( + <> + Press esc to disable tab trapping + + )} + + )} +
+ +
+
+
); } diff --git a/www/src/theme/Playground/styles.module.css b/www/src/theme/Playground/styles.module.css index d107439f91..f2b9564883 100644 --- a/www/src/theme/Playground/styles.module.css +++ b/www/src/theme/Playground/styles.module.css @@ -31,3 +31,30 @@ padding: 1rem; background-color: var(--ifm-pre-background); } + +.editorToolbar { + position: absolute; + right: calc(var(--ifm-pre-padding) / 2); + top: calc(var(--ifm-pre-padding) / 2); + display: flex; + column-gap: 0.2rem; +} + +.editorInfoMessage { + font-size: 70%; + pointer-events: none; +} + +/* https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/theme/CodeBlock/Content/styles.module.css */ +.buttonGroup button { + display: flex; + align-items: center; + background: var(--prism-background-color); + color: var(--prism-color); + border: 1px solid var(--ifm-color-emphasis-300); + border-radius: var(--ifm-global-radius); + padding: 0.4rem; + line-height: 0; + transition: opacity var(--ifm-transition-fast) ease-in-out; + opacity: 1; +}