@vtex/admin-ui-react

You can use the jsx function to create new components using elements or components as reference. It generates an OndaJSXComponent that inherits and enhances the reference types and styles.

Usage no npm install needed!

<script type="module">
  import vtexAdminUiReact from 'https://cdn.skypack.dev/@vtex/admin-ui-react';
</script>

README

Onda component model

jsx

You can use the jsx function to create new components using elements or components as reference. It generates an OndaJSXComponent that inherits and enhances the reference types and styles.

Referencing elements

To reference elements, simply pass its string representation to the function.

const BlueSquare = jsx('div')({
  bg: 'blue',
  size: 50,
})

render(<BlueSquare />)

Aliasing

jsx is aliased with any valid JSX.Element for faster typing.

const BlueSquare = jsx('div')({
  bg: 'blue',
  size: 50,
})

render(<BlueSquare />)

Referencing components

The idea is the same as elements. It will inherit the types and behavior of the passed component.

import { motion } from 'framer-motion'

const Scale = jsx(motion.div)({
  bg: 'blue',
  size: 50,
})

render(<Scale animate={{ scale: 2 }} transition={{ duration: 0.5 }} />)

Variants

Variants are props that change the component look. You can set their default values within defaultProps, as shown in the example below.

const Square = jsx('div')({
  size: 100,
  variants: {
    color: {
      blue: {
        bg: 'blue',
        ':hover': {
          bg: 'blue.hover',
        },
      },
      red: {
        bg: 'red',
        ':hover': {
          bg: 'red.hover',
        },
      },
    },
  },
})

Square.defaultProps = {
  color: 'blue',
}

render(
  <Set>
    <Square />
    <Square color="red" />
  </Set>
)

Synching variants

In some cases, you may want to attach styles if two or more variants have specific values. This happens when a variant style depends on other variants, and we call this a variant overlap. To deal with that you can use the sync array, which has the type:

Name Type Description Required Default
csx StyleObject Style to apply if the two variants exists 🚫
[k in keyof variants] keyof variants[k] Variants values to sync 🚫 🚫

In the example below, we have a square with a solid or an outline filling. The square can also be either red or blue. We have a variant overlap here because to set the final style of our square we need to know the value of both fill and color variants.

const Square = jsx('div')(
  {
    size: 100,
    variants: {
      fill: {
        outline: {
          borderWidth: 2,
          borderStyle: 'solid',
        },
        solid: {
          border: 'none',
        },
      },
      color: {
        blue: {
          bg: 'blue',
          ':hover': {
            bg: 'blue.hover',
          },
        },
        red: {
          bg: 'red',
          ':hover': {
            bg: 'red.hover',
          },
        },
      },
    },
  },
  [
    {
      // if the color is blue and fill outline
      color: 'blue',
      fill: 'outline',
      csx: {
        bg: 'transparent',
        color: 'blue',
        ':hover': {
          bg: 'blue.secondary.hover',
        },
      },
    },
    {
      // if the color is red and fill outline
      color: 'red',
      fill: 'outline',
      csx: {
        bg: 'transparent',
        color: 'red',
        ':hover': {
          bg: 'red.secondary.hover',
        },
      },
    },
  ]
)

Square.defaultProps = {
  color: 'blue',
  fill: 'solid',
}

render(
  <Set>
    <Square />
    <Square fill="outline" />
    <Square color="red" />
    <Square color="red" fill="outline" />
  </Set>
)

Options

Options are used to add extra behavior on the component.

interface DisplayOptions {
  visible?: boolean
}

const Display = jsx('div')({}, {
  // you need to declare the used options here.
  options: ['visible'],
  /**
   * options: component options
   * props: other props
   * system: return of admin-core/useSystem
   */
  useOptions(options: DisplayOptions, props, system) {
    const { children, ...divProps } = props
    const { visible } options

    return {
      ...divProps,
      children: visible ? children : null
    }
  }
})

Display.defaultProps = {
  visible: true
}

Polymorphism

Every component generated by jsx is polymorphic. With the as prop you can define the component render type, to extend or change its behavior.

const Button = jsx('button')({
  cursor: 'pointer',
  bg: 'blue',
  color: 'light.primary',
  fontSize: 1,
  height: 32,
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
  paddingX: 2,
  borderRadius: 'default',
  textAlign: 'center',
})

render(
  <Set>
    <Button>Button</Button>
    <Button as="a" href="">
      Button that is a link
    </Button>
  </Set>
)

Typescript Props

You can obtain the type of any component created with jsx using:

  • React.ComponentPropsWithRef: When refs are supported
  • React.ComponentPropsWithoutRef: When refs are not supported

Example without options:

const Button = jsx('button')({})

type ButtonProps = React.ComponentPropsWithRef<typeof Button>

Example with options:

const Button = jsx('button')(
  {},
  {
    useOptions(options: ButtonOptions, props) {
      /** ... */
    },
  }
)

interface ButtonOptions {}

type ButtonProps = React.ComponentPropsWithRef<typeof Button> & ButtonOptions