Skip to content

Commit

Permalink
feat(element): support element-ui slot (#2162)
Browse files Browse the repository at this point in the history
  • Loading branch information
muuyao authored Sep 17, 2021
1 parent cdf8405 commit 205e164
Show file tree
Hide file tree
Showing 13 changed files with 139 additions and 89 deletions.
55 changes: 0 additions & 55 deletions packages/element/src/__builtins__/shared/get-component-by-tag.ts

This file was deleted.

2 changes: 1 addition & 1 deletion packages/element/src/__builtins__/shared/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from './get-component-by-tag'
export * from './transform-component'
export * from './resolve-component'
export * from './create-context'
export * from './utils'
Expand Down
21 changes: 8 additions & 13 deletions packages/element/src/__builtins__/shared/resolve-component.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
import { Component } from 'vue'
import { h, toRaw } from '@vue/composition-api'
import { Component, VNode } from 'vue'
import { SlotTypes } from '.'
import { isVnode } from './utils'

export const resolveComponent = (
child?:
| Component
| string
| number
| boolean
| ((...args: any[]) => VNode[] | VNode),
child?: SlotTypes,
props?: Record<string, any>
) => {
if (child) {
if (
typeof child === 'string' ||
typeof child === 'number' ||
typeof child === 'boolean'
) {
if (typeof child === 'string' || typeof child === 'number') {
return child
} else if (typeof child === 'function') {
return (child as Function)(props)
} else if (isVnode(child)) {
return child
} else {
return h(toRaw(child), { props })
return h(toRaw(child as Component), { props })
}
}

Expand Down
65 changes: 65 additions & 0 deletions packages/element/src/__builtins__/shared/transform-component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import type { Component } from 'vue'
import { merge } from '@formily/shared'
import { h } from '@formily/vue'
import { isVue2, h as hInVue2, defineComponent } from 'vue-demi'

type ListenersTransformRules = Record<string, string>

export const transformComponent = <T extends Record<string, any>>(
tag: any,
transformRules?: ListenersTransformRules,
defaultProps?: Partial<T>
): Component<T> | any => {
if (isVue2) {
return defineComponent({
setup(props, { attrs, slots, listeners }) {
return () => {
const data = {
attrs: {
...attrs,
},
on: {
...listeners,
},
}

if (transformRules) {
const transformListeners = transformRules
Object.keys(transformListeners).forEach((extract) => {
if (data.on !== undefined) {
data.on[transformListeners[extract]] = listeners[extract]
}
})
}
if (defaultProps) {
data.attrs = merge(defaultProps, data.attrs)
}

return h(tag, data, slots)
}
},
})
} else {
return defineComponent({
setup(props, { attrs, slots }) {
return () => {
let data = {
...attrs,
}
if (transformRules) {
const listeners = transformRules
Object.keys(listeners).forEach((extract) => {
const event = listeners[extract]
data[`on${event[0].toUpperCase()}${event.slice(1)}`] =
attrs[`on${extract[0].toUpperCase()}${extract.slice(1)}`]
})
}
if (defaultProps) {
data = merge(defaultProps, data)
}
return h(tag, data, slots)
}
},
})
}
}
10 changes: 10 additions & 0 deletions packages/element/src/__builtins__/shared/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ export function isValidElement(element) {
) // remove text node
}

export function isVnode(element: any): boolean {
return (
element &&
typeof element === 'object' &&
'componentOptions' in element &&
'context' in element &&
element.tag !== undefined
)
}

export function isVueOptions(options) {
return (
options &&
Expand Down
4 changes: 2 additions & 2 deletions packages/element/src/checkbox/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { connect, mapProps, h, mapReadPretty } from '@formily/vue'
import { defineComponent, PropType } from '@vue/composition-api'
import {
composeExport,
getComponentByTag,
transformComponent,
resolveComponent,
SlotTypes,
} from '../__builtins__/shared'
Expand Down Expand Up @@ -83,7 +83,7 @@ export type CheckboxGroupProps = ElCheckboxGroupProps & {
optionType: 'default' | 'button'
}

const TransformElCheckboxGroup = getComponentByTag(ElCheckboxGroup, {
const TransformElCheckboxGroup = transformComponent(ElCheckboxGroup, {
change: 'input',
})

Expand Down
11 changes: 7 additions & 4 deletions packages/element/src/date-picker/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getComponentByTag } from '../__builtins__/shared'
import { transformComponent } from '../__builtins__/shared'
import { connect, mapProps, mapReadPretty } from '@formily/vue'

import type { DatePicker as ElDatePickerProps } from 'element-ui'
Expand All @@ -7,9 +7,12 @@ import { PreviewText } from '../preview-text'

export type DatePickerProps = ElDatePickerProps

const TransformElDatePicker = getComponentByTag<DatePickerProps>(ElDatePicker, {
change: 'input',
})
const TransformElDatePicker = transformComponent<DatePickerProps>(
ElDatePicker,
{
change: 'input',
}
)

const getDefaultFormat = (props, formatType = 'format') => {
const type = props.type
Expand Down
4 changes: 2 additions & 2 deletions packages/element/src/input-number/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getComponentByTag } from '../__builtins__/shared'
import { transformComponent } from '../__builtins__/shared'
import { connect, mapProps, mapReadPretty } from '@formily/vue'

import type { InputNumber as _ElInputNumberProps } from 'element-ui'
Expand All @@ -7,7 +7,7 @@ import { PreviewText } from '../preview-text'

export type InputNumberProps = _ElInputNumberProps

const TransformElInputNumber = getComponentByTag<InputNumberProps>(
const TransformElInputNumber = transformComponent<InputNumberProps>(
ElInputNumber,
{
change: 'input',
Expand Down
4 changes: 2 additions & 2 deletions packages/element/src/input/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { composeExport, getComponentByTag } from '../__builtins__/shared'
import { composeExport, transformComponent } from '../__builtins__/shared'
import { connect, mapProps, mapReadPretty } from '@formily/vue'
import { PreviewText } from '../preview-text'
import type { Input as ElInputProps } from 'element-ui'
import { Input as ElInput } from 'element-ui'

export type InputProps = ElInputProps

const TransformElInput = getComponentByTag<InputProps>(ElInput, {
const TransformElInput = transformComponent<InputProps>(ElInput, {
change: 'input',
})

Expand Down
4 changes: 2 additions & 2 deletions packages/element/src/radio/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { connect, mapProps, h, mapReadPretty } from '@formily/vue'
import { defineComponent, PropType } from '@vue/composition-api'
import {
composeExport,
getComponentByTag,
transformComponent,
resolveComponent,
SlotTypes,
} from '../__builtins__/shared'
Expand Down Expand Up @@ -31,7 +31,7 @@ export type RadioGroupProps = ElRadioGroupProps & {

export type RadioProps = ElRadioProps

const TransformElRadioGroup = getComponentByTag(ElRadioGroup, {
const TransformElRadioGroup = transformComponent(ElRadioGroup, {
change: 'input',
})

Expand Down
32 changes: 28 additions & 4 deletions packages/element/src/select/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ import type {
Option as ElOptionProps,
} from 'element-ui'
import { Select as ElSelect, Option as ElOption } from 'element-ui'
import { resolveComponent, SlotTypes } from '../__builtins__'

export type SelectProps = ElSelectProps & {
options?: Array<ElOptionProps | string>
options?: Array<
Omit<ElOptionProps, 'label'> & {
label: SlotTypes
}
>
}

const SelectOption = defineComponent<SelectProps>({
Expand All @@ -26,11 +31,30 @@ const SelectOption = defineComponent<SelectProps>({
if (typeof option === 'string') {
return h(
ElOption,
{ props: { label: option, value: option } },
{}
{ props: { value: option } },
{
default: () => [
resolveComponent(slots?.option ?? option, { option }),
],
}
)
} else {
return h(ElOption, { props: option }, {})
return h(
ElOption,
{
props: {
...option,
label: '',
},
},
{
default: () => [
resolveComponent(slots?.option ?? option.label, {
option,
}),
],
}
)
}
}),
}
Expand Down
11 changes: 7 additions & 4 deletions packages/element/src/time-picker/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { getComponentByTag } from '../__builtins__/shared'
import { transformComponent } from '../__builtins__/shared'
import { connect, mapProps, mapReadPretty } from '@formily/vue'
import { PreviewText } from '../preview-text'
import type { TimePicker as ElTimePickerProps } from 'element-ui'
import { TimePicker as ElTimePicker } from 'element-ui'

export type TimePickerProps = ElTimePickerProps

const TransformElTimePicker = getComponentByTag<TimePickerProps>(ElTimePicker, {
change: 'input',
})
const TransformElTimePicker = transformComponent<TimePickerProps>(
ElTimePicker,
{
change: 'input',
}
)

export const TimePicker = connect(
TransformElTimePicker,
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -19619,6 +19619,11 @@ vue-frag@^1.1.4:
resolved "https://registry.yarnpkg.com/vue-frag/-/vue-frag-1.1.5.tgz#1158f92361dff2c312e00b8ca85334c329e566e7"
integrity sha512-g+PP9pjW1gnrmPjy2Sa5jK/bfxYHK8Hgt1sVs/Y/7KT+srGJUwtGNwXNTUvWv/zJ2yGcvJVEH98eIrICyZX9Ng==

vue-hoc@^0.4.7:
version "0.4.7"
resolved "https://registry.nlark.com/vue-hoc/download/vue-hoc-0.4.7.tgz#4d3322ba89b8b0e42b19045ef536c21d948a4fac"
integrity sha1-TTMiuom4sOQrGQRe9TbCHZSKT6w=

vue-hot-reload-api@^2.3.0:
version "2.3.4"
resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz#532955cc1eb208a3d990b3a9f9a70574657e08f2"
Expand Down

0 comments on commit 205e164

Please sign in to comment.