Skip to content

Commit 2d413dd

Browse files
committed
Enable embedded CSS formatting on save
1 parent bcb7399 commit 2d413dd

File tree

7 files changed

+91
-1
lines changed

7 files changed

+91
-1
lines changed

.changeset/ninety-books-itch.md

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
'playroom': minor
3+
---
4+
5+
Enable embedded CSS formatting on save
6+
7+
CSS authored inside `style` tags inside a playroom will now be formatted as CSS when wrapped in a `css` template literal tag. This takes advantage of [prettier's embedded language formatting capabilities].
8+
9+
A `css` template literal tag can be injected into your playroom scope via the [custom scope] feature:
10+
11+
```js
12+
// customScope.js
13+
14+
export default () => {
15+
return {
16+
css: (css) => css,
17+
};
18+
};
19+
```
20+
21+
This template literal tag can then be used in your playroom:
22+
23+
```jsx
24+
<style>
25+
{css`
26+
.foo {
27+
color: red;
28+
}
29+
`}
30+
</style>
31+
```
32+
33+
[custom scope]: https://github.com/seek-oss/playroom?tab=readme-ov-file#custom-scope
34+
[prettier's embedded language formatting capabilities]: https://prettier.io/docs/options#embedded-language-formatting

README.md

+31
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,45 @@ export default function FrameComponent({ theme, children }) {
150150
You can provide extra variables within the scope of your JSX via the `scope` option, which is a path to a file that exports a `useScope` Hook that returns a scope object. For example, if you wanted to expose a context-based `theme` variable to consumers of your Playroom:
151151

152152
```js
153+
// scope.js
154+
153155
import { useTheme } from '../path/to/your/theming-system';
154156

155157
export default function useScope() {
156158
return {
157159
theme: useTheme(),
158160
};
161+
}
162+
```
163+
164+
### Embedded CSS Formatting
165+
166+
By injecting a `css` template literal tag into your playroom scope, embedded CSS can be formatted on save thanks to [prettier's embedded language formatting capabilities]:
167+
168+
```js
169+
// scope.js
170+
171+
export default function useScope() {
172+
return {
173+
css: (css) => css,
174+
};
175+
}
159176
```
160177

178+
The `css` function can then be used as a template literal tag to format CSS authored inside `style` tags:
179+
180+
```jsx
181+
<style>
182+
{css`
183+
.foo {
184+
color: red;
185+
}
186+
`}
187+
</style>
188+
```
189+
190+
[prettier's embedded language formatting capabilities]: https://prettier.io/docs/options#embedded-language-formatting
191+
161192
## Theme Support
162193

163194
If your component library has multiple themes, you can customise Playroom to render every theme simultaneously via the `themes` configuration option.

cypress/e2e/editor.cy.ts

+16
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import dedent from 'dedent';
12
import {
23
formatCode,
34
typeCode,
@@ -32,4 +33,19 @@ describe('Editor', () => {
3233
formatCode();
3334
assertCodePaneLineCount(6);
3435
});
36+
37+
it.only('formats css in a style block', () => {
38+
typeCode(
39+
'<style>{{}css`html {{} border: 1px solid red; {}}`{rightarrow}{backspace}{}}'
40+
);
41+
assertCodePaneLineCount(1);
42+
formatCode();
43+
assertCodePaneContains(dedent`
44+
<style>{css\`
45+
html {
46+
border: 1px solid red;
47+
}
48+
\`}</style>\n
49+
`);
50+
});
3551
});

cypress/projects/basic/useScope.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
export default () => ({
22
hello: () => 'HELLO',
33
world: () => 'WORLD',
4+
// Identity function for formatting CSS
5+
css: (s) => s,
46
});

cypress/projects/themed/playroom.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module.exports = {
22
components: './components',
33
snippets: './snippets',
44
themes: './themes',
5+
scope: './scope',
56
outputPath: './dist',
67
openBrowser: false,
78
paramType: 'search',

cypress/projects/themed/scope.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default () => {
2+
return {
3+
css: (css) => css,
4+
};
5+
};

src/utils/formatting.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import prettier from 'prettier/standalone';
22
import babel from 'prettier/parser-babel';
3+
import postcss from 'prettier/parser-postcss';
34
import type { CursorPosition } from '../StoreContext/StoreContext';
45
import { insertAtCursor } from './cursor';
56

@@ -21,7 +22,7 @@ export const runPrettier = ({
2122
return prettier.formatWithCursor(code, {
2223
cursorOffset,
2324
parser: 'babel',
24-
plugins: [babel],
25+
plugins: [babel, postcss],
2526
});
2627
} catch (e) {
2728
// Just a formatting error so we pass

0 commit comments

Comments
 (0)