Skip to content
This repository has been archived by the owner on Oct 23, 2023. It is now read-only.

Latest commit

 

History

History
146 lines (112 loc) · 3.52 KB

README.md

File metadata and controls

146 lines (112 loc) · 3.52 KB

@polymorphic-factory/vue

CodeCov MIT License Github Stars Bundle Size NPM Downloads

Create polymorphic VueJS components with a customizable styled function.

A polymorphic component is a component that can be rendered with a different element.

Known drawbacks for the type definitions:

Event handlers are not typed correctly when using the as prop.

This is a deliberate decision to keep the usage as simple as possible.

Installation

npm install @polymorphic-factory/vue

or

yarn add @polymorphic-factory/vue

or

pnpm install @polymorphic-factory/vue

Usage

Import the polymorphic factory and create your element factory.

import { polymorphicFactory } from '@polymorphic-factory/vue'
const poly = polymorphicFactory()

Custom styled function

You can override the default implementation by passing styled function in the options.

import { defineComponent } from 'vue'
const poly = polymorphicFactory({
  styled: (originalComponent, options) =>
    defineComponent({
      props: ['as'],
      setup(props, { slots, attrs }) {
        const component = props.as || originalComponent

        return () =>
          h(
            component,
            { 'data-custom-styled': true, 'data-options': JSON.stringify(options), ...attrs },
            slots,
          )
      },
    }),
})

const WithOptions = poly('div', { hello: 'world' })

const App = () => {
  return (
    <>
      <poly.div hello="world" />
      {/* renders <div data-custom-styled hello="world" /> */}

      <WithOptions />
      {/* renders <div data-custom-styled data-options="{ \"hello\": \"world\" }" /> */}
    </>
  )
}

Inline

Use the element factory to create elements inline. Every JSX element is supported div, main, aside, etc.

<>
  <poly.div />
  <poly.main>
    <poly.section>
      <poly.div as="p">This is rendered as a p element</poly.div>
    </poly.section>
  </poly.main>
</>

Factory

Use the factory to wrap custom components.

const OriginalComponent = defineComponent({
  setup(props) {
    return () => <div data-original="true" {...props} />
  },
})
const MyComponent = poly(OriginalComponent)

const App = h(MyComponent)
// render <div data-original="true" />

It still supports the as prop, which would replace the OriginalComponent.

<MyComponent as="div" />
// renders <div />

Types

import type { HTMLPolymorphicComponents, HTMLPolymorphicProps } from '@polymorphic-factory/vue'

type PolymorphicDiv = HTMLPolymorphicComponents['div']
type DivProps = HTMLPolymorphicProps<'div'>

License

MIT © Tim Kolberger