@uni-component/core
v0.9.0
Published
Unified Component
Downloads
11
Maintainers
Readme
uni-component
Unified Component: Write once component, Run in multiple lib/platform.
Depend on @uni-store.
Unified Component core parts:
setup
, like vue setup, just define the component state. The state can be used to any platforms. This should be contained pure component state logic.render
, optional. This should be used when platform support render function, like : web platform or miniapp which supported runtime render.
Refactor vuetify@next with uni-component.
Or see components for more uni-component usage cases.
Installation
pnpm add @uni-component/core
# or with yarn
yarn add @uni-component/core
# or with npm
npm install @uni-component/core
Usage
More cases, see @uni-component/components.
Define a component
import {
h,
PropType,
uniComponent,
uni2Platform,
computed,
ref
} from '@uni-component/core'
// pure setup state
export const UniButton = uniComponent('uni-button', {
type: {
type: String as PropType<'button' | 'submit' | 'reset'>,
default: 'button'
},
text: String,
icon: String,
primary: Boolean,
onClick: Function as PropType<(e?: MouseEvent) => any>
}, (name, props) => {
const n = ref(0)
const rootClass = computed(() => {
return {
[`${name}-primary`]: props.primary
}
})
const clickAction = (e?: MouseEvent) => {
n.value += 1
// do others
props.onClick && props.onClick(e)
}
return {
n,
rootClass,
clickAction
}
})
// platform component with pure render function
export const CubeButton = uni2Platform(UniButton, (props, state, { renders }) => {
const { type, text } = props
// rootClass always contain Component name, like 'cube-button'
const { rootClass, n, clickAction } = state
const t = text ? text : (renders.defaultRender && renders.defaultRender())
return (
<button class={rootClass} type={type} onClick={clickAction}>
<span>{ t } { n }</span>
</button>
)
})
With Vue 3
Install:
pnpm add @uni-component/vue
# or with yarn
yarn add @uni-component/vue
# or with npm
npm install @uni-component/vue
Use:
/// <reference types="@uni-component/vue/platform" />
import { h, Fragment } from '@uni-component/core'
import '@uni-component/vue'
import { createApp } from 'vue'
const App = () => {
return (
<>
<CubeButton>child</CubeButton>
<CubeButton primary={true} text='text'></CubeButton>
</>
)
}
createApp(App).mount('#root')
JSX with tsconfig: { "jsxFactory": "h", "jsxFragmentFactory": "Fragment" }
With React
Install:
pnpm add @uni-component/react
# or with yarn
yarn add @uni-component/react
# or with npm
npm install @uni-component/react
Use:
/// <reference types="@uni-component/react/platform" />
import { h, Fragment } from '@uni-component/core'
import '@uni-component/react'
import ReactDOM from 'react-dom'
const App = () => {
return (
<>
<CubeButton>child</CubeButton>
<CubeButton primary={true} text='text'></CubeButton>
</>
)
}
ReactDOM.render(<App />, document.getElementById('root'))
JSX with tsconfig: { "jsxFactory": "h", "jsxFragmentFactory": "Fragment" }
Documentation
Define pure state - Headless Component
In my opinion, the pure state is a headless component.
Use uniComponent
API.
Object props:
import { uniComponent, classNames, UniNode } from '@uni-component/core'
const UniXxYy = uniComponent('uni-xx-yy', {
type: {
type: String as PropType<'button' | 'submit' | 'reset'>,
default: 'button'
},
text: String,
icon: String,
primary: Boolean,
onClick: Function as PropType<(e?: MouseEvent) => any>,
xxRender: Function as PropType<(param: {}) => UniNode | undefined>,
}, (name, props, context) => {
// name is 'UniXxYy'
const n = ref(0)
const rootClass = computed(() => {
return {
[`${name}-primary`]: props.primary
}
})
// other class you should always use classNames
const otherClass = computed(() => {
return classNames({
[`${name}-child-xx`]: props.type === 'reset'
})
})
const clickAction = (e?: MouseEvent) => {
n.value += 1
// do others
props.onClick && props.onClick(e)
}
return {
n,
rootClass,
clickAction
}
})
Notice: xxRender
prop will be treated as render function(React - render function, vue - scope slot)
Array props:
const UniXxYy = uniComponent('uni-xx-yy', ['a', 'b'], (name, props, context) => {
// name is 'UniXxYy'
// props.a and props.b can be any value
// ...
return {
// ...
}
})
No props:
const UniXxYy = uniComponent('uni-xx-yy', (name, props, context) => {
// name is 'UniXxYy'
// ...
return {
// ...
}
})
About context
param
{
// renders contained all `xxRender` in props
// renders.defaultRender() is used to replace `props.children` in react and `slots.default` in vue
renders: Record<string, (...args: any[]) => any>
// all element attrs, no ref and key
attrs: Record<string, any>
// element attrs without `class, style, id`
$attrs: Record<string, any>
// original props setted by usage case
// without default props
nodeProps?: Record<string, any> | null
}
Define platform component
This is optional.
Use uni2Platform(UniComponent, render: (props, state, context) => UniNode | undefined)
API.
UniComponent
headless component, theuniComponent()
resultrender()
pure render function.- About
state
param{ rootClass: string, rootStyle: {[key: string]: 'string value'}, rootId: string | undefined // other state with your custom state // n, // xxAction, //... }
- About
Demo:
// platform component with pure render function
const XxYy = uni2Platform(UniXxYy, (props, state, { renders }) => {
const { type, text } = props
// rootClass always contain Component name, like 'uni-xx-yy'
const { rootClass, rootStyle, rootId, n, clickAction } = state
const t = text ? text : (renders.defaultRender && renders.defaultRender())
return (
<button id={rootId} class={rootClass} style={rootStyle} type={type} onClick={clickAction}>
<span>{ t } { n }</span>
</button>
)
})
Reference a DOM element or Component
Use useRef
API and ref
attribute.
import { useRef } from '@uni-component/core'
const UniXxYy = uniComponent('uni-xx-yy', (name) => {
// name is 'UniXxYy'
const ele = ref<HTMLElement>()
const setEleRef = useRef(ele)
// buttonComponent will be the state of CubeButton
// defined in UniButton
const buttonComponent = ref<{
n: number,
clickAction: (e?: MouseEvent) => void
}>()
const setButtonComponentRef = useRef(buttonComponent)
return {
setEleRef,
setButtonComponentRef,
}
})
render:
const XxYy = uni2Platform(UniXxYy, (props, state) => {
const { setEleRef, setButtonComponentRef } = state
return (
<div ref={setEleRef}>
<CubeButton ref={setButtonComponentRef}>xx</CubeButton>
</div>
)
})
Notice: The ref value will be this component's state result when referenced a component
Lifecycles
Only 3 lifecycles: mounted
, updated
and unmounted
.
import { onMounted, onUpdated, onUnmounted } from '@uni-component/core'
const UniXxYy = uniComponent('uni-xx-yy', (name) => {
onMounted(() => {
console.log('mounted')
})
onUpdated(() => {
console.log('updated')
})
onUnmounted(() => {
console.log('unmounted')
})
return {
// ...
}
})
Provide and Inject
Like vue 3 Provide / Inject.
Provide:
// parent component
import { provide } from '@uni-component/core'
const UniXxYy = uniComponent('uni-xx-yy', (name) => {
provide('xx-key', {
// xx: xxValue
// ...
})
return {
// ...
}
})
Inject:
// child component
import { inject } from '@uni-component/core'
const UniXxYyChild = uniComponent('uni-xx-yy-child', (name) => {
// const xxProvide = inject('xx-key')
// with default value
const xxYyProvideValue = inject('xx-key', {
// xx: defaultValue
// ...
})
return {
// ...
}
})
Other API
classNames()
, process element class names. Same as classnames.const mergedStyle = mergeStyle(stringStyle, objectStyle, ...(string or object styles))
, merge styles.mergedStyle
is an object.