Skip to content

Commit 6030387

Browse files
committed
Polaris sandbox implementation based on playroom.
1 parent da094b9 commit 6030387

36 files changed

+3248
-84
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ node_modules
1414
/polaris-tokens/build
1515
/polaris.shopify.com/public/sitemap.xml
1616
/polaris.shopify.com/public/og-images
17+
/polaris.shopify.com/public/icons
18+
/polaris.shopify.com/public/playroom

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ dist
33
node_modules
44
/polaris-react/build
55
/polaris-react/build-internal
6+
/polaris.shopify.com/public/sandbox

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838
"preversion-packages": "turbo run preversion",
3939
"version-packages": "yarn preversion-packages && changeset version",
4040
"release": "turbo run build --filter=polaris.shopify.com^... && changeset publish",
41-
"preversion": "echo \"Error: use @changsets/cli to version packages\" && exit 1"
41+
"preversion": "echo \"Error: use @changsets/cli to version packages\" && exit 1",
42+
"postinstall": "patch-package"
4243
},
4344
"devDependencies": {
4445
"@babel/core": "^7.15.0",
@@ -68,6 +69,8 @@
6869
"jest-preset-stylelint": "^5.0.3",
6970
"jest-watch-typeahead": "^1.0.0",
7071
"npm-run-all": "^4.1.5",
72+
"patch-package": "^6.4.7",
73+
"postinstall-postinstall": "^2.1.0",
7174
"prettier": "^2.5.0",
7275
"rollup": "^2.70.2",
7376
"rollup-plugin-node-externals": "^4.0.0",

patches/playroom+0.28.0.patch

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
diff --git a/node_modules/playroom/README.md b/node_modules/playroom/README.md
2+
index 6c82bbe..f05b80b 100644
3+
--- a/node_modules/playroom/README.md
4+
+++ b/node_modules/playroom/README.md
5+
@@ -160,6 +160,12 @@ export { themeB } from './themeB';
6+
// etc...
7+
```
8+
9+
+## Additional Code Transformations
10+
+
11+
+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.
12+
+
13+
+One example is [wrapping code in an IIFE for state support](https://github.com/seek-oss/playroom/issues/66).
14+
+
15+
## TypeScript Support
16+
17+
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.
18+
diff --git a/node_modules/playroom/lib/defaultModules/processCode.js b/node_modules/playroom/lib/defaultModules/processCode.js
19+
new file mode 100644
20+
index 0000000..36a436c
21+
--- /dev/null
22+
+++ b/node_modules/playroom/lib/defaultModules/processCode.js
23+
@@ -0,0 +1 @@
24+
+export default code => code;
25+
diff --git a/node_modules/playroom/lib/makeWebpackConfig.js b/node_modules/playroom/lib/makeWebpackConfig.js
26+
index 56defa7..1e7cf3b 100644
27+
--- a/node_modules/playroom/lib/makeWebpackConfig.js
28+
+++ b/node_modules/playroom/lib/makeWebpackConfig.js
29+
@@ -54,6 +54,9 @@ module.exports = async (playroomConfig, options) => {
30+
__PLAYROOM_ALIAS__USE_SCOPE__: playroomConfig.scope
31+
? relativeResolve(playroomConfig.scope)
32+
: require.resolve('./defaultModules/useScope'),
33+
+ __PLAYROOM_ALIAS__PROCESS_CODE__: playroomConfig.processCode
34+
+ ? relativeResolve(playroomConfig.processCode)
35+
+ : require.resolve('./defaultModules/processCode'),
36+
},
37+
},
38+
module: {
39+
diff --git a/node_modules/playroom/src/utils/compileJsx.ts b/node_modules/playroom/src/utils/compileJsx.ts
40+
index dadea77..82d080c 100644
41+
--- a/node_modules/playroom/src/utils/compileJsx.ts
42+
+++ b/node_modules/playroom/src/utils/compileJsx.ts
43+
@@ -1,9 +1,18 @@
44+
import { transform } from '@babel/standalone';
45+
+/* eslint-disable-next-line import/no-unresolved */
46+
+import processCode from '__PLAYROOM_ALIAS__PROCESS_CODE__';
47+
48+
-export const compileJsx = (code: string) =>
49+
- transform(`<React.Fragment>${code.trim() || ''}</React.Fragment>`, {
50+
+export const compileJsx = (code: string) => {
51+
+ const processedCode = processCode(code);
52+
+
53+
+ if (typeof processedCode !== 'string') {
54+
+ throw new Error('processCode function must return a string of code.');
55+
+ }
56+
+
57+
+ return transform(`<React.Fragment>${processedCode.trim()}</React.Fragment>`, {
58+
presets: ['react'],
59+
}).code;
60+
+}
61+
62+
export const validateCode = (code: string) => {
63+
try {
64+
diff --git a/node_modules/playroom/src/utils/formatting.ts b/node_modules/playroom/src/utils/formatting.ts
65+
index a1819bf..70ac15c 100644
66+
--- a/node_modules/playroom/src/utils/formatting.ts
67+
+++ b/node_modules/playroom/src/utils/formatting.ts
68+
@@ -133,10 +133,10 @@ export const formatAndInsert = ({
69+
snippet,
70+
});
71+
72+
- return formatCode({
73+
+ return {
74+
code: newCode,
75+
cursor: updatedCursor,
76+
- });
77+
+ };
78+
};
79+
80+
export const formatForInsertion = ({

polaris-react/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,3 +413,4 @@ export {
413413
SELECT_ALL_ITEMS as INDEX_TABLE_SELECT_ALL_ITEMS,
414414
SelectionType as IndexTableSelectionType,
415415
} from './utilities/index-provider';
416+
export {useBreakpoints} from './utilities/breakpoints';

polaris.shopify.com/.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module.exports = {
22
root: true,
33
extends: ['next/core-web-vitals'],
4+
ignorePatterns: ['public/sandbox'],
45
rules: {},
56
};

polaris.shopify.com/constants.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Not a TS file because our playroom.config.js needs to access it also, and can't understand ts imports.
2+
module.exports = {
3+
playroom: {
4+
baseUrl: '/playroom/',
5+
},
6+
};

polaris.shopify.com/next.config.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,22 @@ const nextConfig = {
88
experimental: {
99
scrollRestoration: true,
1010
},
11+
async rewrites() {
12+
return [
13+
// We want to rewrite the sandbox route in production
14+
// to point at the public directory that our playroom assets are built to
15+
// We leverage a rewrite here instead of a redirect in order to preserve
16+
// a "pretty" url for the main playroom editor.
17+
...(process.env.NODE_ENV !== 'production'
18+
? [
19+
{
20+
source: '/playroom/:path*',
21+
destination: 'http://localhost:9000/:path*',
22+
},
23+
]
24+
: []),
25+
];
26+
},
1127
async headers() {
1228
return [
1329
{
@@ -31,6 +47,22 @@ const nextConfig = {
3147

3248
async redirects() {
3349
return [
50+
// We run a redirect to port 9000 for non prod environments
51+
// as playroom files aren't built to the public directory in dev mode.
52+
// We redirect to /preview/index.html here because Playroom's webpack is configured
53+
// to generate an html file for the preview page that reaches for assets in the root directory via a relative path.
54+
// 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
55+
// such that it resolves the relative asset requests correctly.
56+
{
57+
source: '/playroom',
58+
destination: '/playroom/index.html',
59+
permanent: true,
60+
},
61+
{
62+
source: '/playroom/preview',
63+
destination: '/playroom/preview/index.html',
64+
permanent: true,
65+
},
3466
{
3567
source: '/components/get-started',
3668
destination: '/components',

polaris.shopify.com/package.json

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,21 @@
33
"version": "0.13.0",
44
"private": true,
55
"scripts": {
6-
"build": "next build",
7-
"dev": "open http://localhost:3000 && next dev",
6+
"build": "yarn playroom:build && next build",
7+
"dev": "concurrently \"open http://localhost:3000 && next dev\" \"npm:playroom:start\"",
88
"start": "next start",
99
"lint": "run-p lint:*",
1010
"lint:js": "TIMING=1 eslint --cache .",
1111
"lint:styles": "stylelint '**/*.{css,scss}'",
1212
"clean": "rm -rf .turbo node_modules .next *.tsbuildinfo",
1313
"create-component": "generact --root src/components src/components/Template/Template.tsx",
1414
"gen-assets": "node scripts/gen-assets.mjs",
15-
"get-props": "ts-node --skip-project ./scripts/get-props.ts"
15+
"get-props": "ts-node --skip-project ./scripts/get-props.ts",
16+
"playroom:start": "playroom start",
17+
"playroom:build": "playroom build"
1618
},
1719
"dependencies": {
18-
"@floating-ui/react-dom-interactions": "^0.6.1",
20+
"@floating-ui/react-dom-interactions": "^0.10.1",
1921
"@headlessui/react": "^1.6.5",
2022
"@shopify/polaris": "^10.0.0",
2123
"@shopify/polaris-icons": "^5.4.0",
@@ -28,8 +30,8 @@
2830
"react": "^17.0.2",
2931
"react-dom": "^17.0.2",
3032
"react-markdown": "^8.0.2",
31-
"use-dark-mode": "^2.3.1",
32-
"remark-gfm": "^3.0.1"
33+
"remark-gfm": "^3.0.1",
34+
"use-dark-mode": "^2.3.1"
3335
},
3436
"devDependencies": {
3537
"@types/gtag.js": "^0.0.10",
@@ -38,16 +40,20 @@
3840
"@types/node": "17.0.21",
3941
"@types/prismjs": "^1.26.0",
4042
"@types/react": "*",
43+
"concurrently": "ˆ7.3.0",
4144
"eslint-config-next": "12.1.0",
4245
"eslint": "8.10.0",
4346
"execa": "^6.1.0",
4447
"frontmatter": "^0.0.3",
48+
"babel-plugin-preval": "^5.1.0",
4549
"get-site-urls": "3.0.0-alpha.1",
4650
"generact": "^0.4.0",
4751
"globby": "^11.1.0",
4852
"js-yaml": "^4.1.0",
53+
"playroom": "^0.28.0",
4954
"marked": "^4.0.16",
5055
"puppeteer": "^16.0.0",
56+
"style-loader": "^3.3.1",
5157
"rehype-raw": "^6.1.1",
5258
"sass": "^1.49.9",
5359
"typescript": "^4.7.4"

polaris.shopify.com/pages/_app.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type {AppProps} from 'next/app';
22
import Head from 'next/head';
33
import Script from 'next/script';
4-
import {useEffect} from 'react';
4+
import {Fragment, useEffect} from 'react';
55
import {useRouter} from 'next/router';
66

77
import '../src/styles/globals.scss';
@@ -16,10 +16,17 @@ const gaPageView = (url: string) => {
1616
// Remove dark mode flicker. Minified version of https://github.com/donavon/use-dark-mode/blob/develop/noflash.js.txt
1717
const noflash = `!function(){var b="darkMode",g="dark-mode",j="light-mode";function d(a){document.body.classList.add(a?g:j),document.body.classList.remove(a?j:g)}var e="(prefers-color-scheme: dark)",c=window.matchMedia(e),h=c.media===e,a=null;try{a=localStorage.getItem(b)}catch(k){}var f=null!==a;if(f&&(a=JSON.parse(a)),f)d(a);else if(h)d(c.matches),localStorage.setItem(b,c.matches);else{var i=document.body.classList.contains(g);localStorage.setItem(b,JSON.stringify(i))}}()`;
1818

19-
function MyApp({Component, pageProps}: AppProps) {
19+
function MyApp({Component, pageProps, ...appProps}: AppProps) {
2020
const router = useRouter();
2121
const isProd = process.env.NODE_ENV === 'production';
2222

23+
// We're using router.pathname here to check for a specific incoming route to render in a Fragment instead of
24+
// the Page component. This will work fine for statically generated assets / pages
25+
// Any SSR pages may break due to router sometimes being undefined on first render.
26+
// see https://stackoverflow.com/questions/61040790/userouter-withrouter-receive-undefined-on-query-in-first-render
27+
28+
const isLayoutNeeded = !appProps.router.asPath.startsWith('/sandbox');
29+
const LayoutComponent = isLayoutNeeded ? Page : Fragment;
2330
useEffect(() => {
2431
if (!isProd) return;
2532

@@ -64,7 +71,7 @@ function MyApp({Component, pageProps}: AppProps) {
6471
</>
6572
) : null}
6673

67-
<Page>
74+
<LayoutComponent>
6875
<script dangerouslySetInnerHTML={{__html: noflash}}></script>
6976

7077
<Head>
@@ -74,7 +81,7 @@ function MyApp({Component, pageProps}: AppProps) {
7481
</Head>
7582

7683
<Component {...pageProps} />
77-
</Page>
84+
</LayoutComponent>
7885
</>
7986
);
8087
}

0 commit comments

Comments
 (0)