Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Props auto complete does not support function component #139

Closed
PinkyJie opened this issue Mar 26, 2020 · 10 comments
Closed

Props auto complete does not support function component #139

PinkyJie opened this issue Mar 26, 2020 · 10 comments

Comments

@PinkyJie
Copy link

PinkyJie commented Mar 26, 2020

Thanks for this great project!

I'm trying to apply playroom our own component library which is fully written in Typescript. Just notice that for Class component the props auto complete(popup in editor) works very well, but for functional component, it can render the component in UI, but no props popup.

I assume playroom use react-docgen-typescript to extract props definition from typescript files, I found an example in react-docgen-typescript's Readme file:

import * as React from 'react';

/**
 * Grid properties.
 */
export interface GridProps {
    /** prop1 description */
    prop1?: string;
    /** prop2 description */
    prop2: number;
    /**
     * prop3 description
     */
    prop3: () => void;
    /** Working grid description */
    prop4: 'option1' | 'option2' | 'option3';
}

/**
 * Form Grid.
 */
export const Grid = (props: GridProps) => {
    return <div>Grid</div>;
};

There is no props popup for this component in UI.

@adrienharnay
Copy link
Contributor

I second this, and since the last update auto-complete doesn't work anymore (works for component name but not prop name or prop value).

I use this patch that partially works (works for component name and prop name but not prop value):

diff --git a/node_modules/playroom/lib/getStaticTypes.js b/node_modules/playroom/lib/getStaticTypes.js
index 2ec7f03..9f436c0 100644
--- a/node_modules/playroom/lib/getStaticTypes.js
+++ b/node_modules/playroom/lib/getStaticTypes.js
@@ -5,14 +5,17 @@ const mapValues = require('lodash/mapValues');
 const omit = require('lodash/omit');
 
 const stringRegex = /^"(.*)"$/;
-const parsePropTypeName = (propTypeName) => {
-  return propTypeName
-    .split(' | ')
+const parsePropTypeName = (propType) => {
+  const propValues = propType.name === 'enum' ?
+    propType.value.map(value => value.value) :
+    propType.name.replace(/ \| \[[^\]]*\]/g, '').split(' | ');
+
+  return propValues
     .filter((x) => stringRegex.test(x))
     .map((x) => x.replace(stringRegex, '$1'));
 };
 
-const filterProps = (props) => omit(props, 'className', 'children');
+const filterProps = (props) => omit(props, 'className', 'style', 'children', 'ref');
 
 module.exports = async (playroomConfig) => {
   const {
@@ -28,14 +31,31 @@ module.exports = async (playroomConfig) => {
 
   try {
     const { parse } = require('react-docgen-typescript').withCustomConfig(
-      tsConfigPath
+      tsConfigPath,
+      {
+        shouldExtractLiteralValuesFromEnum: true,
+      }
     );
     const files = await fastGlob(typeScriptFiles, { cwd, absolute: true });
     const types = parse(files);
     const typesByDisplayName = keyBy(types, 'displayName');
     const parsedTypes = mapValues(typesByDisplayName, (component) =>
       mapValues(filterProps(component.props || {}), (prop) =>
-        parsePropTypeName(prop.type.name)
+        parsePropTypeName(prop.type)
       )
     );
 

I would love to find a solution that works for both class components and function components. @markdalgleish do you confirm you are using class components? Or is the problem somewhere else? With a little insight I would be glad to submit a PR

@michaeltaranto
Copy link
Contributor

All the components in braid are written in typescript and are functions not classes. So this would need some further investigation.

Haven't looked into this issue specifically though.

@maraisr
Copy link
Contributor

maraisr commented May 15, 2020

I know for us we annotate all our FunctionComponents as FunctionComponent<Props>:

eg:

interface GridProps {
	...
}

const Grid: FunctionComponent<GridProps> = (props) => <div>Grid</div>;

class GridClass extends PureComponent<any, GridProps> {
	render() {
		return <div>Grid</div>;
	}
}

both of these work fine for us.

@adrienharnay
Copy link
Contributor

Strange, that is what we're doing as well. I've tried both with and without the patch on 0.18.1. To be accurate, this is exactly what we're doing:

types.ts

interface GridProps {
  ...
}

Grid.tsx

import { GridProps } from './types'; 

const Grid: FunctionComponent<GridProps> = (props) => <div>Grid</div>;

@possibilities
Copy link

I have this same problem but wanted to add another counter-example. The material ui example in this repo (or just add @material-ui/core to your own playroom) work fine in playroom and they're also written as functional components. It's mystery to me why some libraries work and others don't.

/~https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/Avatar/Avatar.d.ts

Thanks to others who are looking into this. I'm going to dig as deep as I can and get back here if I come up with anything.

@possibilities
Copy link

possibilities commented May 31, 2020

Ah, OK, I see now that I look at some other open issues that maybe it's not a good counterexample because I think the reason it works is that @material-ui also defined proptypes.

I realized this because here it's suggested that using a babel plugin that generates proptypes from TS types is a possible workaround: #70

No proptypes in braid but I wonder if there isn't something underlying (in sku?) that is generating proptypes allowing it all to work?

See also:

@possibilities
Copy link

possibilities commented May 31, 2020

OK, I teased apart my own issue at least so posting back. Hopefully not too tangential/noisy from the OP.

When I publish my component library and deploy it's accompanying docs website I also build a copy of playroom, etc. This works fine. All my props are autocompleted, both keys and values. All of my components export an interface... causing this to all work out-of-the box.

The problem I'm having is that I have another instance of playroom where I import components from 3rd party libraries as well as my own component library. Here autocompletion doesn't work. This is all explained by the fact that react-docgen-typescript doesn't support reading types from d.ts files. My component library exports types from the component tsx files but when I build it those are transpiled away and d.ts files are created (new to TS but assume this is typical).

I think it'd be best if playroom config took an option e.g. staticTypes that it would use if present rather than calling lib/getStaticTypes (see /~https://github.com/seek-oss/playroom/blob/master/lib/getStaticTypes.js).

I was able to generate the correct types pretty easily for my library, just need a way to load them. Would it be worthwhile to submit a patch? Happy to work on it.

Example of using getStaticTypes externally:

> cat ./generate-static-types.js
#!/usr/bin/env node
const getStaticTypes = require('playroom/lib/getStaticTypes')
const playroomConfig = require('./playroom.config')
const main = async () =>
  console.info(JSON.stringify(await getStaticTypes(playroomConfig), null, 2))
main()
> ./generate-static-types.js > ./static-types.json
> cat ./static-types.json| head -n 10
{
  "Column": {
    "width": [
      "content",
      "1/2",
      "1/3",
      "2/3",
      "1/4",
      "3/4",

@yinonov
Copy link

yinonov commented Jun 8, 2020

I'm not coming from a react background but love the concept of playroom and got it working until the autocomplete part.

is it possible to integrate autocompletion on non-react patterns? would like to know before digging in.

p.s.
our dev environment include ts files and some components extend other components so probably in most use cases the props are inherited

@pladaria
Copy link

I was able to get props autocomplete using babel-plugin-typescript-to-proptypes

my playroom webpack config includes:

...
use: [
    {
        loader: 'babel-loader',
        options: {
            babelrc: true,
            configFile: './.babelrc', 
            plugins: ['babel-plugin-typescript-to-proptypes'],
        },
    },
],
...

@michaeltaranto
Copy link
Contributor

Upgraded to use the latest docgen versions as part of #232, and functional components seem to be working.

Closed by #232

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants