Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
409f579
Polaris sandbox implementation based on playroom.
gwyneplaine Aug 26, 2022
e11fe2a
revert change to floating-ui tooltip config
gwyneplaine Sep 26, 2022
b499349
remove darkmode button
gwyneplaine Sep 27, 2022
8dbecb4
Change CopyButton to be more explicit CopyURL
gwyneplaine Sep 27, 2022
13d19c7
update header copy in sandbox to use status badge
gwyneplaine Sep 27, 2022
ba33716
fix ts error in SandboxHeader component
gwyneplaine Sep 27, 2022
362731d
minor copy consistency tweaks
gwyneplaine Sep 27, 2022
d668c15
update eslintrc to reflect change to playroom build folder
gwyneplaine Sep 27, 2022
f3fcb3a
changeset
gwyneplaine Sep 27, 2022
0aa4f5d
Update Sandbox 1-liner on homepage
jesstelford Sep 28, 2022
8a826f2
Sandbox header has distinct title + header with link to help
jesstelford Sep 28, 2022
1948535
Support passing a className prop to buttons on docs site
jesstelford Sep 28, 2022
82a4e7b
Support all css sizes for icons on docs site
jesstelford Sep 28, 2022
7228eac
<StableButton> allows changing button text without the width jumping …
jesstelford Sep 28, 2022
a9db423
Restyle Sandbox header to be clearer
jesstelford Sep 28, 2022
b39ff26
Rework Sandbox help dialog for better flow and content
jesstelford Sep 28, 2022
b91b7b5
Show Sandbox onboarding for firsttime visitors
jesstelford Sep 28, 2022
2d0524f
Add a 320px breakpoint to Playroom Sandbox
jesstelford Sep 28, 2022
91f01bc
Ask Typescript politely to stop being silly
jesstelford Sep 28, 2022
bac53ea
Update polaris.shopify.com/src/components/SandboxHelpDialog/SandboxDi…
gwyneplaine Sep 30, 2022
3b63e2b
remove unused styles
gwyneplaine Oct 5, 2022
2e5ea13
minor updates to sandbox CTA to accommodate new website ux updates
gwyneplaine Oct 5, 2022
788e756
remove icons from .gitignore
gwyneplaine Oct 5, 2022
714fda2
remove unused spread argument, remove playroom specific scripts in pk…
gwyneplaine Oct 5, 2022
aae80f7
[polaris.shopify.com] Improve design of sandbox (#7366)
martenbjork Oct 6, 2022
be05091
Fix up some comments in the playroom config
jesstelford Oct 6, 2022
b4703b8
Name a magic number & tweak some comments
jesstelford Oct 6, 2022
c5ce2a1
fix inconsistent file naming
gwyneplaine Oct 7, 2022
fef8b2f
remove videoRef and initialFocus prop as this was breaking a11y for t…
gwyneplaine Oct 7, 2022
db2c33f
Resolve conflicting yarn.lock
jesstelford Oct 10, 2022
e4eb0b3
create SandboxContainer component, and replace markup in sandbox.tsx …
gwyneplaine Oct 13, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fast-boats-matter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'polaris.shopify.com': patch
---

Improved the design of the Sandbox feature.
5 changes: 5 additions & 0 deletions .changeset/gorgeous-rabbits-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'polaris.shopify.com': minor
---

Added Playroom integration to Polaris docs site.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ node_modules
/polaris.shopify.com/.cache/
/polaris.shopify.com/public/sitemap.xml
/polaris.shopify.com/public/og-images
/polaris.shopify.com/public/playroom
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ dist
node_modules
/polaris-react/build
/polaris-react/build-internal
/polaris.shopify.com/public/sandbox
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
"version-packages": "yarn preversion-packages && changeset version",
"release": "turbo run build --filter='!polaris.shopify.com' && changeset publish",
"preversion": "echo \"Error: use @changsets/cli to version packages\" && exit 1",
"new-migration": "yarn workspace @shopify/polaris-migrator generate"
"new-migration": "yarn workspace @shopify/polaris-migrator generate",
"postinstall": "patch-package"
},
"devDependencies": {
"@babel/core": "^7.15.0",
Expand Down Expand Up @@ -73,6 +74,8 @@
"jest-preset-stylelint": "^5.0.3",
"jest-watch-typeahead": "^1.0.0",
"npm-run-all": "^4.1.5",
"patch-package": "^6.4.7",
"postinstall-postinstall": "^2.1.0",
"prettier": "^2.5.0",
"rollup": "^2.70.2",
"rollup-plugin-node-externals": "^4.0.0",
Expand Down
80 changes: 80 additions & 0 deletions patches/playroom+0.28.0.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
diff --git a/node_modules/playroom/README.md b/node_modules/playroom/README.md
index 6c82bbe..f05b80b 100644
--- a/node_modules/playroom/README.md
+++ b/node_modules/playroom/README.md
@@ -160,6 +160,12 @@ export { themeB } from './themeB';
// etc...
```

+## Additional Code Transformations
+
+A hook into the internal processing of code is available via the `processCode` option, which is a path to a file that exports a function that receives the code as entered into the editor, and returns the new code to be rendered.
+
+One example is [wrapping code in an IIFE for state support](https://github.com/seek-oss/playroom/issues/66).
+
## TypeScript Support

If a `tsconfig.json` file is present in your project, static prop types are parsed using [react-docgen-typescript](https://github.com/styleguidist/react-docgen-typescript) to provide better autocompletion in the Playroom editor.
diff --git a/node_modules/playroom/lib/defaultModules/processCode.js b/node_modules/playroom/lib/defaultModules/processCode.js
new file mode 100644
index 0000000..36a436c
--- /dev/null
+++ b/node_modules/playroom/lib/defaultModules/processCode.js
@@ -0,0 +1 @@
+export default code => code;
diff --git a/node_modules/playroom/lib/makeWebpackConfig.js b/node_modules/playroom/lib/makeWebpackConfig.js
index 56defa7..1e7cf3b 100644
--- a/node_modules/playroom/lib/makeWebpackConfig.js
+++ b/node_modules/playroom/lib/makeWebpackConfig.js
@@ -54,6 +54,9 @@ module.exports = async (playroomConfig, options) => {
__PLAYROOM_ALIAS__USE_SCOPE__: playroomConfig.scope
? relativeResolve(playroomConfig.scope)
: require.resolve('./defaultModules/useScope'),
+ __PLAYROOM_ALIAS__PROCESS_CODE__: playroomConfig.processCode
+ ? relativeResolve(playroomConfig.processCode)
+ : require.resolve('./defaultModules/processCode'),
},
},
module: {
diff --git a/node_modules/playroom/src/utils/compileJsx.ts b/node_modules/playroom/src/utils/compileJsx.ts
index dadea77..82d080c 100644
--- a/node_modules/playroom/src/utils/compileJsx.ts
+++ b/node_modules/playroom/src/utils/compileJsx.ts
@@ -1,9 +1,18 @@
import { transform } from '@babel/standalone';
+/* eslint-disable-next-line import/no-unresolved */
+import processCode from '__PLAYROOM_ALIAS__PROCESS_CODE__';

-export const compileJsx = (code: string) =>
- transform(`<React.Fragment>${code.trim() || ''}</React.Fragment>`, {
+export const compileJsx = (code: string) => {
+ const processedCode = processCode(code);
+
+ if (typeof processedCode !== 'string') {
+ throw new Error('processCode function must return a string of code.');
+ }
+
+ return transform(`<React.Fragment>${processedCode.trim()}</React.Fragment>`, {
presets: ['react'],
}).code;
+}

export const validateCode = (code: string) => {
try {
diff --git a/node_modules/playroom/src/utils/formatting.ts b/node_modules/playroom/src/utils/formatting.ts
index a1819bf..70ac15c 100644
--- a/node_modules/playroom/src/utils/formatting.ts
+++ b/node_modules/playroom/src/utils/formatting.ts
@@ -133,10 +133,10 @@ export const formatAndInsert = ({
snippet,
});

- return formatCode({
+ return {
code: newCode,
cursor: updatedCursor,
- });
+ };
};

export const formatForInsertion = ({
1 change: 1 addition & 0 deletions polaris.shopify.com/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module.exports = {
root: true,
extends: ['next/core-web-vitals'],
ignorePatterns: ['public/playroom'],
rules: {},
};
6 changes: 6 additions & 0 deletions polaris.shopify.com/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Not a TS file because our playroom.config.js needs to access it also, and can't understand ts imports.
module.exports = {
playroom: {
baseUrl: '/playroom/',
},
};
32 changes: 32 additions & 0 deletions polaris.shopify.com/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,41 @@ const nextConfig = {
experimental: {
scrollRestoration: true,
},
async rewrites() {
return [
// We want to rewrite the sandbox route in production
// to point at the public directory that our playroom assets are built to
// We leverage a rewrite here instead of a redirect in order to preserve
// a "pretty" url for the main playroom editor.
...(process.env.NODE_ENV !== 'production'
? [
{
source: '/playroom/:path*',
destination: 'http://localhost:9000/:path*',
},
]
: []),
];
},

async redirects() {
return [
// We run a redirect to port 9000 for non prod environments
// as playroom files aren't built to the public directory in dev mode.
// We redirect to /preview/index.html here because Playroom's webpack is configured
// to generate an html file for the preview page that reaches for assets in the root directory via a relative path.
// In this case we don't care about a pretty url, and want to make absolutely certain that the browser is pointing to preview/index.html
// such that it resolves the relative asset requests correctly.
{
source: '/playroom',
destination: '/playroom/index.html',
permanent: true,
},
{
source: '/playroom/preview',
destination: '/playroom/preview/index.html',
permanent: true,
},
{
source: '/components/get-started',
destination: '/components',
Expand Down
8 changes: 6 additions & 2 deletions polaris.shopify.com/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
"version": "0.21.1",
"private": true,
"scripts": {
"build": "yarn gen-assets && next build",
"build": "yarn gen-assets && playroom build && next build",
"start": "next start",
"dev": "run-p dev:*",
"dev:server": "open http://localhost:3000 && next dev",
"dev:playroom": "playroom start",
"dev:watch-md": "node scripts/watch-md.mjs",
"lint": "run-p lint:*",
"lint:js": "TIMING=1 eslint --cache .",
Expand All @@ -18,7 +19,7 @@
"gen-assets": "node scripts/gen-assets.mjs"
},
"dependencies": {
"@floating-ui/react-dom-interactions": "^0.6.1",
"@floating-ui/react-dom-interactions": "^0.10.1",
"@headlessui/react": "^1.6.5",
"@shopify/polaris": "^10.7.0",
"@shopify/polaris-icons": "^6.4.0",
Expand Down Expand Up @@ -51,13 +52,16 @@
"eslint-config-next": "12.1.0",
"execa": "^6.1.0",
"frontmatter": "^0.0.3",
"babel-plugin-preval": "^5.1.0",
"generact": "^0.4.0",
"get-site-urls": "3.0.0-alpha.1",
"globby": "^11.1.0",
"js-yaml": "^4.1.0",
"lodash.set": "^4.3.2",
"playroom": "^0.28.0",
"marked": "^4.0.16",
"puppeteer": "^16.0.0",
"style-loader": "^3.3.1",
"rehype-raw": "^6.1.1",
"sass": "^1.49.9",
"typescript": "^4.7.4"
Expand Down
8 changes: 7 additions & 1 deletion polaris.shopify.com/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ function MyApp({Component, pageProps}: AppProps) {
const isProd = process.env.NODE_ENV === 'production';
const darkMode = useDarkMode(false);

// We're using router.pathname here to check for a specific incoming route to render in a Fragment instead of
// the Page component. This will work fine for statically generated assets / pages
// Any SSR pages may break due to router sometimes being undefined on first render.
// see https://stackoverflow.com/questions/61040790/userouter-withrouter-receive-undefined-on-query-in-first-render

useEffect(() => {
if (!isProd) return;

Expand All @@ -43,6 +48,7 @@ function MyApp({Component, pageProps}: AppProps) {
}.png`;

const isPolarisExample = router.asPath.startsWith('/examples');
const isPolarisSandbox = router.asPath.startsWith('/sandbox');

useEffect(() => {
document.documentElement.style.setProperty(
Expand Down Expand Up @@ -91,7 +97,7 @@ function MyApp({Component, pageProps}: AppProps) {
!isPolarisExample && 'styles-for-site-but-not-polaris-examples',
)}
>
{isPolarisExample ? (
{isPolarisExample || isPolarisSandbox ? (
<Component {...pageProps} />
) : (
<Frame darkMode={darkMode}>
Expand Down
95 changes: 95 additions & 0 deletions polaris.shopify.com/pages/sandbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import {useEffect, useRef, useState} from 'react';
import type {InferGetServerSidePropsType, GetServerSideProps} from 'next';
import {useRouter} from 'next/router';

import SandboxHeader from '../src/components/SandboxHeader';
import SandboxHelpDialog from '../src/components/SandboxHelpDialog';
import SandboxContainer from '../src/components/SandboxContainer';

export const getServerSideProps: GetServerSideProps = async ({query}) => {
// We need to pass initial query param to our nested iframe
const initialSearchParams = new URLSearchParams(
query as Record<string, string>,
).toString();
return {
props: {
initialSearchParams: `?${initialSearchParams}`,
},
};
};

const MS_DELAY_BEFORE_SHOW_ONBOARDING = 500;

export default function Sandbox({
initialSearchParams,
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
const iframeRef = useRef<HTMLIFrameElement>(null);
const router = useRouter();
const searchValue = useRef('');
const [isHelpOpen, setHelpIsOpen] = useState(false);

// After the page has rendered at least once, we might show the help dialog
// (so it animates onto the screen nicely)
useEffect(() => {
const helpTimeout = setTimeout(() => {
const hasAlreadyBeenOnboarded = localStorage.getItem('onboarded');
if (hasAlreadyBeenOnboarded) {
return;
}
localStorage.setItem('onboarded', 'true');
setHelpIsOpen(true);
}, MS_DELAY_BEFORE_SHOW_ONBOARDING);
return () => clearTimeout(helpTimeout);
}, []);

useEffect(() => {
/**
* We want to mirror the iframes url in the parent (aka browser) to support URL sharing.
* the iframes onload handler isn't invoked when the iframes url changes so we're polling here instead.
*/
const iframeUrlPoll = setInterval(() => {
if (
iframeRef?.current?.contentWindow &&
iframeRef.current.contentWindow.location.search !== searchValue.current
) {
searchValue.current = iframeRef.current.contentWindow.location.search;
const iframeQueryObj = Object.fromEntries(
new URLSearchParams(searchValue.current),
);

router.replace(
{
query: iframeQueryObj,
},
undefined,
{
shallow: true,
},
);
}
}, 200);
return () => clearInterval(iframeUrlPoll);
}, [router]);

return (
<SandboxContainer>
<SandboxHeader
setHelpIsOpen={setHelpIsOpen}
url={typeof window !== 'undefined' ? window.location.href : ''}
/>
<SandboxHelpDialog {...{isOpen: isHelpOpen, setIsOpen: setHelpIsOpen}} />
<iframe
id="main"
ref={iframeRef}
style={{
border: 0,
padding: 0,
margin: 0,
}}
src={`/playroom${initialSearchParams}`}
width="100%"
height="100%"
/>
</SandboxContainer>
);
}
Loading