Skip to content

Commit

Permalink
Merge branch 'trunk' of github.com:WordPress/playground-tools into up…
Browse files Browse the repository at this point in the history
…date/playground-dependencies
  • Loading branch information
sejas committed Oct 17, 2024
2 parents a73938c + 616f6cb commit 34ec26b
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 102 deletions.
1 change: 1 addition & 0 deletions packages/wordpress-playground-block/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ In order to contribute to `wordpress-playground-block`, you'll need to first ins

- Make sure you have `nvm` installed. If you need to install it first,
[follow these installation instructions](https://github.com/nvm-sh/nvm#installation).
- Install wp-now globally to power the local development environment by running `npm install -g @wp-now/wp-now`
- Install `nx` by running `npm install -g nx`.

Once the global dependencies are installed, you can start using the repo:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Contributors: wordpressdotorg, dawidurbanski, zieladam
Tags: code, interactive, playground, block
Requires at least: 6.0
Tested up to: 6.6
Stable tag: 0.2.13
Stable tag: 0.2.17
Requires PHP: 7.0
License: GPLv2
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,23 @@ import {
// @ts-ignore
} from 'https://playground.wordpress.net/client/index.js';

export default async function downloadZippedPlugin(client: PlaygroundClient) {
export default async function downloadZippedPackage(
client: PlaygroundClient,
codeEditorMode

Check failure on line 9 in packages/wordpress-playground-block/src/components/playground-preview/download-zipped-package.ts

View workflow job for this annotation

GitHub Actions / Lint and typecheck

Parameter 'codeEditorMode' implicitly has an 'any' type.
) {
const docroot = await client.documentRoot;
const pluginPath = docroot + '/wp-content/plugins/demo-plugin';

let pluginPath = docroot + '/wp-content/plugins/demo-plugin';
let fileName = 'wordpress-playground-plugin.zip';

if (codeEditorMode == 'theme') {
pluginPath = docroot + '/wp-content/themes/demo-theme';
fileName = 'wordpress-playground-theme.zip';
}

const zipFile = new File(
[await zipPlaygroundFiles(client, pluginPath)],
'wordpress-playground-plugin.zip',
fileName,
{
type: 'application/zip',
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
useState,
createInterpolateElement,
} from '@wordpress/element';
import { Button, Spinner } from '@wordpress/components';
import { Button, Spinner, withSpokenMessages } from '@wordpress/components';
import {
Icon,
plus,
Expand All @@ -32,7 +32,8 @@ import {
import useEditorFiles, { isErrorLogFile } from './use-editor-files';
import { LanguageSupport } from '@codemirror/language';
import { writePluginFiles } from './write-plugin-files';
import downloadZippedPlugin from './download-zipped-plugin';
import { writeThemeFiles } from './write-theme-files';
import downloadZippedPackage from './download-zipped-package';
import classnames from 'classnames';
import FileManagementModals, { FileManagerRef } from './file-management-modals';
import {
Expand All @@ -49,6 +50,7 @@ export type PlaygroundDemoProps = Attributes & {
inFullPageView?: boolean;
baseAttributesForFullPageView?: object;
onStateChange?: (state: any) => void;
speak: (message: string, ariaLive?: string) => void;
};

const languages: Record<string, LanguageSupport> = {
Expand Down Expand Up @@ -83,12 +85,13 @@ function getRefreshPath(lastPath: string) {
return url.pathname + url.search;
}

export default function PlaygroundPreview({
function PlaygroundPreview({
inBlockEditor,
blueprint,
blueprintUrl,
configurationSource,
codeEditor,
codeEditorMode,
codeEditorSideBySide,
codeEditorReadOnly,
codeEditorTranspileJsx,
Expand All @@ -112,6 +115,7 @@ export default function PlaygroundPreview({
inFullPageView = false,
baseAttributesForFullPageView = {},
onStateChange,
speak,
}: PlaygroundDemoProps) {
const {
files,
Expand All @@ -135,6 +139,7 @@ export default function PlaygroundPreview({
const afterPreviewRef = useRef<HTMLSpanElement>(null);
const playgroundClientRef = useRef<PlaygroundClient | null>(null);
const fileMgrRef = useRef<FileManagerRef>(null);
const downloadButtonRef = useRef<HTMLAnchorElement>(null);
const codeMirrorRef = useRef<any>(null);

/**
Expand Down Expand Up @@ -169,19 +174,19 @@ export default function PlaygroundPreview({
const [dismissedExitWithKeyboardTip, setDismissedExitWithKeyboardTip] =
useState(localStorage[dismissedExitWithKeyboardTipKey] === 'true');
function dismissExitWithKeyboardTip() {
// Shift focus to previous focusable control
// so focus is not lost as the tip disappears
if (downloadButtonRef?.current) {
downloadButtonRef.current.focus();
}

localStorage[dismissedExitWithKeyboardTipKey] = 'true';
setDismissedExitWithKeyboardTip(true);

// Shift focus to editor so focus is not lost as the tip disappears
if (codeMirrorRef?.current?.view?.dom) {
const contentEditableElement: HTMLElement =
codeMirrorRef.current.view.dom.querySelector(
'[contenteditable=true]'
);
if (contentEditableElement) {
contentEditableElement.focus();
}
}
speak(
// translators: This describes a UI notice that has been dismissed by the user.
__('Notice dismissed.'),
'polite'
);
}

/**
Expand Down Expand Up @@ -259,7 +264,22 @@ export default function PlaygroundPreview({
await client.isReady();
playgroundClientRef.current = client;

await reinstallEditedPlugin();
// Hack: Delay the announcement to give iframe loading percentage
// announcements for the iframe a chance to be queued before this
// "loading complete" announcement. Without this, macOS VoiceOver
// often speaks "WordPress Playground loaded. 10% loaded" which
// is a miscommunication because Playground has already loaded.
setTimeout(
() =>
speak(
// translators: This says that the Playground preview has loaded.
__('WordPress Playground loaded.'),
'polite'
),
500
);

await reinstallEditedCode();

if (configurationSource === 'block-attributes') {
let postId = 0;
Expand Down Expand Up @@ -345,7 +365,7 @@ export default function PlaygroundPreview({
const [transpilationFailures, setTranspilationFailures] = useState<
TranspilationFailure[]
>([]);
async function reinstallEditedPlugin() {
async function reinstallEditedCode() {
if (!playgroundClientRef.current || !codeEditor) {
return;
}
Expand All @@ -354,6 +374,7 @@ export default function PlaygroundPreview({

const client = playgroundClientRef.current;
let finalFiles = files;

if (codeEditorTranspileJsx) {
const { failures, transpiledFiles } = await transpilePluginFiles(
finalFiles
Expand All @@ -370,12 +391,17 @@ export default function PlaygroundPreview({
}
finalFiles = transpiledFiles;
}
await writePluginFiles(client, finalFiles);

if (codeEditorMode === 'theme') {
await writeThemeFiles(client, finalFiles);
} else {
await writePluginFiles(client, finalFiles);
}
}

const handleReRunCode = useCallback(() => {
async function doHandleRun() {
await reinstallEditedPlugin();
await reinstallEditedCode();

// Refresh Playground iframe
const lastPath = await playgroundClientRef.current!.getCurrentURL();
Expand All @@ -388,7 +414,7 @@ export default function PlaygroundPreview({
} else {
doHandleRun();
}
}, [reinstallEditedPlugin]);
}, [reinstallEditedCode]);

const keymapExtension = useMemo(
() =>
Expand Down Expand Up @@ -428,31 +454,24 @@ export default function PlaygroundPreview({
'WordPress website which may be a challenge for screen readers.'
);

const activeStatusLabel = playgroundClientRef.current
? // translators: State of the playground iframe after it has loaded.
__('Loaded')
: // translators: State of the playground iframe while it is loading.
__('Loading');
// translators: State of the playground iframe before the user activates it.
const inactivateStatusLabel = __('Not Activated');
const beforePlaygroundPreviewLabel = sprintf(
// translators: %s: status of the Playground preview
__('Beginning of Playground Preview - %s'),
isLivePreviewActivated ? activeStatusLabel : inactivateStatusLabel
);

return (
<section
aria-label={__('WordPress Playground')}
className={mainContainerClass}
>
<header className="wordpress-playground-header">
{!inBlockEditor && !inFullPageView && (
<Button
variant="link"
className="wordpress-playground-header__full-page-link"
onClick={() => {
window.open(getFullPageUrl(), '_blank');
}}
aria-label={
// Add dedicated aria-label for screen readers
// because an arrow is added to the main button
// label via CSS pseudo-element, and our users with
// screen readers do not need an arrow read to them.
__('Open in New Tab')
}
>
{__('Open in New Tab')}
</Button>
)}
</header>
<div className={contentContainerClass}>
{codeEditor && (
<div className="code-container">
Expand Down Expand Up @@ -535,13 +554,15 @@ export default function PlaygroundPreview({
</Button>
)}
<Button
ref={downloadButtonRef}
aria-label={__('Download Code as a Zip file')}
variant="secondary"
className="file-tab file-tab-extra"
onClick={() => {
if (playgroundClientRef.current) {
downloadZippedPlugin(
playgroundClientRef.current
downloadZippedPackage(
playgroundClientRef.current,
codeEditorMode
);
}
}}
Expand Down Expand Up @@ -696,10 +717,7 @@ export default function PlaygroundPreview({
tabIndex={-1}
ref={beforePreviewRef}
>
{
// translators: screen reader text noting beginning of the playground iframe
__('Beginning of Playground Preview')
}
{beforePlaygroundPreviewLabel}
</span>
<a
href="#"
Expand Down Expand Up @@ -789,7 +807,7 @@ export default function PlaygroundPreview({
<footer className="wordpress-playground-footer">
<a
href="https://w.org/playground"
className="wordpress-playground-footer__link"
className="wordpress-playground-footer__powered_by_link"
target="_blank"
aria-label={
// Provide dedicated ARIA label because NVDA does not
Expand All @@ -807,7 +825,7 @@ export default function PlaygroundPreview({
),
{
span1: (
<span className="wordpress-playground-footer__powered" />
<span className="wordpress-playground-footer__powered_text" />
),
WordPressIcon: (
<>
Expand All @@ -826,12 +844,32 @@ export default function PlaygroundPreview({
</>
),
span2: (
<span className="wordpress-playground-footer__link-text" />
<span className="wordpress-playground-footer__powered_by_link-text" />
),
}
)}
</a>
{!inBlockEditor && !inFullPageView && (
<Button
variant="link"
className="wordpress-playground-footer__full-page-link"
onClick={() => {
window.open(getFullPageUrl(), '_blank');
}}
aria-label={
// Add dedicated aria-label for screen readers
// because an arrow is added to the main button
// label via CSS pseudo-element, and our users with
// screen readers do not need an arrow read to them.
__('Open in New Tab')
}
>
{__('Open in New Tab')}
</Button>
)}
</footer>
</section>
);
}

export default withSpokenMessages(PlaygroundPreview);
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { EditorFile } from '../../index';
import {
PlaygroundClient,
activateTheme,
// @ts-ignore
} from 'https://playground.wordpress.net/client/index.js';

export const writeThemeFiles = async (
client: PlaygroundClient,
files: EditorFile[]
) => {
const docroot = await client.documentRoot;
const themeFolderName = 'demo-theme';
const themePath = docroot + '/wp-content/themes/' + themeFolderName;
if (await client.fileExists(themePath)) {
await client.rmdir(themePath, {
recursive: true,
});
}
await client.mkdir(themePath);

for (const file of files) {
const filePath = `${themePath}/${file.name}`;
const parentDir = filePath.split('/').slice(0, -1).join('/');
await client.mkdir(parentDir);
await client.writeFile(filePath, file.contents);
}

try {
await activateTheme(client, {
themeFolderName,
});
} catch (e) {
console.error(e);
}
};
Loading

0 comments on commit 34ec26b

Please sign in to comment.