playroom 0.28.1 → 0.28.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.babelrc CHANGED
@@ -3,11 +3,5 @@
3
3
  "@babel/preset-typescript",
4
4
  "@babel/preset-env",
5
5
  "@babel/preset-react"
6
- ],
7
- "plugins": [
8
- "@babel/plugin-proposal-class-properties",
9
- "@babel/plugin-proposal-optional-chaining",
10
- "@babel/plugin-proposal-nullish-coalescing-operator",
11
- "@vanilla-extract/babel-plugin"
12
6
  ]
13
7
  }
@@ -0,0 +1,8 @@
1
+ # Changesets
2
+
3
+ Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
4
+ with multi-package repos, or single-package repos to help you version and publish your code. You can
5
+ find the full documentation for it [in our repository](https://github.com/changesets/changesets)
6
+
7
+ We have a quick list of common questions to get you started engaging with this project in
8
+ [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@changesets/config@2.2.0/schema.json",
3
+ "changelog": "@changesets/cli/changelog",
4
+ "commit": false,
5
+ "fixed": [],
6
+ "linked": [],
7
+ "access": "public",
8
+ "baseBranch": "master",
9
+ "updateInternalDependencies": "patch",
10
+ "ignore": []
11
+ }
@@ -15,24 +15,28 @@ jobs:
15
15
  - name: Checkout Repo
16
16
  uses: actions/checkout@v3
17
17
 
18
+ - name: Set up pnpm
19
+ uses: pnpm/action-setup@v2.2.2
20
+
18
21
  - name: Set up Node.js
19
22
  uses: actions/setup-node@v3
20
23
  with:
21
24
  node-version-file: 'package.json'
25
+ cache: 'pnpm'
22
26
 
23
27
  - name: Install Dependencies
24
- run: yarn --frozen-lockfile
28
+ run: pnpm i
25
29
 
26
30
  - name: Build
27
- run: yarn build:themed
31
+ run: pnpm build:themed
28
32
 
29
33
  - name: Deploy to surge
30
- run: yarn deploy-preview -d playroom--${GITHUB_SHA}.surge.sh
34
+ run: pnpm deploy-preview -d playroom--${GITHUB_SHA}.surge.sh
31
35
  env:
32
36
  SURGE_LOGIN: ${{ secrets.SURGE_LOGIN }}
33
37
  SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }}
34
38
 
35
39
  - name: Update PR status
36
- run: yarn post-commit-status
40
+ run: pnpm post-commit-status
37
41
  env:
38
42
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -15,20 +15,26 @@ jobs:
15
15
  - name: Checkout Repo
16
16
  uses: actions/checkout@v3
17
17
  with:
18
- # This makes Actions fetch all Git history for semantic-release
18
+ # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
19
19
  fetch-depth: 0
20
- token: ${{ secrets.GITHUB_TOKEN }}
20
+
21
+ - name: Set up pnpm
22
+ uses: pnpm/action-setup@v2.2.2
21
23
 
22
24
  - name: Set up Node.js
23
25
  uses: actions/setup-node@v3
24
26
  with:
25
27
  node-version-file: 'package.json'
28
+ cache: 'pnpm'
26
29
 
27
30
  - name: Install Dependencies
28
- run: yarn --frozen-lockfile
31
+ run: pnpm i
29
32
 
30
- - name: Publish to npm
31
- run: yarn semantic-release
33
+ - name: Create Release Pull Request or Publish to npm
34
+ uses: changesets/action@v1
35
+ with:
36
+ version: pnpm run version
37
+ publish: pnpm release
32
38
  env:
33
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39
+ GITHUB_TOKEN: ${{ secrets.SEEK_OSS_CI_GITHUB_TOKEN }}
34
40
  NPM_TOKEN: ${{ secrets.SEEK_OSS_CI_NPM_TOKEN }}
@@ -16,13 +16,17 @@ jobs:
16
16
  fetch-depth: 0
17
17
  token: ${{ secrets.GITHUB_TOKEN }}
18
18
 
19
+ - name: Set up pnpm
20
+ uses: pnpm/action-setup@v2.2.2
21
+
19
22
  - name: Set up Node.js
20
23
  uses: actions/setup-node@v3
21
24
  with:
22
25
  node-version-file: 'package.json'
26
+ cache: 'pnpm'
23
27
 
24
28
  - name: Install dependencies
25
- run: yarn --frozen-lockfile
29
+ run: pnpm i
26
30
 
27
31
  - name: Publish
28
32
  uses: seek-oss/changesets-snapshot@v0
@@ -12,19 +12,46 @@ jobs:
12
12
  - name: Checkout Repo
13
13
  uses: actions/checkout@v3
14
14
 
15
+ - name: Set up pnpm
16
+ uses: pnpm/action-setup@v2.2.2
17
+
15
18
  - name: Set up Node.js
16
19
  uses: actions/setup-node@v3
17
20
  with:
18
21
  node-version-file: 'package.json'
19
22
 
23
+ - name: Get pnpm store directory
24
+ id: pnpm-cache
25
+ shell: bash
26
+ run: |
27
+ echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
28
+
29
+ - name: Cache node modules
30
+ uses: actions/cache@v3
31
+ with:
32
+ path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
33
+ key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
34
+ restore-keys: |
35
+ ${{ runner.os }}-pnpm-store-
36
+
37
+ - name: Cache Cypress binary
38
+ uses: actions/cache@v3
39
+ with:
40
+ path: ~/.cache/Cypress
41
+ key: cypress-${{ runner.os }}-cypress-${{ hashFiles('**/pnpm-lock.yaml') }}
42
+ restore-keys: |
43
+ cypress-${{ runner.os }}-cypress-
44
+
20
45
  - name: Install Dependencies
21
- run: yarn --frozen-lockfile
46
+ run: pnpm i
22
47
 
23
48
  - name: Lint
24
- run: yarn lint
49
+ run: pnpm lint
25
50
 
26
51
  - name: Test
27
- run: yarn test
52
+ run: pnpm test
28
53
 
29
54
  - name: Cypress
30
- run: yarn cypress
55
+ run: |
56
+ pnpm cypress:verify
57
+ pnpm cypress
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+ . "$(dirname "$0")/_/husky.sh"
3
+
4
+ pnpm exec lint-staged
package/.nvmrc CHANGED
@@ -1 +1 @@
1
- lts/*
1
+ 16.13.0
package/CHANGELOG.md ADDED
@@ -0,0 +1,26 @@
1
+ # playroom
2
+
3
+ ## 0.28.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 8030325: Update all dependencies
8
+ - 8030325: Fix error message on gutter marker tooltip
9
+
10
+ Playroom wraps the code in a Fragment to compile it and then removes it from the error message displayed as a tooltip on the gutter marker if it fails to compile.
11
+
12
+ The logic has been improved to remove the first occurence of an opening `<React.Fragment>` and the last occurence of `</React.Fragment>`.
13
+
14
+ Errors should no longer incorrectly have a stray closing fragment:
15
+
16
+ ```diff
17
+ "unknown: Expected corresponding JSX closing tag for <Boxerror>. (3:0)
18
+
19
+ 1 | <Boxerror>
20
+ 2 | ...
21
+ -> 3 | </Box></React.Fragment>
22
+ +> 3 | </Box>
23
+ | ^"
24
+ ```
25
+
26
+ - cbcf1cf: Update dependencies (and move to pnpm internally)
File without changes
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from 'cypress';
2
+
3
+ export default defineConfig({
4
+ defaultCommandTimeout: 10000,
5
+ video: false,
6
+ e2e: {},
7
+ });
package/lib/build.js CHANGED
@@ -16,7 +16,7 @@ module.exports = async (config, callback = noop) => {
16
16
 
17
17
  if (stats.hasErrors()) {
18
18
  const info = stats.toJson();
19
- return callback(info.errors.join('\n\n'));
19
+ return callback(info.errors.map((error) => error.message).join('\n\n'));
20
20
  }
21
21
 
22
22
  return callback();
package/package.json CHANGED
@@ -1,55 +1,20 @@
1
1
  {
2
2
  "name": "playroom",
3
- "version": "0.28.1",
3
+ "version": "0.28.2",
4
4
  "description": "Design with code, powered by your own component library",
5
5
  "main": "utils/index.js",
6
6
  "types": "utils/index.d.ts",
7
7
  "bin": {
8
8
  "playroom": "bin/cli.js"
9
9
  },
10
- "scripts": {
11
- "cypress": "start-server-and-test build-and-serve:all '9000|9001' 'cypress run'",
12
- "cypress:dev": "start-server-and-test start:all '9000|9001' 'cypress open'",
13
- "start:basic": "./bin/cli.js start --config cypress/projects/basic/playroom.config.js",
14
- "build:basic": "./bin/cli.js build --config cypress/projects/basic/playroom.config.js",
15
- "serve:basic": "PORT=9000 serve cypress/projects/basic/dist",
16
- "start:themed": "./bin/cli.js start --config cypress/projects/themed/playroom.config.js",
17
- "build:themed": "./bin/cli.js build --config cypress/projects/themed/playroom.config.js",
18
- "serve:themed": "PORT=9001 serve --config ../serve.json cypress/projects/themed/dist",
19
- "start:all": "concurrently 'npm:start:basic' 'npm:start:themed'",
20
- "build:all": "concurrently 'npm:build:basic' 'npm:build:themed'",
21
- "serve:all": "concurrently 'npm:serve:basic' 'npm:serve:themed'",
22
- "build-and-serve:all": "yarn build:all && yarn serve:all",
23
- "commit": "git-cz",
24
- "lint": "eslint . && prettier --list-different '**/*.{js,md,less,ts,tsx}' && tsc --noEmit",
25
- "format": "prettier --write '**/*.{js,md,less,ts,tsx}'",
26
- "semantic-release": "semantic-release",
27
- "test": "jest src",
28
- "post-commit-status": "node scripts/postCommitStatus.js",
29
- "deploy-preview": "surge -p ./cypress/projects/themed/dist"
30
- },
31
- "husky": {
32
- "hooks": {
33
- "commit-msg": "commitlint --edit --extends seek",
34
- "pre-commit": "lint-staged"
35
- }
36
- },
37
10
  "lint-staged": {
38
11
  "**/*.{js,ts,tsx}": [
39
- "yarn eslint"
12
+ "eslint"
40
13
  ],
41
- "**/*.{js,md,less,ts,tsx}": [
14
+ "**/*.{js,md,ts,tsx}": [
42
15
  "prettier --write"
43
16
  ]
44
17
  },
45
- "config": {
46
- "commitizen": {
47
- "path": "cz-conventional-changelog"
48
- }
49
- },
50
- "release": {
51
- "success": false
52
- },
53
18
  "repository": {
54
19
  "type": "git",
55
20
  "url": "https://github.com/seek-oss/playroom.git"
@@ -61,92 +26,106 @@
61
26
  },
62
27
  "homepage": "https://github.com/seek-oss/playroom#readme",
63
28
  "dependencies": {
64
- "@babel/cli": "^7.13.10",
65
- "@babel/core": "^7.13.10",
66
- "@babel/preset-env": "^7.13.10",
67
- "@babel/preset-react": "^7.12.13",
68
- "@babel/preset-typescript": "^7.13.0",
69
- "@babel/standalone": "^7.13.11",
70
- "@soda/friendly-errors-webpack-plugin": "^1.8.0",
29
+ "@babel/cli": "^7.19.3",
30
+ "@babel/core": "^7.20.5",
31
+ "@babel/preset-env": "^7.20.2",
32
+ "@babel/preset-react": "^7.18.6",
33
+ "@babel/preset-typescript": "^7.18.6",
34
+ "@babel/standalone": "^7.20.6",
35
+ "@soda/friendly-errors-webpack-plugin": "^1.8.1",
71
36
  "@types/base64-url": "^2.2.0",
72
- "@types/codemirror": "^0.0.108",
37
+ "@types/codemirror": "^5.60.5",
73
38
  "@types/dedent": "^0.7.0",
74
- "@types/history": "^4.7.8",
75
- "@types/lodash": "^4.14.168",
39
+ "@types/lodash": "^4.14.191",
76
40
  "@types/lz-string": "^1.3.34",
77
- "@types/prettier": "^2.2.3",
78
- "@types/react": "^18.0.9",
79
- "@types/react-dom": "^18.0.4",
80
- "@vanilla-extract/babel-plugin": "^1.1.5",
81
- "@vanilla-extract/css": "^1.7.0",
82
- "@vanilla-extract/css-utils": "^0.1.2",
83
- "@vanilla-extract/sprinkles": "^1.4.0",
84
- "@vanilla-extract/webpack-plugin": "^2.1.8",
85
- "babel-loader": "^8.2.2",
86
- "classnames": "^2.3.1",
87
- "codemirror": "^5.59.4",
88
- "command-line-args": "^5.1.1",
89
- "command-line-usage": "^6.1.1",
90
- "copy-to-clipboard": "^3.3.1",
91
- "css-loader": "^5.1.3",
41
+ "@types/prettier": "^2.7.1",
42
+ "@types/react": "^18.0.26",
43
+ "@types/react-dom": "^18.0.9",
44
+ "@vanilla-extract/css": "^1.9.2",
45
+ "@vanilla-extract/css-utils": "^0.1.3",
46
+ "@vanilla-extract/sprinkles": "^1.5.1",
47
+ "@vanilla-extract/webpack-plugin": "2.1.12",
48
+ "babel-loader": "^9.1.0",
49
+ "classnames": "^2.3.2",
50
+ "codemirror": "^5.65.10",
51
+ "command-line-args": "^5.2.1",
52
+ "command-line-usage": "^6.1.3",
53
+ "copy-to-clipboard": "^3.3.3",
54
+ "css-loader": "^6.7.2",
92
55
  "current-git-branch": "^1.1.0",
93
56
  "dedent": "^0.7.0",
94
- "fast-glob": "^3.2.5",
57
+ "fast-glob": "^3.2.12",
95
58
  "find-up": "^5.0.0",
96
59
  "fuzzy": "^0.1.3",
97
- "history": "^5.0.0",
98
- "html-webpack-plugin": "^5.3.1",
99
- "intersection-observer": "^0.12.0",
100
- "localforage": "^1.9.0",
101
- "locate-path": "^6.0.0",
60
+ "history": "^5.3.0",
61
+ "html-webpack-plugin": "^5.5.0",
62
+ "intersection-observer": "^0.12.2",
63
+ "localforage": "^1.10.0",
102
64
  "lodash": "^4.17.21",
103
65
  "lz-string": "^1.4.4",
104
- "mini-css-extract-plugin": "^2.6.0",
66
+ "mini-css-extract-plugin": "^2.7.2",
105
67
  "parse-prop-types": "^0.3.0",
106
- "polished": "^4.1.4",
107
- "portfinder": "^1.0.28",
108
- "prettier": "^2.2.1",
109
- "prop-types": "^15.7.2",
110
- "query-string": "^6.14.1",
111
- "re-resizable": "^6.9.6",
112
- "react-docgen-typescript": "^2.1.0",
68
+ "polished": "^4.2.2",
69
+ "portfinder": "^1.0.32",
70
+ "prettier": "^2.8.1",
71
+ "prop-types": "^15.8.1",
72
+ "query-string": "^7.1.3",
73
+ "re-resizable": "^6.9.9",
74
+ "react-docgen-typescript": "^2.2.2",
113
75
  "react-use": "^17.4.0",
114
76
  "read-pkg-up": "^7.0.1",
115
77
  "scope-eval": "^1.0.0",
116
- "typescript": "^4.3.2",
117
- "url-join": "^4.0.1",
118
- "use-debounce": "^3.3.0",
119
- "webpack": "^5.26.0",
120
- "webpack-dev-server": "^4.2.0",
121
- "webpack-merge": "^5.7.3"
78
+ "typescript": "^4.5.4",
79
+ "use-debounce": "^9.0.2",
80
+ "webpack": "^5.75.0",
81
+ "webpack-dev-server": "^4.11.1",
82
+ "webpack-merge": "^5.8.0"
122
83
  },
123
84
  "devDependencies": {
124
- "@commitlint/cli": "^12.0.1",
125
- "@octokit/rest": "^18.3.5",
126
- "@types/jest": "^26.0.20",
127
- "commitizen": "^4.2.3",
128
- "commitlint-config-seek": "^1.0.0",
129
- "concurrently": "^6.0.0",
130
- "cypress": "^6.7.1",
131
- "cz-conventional-changelog": "^3.3.0",
132
- "eslint": "^7.22.0",
133
- "eslint-config-seek": "^7.0.8",
134
- "husky": "^4.3.8",
135
- "jest": "^26.6.3",
136
- "lint-staged": "^10.5.4",
85
+ "@changesets/cli": "^2.25.2",
86
+ "@octokit/rest": "^19.0.5",
87
+ "@types/jest": "^29.2.4",
88
+ "concurrently": "^7.6.0",
89
+ "cypress": "^12.0.2",
90
+ "eslint": "^8.29.0",
91
+ "eslint-config-seek": "^10.1.2",
92
+ "husky": "^8.0.2",
93
+ "jest": "^29.3.1",
94
+ "lint-staged": "^13.1.0",
137
95
  "react": "^18.0.1",
138
96
  "react-dom": "^18.0.1",
139
- "semantic-release": "^17.4.2",
140
- "serve": "^11.3.2",
141
- "start-server-and-test": "^1.12.0",
142
- "surge": "^0.22.1"
97
+ "serve": "^14.1.2",
98
+ "start-server-and-test": "^1.15.2",
99
+ "surge": "^0.23.1"
143
100
  },
144
101
  "peerDependencies": {
145
102
  "react": "^16.8 || ^17 || ^18",
146
103
  "react-dom": "^16.8 || ^17 || ^18"
147
104
  },
105
+ "packageManager": "pnpm@7.18.1",
148
106
  "volta": {
149
- "node": "12.22.12",
150
- "yarn": "1.22.19"
107
+ "node": "16.13.0"
108
+ },
109
+ "scripts": {
110
+ "cypress": "start-server-and-test build-and-serve:all '9000|9001' 'cypress run'",
111
+ "cypress:dev": "start-server-and-test start:all '9000|9001' 'cypress open --browser chrome --e2e'",
112
+ "cypress:verify": "cypress verify",
113
+ "start:basic": "./bin/cli.js start --config cypress/projects/basic/playroom.config.js",
114
+ "build:basic": "./bin/cli.js build --config cypress/projects/basic/playroom.config.js",
115
+ "serve:basic": "PORT=9000 serve --no-request-logging cypress/projects/basic/dist",
116
+ "start:themed": "./bin/cli.js start --config cypress/projects/themed/playroom.config.js",
117
+ "build:themed": "./bin/cli.js build --config cypress/projects/themed/playroom.config.js",
118
+ "serve:themed": "PORT=9001 serve --config ../serve.json --no-request-logging cypress/projects/themed/dist",
119
+ "start:all": "concurrently 'npm:start:basic' 'npm:start:themed'",
120
+ "build:all": "concurrently 'npm:build:basic' 'npm:build:themed'",
121
+ "serve:all": "concurrently 'npm:serve:basic' 'npm:serve:themed'",
122
+ "build-and-serve:all": "pnpm build:all && pnpm serve:all",
123
+ "lint": "eslint . && prettier --list-different '**/*.{js,md,ts,tsx}' && tsc --noEmit",
124
+ "format": "prettier --write '**/*.{js,md,ts,tsx}'",
125
+ "version": "changeset version",
126
+ "release": "changeset publish",
127
+ "test": "jest src",
128
+ "post-commit-status": "node scripts/postCommitStatus.js",
129
+ "deploy-preview": "surge -p ./cypress/projects/themed/dist"
151
130
  }
152
- }
131
+ }
@@ -6,7 +6,11 @@ import 'codemirror/theme/neo.css';
6
6
 
7
7
  import { StoreContext, CursorPosition } from '../../StoreContext/StoreContext';
8
8
  import { formatCode as format } from '../../utils/formatting';
9
- import { compileJsx } from '../../utils/compileJsx';
9
+ import {
10
+ closeFragmentTag,
11
+ compileJsx,
12
+ openFragmentTag,
13
+ } from '../../utils/compileJsx';
10
14
 
11
15
  import * as styles from './CodeEditor.css';
12
16
 
@@ -60,21 +64,27 @@ const validateCode = (editorInstance: Editor, code: string) => {
60
64
  try {
61
65
  compileJsx(code);
62
66
  } catch (err) {
63
- const errorMessage = err && (err.message || '');
67
+ const errorMessage = err instanceof Error ? err.message : '';
64
68
  const matches = errorMessage.match(/\(([0-9]+):/);
65
69
  const lineNumber =
66
70
  matches && matches.length >= 2 && matches[1] && parseInt(matches[1], 10);
67
71
 
68
72
  if (lineNumber) {
73
+ // Remove our wrapping Fragment from error message
74
+ const openWrapperStartIndex = errorMessage.indexOf(openFragmentTag);
75
+ const closeWrapperStartIndex = errorMessage.lastIndexOf(closeFragmentTag);
76
+ const formattedMessage = [
77
+ errorMessage.slice(0, openWrapperStartIndex),
78
+ errorMessage.slice(
79
+ openWrapperStartIndex + openFragmentTag.length,
80
+ closeWrapperStartIndex
81
+ ),
82
+ errorMessage.slice(closeWrapperStartIndex + closeFragmentTag.length),
83
+ ].join('');
84
+
69
85
  const marker = document.createElement('div');
70
86
  marker.setAttribute('class', styles.errorMarker);
71
- marker.setAttribute(
72
- 'title',
73
- // Remove our wrapping Fragment from error message
74
- (err.message || '')
75
- .replace(/\<React\.Fragment\>/, '')
76
- .replace(/\<\/React\.Fragment\>$/, '')
77
- );
87
+ marker.setAttribute('title', formattedMessage);
78
88
  marker.innerText = String(lineNumber);
79
89
  editorInstance.setGutterMarker(lineNumber - 1, 'errorGutter', marker);
80
90
  }
@@ -97,11 +107,10 @@ export const CodeEditor = ({ code, onChange, previewCode, hints }: Props) => {
97
107
  const insertionPointRef = useRef<ReturnType<Editor['addLineClass']> | null>(
98
108
  null
99
109
  );
100
- const [{ cursorPosition, highlightLineNumber }, dispatch] = useContext(
101
- StoreContext
102
- );
110
+ const [{ cursorPosition, highlightLineNumber }, dispatch] =
111
+ useContext(StoreContext);
103
112
 
104
- const [debouncedChange] = useDebouncedCallback(
113
+ const debouncedChange = useDebouncedCallback(
105
114
  (newCode: string) => onChange(newCode),
106
115
  100
107
116
  );
@@ -247,7 +256,6 @@ export const CodeEditor = ({ code, onChange, previewCode, hints }: Props) => {
247
256
  autoCloseBrackets: true,
248
257
  theme: 'neo',
249
258
  gutters: ['errorGutter', 'CodeMirror-linenumbers', styles.foldGutter],
250
- // @ts-expect-error
251
259
  hintOptions: { schemaInfo: hints },
252
260
  viewportMargin: 50,
253
261
  lineNumbers: true,
@@ -120,10 +120,11 @@ export const fakeCheckbox = style([
120
120
  background: colorPaletteVars.background.surface,
121
121
  },
122
122
  selectors: {
123
- [`${checkbox}:hover:not(:focus) ~ &::before, ${checkbox}:focus ~ &::before`]: {
124
- opacity: 1,
125
- transform: 'scale(1)',
126
- },
123
+ [`${checkbox}:hover:not(:focus) ~ &::before, ${checkbox}:focus ~ &::before`]:
124
+ {
125
+ opacity: 1,
126
+ transform: 'scale(1)',
127
+ },
127
128
  },
128
129
  },
129
130
  ]);
@@ -77,9 +77,8 @@ function FrameOption<Option>({
77
77
  }
78
78
 
79
79
  export default ({ availableWidths, availableThemes }: FramesPanelProps) => {
80
- const [{ visibleWidths = [], visibleThemes = [] }, dispatch] = useContext(
81
- StoreContext
82
- );
80
+ const [{ visibleWidths = [], visibleThemes = [] }, dispatch] =
81
+ useContext(StoreContext);
83
82
  const hasThemes =
84
83
  availableThemes.filter(
85
84
  (themeName) => themeName !== '__PLAYROOM__NO_THEME__'
@@ -66,7 +66,7 @@ export default ({ components, themes, widths, snippets }: PlayroomProps) => {
66
66
  dispatch,
67
67
  ] = useContext(StoreContext);
68
68
 
69
- const [updateEditorSize] = useDebouncedCallback(
69
+ const updateEditorSize = useDebouncedCallback(
70
70
  ({
71
71
  isVerticalEditor,
72
72
  offsetWidth,
@@ -84,7 +84,7 @@ export default ({ components, themes, widths, snippets }: PlayroomProps) => {
84
84
  1
85
85
  );
86
86
 
87
- const [resetEditorPosition] = useDebouncedCallback(() => {
87
+ const resetEditorPosition = useDebouncedCallback(() => {
88
88
  if (editorPosition === 'undocked') {
89
89
  dispatch({ type: 'resetEditorPosition' });
90
90
  }
@@ -25,23 +25,20 @@ export interface PreviewProps {
25
25
  }>;
26
26
  }
27
27
  export default ({ themes, components, FrameComponent }: PreviewProps) => {
28
- const { themeName, code } = useParams(
29
- (rawParams): PreviewState => {
30
- if (rawParams.code) {
31
- const result = JSON.parse(
32
- lzString.decompressFromEncodedURIComponent(String(rawParams.code)) ??
33
- ''
34
- );
35
-
36
- return {
37
- code: compileJsx(result.code),
38
- themeName: result.theme,
39
- };
40
- }
41
-
42
- return {};
28
+ const { themeName, code } = useParams((rawParams): PreviewState => {
29
+ if (rawParams.code) {
30
+ const result = JSON.parse(
31
+ lzString.decompressFromEncodedURIComponent(String(rawParams.code)) ?? ''
32
+ );
33
+
34
+ return {
35
+ code: compileJsx(result.code),
36
+ themeName: result.theme,
37
+ };
43
38
  }
44
- );
39
+
40
+ return {};
41
+ });
45
42
 
46
43
  const resolvedTheme = themeName ? themes[themeName] : null;
47
44
 
@@ -77,9 +77,8 @@ const scrollToHighlightedSnippet = (
77
77
 
78
78
  export default ({ snippets, onHighlight, onClose }: Props) => {
79
79
  const [searchTerm, setSearchTerm] = useState<string>('');
80
- const [highlightedIndex, setHighlightedIndex] = useState<HighlightIndex>(
81
- null
82
- );
80
+ const [highlightedIndex, setHighlightedIndex] =
81
+ useState<HighlightIndex>(null);
83
82
  const listEl = useRef<HTMLUListElement | null>(null);
84
83
  const highlightedEl = useRef<HTMLLIElement | null>(null);
85
84
  const closeHandler = (returnValue: ReturnedSnippet) => {
@@ -87,7 +86,7 @@ export default ({ snippets, onHighlight, onClose }: Props) => {
87
86
  onClose(returnValue);
88
87
  }
89
88
  };
90
- const [debouncedPreview] = useDebouncedCallback(
89
+ const debouncedPreview = useDebouncedCallback(
91
90
  (previewSnippet: ReturnedSnippet) => {
92
91
  if (typeof onHighlight === 'function') {
93
92
  onHighlight(previewSnippet);
@@ -95,7 +94,7 @@ export default ({ snippets, onHighlight, onClose }: Props) => {
95
94
  },
96
95
  50
97
96
  );
98
- const [debounceScrollToHighlighted] = useDebouncedCallback(
97
+ const debounceScrollToHighlighted = useDebouncedCallback(
99
98
  scrollToHighlightedSnippet,
100
99
  50
101
100
  );
@@ -117,270 +117,276 @@ interface CreateReducerParams {
117
117
  themes: PlayroomProps['themes'];
118
118
  widths: PlayroomProps['widths'];
119
119
  }
120
- const createReducer = ({
121
- themes: configuredThemes,
122
- widths: configuredWidths,
123
- }: CreateReducerParams) => (state: State, action: Action): State => {
124
- switch (action.type) {
125
- case 'initialLoad': {
126
- return {
127
- ...state,
128
- ...action.payload,
129
- };
130
- }
120
+ const createReducer =
121
+ ({
122
+ themes: configuredThemes,
123
+ widths: configuredWidths,
124
+ }: CreateReducerParams) =>
125
+ (state: State, action: Action): State => {
126
+ switch (action.type) {
127
+ case 'initialLoad': {
128
+ return {
129
+ ...state,
130
+ ...action.payload,
131
+ };
132
+ }
131
133
 
132
- case 'updateCode': {
133
- const { code, cursor } = action.payload;
134
- store.setItem('code', code);
134
+ case 'updateCode': {
135
+ const { code, cursor } = action.payload;
136
+ store.setItem('code', code);
135
137
 
136
- return {
137
- ...state,
138
- code,
139
- cursorPosition: cursor || state.cursorPosition,
140
- };
141
- }
138
+ return {
139
+ ...state,
140
+ code,
141
+ cursorPosition: cursor || state.cursorPosition,
142
+ };
143
+ }
142
144
 
143
- case 'dismissMessage': {
144
- return {
145
- ...state,
146
- statusMessage: undefined,
147
- };
148
- }
145
+ case 'dismissMessage': {
146
+ return {
147
+ ...state,
148
+ statusMessage: undefined,
149
+ };
150
+ }
149
151
 
150
- case 'copyToClipboard': {
151
- const { url, trigger } = action.payload;
152
+ case 'copyToClipboard': {
153
+ const { url, trigger } = action.payload;
152
154
 
153
- copy(url);
155
+ copy(url);
154
156
 
155
- return {
156
- ...state,
157
- statusMessage:
158
- trigger === 'toolbarItem'
159
- ? {
160
- message: 'Copied to clipboard',
161
- tone: 'positive',
162
- }
163
- : undefined,
164
- };
165
- }
157
+ return {
158
+ ...state,
159
+ statusMessage:
160
+ trigger === 'toolbarItem'
161
+ ? {
162
+ message: 'Copied to clipboard',
163
+ tone: 'positive',
164
+ }
165
+ : undefined,
166
+ };
167
+ }
166
168
 
167
- case 'persistSnippet': {
168
- const { snippet } = action.payload;
169
- const { activeToolbarPanel, ...currentState } = state;
169
+ case 'persistSnippet': {
170
+ const { snippet } = action.payload;
171
+ const { activeToolbarPanel, ...currentState } = state;
170
172
 
171
- const { code, cursor } = formatAndInsert({
172
- code: state.code,
173
- snippet: snippet.code,
174
- cursor: state.cursorPosition,
175
- });
173
+ const { code, cursor } = formatAndInsert({
174
+ code: state.code,
175
+ snippet: snippet.code,
176
+ cursor: state.cursorPosition,
177
+ });
176
178
 
177
- return {
178
- ...resetPreview(currentState),
179
- code,
180
- cursorPosition: cursor,
181
- };
182
- }
179
+ return {
180
+ ...resetPreview(currentState),
181
+ code,
182
+ cursorPosition: cursor,
183
+ };
184
+ }
183
185
 
184
- case 'updateCursorPosition': {
185
- const { position, code } = action.payload;
186
- const newCode = code && code !== state.code ? code : state.code;
186
+ case 'updateCursorPosition': {
187
+ const { position, code } = action.payload;
188
+ const newCode = code && code !== state.code ? code : state.code;
187
189
 
188
- return {
189
- ...state,
190
- code: newCode,
191
- cursorPosition: position,
192
- statusMessage: undefined,
193
- validCursorPosition: isValidLocation({
190
+ return {
191
+ ...state,
194
192
  code: newCode,
195
- cursor: position,
196
- }),
197
- };
198
- }
199
-
200
- case 'previewSnippet': {
201
- const { snippet } = action.payload;
202
-
203
- const previewRenderCode = snippet
204
- ? formatAndInsert({
205
- code: state.code,
206
- snippet: snippet.code,
207
- cursor: state.cursorPosition,
208
- }).code
209
- : undefined;
193
+ cursorPosition: position,
194
+ statusMessage: undefined,
195
+ validCursorPosition: isValidLocation({
196
+ code: newCode,
197
+ cursor: position,
198
+ }),
199
+ };
200
+ }
210
201
 
211
- return {
212
- ...state,
213
- previewRenderCode,
214
- };
215
- }
202
+ case 'previewSnippet': {
203
+ const { snippet } = action.payload;
216
204
 
217
- case 'toggleToolbar': {
218
- const { panel } = action.payload;
219
- const { activeToolbarPanel: currentPanel, ...currentState } = state;
220
- const shouldOpen = panel !== currentPanel;
205
+ const previewRenderCode = snippet
206
+ ? formatAndInsert({
207
+ code: state.code,
208
+ snippet: snippet.code,
209
+ cursor: state.cursorPosition,
210
+ }).code
211
+ : undefined;
221
212
 
222
- if (shouldOpen) {
223
- if (panel === 'preview' && state.code.trim().length === 0) {
224
- return {
225
- ...state,
226
- statusMessage: {
227
- message: 'Must have code to preview',
228
- tone: 'critical',
229
- },
230
- };
231
- }
213
+ return {
214
+ ...state,
215
+ previewRenderCode,
216
+ };
217
+ }
232
218
 
233
- if (panel === 'snippets') {
234
- const validCursorPosition = isValidLocation({
235
- code: currentState.code,
236
- cursor: currentState.cursorPosition,
237
- });
219
+ case 'toggleToolbar': {
220
+ const { panel } = action.payload;
221
+ const { activeToolbarPanel: currentPanel, ...currentState } = state;
222
+ const shouldOpen = panel !== currentPanel;
238
223
 
239
- if (!validCursorPosition) {
224
+ if (shouldOpen) {
225
+ if (panel === 'preview' && state.code.trim().length === 0) {
240
226
  return {
241
- ...currentState,
227
+ ...state,
242
228
  statusMessage: {
243
- message: "Can't insert snippet at cursor",
229
+ message: 'Must have code to preview',
244
230
  tone: 'critical',
245
231
  },
246
- validCursorPosition,
247
232
  };
248
233
  }
249
234
 
250
- const { code, cursor } = formatForInsertion({
251
- code: currentState.code,
252
- cursor: currentState.cursorPosition,
253
- });
235
+ if (panel === 'snippets') {
236
+ const validCursorPosition = isValidLocation({
237
+ code: currentState.code,
238
+ cursor: currentState.cursorPosition,
239
+ });
240
+
241
+ if (!validCursorPosition) {
242
+ return {
243
+ ...currentState,
244
+ statusMessage: {
245
+ message: "Can't insert snippet at cursor",
246
+ tone: 'critical',
247
+ },
248
+ validCursorPosition,
249
+ };
250
+ }
251
+
252
+ const { code, cursor } = formatForInsertion({
253
+ code: currentState.code,
254
+ cursor: currentState.cursorPosition,
255
+ });
256
+
257
+ return {
258
+ ...currentState,
259
+ statusMessage: undefined,
260
+ activeToolbarPanel: panel,
261
+ previewEditorCode: code,
262
+ highlightLineNumber: cursor.line,
263
+ };
264
+ }
254
265
 
255
266
  return {
256
- ...currentState,
267
+ ...resetPreview(currentState),
257
268
  statusMessage: undefined,
258
269
  activeToolbarPanel: panel,
259
- previewEditorCode: code,
260
- highlightLineNumber: cursor.line,
261
270
  };
262
271
  }
263
272
 
264
- return {
265
- ...resetPreview(currentState),
266
- statusMessage: undefined,
267
- activeToolbarPanel: panel,
268
- };
273
+ return resetPreview(currentState);
269
274
  }
270
275
 
271
- return resetPreview(currentState);
272
- }
276
+ case 'closeToolbar': {
277
+ const { activeToolbarPanel, ...currentState } = state;
273
278
 
274
- case 'closeToolbar': {
275
- const { activeToolbarPanel, ...currentState } = state;
279
+ return resetPreview(currentState);
280
+ }
276
281
 
277
- return resetPreview(currentState);
278
- }
282
+ case 'hideEditor': {
283
+ return {
284
+ ...state,
285
+ activeToolbarPanel: undefined,
286
+ editorHidden: true,
287
+ };
288
+ }
279
289
 
280
- case 'hideEditor': {
281
- return {
282
- ...state,
283
- activeToolbarPanel: undefined,
284
- editorHidden: true,
285
- };
286
- }
290
+ case 'showEditor': {
291
+ return {
292
+ ...state,
293
+ editorHidden: false,
294
+ };
295
+ }
287
296
 
288
- case 'showEditor': {
289
- return {
290
- ...state,
291
- editorHidden: false,
292
- };
293
- }
297
+ case 'updateColorScheme': {
298
+ const { colorScheme } = action.payload;
299
+ store.setItem('colorScheme', colorScheme);
294
300
 
295
- case 'updateColorScheme': {
296
- const { colorScheme } = action.payload;
297
- store.setItem('colorScheme', colorScheme);
301
+ return {
302
+ ...state,
303
+ colorScheme,
304
+ };
305
+ }
298
306
 
299
- return {
300
- ...state,
301
- colorScheme,
302
- };
303
- }
307
+ case 'updateEditorPosition': {
308
+ const { position } = action.payload;
309
+ store.setItem('editorPosition', position);
304
310
 
305
- case 'updateEditorPosition': {
306
- const { position } = action.payload;
307
- store.setItem('editorPosition', position);
311
+ return {
312
+ ...state,
313
+ editorPosition: position,
314
+ };
315
+ }
308
316
 
309
- return {
310
- ...state,
311
- editorPosition: position,
312
- };
313
- }
317
+ case 'resetEditorPosition': {
318
+ store.setItem('editorPosition', defaultPosition);
314
319
 
315
- case 'resetEditorPosition': {
316
- store.setItem('editorPosition', defaultPosition);
320
+ return {
321
+ ...state,
322
+ editorPosition: defaultPosition,
323
+ };
324
+ }
317
325
 
318
- return {
319
- ...state,
320
- editorPosition: defaultPosition,
321
- };
322
- }
326
+ case 'updateEditorHeight': {
327
+ const { size } = action.payload;
328
+ store.setItem('editorHeight', size);
323
329
 
324
- case 'updateEditorHeight': {
325
- const { size } = action.payload;
326
- store.setItem('editorHeight', size);
330
+ return {
331
+ ...state,
332
+ editorHeight: size,
333
+ };
334
+ }
327
335
 
328
- return {
329
- ...state,
330
- editorHeight: size,
331
- };
332
- }
336
+ case 'updateEditorWidth': {
337
+ const { size } = action.payload;
338
+ store.setItem('editorWidth', size);
333
339
 
334
- case 'updateEditorWidth': {
335
- const { size } = action.payload;
336
- store.setItem('editorWidth', size);
340
+ return {
341
+ ...state,
342
+ editorWidth: size,
343
+ };
344
+ }
337
345
 
338
- return {
339
- ...state,
340
- editorWidth: size,
341
- };
342
- }
346
+ case 'updateVisibleThemes': {
347
+ const { themes } = action.payload;
348
+ const visibleThemes = configuredThemes.filter((t) =>
349
+ themes.includes(t)
350
+ );
351
+ store.setItem('visibleThemes', visibleThemes);
343
352
 
344
- case 'updateVisibleThemes': {
345
- const { themes } = action.payload;
346
- const visibleThemes = configuredThemes.filter((t) => themes.includes(t));
347
- store.setItem('visibleThemes', visibleThemes);
353
+ return {
354
+ ...state,
355
+ visibleThemes,
356
+ };
357
+ }
348
358
 
349
- return {
350
- ...state,
351
- visibleThemes,
352
- };
353
- }
359
+ case 'resetVisibleThemes': {
360
+ const { visibleThemes, ...restState } = state;
361
+ store.removeItem('visibleThemes');
354
362
 
355
- case 'resetVisibleThemes': {
356
- const { visibleThemes, ...restState } = state;
357
- store.removeItem('visibleThemes');
363
+ return restState;
364
+ }
358
365
 
359
- return restState;
360
- }
366
+ case 'updateVisibleWidths': {
367
+ const { widths } = action.payload;
368
+ const visibleWidths = configuredWidths.filter((w) =>
369
+ widths.includes(w)
370
+ );
371
+ store.setItem('visibleWidths', visibleWidths);
361
372
 
362
- case 'updateVisibleWidths': {
363
- const { widths } = action.payload;
364
- const visibleWidths = configuredWidths.filter((w) => widths.includes(w));
365
- store.setItem('visibleWidths', visibleWidths);
373
+ return {
374
+ ...state,
375
+ visibleWidths,
376
+ };
377
+ }
366
378
 
367
- return {
368
- ...state,
369
- visibleWidths,
370
- };
371
- }
379
+ case 'resetVisibleWidths': {
380
+ const { visibleWidths, ...restState } = state;
381
+ store.removeItem('visibleWidths');
372
382
 
373
- case 'resetVisibleWidths': {
374
- const { visibleWidths, ...restState } = state;
375
- store.removeItem('visibleWidths');
383
+ return restState;
384
+ }
376
385
 
377
- return restState;
386
+ default:
387
+ return state;
378
388
  }
379
-
380
- default:
381
- return state;
382
- }
383
- };
389
+ };
384
390
 
385
391
  type StoreContextValues = [State, Dispatch<Action>];
386
392
 
@@ -414,7 +420,7 @@ export const StoreProvider = ({
414
420
  createReducer({ themes, widths }),
415
421
  initialState
416
422
  );
417
- const [debouncedCodeUpdate] = useDebouncedCallback(
423
+ const debouncedCodeUpdate = useDebouncedCallback(
418
424
  (params: DebounceUpdateUrl) => {
419
425
  // Ensure that when removing theme/width preferences
420
426
  // they are also removed from the url. Replacing state
@@ -448,22 +454,14 @@ export const StoreProvider = ({
448
454
  widthsFromQuery = parsedWidths;
449
455
  }
450
456
 
451
- Promise.all<
452
- string | null,
453
- EditorPosition | null,
454
- number | null,
455
- number | null,
456
- number[] | null,
457
- string[] | null,
458
- ColorScheme | null
459
- >([
460
- store.getItem('code'),
461
- store.getItem('editorPosition'),
462
- store.getItem('editorHeight'),
463
- store.getItem('editorWidth'),
464
- store.getItem('visibleWidths'),
465
- store.getItem('visibleThemes'),
466
- store.getItem('colorScheme'),
457
+ Promise.all([
458
+ store.getItem<string>('code'),
459
+ store.getItem<EditorPosition>('editorPosition'),
460
+ store.getItem<number>('editorHeight'),
461
+ store.getItem<number>('editorWidth'),
462
+ store.getItem<number[]>('visibleWidths'),
463
+ store.getItem<string[]>('visibleThemes'),
464
+ store.getItem<ColorScheme>('colorScheme'),
467
465
  ]).then(
468
466
  ([
469
467
  storedCode,
@@ -1,7 +1,10 @@
1
1
  import { transform } from '@babel/standalone';
2
2
 
3
+ export const openFragmentTag = '<React.Fragment>';
4
+ export const closeFragmentTag = '</React.Fragment>';
5
+
3
6
  export const compileJsx = (code: string) =>
4
- transform(`<React.Fragment>${code.trim() || ''}</React.Fragment>`, {
7
+ transform(`${openFragmentTag}${code.trim() || ''}${closeFragmentTag}`, {
5
8
  presets: ['react'],
6
9
  }).code;
7
10
 
package/tsconfig.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "noUnusedLocals": true,
9
9
  "strict": true,
10
10
  "jsx": "preserve",
11
- "lib": ["dom", "es2015"],
11
+ "lib": ["dom", "es2019"],
12
12
  "target": "es5"
13
13
  },
14
14
  "include": ["lib", "src", "@types"]
package/cypress.json DELETED
@@ -1,4 +0,0 @@
1
- {
2
- "defaultCommandTimeout": 10000,
3
- "video": false
4
- }