Improving component registration process

Hi all,

Has there been any recent improvements with registering components?

I have a lot of code components to register and wanted to check in before I go about adding props, slots etc…

Hi @political_magpie! You can check the (updated) documentation in https://docs.plasmic.app/learn/registering-code-components/. Is there anything specific you are looking for?

Curious when was it updated and what the new bits are?
What I was hoping for was a way to recognise a components metadata and automatically generate it. Then a way to override this defaults metadata .

Specifically @tiago . What I am trying to register is all the props for all the Chakra Pro components, with slots and default values etc. I already have registered all the Chakra UI components, so can use name: getPlasmicComponentName("..."), for that. It currently seems like a mammoth task to registered these, it’s also very confusing.

As they are typescript file I heard that this could be automated, is that true and how do I/we do that?

I think the registration process is a sticking point for the adoption of Plasmic. Any effort/help in this space would be greatly appreciated by me and the community. Often hybrid design/devs are drawn to tools like Plasmic and get a lot of push back from developers that say they have to code twice. So I want to make this a none issue and ideally not even have to rely on them.

@verbal_sparrow helped me a while back on on the core Chakra UI components and I know he would also be interested in a better registration process, so looping him in here.

Here is one or hundreds of component examples:

//LoginWithCentredForm/register.tsx

<Container 
    className={className}
    maxW="lg" py={{ base: '12', md: '24' }} px={{ base: '0', sm: '8' }}>
    <Stack spacing="8">
      <Stack spacing="6">
        <Logo />
        <Stack spacing={{ base: '2', md: '3' }} textAlign="center">
          <Heading size={useBreakpointValue({ base: 'xs', md: 'sm' })}>
            Log in to your account
          </Heading>
          <HStack spacing="1" justify="center">
            <Text color="muted">Dont have an account?</Text>
            <Button variant="link" colorScheme="pink">
              Sign up
            </Button>
          </HStack>
        </Stack> 
      </Stack>
              
      <Box
        py={{ base: '0', sm: '8' }}
        px={{ base: '4', sm: '10' }}
        // bg={useBreakpointValue({ base: 'transparent', sm: 'bg-surface' })}
        boxShadow={{ base: 'none', sm: useColorModeValue('md', 'md-dark') }}
        borderRadius={{ base: 'none', sm: 'xl' }}
      >

        <Stack spacing="6">
          <Stack spacing="5">
            <FormControl>
              <FormLabel htmlFor="email">Email</FormLabel>
              <Input id="email" type="email" />
            </FormControl>
            <PasswordField />
          </Stack>
          <HStack justify="space-between">
            <Checkbox defaultChecked>Remember me</Checkbox>
            <Button variant="link" colorScheme="pink" size="sm">
              Forgot password?
            </Button>
          </HStack>
          <Stack spacing="6">
            <Button variant="primary">Sign in</Button>
            <HStack>
              <Divider />
              <Text fontSize="sm" whiteSpace="nowrap" color="muted">
                or continue with
              </Text>
              <Divider />
            </HStack>
            <OAuthButtonGroup />
          </Stack>
        </Stack>
      </Box>
    </Stack> 
  </Container>

The best registration process so far has been GPT4

Not 100% success rate at first go, but could be the ultimate solution for this, as long as it has internet access

I was gonna mention AI. Your on the ball as usual.

WOW. After a number of attempts and asking ChatGPT to refer to Plasmic registration docs I got this back:

// registration.js

import { registerComponent } from '@plasmicapp/host';
import { ReactNode } from 'react';

export interface AppProps {
  className?: string;
  children?: ReactNode;
  maxW?: string;
  py?: {
    base?: string;
    md?: string;
  };
  px?: {
    base?: string;
    sm?: string;
  };
}

export function App({
  className,
  children,
  ...rest
}: AppProps) {
  return (
    // Component implementation
  );
}

registerComponent(App, {
  name: 'App',
  props: {
    className: {
      type: 'string',
      defaultValue: '',
    },
    children: {
      type: 'slot',
      allowedComponents: ['Logo', 'Stack', 'Box', 'FormControl', 'FormLabel', 'Input', 'PasswordField', 'Checkbox', 'Button', 'Divider', 'Text', 'Heading', 'HStack', 'OAuthButtonGroup'],
      defaultValue: [
        {
          type: 'component',
          name: 'Logo',
          props: {},
        },
        {
          type: 'component',
          name: 'Stack',
          props: {
            spacing: '8',
            children: [
              {
                type: 'component',
                name: 'Stack',
                props: {
                  spacing: { base: '2', md: '3' },
                  textAlign: 'center',
                  children: [
                    {
                      type: 'component',
                      name: 'Heading',
                      props: {
                        size: { base: 'xs', md: 'sm' },
                        children: {
                          type: 'text',
                          value: 'Log in to your account',
                        },
                      },
                    },
                    {
                      type: 'component',
                      name: 'HStack',
                      props: {
                        spacing: '1',
                        justify: 'center',
                        children: [
                          {
                            type: 'component',
                            name: 'Text',
                            props: {
                              color: 'muted',
                              children: {
                                type: 'text',
                                value: 'Don\'t have an account?',
                              },
                            },
                          },
                          {
                            type: 'component',
                            name: 'Button',
                            props: {
                              variant: 'link',
                              colorScheme: 'pink',
                              children: {
                                type: 'text',
                                value: 'Sign up',
                              },
                            },
                          },
                        ],
                      },
                    },
                  ],
                },
              },
            ],
          },
        },
        {
          type: 'component',
          name: 'Box',
          props: {
            py: { base: '0', sm: '8' },
            px: { base: '4', sm: '10' },
            boxShadow: { base: 'none', sm: 'md' },
            borderRadius: { base: 'none', sm: 'xl' },
            children: [
              {
                type: 'component',
                name: 'Stack',
                props: {
                  spacing: '6',
                  children: [
                    {
                      type: 'component',
                      name: 'Stack',
                      props: {
                        spacing: '5',
                        children: [
                          {
                            type: 'component',
                            name: 'FormControl',
                            props: {
                              children: [
                                {
                                  type: 'component',
                                  name: 'FormLabel',
                                  props: {
                                    htmlFor: 'email',
                                    children: {
                                      type: 'text',
                                      value: 'Email',
                                    },
                                  },
                                },
                                {
                                  type: 'component',
                                  name: 'Input',
                                  props: {
                                    id: 'email',
                                    type: 'email',
                                  },
                                },
                              ],
                            },
                          },
                          {
                            type: 'component',
                            name: 'PasswordField',
                            props: {},
                          },
                        ],
                      },
                    },
                    {
                      type: 'component',
                      name: 'HStack',
                      props: {
                        justify: 'space-between',
                        children: [
                          {
                            type: 'component',
                            name: 'Checkbox',
                            props: {
                              defaultChecked: true,
                              children: {
                                type: 'text',
                                value: 'Remember me',
                              },
                            },
                          },
                          {
                            type: 'component',
                            name: 'Button',
                            props: {
                              variant: 'link',
                              colorScheme: 'pink',
                              size: 'sm',
                              children: {
                                type: 'text',
                                value: 'Forgot password?',
                              },
                            },
                          },
                        ],
                      },
                    },
                    {
                      type: 'component',
                      name: 'Stack',
                      props: {
                        spacing: '6',
                        children: [
                          {
                            type: 'component',
                            name: 'Button',
                            props: {
                              variant: 'primary',
                              children: {
                                type: 'text',
                                value: 'Sign in',
                              },
                            },
                          },
                          {
                            type: 'component',
                            name: 'HStack',
                            props: {
                              children: [
                                {
                                  type: 'component',
                                  name: 'Divider',
                                  props: {},
                                },
                                {
                                  type: 'component',
                                  name: 'Text',
                                  props: {
                                    fontSize: 'sm',
                                    whiteSpace: 'nowrap',
                                    color: 'muted',
                                    children: {
                                      type: 'text',
                                      value: 'or continue with',
                                    },
                                  },
                                },
                                {
                                  type: 'component',
                                  name: 'Divider',
                                  props: {},
                                },
                              ],
                            },
                          },
                          {
                            type: 'component',
                            name: 'OAuthButtonGroup',
                            props: {},
                          },
                        ],
                      },
                    },
                  ],
                },
              },
            ],
          },
        },
      ],
    },
  },
});

What would be the best GTP question/script to generate even better code?

Ironically ChatGPT 4 is a little outdated:
“…always refer to the official Plasmic documentation for the most up-to-date information, as the specifics might have changed after my last training cut-off in September 2021.”

@yang heres the post Yang

The format I would like to use is the same as this Chakra UI Card component:

import { CardProps, CardHeaderProps, CardBodyProps, CardFooterProps, IconProps } from "@chakra-ui/react";
import { CodeComponentMeta } from "@plasmicapp/host/registerComponent";
import {
  getComponentNameAndImportMeta,
  getPlasmicComponentName,
} from "./utils";

export const cardMeta: CodeComponentMeta<CardProps> = {
  ...getComponentNameAndImportMeta("Card"),
  props: {
    size: {
      type: "choice",
      options: ["sm", "md", "lg"],
      // defaultValue: "lg",
    },
    variant: {
      type: "choice",
      options: ["primary", "elevated", "outline", "filled", "unstyled"],
      defaultValue: "primary",
    },
    children: {
      type: "slot",
      allowedComponents: [
        getPlasmicComponentName("CardBody,CardHeader, CardFooter"),
      ],
      defaultValue: [
        {
          type: "component",
          name: getPlasmicComponentName("CardHeader"),
        },
        {
          type: "component",
          name: getPlasmicComponentName("CardBody"),
        },
        {
          type: "component",
          name: getPlasmicComponentName("CardFooter"),
        },
      ],
    },
  },
};
export const cardHeaderMeta: CodeComponentMeta<CardHeaderProps> = {
  ...getComponentNameAndImportMeta("CardHeader", "Card"),
  props: {
    size: {
      type: "choice",
      options: ["sm", "md", "lg"],
    },
    // children: {
    //   type: "slot",
    //   allowedComponents: [getPlasmicComponentName("ImageWithOverlay")],

    //   defaultValue: [
    //     {
    //       type: "component",
    //       name: getPlasmicComponentName("ImageWithOverlay"),
    //     },
    //   ],
    // },
  },
};
export const cardBodyMeta: CodeComponentMeta<CardBodyProps> = {
  ...getComponentNameAndImportMeta("CardBody", "Card"),
  props: {
    children: {
      type: "slot",
      allowedComponents: [
        getPlasmicComponentName("Tag"),
        getPlasmicComponentName("Text")
      ],
      defaultValue: [
        { type: "component", name: getPlasmicComponentName("Tag") },
        { type: "component", name: getPlasmicComponentName("Tag") },
        { type: "component", name: getPlasmicComponentName("Tag") },
        { type: "component", name: getPlasmicComponentName("Tag") },
        { type: "component", name: getPlasmicComponentName("Tag") },
        { type: "component", name: getPlasmicComponentName("Tag") },
        { type: "component", name: getPlasmicComponentName("Text") },
      ],
    },
  },
};
export const cardFooterMeta: CodeComponentMeta<CardFooterProps> = {
  ...getComponentNameAndImportMeta("CardFooter", "Card"),
  props: {
    children: {
      type: "slot",
      allowedComponents: [
        getPlasmicComponentName("Stack"),
        getPlasmicComponentName("IconButton")
],

      defaultValue: [
        {
          type: "component",
          name: getPlasmicComponentName("Stack"),
          props: {
            children: [
              {
                type: "component",
                name: getPlasmicComponentName("IconButton"),
              },
              {
                type: "component",
                name: getPlasmicComponentName("IconButton"),
              },
              {
                type: "component",
                name: getPlasmicComponentName("IconButton"),
              },
              {
                type: "component",
                name: getPlasmicComponentName("IconButton"),
              },
              {
                type: "component",
                name: getPlasmicComponentName("IconButton"),
              },
              {
                type: "component",
                name: getPlasmicComponentName("IconButton"),
              },
            ],
          },
        },
        { type: "component", name: getPlasmicComponentName("Tag") },
      ],
    },
  },
};

What would be great @yang is for a complex code component, to have the the same ability as copy/paste form Figma.
So if sub components are recognised, you can offer to replacement similar to:

Now that would be pour AWESOMENESS!

@verbal_sparrow agree ^^^?

Thinking laterally, maybe a temporary way to do this…

  1. Use a HTML to Figma plugin ( use Vercel deployment as have code components)
  2. Change layers name and add slots etc… in Figma
  3. Use Plasmic’s copy/paste Figma plugin
  4. “Replace with Plasmic components of the same name if possible”
  5. Clean up complex component