playroom 0.34.2 → 0.36.0
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/.github/workflows/preview-site.yml +3 -3
- package/.github/workflows/release.yml +3 -3
- package/.github/workflows/snapshot.yml +3 -3
- package/.github/workflows/validate.yml +5 -5
- package/.nvmrc +1 -1
- package/CHANGELOG.md +55 -0
- package/README.md +6 -0
- package/bin/cli.cjs +2 -1
- package/cypress/e2e/editor.cy.js +1 -1
- package/cypress/e2e/keymaps.cy.js +1507 -11
- package/cypress/e2e/scope.cy.js +1 -1
- package/cypress/e2e/smoke.cy.js +2 -2
- package/cypress/e2e/toolbar.cy.js +1 -2
- package/cypress/e2e/urlHandling.cy.js +4 -5
- package/cypress/support/utils.js +62 -54
- package/lib/makeWebpackConfig.js +0 -3
- package/lib/provideDefaultConfig.js +13 -2
- package/package.json +18 -17
- package/src/Playroom/CatchErrors/CatchErrors.tsx +5 -6
- package/src/Playroom/CodeEditor/CodeEditor.tsx +11 -0
- package/src/Playroom/CodeEditor/keymaps/comment.ts +326 -0
- package/src/Playroom/CodeEditor/keymaps/wrap.ts +4 -1
- package/src/Playroom/Frame.tsx +9 -5
- package/src/Playroom/FramesPanel/FramesPanel.css.ts +19 -0
- package/src/Playroom/FramesPanel/FramesPanel.tsx +89 -46
- package/src/Playroom/Preview.tsx +12 -3
- package/src/Playroom/PreviewPanel/PreviewPanel.tsx +1 -1
- package/src/Playroom/SettingsPanel/SettingsPanel.tsx +11 -7
- package/src/Playroom/Stack/Stack.css.ts +4 -35
- package/src/Playroom/Stack/Stack.tsx +2 -9
- package/src/Playroom/Toolbar/Toolbar.tsx +2 -2
- package/src/Playroom/sprinkles.css.ts +1 -0
- package/src/StoreContext/StoreContext.tsx +31 -6
- package/src/index.d.ts +2 -0
- package/src/utils/params.ts +5 -8
- package/src/utils/usePreviewUrl.ts +2 -1
- package/utils/index.d.ts +3 -0
- package/utils/index.js +21 -7
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { style, createVar } from '@vanilla-extract/css';
|
|
1
|
+
import { style, createVar, styleVariants } from '@vanilla-extract/css';
|
|
3
2
|
import { vars } from '../sprinkles.css';
|
|
4
3
|
|
|
5
4
|
const size = createVar();
|
|
@@ -12,38 +11,8 @@ export const gap = style({
|
|
|
12
11
|
},
|
|
13
12
|
});
|
|
14
13
|
|
|
15
|
-
export const
|
|
14
|
+
export const spaceScale = styleVariants(vars.space, (space) => ({
|
|
16
15
|
vars: {
|
|
17
|
-
[size]:
|
|
16
|
+
[size]: space,
|
|
18
17
|
},
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
export const xsmall = style({
|
|
22
|
-
vars: {
|
|
23
|
-
[size]: calc(vars.grid).multiply(2).toString(),
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
export const small = style({
|
|
28
|
-
vars: {
|
|
29
|
-
[size]: calc(vars.grid).multiply(3).toString(),
|
|
30
|
-
},
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
export const medium = style({
|
|
34
|
-
vars: {
|
|
35
|
-
[size]: calc(vars.grid).multiply(4).toString(),
|
|
36
|
-
},
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
export const large = style({
|
|
40
|
-
vars: {
|
|
41
|
-
[size]: calc(vars.grid).multiply(6).toString(),
|
|
42
|
-
},
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
export const xlarge = style({
|
|
46
|
-
vars: {
|
|
47
|
-
[size]: calc(vars.grid).multiply(12).toString(),
|
|
48
|
-
},
|
|
49
|
-
});
|
|
18
|
+
}));
|
|
@@ -15,14 +15,7 @@ type ReactNodeNoStrings =
|
|
|
15
15
|
|
|
16
16
|
interface Props {
|
|
17
17
|
children: ReactNodeNoStrings;
|
|
18
|
-
space:
|
|
19
|
-
| 'none'
|
|
20
|
-
| 'xxsmall'
|
|
21
|
-
| 'xsmall'
|
|
22
|
-
| 'small'
|
|
23
|
-
| 'medium'
|
|
24
|
-
| 'large'
|
|
25
|
-
| 'xlarge';
|
|
18
|
+
space: keyof typeof styles.spaceScale;
|
|
26
19
|
dividers?: boolean;
|
|
27
20
|
}
|
|
28
21
|
|
|
@@ -31,7 +24,7 @@ export const Stack = ({ children, space, dividers = false }: Props) => (
|
|
|
31
24
|
{Children.toArray(children).map((item, index) => (
|
|
32
25
|
<div
|
|
33
26
|
key={index}
|
|
34
|
-
className={classnames(styles.gap,
|
|
27
|
+
className={classnames(styles.gap, styles.spaceScale[space])}
|
|
35
28
|
>
|
|
36
29
|
{dividers && index > 0 ? (
|
|
37
30
|
<div className={styles.gap}>
|
|
@@ -81,7 +81,7 @@ export default ({ themes: allThemes, widths: allWidths, snippets }: Props) => {
|
|
|
81
81
|
{hasSnippets && (
|
|
82
82
|
<ToolbarItem
|
|
83
83
|
active={isSnippetsOpen}
|
|
84
|
-
title={`Insert snippet (${isMac() ? '
|
|
84
|
+
title={`Insert snippet (${isMac() ? '⌘K' : 'Ctrl+K'})`}
|
|
85
85
|
disabled={!validCursorPosition}
|
|
86
86
|
data-testid="toggleSnippets"
|
|
87
87
|
onClick={() => {
|
|
@@ -127,7 +127,7 @@ export default ({ themes: allThemes, widths: allWidths, snippets }: Props) => {
|
|
|
127
127
|
|
|
128
128
|
<div>
|
|
129
129
|
<ToolbarItem
|
|
130
|
-
title=
|
|
130
|
+
title={`Copy Playroom link (${isMac() ? '⌘⇧C' : 'Ctrl+Shift+C'})`}
|
|
131
131
|
success={copying}
|
|
132
132
|
onClick={copyHandler}
|
|
133
133
|
data-testid="copyToClipboard"
|
|
@@ -40,6 +40,7 @@ interface DebounceUpdateUrl {
|
|
|
40
40
|
code?: string;
|
|
41
41
|
themes?: string[];
|
|
42
42
|
widths?: number[];
|
|
43
|
+
title?: string;
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
export interface CursorPosition {
|
|
@@ -55,6 +56,7 @@ interface StatusMessage {
|
|
|
55
56
|
type ToolbarPanel = 'snippets' | 'frames' | 'preview' | 'settings';
|
|
56
57
|
interface State {
|
|
57
58
|
code: string;
|
|
59
|
+
title?: string;
|
|
58
60
|
previewRenderCode?: string;
|
|
59
61
|
previewEditorCode?: string;
|
|
60
62
|
highlightLineNumber?: number;
|
|
@@ -104,7 +106,8 @@ type Action =
|
|
|
104
106
|
| { type: 'updateVisibleThemes'; payload: { themes: string[] } }
|
|
105
107
|
| { type: 'resetVisibleThemes' }
|
|
106
108
|
| { type: 'updateVisibleWidths'; payload: { widths: number[] } }
|
|
107
|
-
| { type: 'resetVisibleWidths' }
|
|
109
|
+
| { type: 'resetVisibleWidths' }
|
|
110
|
+
| { type: 'updateTitle'; payload: { title: string } };
|
|
108
111
|
|
|
109
112
|
const resetPreview = ({
|
|
110
113
|
previewRenderCode,
|
|
@@ -159,7 +162,7 @@ const createReducer =
|
|
|
159
162
|
statusMessage:
|
|
160
163
|
trigger === 'toolbarItem'
|
|
161
164
|
? {
|
|
162
|
-
message: 'Copied to clipboard',
|
|
165
|
+
message: 'Copied Playroom link to clipboard',
|
|
163
166
|
tone: 'positive',
|
|
164
167
|
}
|
|
165
168
|
: undefined,
|
|
@@ -383,6 +386,15 @@ const createReducer =
|
|
|
383
386
|
return restState;
|
|
384
387
|
}
|
|
385
388
|
|
|
389
|
+
case 'updateTitle': {
|
|
390
|
+
const { title } = action.payload;
|
|
391
|
+
|
|
392
|
+
return {
|
|
393
|
+
...state,
|
|
394
|
+
title,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
|
|
386
398
|
default:
|
|
387
399
|
return state;
|
|
388
400
|
}
|
|
@@ -439,19 +451,23 @@ export const StoreProvider = ({
|
|
|
439
451
|
let codeFromQuery: State['code'];
|
|
440
452
|
let themesFromQuery: State['visibleThemes'];
|
|
441
453
|
let widthsFromQuery: State['visibleWidths'];
|
|
454
|
+
let titleFromQuery: State['title'];
|
|
442
455
|
|
|
443
|
-
|
|
456
|
+
const paramsCode = params.get('code');
|
|
457
|
+
if (paramsCode) {
|
|
444
458
|
const {
|
|
445
459
|
code: parsedCode,
|
|
446
460
|
themes: parsedThemes,
|
|
447
461
|
widths: parsedWidths,
|
|
462
|
+
title: parsedTitle,
|
|
448
463
|
} = JSON.parse(
|
|
449
|
-
lzString.decompressFromEncodedURIComponent(String(
|
|
464
|
+
lzString.decompressFromEncodedURIComponent(String(paramsCode)) ?? ''
|
|
450
465
|
);
|
|
451
466
|
|
|
452
467
|
codeFromQuery = parsedCode;
|
|
453
468
|
themesFromQuery = parsedThemes;
|
|
454
469
|
widthsFromQuery = parsedWidths;
|
|
470
|
+
titleFromQuery = parsedTitle;
|
|
455
471
|
}
|
|
456
472
|
|
|
457
473
|
Promise.all([
|
|
@@ -476,9 +492,15 @@ export const StoreProvider = ({
|
|
|
476
492
|
const editorPosition = storedPosition;
|
|
477
493
|
const editorHeight = storedHeight;
|
|
478
494
|
const editorWidth = storedWidth;
|
|
479
|
-
const visibleWidths =
|
|
495
|
+
const visibleWidths =
|
|
496
|
+
widthsFromQuery ||
|
|
497
|
+
storedVisibleWidths ||
|
|
498
|
+
playroomConfig?.defaultVisibleWidths;
|
|
480
499
|
const visibleThemes =
|
|
481
|
-
hasThemesConfigured &&
|
|
500
|
+
hasThemesConfigured &&
|
|
501
|
+
(themesFromQuery ||
|
|
502
|
+
storedVisibleThemes ||
|
|
503
|
+
playroomConfig?.defaultVisibleThemes);
|
|
482
504
|
const colorScheme = storedColorScheme;
|
|
483
505
|
|
|
484
506
|
dispatch({
|
|
@@ -491,6 +513,7 @@ export const StoreProvider = ({
|
|
|
491
513
|
...(visibleThemes ? { visibleThemes } : {}),
|
|
492
514
|
...(visibleWidths ? { visibleWidths } : {}),
|
|
493
515
|
...(colorScheme ? { colorScheme } : {}),
|
|
516
|
+
title: titleFromQuery,
|
|
494
517
|
ready: true,
|
|
495
518
|
},
|
|
496
519
|
});
|
|
@@ -521,11 +544,13 @@ export const StoreProvider = ({
|
|
|
521
544
|
code: state.code,
|
|
522
545
|
themes: state.visibleThemes,
|
|
523
546
|
widths: state.visibleWidths,
|
|
547
|
+
title: state.title,
|
|
524
548
|
});
|
|
525
549
|
}, [
|
|
526
550
|
state.code,
|
|
527
551
|
state.visibleThemes,
|
|
528
552
|
state.visibleWidths,
|
|
553
|
+
state.title,
|
|
529
554
|
debouncedCodeUpdate,
|
|
530
555
|
]);
|
|
531
556
|
|
package/src/index.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ interface PlayroomConfig {
|
|
|
15
15
|
iframeSandbox?: string;
|
|
16
16
|
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
|
17
17
|
reactDocgenTypescriptConfig?: import('react-docgen-typescript').ParserOptions;
|
|
18
|
+
defaultVisibleThemes?: string[];
|
|
19
|
+
defaultVisibleWidths?: number[];
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
interface InternalPlayroomConfig extends PlayroomConfig {
|
package/src/utils/params.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createBrowserHistory } from 'history';
|
|
2
2
|
import { useState, useEffect } from 'react';
|
|
3
|
-
import queryString, { type ParsedQuery } from 'query-string';
|
|
4
3
|
|
|
5
4
|
import playroomConfig from '../config';
|
|
6
5
|
|
|
@@ -11,10 +10,8 @@ export function updateUrlCode(code: string) {
|
|
|
11
10
|
|
|
12
11
|
const existingQuery = getParamsFromQuery();
|
|
13
12
|
|
|
14
|
-
const newQuery =
|
|
15
|
-
|
|
16
|
-
code,
|
|
17
|
-
});
|
|
13
|
+
const newQuery = new URLSearchParams(existingQuery);
|
|
14
|
+
newQuery.set('code', code);
|
|
18
15
|
|
|
19
16
|
const params =
|
|
20
17
|
playroomConfig.paramType === 'hash' ? `#?${newQuery}` : `?${newQuery}`;
|
|
@@ -24,18 +21,18 @@ export function updateUrlCode(code: string) {
|
|
|
24
21
|
|
|
25
22
|
export function getParamsFromQuery(location = history.location) {
|
|
26
23
|
try {
|
|
27
|
-
return
|
|
24
|
+
return new URLSearchParams(
|
|
28
25
|
playroomConfig.paramType === 'hash'
|
|
29
26
|
? location.hash.replace(/^#/, '')
|
|
30
27
|
: location.search
|
|
31
28
|
);
|
|
32
29
|
} catch (err) {
|
|
33
|
-
return
|
|
30
|
+
return new URLSearchParams();
|
|
34
31
|
}
|
|
35
32
|
}
|
|
36
33
|
|
|
37
34
|
export function useParams<ReturnType>(
|
|
38
|
-
selector: (rawParams:
|
|
35
|
+
selector: (rawParams: URLSearchParams) => ReturnType
|
|
39
36
|
): ReturnType {
|
|
40
37
|
const [params, setParams] = useState(getParamsFromQuery);
|
|
41
38
|
|
|
@@ -9,7 +9,7 @@ const baseUrl = window.location.href
|
|
|
9
9
|
.split('index.html')[0];
|
|
10
10
|
|
|
11
11
|
export default (theme: string) => {
|
|
12
|
-
const [{ code }] = useContext(StoreContext);
|
|
12
|
+
const [{ code, title }] = useContext(StoreContext);
|
|
13
13
|
|
|
14
14
|
const isThemed = theme !== '__PLAYROOM__NO_THEME__';
|
|
15
15
|
|
|
@@ -18,5 +18,6 @@ export default (theme: string) => {
|
|
|
18
18
|
code,
|
|
19
19
|
theme: isThemed ? theme : undefined,
|
|
20
20
|
paramType: playroomConfig.paramType,
|
|
21
|
+
title,
|
|
21
22
|
});
|
|
22
23
|
};
|
package/utils/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ interface CompressParamsOptions {
|
|
|
13
13
|
themes?: string[];
|
|
14
14
|
widths?: number[];
|
|
15
15
|
theme?: string;
|
|
16
|
+
title?: string;
|
|
16
17
|
}
|
|
17
18
|
export const compressParams: (options: CompressParamsOptions) => string;
|
|
18
19
|
|
|
@@ -22,6 +23,7 @@ interface CreateUrlOptions {
|
|
|
22
23
|
themes?: string[];
|
|
23
24
|
widths?: number[];
|
|
24
25
|
paramType?: ParamType;
|
|
26
|
+
title?: string;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
export const createUrl: (options: CreateUrlOptions) => string;
|
|
@@ -31,6 +33,7 @@ interface CreatePreviewUrlOptions {
|
|
|
31
33
|
code?: string;
|
|
32
34
|
theme?: string;
|
|
33
35
|
paramType?: ParamType;
|
|
36
|
+
title?: string;
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
export const createPreviewUrl: (options: CreatePreviewUrlOptions) => string;
|
package/utils/index.js
CHANGED
|
@@ -1,21 +1,29 @@
|
|
|
1
1
|
const lzString = require('lz-string');
|
|
2
2
|
|
|
3
|
-
const compressParams = ({ code, themes, widths, theme }) => {
|
|
3
|
+
const compressParams = ({ code, themes, widths, theme, title }) => {
|
|
4
4
|
const data = JSON.stringify({
|
|
5
5
|
...(code ? { code } : {}),
|
|
6
6
|
...(themes ? { themes } : {}),
|
|
7
7
|
...(widths ? { widths } : {}),
|
|
8
8
|
...(theme ? { theme } : {}),
|
|
9
|
+
...(title ? { title } : {}),
|
|
9
10
|
});
|
|
10
11
|
|
|
11
12
|
return lzString.compressToEncodedURIComponent(data);
|
|
12
13
|
};
|
|
13
14
|
|
|
14
|
-
const createUrl = ({
|
|
15
|
+
const createUrl = ({
|
|
16
|
+
baseUrl,
|
|
17
|
+
code,
|
|
18
|
+
themes,
|
|
19
|
+
widths,
|
|
20
|
+
title,
|
|
21
|
+
paramType = 'hash',
|
|
22
|
+
}) => {
|
|
15
23
|
let path = '';
|
|
16
24
|
|
|
17
|
-
if (code || themes || widths) {
|
|
18
|
-
const compressedData = compressParams({ code, themes, widths });
|
|
25
|
+
if (code || themes || widths || title) {
|
|
26
|
+
const compressedData = compressParams({ code, themes, widths, title });
|
|
19
27
|
|
|
20
28
|
path = `${paramType === 'hash' ? '#' : ''}?code=${compressedData}`;
|
|
21
29
|
}
|
|
@@ -29,11 +37,17 @@ const createUrl = ({ baseUrl, code, themes, widths, paramType = 'hash' }) => {
|
|
|
29
37
|
return path;
|
|
30
38
|
};
|
|
31
39
|
|
|
32
|
-
const createPreviewUrl = ({
|
|
40
|
+
const createPreviewUrl = ({
|
|
41
|
+
baseUrl,
|
|
42
|
+
code,
|
|
43
|
+
theme,
|
|
44
|
+
title,
|
|
45
|
+
paramType = 'hash',
|
|
46
|
+
}) => {
|
|
33
47
|
let path = '';
|
|
34
48
|
|
|
35
|
-
if (code || theme) {
|
|
36
|
-
const compressedData = compressParams({ code, theme });
|
|
49
|
+
if (code || theme || title) {
|
|
50
|
+
const compressedData = compressParams({ code, theme, title });
|
|
37
51
|
|
|
38
52
|
path = `/preview/${paramType === 'hash' ? '#' : ''}?code=${compressedData}`;
|
|
39
53
|
}
|