How do I register code components like this Chakra UI component?

I’m trying to register a more complex code component like this Card. So far I have only imported atomic level components like Button from @chakra-ui/react"

As the examples from Chakra pro don’t come with props, I’m not sure how convert this to something I can edit in Plasmic.

import {
  Box,
  Button,
  Container,
  HStack,
  Icon,
  Square,
  Stack,
  Text,
  useColorModeValue,
} from '@chakra-ui/react'
import * as React from 'react'
import { FiFileText } from 'react-icons/fi'

export const Card = () => (
  <Box as="section" py={{ base: '4', md: '8' }}>
    <Container maxW="3xl">
      <Box
        bg="bg-surface"
        boxShadow={useColorModeValue('sm', 'sm-dark')}
        borderRadius="lg"
        p={{ base: '4', md: '6' }}
      >
        <Stack spacing="5">
          <Stack spacing="1">
            <Text fontSize="lg" fontWeight="medium">
              Invoice
            </Text>
            <Text fontSize="sm" color="muted">
              Please pay the outstanding amount by the end of the following month.
            </Text>
          </Stack>
          <Box borderWidth={{ base: '0', md: '1px' }} p={{ base: '0', md: '4' }} borderRadius="lg">
            <Stack justify="space-between" direction={{ base: 'column', md: 'row' }} spacing="5">
              <HStack spacing="3">
                <Square size="10" bg="bg-subtle" borderRadius="lg">
                  <Icon as={FiFileText} boxSize="5" />
                </Square>
                <Box fontSize="sm">
                  <Text color="empahsized" fontWeight="medium">
                    Invoice_03/2022.pdf
                  </Text>
                  <Text color="muted">1.2MB</Text>
                </Box>
              </HStack>
              <Stack spacing="3" direction={{ base: 'column-reverse', md: 'row' }}>
                <Button variant="secondary">Download</Button>
                <Button variant="primary">View</Button>
              </Stack>
            </Stack>
          </Box>
        </Stack>
      </Box>
    </Container>
  </Box>
)

So far I tried this to edit the 2 Buttons, But I can’t select them in Plasmic.

 registerComponent(Card, {
    name: 'Card',
    importPath: './styles/Card',
    props: {
      children: {
        type: "slot",
        defaultValue: [
          {
            type: "component",
            name: "Button",
            props: {
              children: {
                type: "text",
                value: "Button 1",
              },
            },
          },
          {
            type: "component",
            name: "Button",
            props: {
              children: {
                type: "text",
                value: "Button 2",
              },
            },
          },
        ],
      },
      }
    }
  )

I see this in Plasmic:

image.png

OK. I can see how use className={className} to Allow positioning

<Box className={className} as="section" py={{ base: '4', md: '8' }}>

I guess I 1st need to convert all the prop values like variant="primary" into variant={variant} and it’s a React issue.
But is there anything pure Plasmic related that I should know? Like is it even a good idea to have a Card component, or is it best to just stop at Atomic components, and compose a Card in Plasmic out of them? (edited)

I’m making progress, can now edit Variant and Title, but not sure why my Button is Free position and called Card, whilst the actually Card is set not selectable. Is there an issue with this line

export default function Card(props: ButtonProps, {className}: { className?: string }) {

If you have a Card component that has content that can be customized, your Card component should take in a slot prop…

function Card({children}) {
  return <Box>{children}</Box>;
}

registerComponent(Card, {
  name: "Card",
  props: {
    "children": {
      type: "slot"
    }
  }
});

Then from Plasmic, you’ll be able to control what goes into the children slot

Does the Function need to be in plasmic-host?

the Card function? no, it is just a normal React component, can be in any file imported into plasmic-host

Yes Card Function. OK, just checking as In @verbal_sparrow code (which I’m using) has this Function which I thought might be what you meant, maybe it’s just an error:

function Option({
  value,
  className,
  children,
}: {
  value:string;
  className?: string;
  children: any;

}) {
  return (
      <option className={className} value={value}>
        {children}
      </option>

  );
}

OK I now see my buttons in Plasmic with this code:

<Stack spacing="3" direction={{ base: 'column-reverse', md: 'row' }}>
  {children}
</Stack>

image.png

How about multiple Children, representing Text, Icon etc:

export default function Card({children}) {
    return (    
    <Box as="section" py={{ base: '4', md: '8' }}>
    <Container maxW="3xl">
      <Box
        bg="bg-surface"
        boxShadow={useColorModeValue('sm', 'sm-dark')}
        borderRadius="lg"
        p={{ base: '4', md: '6' }}
      >
        <Stack spacing="5">
          <Stack spacing="1">
            {children}
          </Stack>
          <Box borderWidth={{ base: '0', md: '1px' }} p={{ base: '0', md: '4' }} borderRadius="lg">
            <Stack justify="space-between" direction={{ base: 'column', md: 'row' }} spacing="5">
              <HStack spacing="3">
                <Square size="10" bg="bg-subtle" borderRadius="lg">
                  {children}
                </Square>
                <Box fontSize="sm">
                  {children}
                </Box>
              </HStack>
              <Stack spacing="3" direction={{ base: 'column-reverse', md: 'row' }}>
                {children}
              </Stack>
            </Stack>
          </Box>
        </Stack>
      </Box>
    </Container>
  </Box>
  );
}

Do I need to create a Hierarchy of Children like this example:

children: {
    type: "slot",
    defaultValue: [
      {
        type: "component",
        name: "Button",
        props: {
          children: {
            type: "text",
            value: "Button 1",
          },
        },
      },
      {
        type: "component",
        name: "Button",
        props: {
          children: {
            type: "text",
            value: "Button 2",
          },
        },
      },
    ],
  },

This is too complex for me to follow right now. Is there plans to make this a lot easier?
I see a simpler registration process as pivotal for the adoption of Plasmic by developers. Ideally it would be the same effort as Storybook or simpler. Any plans @yang ?

maybe to back up a bit – what are you trying to build? From the code, it looks like what you’re trying to build is a specific Card layout with “slots” where the user can customize things. You will need to create one prop for each “slot”, one for the title, one for button1 text, one for button2 text, etc. Each of these props will show up as a separate slot in Plasmic

OK @chungwu that’s kinda what I actually have now:

import * as React from 'react'
import {
  Box,
  Button, 
  ButtonProps,
  Container,
  HStack,
  Icon,
  Square,
  Stack,
  Text,
  useColorModeValue,
} from '@chakra-ui/react'
import { FiFileText } from 'react-icons/fi'


export default function Card({ className, title, description, file, size, Button1, Button2 }) {

  Card.defaultProps = {
    title: "title",
    description: "description",
    file: "file",
    size: "size",
    Button1: "Button1",
    Button2: "Button2",
  }
  
    return (    
      <div className={className} >
    <Box as="section" py={{ base: '4', md: '8' }}>
    <Container maxW="3xl">
      <Box
        bg="bg-surface"
        boxShadow={useColorModeValue('sm', 'sm-dark')}
        borderRadius="lg"
        p={{ base: '4', md: '6' }}
      >
        <Stack spacing="5">
        <Stack spacing="1">
            <Text fontSize="lg" fontWeight="medium">
              {title}
            </Text>
            <Text fontSize="sm" color="muted">
              {description}
            </Text>
          </Stack>
          <Box borderWidth={{ base: '0', md: '1px' }} p={{ base: '0', md: '4' }} borderRadius="lg">
            <Stack justify="space-between" direction={{ base: 'column', md: 'row' }} spacing="5">
              <HStack spacing="3">
                <Square size="10" bg="bg-subtle" borderRadius="lg">
                  <Icon as={FiFileText} boxSize="5" />
                </Square>
                <Box fontSize="sm">
                  <Text color="empahsized" fontWeight="medium">
                    {file}
                  </Text>
                  <Text color="muted">{size}</Text>
                </Box>
              </HStack>
              <Stack spacing="3" direction={{ base: 'column-reverse', md: 'row' }}>
                <Button variant="secondary">{Button1}</Button>
                <Button variant="primary">{Button2}</Button>
              </Stack>
            </Stack>
          </Box>
        </Stack>
      </Box>
    </Container>
  </Box>
  </div>
  );
}

But they are not slots just strings:

  registerComponent(Card, {
    name: 'Card',
    importPath: './styles/Card',
    props: {
      title: 'string',
      description: 'string',
      file: 'string',
      size: 'string',
      Button1: 'string',
      Button2: 'string',
      }
    }
  )

So the UI is:

image.png

To answer your question “what are you trying to build?”.
I’d like to show to developers and designers how a more complex code component (like this Card from Chakra Pro), can be used within Plasmic.
I can now change all text - which is great, but basic
Ideally, something with slots, so I can use it as a template, adding elements, changing orders, replacing, deleting elements etc.
Like maybe changing the icon, deleting a button, Adding an image as the header.

Actually. I have a simpler Card that would be better to show:

image.png

ah if you want the elements inside the card to be completely modifiable then you want a Card with just one giant slot, but maybe starting out with some default content.

function Card({children}) {
  return <Box>{children}</Box>;
}
registerComponent(Card, {
  name: "Card",
  props: {
    children: {
      type: "slot",
      defaultValue: [
          {
            type: "component",
            name: "Button",
            props: {
              children: {
                type: "text",
                value: "Button 1",
              },
            },
          },
          {
            type: "component",
            name: "Button",
            props: {
              children: {
                type: "text",
                value: "Button 2",
              },
            },
          },
      ]
    }
  }
});

which is the road you were going down before, except you didn’t render the children prop in your Card component at first