Skip to content

Commit

Permalink
feat: Add initial TypeScript autocomplete support (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
markdalgleish committed Dec 18, 2018
1 parent 659d88a commit 39046d7
Show file tree
Hide file tree
Showing 20 changed files with 1,442 additions and 33 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
@@ -1,7 +1,8 @@
{
"extends": "seek",
"globals": {
"__PLAYROOM_GLOBAL__CONFIG__": true
"__PLAYROOM_GLOBAL__CONFIG__": true,
"__PLAYROOM_GLOBAL__STATIC_TYPES__": true
},
"rules": {
"no-console": 0,
Expand Down
60 changes: 43 additions & 17 deletions README.md
Expand Up @@ -23,7 +23,7 @@ Playroom allows you to create a zero-install code-oriented design environment, b

Send us a PR if you'd like to be in this list!

## Setup
## Getting Started

```bash
$ npm install --save-dev playroom
Expand Down Expand Up @@ -63,7 +63,7 @@ module.exports = {
};
```

Your `components` and `themes` files are expected to export a single object or a series of named exports. For example, your components file might look like this:
Your `components` file is expected to export a single object or a series of named exports. For example:

```js
module.exports = {
Expand All @@ -73,17 +73,21 @@ module.exports = {
};
```

When providing themes, your themes file might look something like this:
Now that your project is configured, you can start a local development server:

```js
module.exports = {
themeA: require('./themeA'),
themeB: require('./themeB')
// etc...
};
```bash
$ npm run playroom:start
```

To build your assets for production:

```bash
$ npm run playroom:build
```

If your components need to be nested within custom provider components, you can provide a custom React component file via the `frameComponent` option, which is a path to a file that might look something like this:
## Custom Frame Component

If your components need to be nested within custom provider components, you can provide a custom React component file via the `frameComponent` option, which is a path to a file that exports a component. For example, if your component library has multiple themes:

```js
import React from 'react';
Expand All @@ -94,6 +98,22 @@ export default ({ theme, children }) => (
);
```

## Theme Support

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

Similar to your `components` file, your `themes` file is expected to export a single object or a series of named exports. For example:

```js
module.exports = {
themeA: require('./themeA'),
themeB: require('./themeB')
// etc...
};
```

## CSS-in-JS Support

If you're using a CSS-in-JS library that generates styles dynamically, you might need to configure it to insert them into the iframe. For example, when using [styled-components](https://www.styled-components.com):

```js
Expand All @@ -108,16 +128,22 @@ export default ({ theme, children, frameWindow }) => (
);
```

Now that your project is configured, you can start a local development server:
## TypeScript Support

```bash
$ npm run playroom:start
```
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.

To build your assets for production:
**By default, all `.ts` and `.tsx` files in the current working directory are included, excluding `node_modules`.**

```bash
$ npm run playroom:build
If you need to customise this behaviour, you can provide a `typeScriptFiles` option in `playroom.config.js`, which is an array of globs.

```js
module.exports = {
...,
typeScriptFiles: [
'src/components/**/*.{ts,tsx}',
'!**/node_modules'
]
};
```

## License
Expand Down
12 changes: 11 additions & 1 deletion cypress/integration/smokeTest.spec.js
@@ -1,4 +1,8 @@
import { typeCode, assertFrameContains } from '../support/utils';
import {
typeCode,
assertFrameContains,
assertTextareaContains
} from '../support/utils';

describe('Smoke test', () => {
it('works', () => {
Expand All @@ -8,4 +12,10 @@ describe('Smoke test', () => {
typeCode('<Bar />');
assertFrameContains('Bar');
});

it('autocompletes', () => {
typeCode('<F{enter} c{enter}={downarrow}{enter} />');
assertFrameContains('Foo');
assertTextareaContains('<Foo color="blue" />');
});
});
18 changes: 16 additions & 2 deletions cypress/projects/basic/components.js
@@ -1,4 +1,18 @@
import React from 'react';
import PropTypes from 'prop-types';

export const Foo = () => <div>Foo</div>;
export const Bar = () => <div>Bar</div>;
const withPropTypes = component => {
component.propTypes = {
color: PropTypes.oneOf(['red', 'blue'])
};

return component;
};

export const Foo = withPropTypes(({ color }) => (
<div style={{ color }}>Foo</div>
));

export const Bar = withPropTypes(({ color }) => (
<div style={{ color }}>Bar</div>
));
9 changes: 8 additions & 1 deletion cypress/support/utils.js
Expand Up @@ -4,7 +4,7 @@ export const typeCode = code =>
.click()
.focused()
.clear({ force: true })
.type(code, { force: true });
.type(code, { force: true, delay: 100 });

export const assertFrameContains = async text => {
const iframe = await cy.get('iframe').first();
Expand All @@ -14,3 +14,10 @@ export const assertFrameContains = async text => {
.find('body')
.contains(text);
};

export const assertTextareaContains = async text => {
return cy
.get('textarea')
.first()
.contains(text);
};
13 changes: 13 additions & 0 deletions examples/typescript/components/Bar/Bar.tsx
@@ -0,0 +1,13 @@
import React, { Component } from 'react';

interface Props {
color: 'red' | 'blue';
}

export default class Bar extends Component<Props> {
render() {
const { color } = this.props;

return <div style={{ color }}>Bar</div>;
}
}
13 changes: 13 additions & 0 deletions examples/typescript/components/Foo/Foo.tsx
@@ -0,0 +1,13 @@
import React, { Component } from 'react';

interface Props {
color: 'red' | 'blue';
}

export default class Foo extends Component<Props> {
render() {
const { color } = this.props;

return <div style={{ color }}>Foo</div>;
}
}
2 changes: 2 additions & 0 deletions examples/typescript/components/index.ts
@@ -0,0 +1,2 @@
export { default as Foo } from './Foo/Foo';
export { default as Bar } from './Bar/Bar';
22 changes: 22 additions & 0 deletions examples/typescript/package.json
@@ -0,0 +1,22 @@
{
"name": "typescript-playroom-example",
"private": true,
"version": "0.0.0",
"description": "TypeScript example for Braid Design System",
"scripts": {
"build": "node ./../../bin/cli build",
"start": "node ./../../bin/cli start"
},
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.2.0",
"@babel/preset-env": "^7.2.0",
"@babel/preset-react": "^7.0.0",
"@babel/preset-typescript": "^7.1.0",
"@types/react": "^16.7.13",
"babel-loader": "^8.0.4"
},
"dependencies": {
"react": "^16.6.3"
}
}
27 changes: 27 additions & 0 deletions examples/typescript/playroom.config.js
@@ -0,0 +1,27 @@
module.exports = {
components: './components/index.ts',
outputPath: './dist',
webpackConfig: () => ({
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-typescript',
'@babel/preset-react'
]
}
}
}
]
},
resolve: {
extensions: ['.js', '.ts', '.tsx']
}
})
};
14 changes: 14 additions & 0 deletions examples/typescript/tsconfig.json
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"jsx": "preserve"
},
"include": [
"components/**/*"
],
"exclude": [
"node_modules"
]
}

0 comments on commit 39046d7

Please sign in to comment.