feat: add component style config

This commit is contained in:
bqy_fe 2021-07-07 22:21:59 +08:00
parent c99baf7132
commit 32ccceb338
43 changed files with 766 additions and 537 deletions

View File

@ -90,6 +90,10 @@ JSON.stringify(
.replace(/\"/g, "'")
```
## 部分功能演示
[![RHfBbn.gif](https://z3.ax1x.com/2021/07/07/RHfBbn.gif)](https://imgtu.com/i/RHfBbn)
## 浏览器支持
本地开发推荐使用`Chrome 80+` 浏览器

3
components.d.ts vendored
View File

@ -13,10 +13,7 @@ declare module 'vue' {
ElDropdown: typeof import('element-plus/es/el-dropdown')['default']
ElDropdownItem: typeof import('element-plus/es/el-dropdown-item')['default']
ElDropdownMenu: typeof import('element-plus/es/el-dropdown-menu')['default']
ElForm: typeof import('element-plus/es/el-form')['default']
ElFormItem: typeof import('element-plus/es/el-form-item')['default']
ElHeader: typeof import('element-plus/es/el-header')['default']
ElInput: typeof import('element-plus/es/el-input')['default']
ElMain: typeof import('element-plus/es/el-main')['default']
ElPopconfirm: typeof import('element-plus/es/el-popconfirm')['default']
ElPopover: typeof import('element-plus/es/el-popover')['default']

View File

@ -20,12 +20,12 @@
"prepare": "husky install"
},
"dependencies": {
"@vant/touch-emulator": "^1.3.0",
"@vueuse/core": "^5.0.3",
"@vueuse/integrations": "^5.0.3",
"@vant/touch-emulator": "^1.3.1",
"@vueuse/core": "^5.1.3",
"@vueuse/integrations": "^5.1.3",
"animate.css": "^4.1.1",
"axios": "^0.21.1",
"dayjs": "^1.10.5",
"dayjs": "^1.10.6",
"dexie": "^3.0.3",
"element-plus": "1.0.2-beta.54",
"lodash": "^4.17.21",
@ -44,8 +44,8 @@
"@commitlint/cli": "^12.1.4",
"@commitlint/config-conventional": "^12.1.4",
"@types/node": "^16.0.0",
"@typescript-eslint/eslint-plugin": "^4.28.1",
"@typescript-eslint/parser": "^4.28.1",
"@typescript-eslint/eslint-plugin": "^4.28.2",
"@typescript-eslint/parser": "^4.28.2",
"@vitejs/plugin-legacy": "^1.4.3",
"@vitejs/plugin-vue": "^1.2.4",
"@vitejs/plugin-vue-jsx": "^1.1.6",
@ -58,9 +58,9 @@
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-vue": "^7.12.1",
"eslint-plugin-vue": "^7.13.0",
"gh-pages": "^3.2.3",
"husky": "^7.0.0",
"husky": "^7.0.1",
"lint-staged": "^11.0.0",
"prettier": "^2.3.2",
"pretty-quick": "^3.1.1",
@ -70,11 +70,11 @@
"stylelint-config-standard": "^22.0.0",
"stylelint-order": "^4.1.0",
"typescript": "^4.3.5",
"vite": "2.3.8",
"vite-plugin-components": "^0.12.0",
"vite": "2.4.1",
"vite-plugin-components": "^0.12.2",
"vite-plugin-style-import": "^1.0.1",
"vite-plugin-windicss": "^1.2.0",
"vue-eslint-parser": "^7.7.2",
"vite-plugin-windicss": "^1.2.4",
"vue-eslint-parser": "^7.8.0",
"vue-tsc": "^0.2.0",
"windicss": "^3.1.4"
},

View File

@ -1,13 +1,13 @@
/*
* @Author:
* @Date: 2021-05-04 05:36:58
* @LastEditTime: 2021-07-04 17:21:34
* @LastEditTime: 2021-07-06 23:51:26
* @LastEditors:
* @Description:
* @FilePath: \vite-vue3-lowcode\preview\views\comp-render.tsx
*/
import { defineComponent, PropType } from 'vue'
import type { VisualEditorBlockData, VisualEditorConfig } from '@/visual-editor/visual-editor.utils'
import type { VisualEditorBlockData } from '@/visual-editor/visual-editor.utils'
import { visualConfig } from '@/visual.config'
export default defineComponent({
@ -21,7 +21,7 @@ export default defineComponent({
setup(props) {
return () =>
visualConfig.componentMap[props.element.componentKey].render({
size: {},
styles: props.element.styles || {},
props: props.element.props || {},
model: {},
block: props.element,

View File

@ -12,18 +12,13 @@ export default {
moduleName: 'baseWidgets',
label: '按钮',
preview: () => <Button type={'primary'}></Button>,
render: ({ props, block, size }) => {
render: ({ props, block, styles }) => {
const { registerRef } = useGlobalProperties()
return (
<Button
ref={(el) => registerRef(el, block._vid)}
style={{
height: size.height ? `${size.height}px` : null,
width: size.width ? `${size.width}px` : null
}}
{...props}
></Button>
<div style={styles}>
<Button ref={(el) => registerRef(el, block._vid)} {...props}></Button>
</div>
)
},
resize: {

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-07-04 16:50:19
* @LastEditTime: 2021-07-07 10:54:50
* @LastEditors:
* @Description: -
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\checkbox\index.tsx
@ -32,7 +32,7 @@ export default {
</Checkbox>
</CheckboxGroup>
),
render: ({ size, block, props }) => {
render: ({ styles, block, props }) => {
const { registerRef } = useGlobalProperties()
const state = reactive({
@ -41,29 +41,28 @@ export default {
})
return (
<Field
{...props}
modelValue={''}
style={{
width: size.width ? `${size.width}px` : null
}}
name={Array.isArray(props.name) ? [...props.name].pop() : props.name}
v-slots={{
input: () => (
<CheckboxGroup
ref={(el) => registerRef(el, block._vid)}
{...props}
v-model={state.checkList}
>
{props.options?.map((item) => (
<Checkbox name={item.value} style={{ marginBottom: '5px' }} shape="square">
{item.label}
</Checkbox>
))}
</CheckboxGroup>
)
}}
/>
<div style={styles}>
<Field
{...props}
modelValue={''}
name={Array.isArray(props.name) ? [...props.name].pop() : props.name}
v-slots={{
input: () => (
<CheckboxGroup
ref={(el) => registerRef(el, block._vid)}
{...props}
v-model={state.checkList}
>
{props.options?.map((item) => (
<Checkbox name={item.value} style={{ marginBottom: '5px' }} shape="square">
{item.label}
</Checkbox>
))}
</CheckboxGroup>
)
}}
/>
</div>
)
},
props: {

View File

@ -26,7 +26,7 @@ export default {
moduleName: 'baseWidgets',
label: '表单项类型 - 时间选择器',
preview: () => <Field name="datetimePicker" label="时间选择器" placeholder={'点击选择'}></Field>,
render: ({ size, block, props }) => {
render: ({ styles, block, props }) => {
const { registerRef } = useGlobalProperties()
const { attrs } = getCurrentInstance()!
@ -46,16 +46,13 @@ export default {
}
const PopupPicker = () => (
<>
<div style={styles}>
<Field
v-model={props.modelValue}
{...props}
readonly
clickable
onClick={() => (state.showPicker = true)}
style={{
width: size.width ? `${size.width}px` : null
}}
name={Array.isArray(props.name) ? [...props.name].pop() : props.name}
v-slots={{
input: () =>
@ -76,7 +73,7 @@ export default {
onCancel={() => (state.showPicker = false)}
/>
</Popup>
</>
</div>
)
return <PopupPicker />

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-06-25 08:49:31
* @LastEditTime: 2021-07-07 21:10:10
* @LastEditors:
* @Description: 线
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\divider\index.tsx
@ -21,20 +21,23 @@ export default {
moduleName: 'baseWidgets',
label: '分割线',
preview: () => <Divider style="width:190px"></Divider>,
render: ({ props, block }) => {
render: ({ props, block, styles }) => {
const { registerRef } = useGlobalProperties()
const style = {
width: '100%',
color: props['text-color'],
borderColor: props['divider-color']
}
return (
<Divider ref={(el) => registerRef(el, block._vid)} {...props} style={style}>
{{
default: () => props.text
}}
</Divider>
<div style={styles}>
<Divider ref={(el) => registerRef(el, block._vid)} {...props} style={style}>
{{
default: () => props.text
}}
</Divider>
</div>
)
},
props: {

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-07-04 16:53:22
* @LastEditTime: 2021-07-07 10:56:20
* @LastEditors:
* @Description:
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\image\index.tsx
@ -30,10 +30,14 @@ export default {
</div>
</div>
),
render: ({ props, block }) => {
render: ({ props, block, styles }) => {
const { registerRef } = useGlobalProperties()
return <Image ref={(el) => registerRef(el, block._vid)} {...props} />
return (
<div style={styles}>
<Image ref={(el) => registerRef(el, block._vid)} {...props} />
</div>
)
},
props: {
src: createEditorInputProp({

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-05-04 05:36:58
* @LastEditTime: 2021-07-03 09:45:56
* @LastEditTime: 2021-07-07 10:56:39
* @LastEditors:
* @Description: -
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\input\index.tsx
@ -18,7 +18,7 @@ export default {
preview: () => (
<Field name="用户名" label="用户名" labelWidth={50} colon placeholder="请输入用户名" />
),
render: ({ model, size, block, props, custom }) => {
render: ({ model, styles, block, props, custom }) => {
const { registerRef } = useGlobalProperties()
let rules = []
@ -27,18 +27,17 @@ export default {
} catch (e) {}
return (
<Field
ref={(el) => registerRef(el, block._vid)}
{...custom}
{...props}
{...model.default}
v-model={props.modelValue}
name={Array.isArray(props.name) ? [...props.name].pop() : props.name}
rules={rules}
style={{
width: size.width ? `${size.width}px` : null
}}
/>
<div style={styles}>
<Field
ref={(el) => registerRef(el, block._vid)}
{...custom}
{...props}
{...model.default}
v-model={props.modelValue}
name={Array.isArray(props.name) ? [...props.name].pop() : props.name}
rules={rules}
/>
</div>
)
},
events: [

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-05-04 05:36:58
* @LastEditTime: 2021-07-04 16:54:00
* @LastEditTime: 2021-07-07 10:56:56
* @LastEditors:
* @Description:
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\nav-bar\index.tsx
@ -19,19 +19,13 @@ export default {
preview: () => (
<NavBar title="标题" left-text="返回" right-text="按钮" left-arrow style={{ width: '100%' }} />
),
render: ({ props, size, block, custom }) => {
render: ({ props, styles, block, custom }) => {
const { registerRef } = useGlobalProperties()
return (
<NavBar
ref={(el) => registerRef(el, block._vid)}
placeholder
{...custom}
{...props}
style={{
width: size.width ? `${size.width}px` : null
}}
/>
<div style={styles}>
<NavBar ref={(el) => registerRef(el, block._vid)} placeholder {...custom} {...props} />
</div>
)
},
props: {

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-06-14 12:24:12
* @LastEditTime: 2021-07-04 16:54:32
* @LastEditTime: 2021-07-07 18:49:16
* @LastEditors:
* @Description:
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\notice-bar\index.tsx
@ -22,10 +22,14 @@ export default {
text={'在代码阅读过程中人们说脏话的频率是衡量代码质量的唯一标准。'}
/>
),
render: ({ block, props }) => {
render: ({ block, props, styles }) => {
const { registerRef } = useGlobalProperties()
return <NoticeBar ref={(el) => registerRef(el, block._vid)} {...props} />
return (
<div style={styles}>
<NoticeBar ref={(el) => registerRef(el, block._vid)} style={{ width: '100%' }} {...props} />
</div>
)
},
events: [
{ label: '点击通知栏时触发', value: 'click' },

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-07-05 10:18:29
* @LastEditTime: 2021-07-07 10:57:41
* @LastEditors:
* @Description: -
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\picker\index.tsx
@ -22,7 +22,7 @@ export default {
moduleName: 'baseWidgets',
label: '表单项类型 - 选择器',
preview: () => <Field name="picker" label="选择器" placeholder={'点击选择'}></Field>,
render: ({ size, block, props }) => {
render: ({ styles, block, props }) => {
const { registerRef } = useGlobalProperties()
const { attrs } = getCurrentInstance()!
@ -49,16 +49,13 @@ export default {
}
const PopupPicker = () => (
<>
<div style={styles}>
<Field
v-model={props.modelValue}
{...props}
readonly
clickable
onClick={() => (state.showPicker = true)}
style={{
width: size.width ? `${size.width}px` : null
}}
name={Array.isArray(props.name) ? [...props.name].pop() : props.name}
>
{{
@ -81,7 +78,7 @@ export default {
onCancel={() => (state.showPicker = false)}
/>
</Popup>
</>
</div>
)
return <PopupPicker />

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-06-12 22:18:48
* @LastEditTime: 2021-07-04 17:00:12
* @LastEditTime: 2021-07-07 10:58:10
* @LastEditors:
* @Description:
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\process\index.tsx
@ -20,10 +20,14 @@ export default {
moduleName: 'baseWidgets',
label: '进度条',
preview: () => <Progress style="width:190px" percentage={50} />,
render: ({ props }) => {
render: ({ props, styles }) => {
const RenderProgress = () => <Progress {...props} pivotText={props.pivotText || undefined} />
return <RenderProgress />
return (
<div style={styles}>
<RenderProgress />
</div>
)
},
props: {
percentage: createEditorInputNumberProp({ label: '进度百分比', defaultValue: 50 }),

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-07-04 17:00:24
* @LastEditTime: 2021-07-07 10:59:56
* @LastEditors:
* @Description: -
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\radio\index.tsx
@ -27,33 +27,32 @@ export default {
<Radio name="2">two</Radio>
</RadioGroup>
),
render: ({ size, block, props }) => {
render: ({ styles, block, props }) => {
const { registerRef } = useGlobalProperties()
return (
<Field
{...props}
modelValue={''}
style={{
width: size.width ? `${size.width}px` : null
}}
name={Array.isArray(props.name) ? [...props.name].pop() : props.name}
v-slots={{
input: () => (
<RadioGroup
ref={(el) => registerRef(el, block._vid)}
{...props}
v-model={props.modelValue}
>
{props.options?.map((item) => (
<Radio name={item.value} style={{ marginBottom: '5px' }}>
{item.label}
</Radio>
))}
</RadioGroup>
)
}}
/>
<div style={styles}>
<Field
{...props}
modelValue={''}
name={Array.isArray(props.name) ? [...props.name].pop() : props.name}
v-slots={{
input: () => (
<RadioGroup
ref={(el) => registerRef(el, block._vid)}
{...props}
v-model={props.modelValue}
>
{props.options?.map((item) => (
<Radio name={item.value} style={{ marginBottom: '5px' }}>
{item.label}
</Radio>
))}
</RadioGroup>
)
}}
/>
</div>
)
},
props: {

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-07-03 09:38:17
* @LastEditTime: 2021-07-07 11:00:22
* @LastEditors:
* @Description: -
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\rate\index.tsx
@ -29,27 +29,26 @@ export default {
v-slots={{ input: () => <Rate modelValue={3} /> }}
></Field>
),
render: ({ size, block, props }) => {
render: ({ styles, block, props }) => {
const { registerRef } = useGlobalProperties()
return (
<Field
{...props}
modelValue={''}
style={{
width: size.width ? `${size.width}px` : null
}}
name={Array.isArray(props.name) ? [...props.name].pop() : props.name}
v-slots={{
input: () => (
<Rate
ref={(el) => registerRef(el, block._vid)}
{...props}
v-model={props.modelValue}
></Rate>
)
}}
/>
<div style={styles}>
<Field
{...props}
modelValue={''}
name={Array.isArray(props.name) ? [...props.name].pop() : props.name}
v-slots={{
input: () => (
<Rate
ref={(el) => registerRef(el, block._vid)}
{...props}
v-model={props.modelValue}
></Rate>
)
}}
/>
</div>
)
},
props: {

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-07-03 09:38:29
* @LastEditTime: 2021-07-07 11:00:37
* @LastEditors:
* @Description: -
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\slider\index.tsx
@ -29,27 +29,26 @@ export default {
v-slots={{ input: () => <Slider modelValue={3} /> }}
></Field>
),
render: ({ size, block, props }) => {
render: ({ styles, block, props }) => {
const { registerRef } = useGlobalProperties()
return (
<Field
{...props}
modelValue={''}
style={{
width: size.width ? `${size.width}px` : null
}}
name={Array.isArray(props.name) ? [...props.name].pop() : props.name}
v-slots={{
input: () => (
<Slider
ref={(el) => registerRef(el, block._vid)}
{...props}
v-model={props.modelValue}
></Slider>
)
}}
/>
<div style={styles}>
<Field
{...props}
modelValue={''}
name={Array.isArray(props.name) ? [...props.name].pop() : props.name}
v-slots={{
input: () => (
<Slider
ref={(el) => registerRef(el, block._vid)}
{...props}
v-model={props.modelValue}
></Slider>
)
}}
/>
</div>
)
},
props: {

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-07-03 09:38:50
* @LastEditTime: 2021-07-07 11:00:52
* @LastEditors:
* @Description: ' -
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\stepper\index.tsx
@ -30,27 +30,26 @@ export default {
v-slots={{ input: () => <Stepper modelValue={3} /> }}
></Field>
),
render: ({ size, block, props }) => {
render: ({ styles, block, props }) => {
const { registerRef } = useGlobalProperties()
return (
<Field
{...props}
modelValue={''}
style={{
width: size.width ? `${size.width}px` : null
}}
name={Array.isArray(props.name) ? [...props.name].pop() : props.name}
v-slots={{
input: () => (
<Stepper
ref={(el) => registerRef(el, block._vid)}
{...props}
v-model={props.modelValue}
></Stepper>
)
}}
/>
<div style={styles}>
<Field
{...props}
modelValue={''}
name={Array.isArray(props.name) ? [...props.name].pop() : props.name}
v-slots={{
input: () => (
<Stepper
ref={(el) => registerRef(el, block._vid)}
{...props}
v-model={props.modelValue}
></Stepper>
)
}}
/>
</div>
)
},
props: {

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-06-14 12:24:12
* @LastEditTime: 2021-07-04 17:01:36
* @LastEditTime: 2021-07-07 11:01:14
* @LastEditors:
* @Description:
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\swipe\index.tsx
@ -29,23 +29,25 @@ export default {
<SwipeItem style={swipeItemStyle}>4</SwipeItem>
</Swipe>
),
render: ({ block, props }) => {
render: ({ block, props, styles }) => {
const { registerRef } = useGlobalProperties()
return (
<Swipe
ref={(el) => registerRef(el, block._vid)}
{...props}
style={{ height: `${props.height}px` }}
>
{props.images?.map((item) => (
<>
<SwipeItem key={item}>
<img style={{ width: '100%' }} src={item} />
</SwipeItem>
</>
))}
</Swipe>
<div style={styles}>
<Swipe
ref={(el) => registerRef(el, block._vid)}
{...props}
style={{ height: `${props.height}px` }}
>
{props.images?.map((item) => (
<>
<SwipeItem key={item}>
<img style={{ width: '100%' }} src={item} />
</SwipeItem>
</>
))}
</Swipe>
</div>
)
},
props: createFieldProps(),

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-07-04 17:02:06
* @LastEditTime: 2021-07-07 11:01:29
* @LastEditors:
* @Description: -
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\switch\index.tsx
@ -24,27 +24,26 @@ export default {
preview: () => (
<Field name="switch" label="开关" v-slots={{ input: () => <Switch size={20} /> }} />
),
render: ({ size, block, props }) => {
render: ({ styles, block, props }) => {
const { registerRef } = useGlobalProperties()
return (
<Field
{...props}
modelValue={''}
style={{
width: size.width ? `${size.width}px` : null
}}
name={Array.isArray(props.name) ? [...props.name].pop() : props.name}
v-slots={{
input: () => (
<Switch
ref={(el) => registerRef(el, block._vid)}
{...props}
v-model={props.modelValue}
/>
)
}}
/>
<div style={styles}>
<Field
{...props}
modelValue={''}
name={Array.isArray(props.name) ? [...props.name].pop() : props.name}
v-slots={{
input: () => (
<Switch
ref={(el) => registerRef(el, block._vid)}
{...props}
v-model={props.modelValue}
/>
)
}}
/>
</div>
)
},
props: {

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-06-25 08:51:29
* @LastEditTime: 2021-07-07 11:01:54
* @LastEditors:
* @Description:
* @FilePath: \vite-vue3-lowcode\src\packages\base-widgets\text\index.tsx
@ -21,7 +21,7 @@ export default {
moduleName: 'baseWidgets',
label: '文本',
preview: () => <span></span>,
render: ({ props, block }) => {
render: ({ props, block, styles }) => {
const { registerRef } = useGlobalProperties()
return (
@ -30,7 +30,8 @@ export default {
style={{
color: props.color,
fontSize: `${parseFloat(props.size)}px`,
fontFamily: props.font
fontFamily: props.font,
...styles
}}
>
{props.text || '默认文本'}

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-06-27 18:01:21
* @LastEditTime: 2021-07-07 21:23:23
* @LastEditors:
* @Description:
* @FilePath: \vite-vue3-lowcode\src\packages\container-component\form\index.tsx
@ -27,7 +27,7 @@ export default {
</div>
</Form>
),
render: function ({ props, custom, block }) {
render: function ({ props, styles, block }) {
const { slots } = getCurrentInstance()!
const { registerRef } = useGlobalProperties()
@ -36,9 +36,16 @@ export default {
}
return (
<Form ref={(el) => registerRef(el, block._vid)} {...custom} {...props} onSubmit={onSubmit}>
{renderSlot(slots, 'default')}
</Form>
<div style={styles}>
<Form
ref={(el) => registerRef(el, block._vid)}
{...props}
style={{ width: '100%' }}
onSubmit={onSubmit}
>
{renderSlot(slots, 'default')}
</Form>
</div>
)
},
resize: {

View File

@ -6,5 +6,6 @@
* @update: 2021/5/2 16:15
*/
.van-row {
width: 100%;
padding: 2px;
}

View File

@ -2,7 +2,7 @@ import { Col, Row } from 'vant'
import { renderSlot, getCurrentInstance } from 'vue'
import { createEditorInputProp, createEditorSelectProp } from '@/visual-editor/visual-editor.props'
import type { VisualEditorComponent } from '@/visual-editor/visual-editor.utils'
import styles from './index.module.scss'
import styleModule from './index.module.scss'
import { useGlobalProperties } from '@/hooks/useGlobalProperties'
interface SlotItem {
@ -36,7 +36,7 @@ export default {
<Col span="8">span: 8</Col>
</Row>
),
render: function ({ props, size, block, custom }) {
render: function ({ props, styles, block, custom }) {
const { slots } = getCurrentInstance()!
const { registerRef } = useGlobalProperties()
@ -51,27 +51,25 @@ export default {
}
return (
<Row
ref={(el) => registerRef(el, block._vid)}
{...custom}
{...props}
style={{
height: size.height ? `${size.height}px` : null,
width: size.width ? `${size.width}px` : null
}}
class={styles.vanRow}
>
{Object.values(Object.keys(props.slots).length ? props.slots : createSlots('12:12'))
?.filter((item) => typeof item !== 'string')
.map((spanItem: SlotItem, spanIndex) => {
slotsTemp[block._vid][`slot${spanIndex}`] = spanItem
return (
<>
<Col span={spanItem.span}>{renderSlot(slots, `slot${spanIndex}`)}</Col>
</>
)
})}
</Row>
<div style={styles}>
<Row
ref={(el) => registerRef(el, block._vid)}
{...custom}
{...props}
class={styleModule.vanRow}
>
{Object.values(Object.keys(props.slots).length ? props.slots : createSlots('12:12'))
?.filter((item) => typeof item !== 'string')
.map((spanItem: SlotItem, spanIndex) => {
slotsTemp[block._vid][`slot${spanIndex}`] = spanItem
return (
<>
<Col span={spanItem.span}>{renderSlot(slots, `slot${spanIndex}`)}</Col>
</>
)
})}
</Row>
</div>
)
},
resize: {

View File

@ -0,0 +1,7 @@
.format-input-number {
:global {
.el-input-group__append {
padding: 0 10px;
}
}
}

View File

@ -0,0 +1,75 @@
/*
* @Author:
* @Date: 2021-07-06 22:14:13
* @LastEditTime: 2021-07-07 16:32:50
* @LastEditors:
* @Description:
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\common\format-input-number\index.tsx
*/
import { defineComponent } from 'vue'
import { ElInput } from 'element-plus'
import type { PropType } from 'vue'
import { useVModel } from '@vueuse/core'
import styles from './index.module.scss'
export const FormatInputNumber = defineComponent({
props: {
modelValue: {
type: [String] as PropType<string>,
default: ''
},
symbol: {
// 符号
type: String as PropType<string>,
default: 'px'
},
max: {
type: [Number],
default: 100
},
min: {
type: [Number],
default: 0
}
},
emits: ['update:modelValue'],
setup(props, { attrs }) {
const modelValue = useVModel(props, 'modelValue')
const onInput = (val) => {
let num = parseFloat(`${val}`.replace(/[^0-9]/gi, ''))
num = Number.isNaN(num) ? 0 : num
num = Math.max(props.min, num)
num = Math.min(props.max, num)
modelValue.value = num + props.symbol
}
const increment = () => {
onInput(parseFloat(modelValue.value) + 1)
}
const cutdown = () => {
onInput(Math.max(props.min, parseFloat(modelValue.value) - 1))
}
return () => (
<div class={styles.formatInputNumber}>
<ElInput
model-value={modelValue.value}
placeholder={'请输入内容'}
{...attrs}
onInput={onInput}
>
{{
append: () => (
<div class={'flex flex-col'}>
<div onClick={increment} class={'el-icon-arrow-up cursor-pointer'}></div>
<div onClick={cutdown} class={'el-icon-arrow-down cursor-pointer'}></div>
</div>
)
}}
</ElInput>
</div>
)
}
})

View File

@ -107,7 +107,7 @@ export default defineComponent({
.logo {
width: 60px;
height: 60px;
background-image: url('../../../assets/logo.png');
background-image: url('@/assets/logo.png');
background-repeat: no-repeat;
background-size: contain;
}

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-06-01 13:22:14
* @LastEditTime: 2021-07-04 21:36:26
* @LastEditTime: 2021-07-06 20:32:39
* @LastEditors:
* @Description:
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\left-aside\components\base-widgets\index.tsx
@ -29,7 +29,7 @@ export default defineComponent({
console.log('当前拖拽的组件:', comp)
const newComp = cloneDeep(comp)
newComp._vid = Date.now()
return createNewBlock({ left: 0, top: 0, component: newComp })
return createNewBlock(newComp)
}
return () => (

View File

@ -28,7 +28,7 @@ export default defineComponent({
console.log('当前拖拽的组件:', comp)
const newComp = cloneDeep(comp)
newComp._vid = Date.now()
return createNewBlock({ left: 0, top: 0, component: newComp })
return createNewBlock(newComp)
}
return () => (

View File

@ -1,7 +1,7 @@
<!--
* @Author: 卜启缘
* @Date: 2021-06-24 18:36:03
* @LastEditTime: 2021-07-04 19:48:28
* @LastEditTime: 2021-07-07 21:48:03
* @LastEditors: 卜启缘
* @Description: 接口请求
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\left-aside\components\data-source\data-fetch.vue
@ -50,7 +50,7 @@
</template>
<script setup lang="tsx">
import { reactive, computed } from 'vue'
import { reactive, ref, computed } from 'vue'
import {
ElForm,
ElFormItem,
@ -71,7 +71,6 @@ import { useImportSwaggerJsonModal } from './utils'
interface IState {
activeNames: string[]
ruleFormRef: any
ruleForm: FetchApiItem
}
@ -108,10 +107,10 @@ const createEmptyApiItem = (): FetchApiItem => ({
recv: '' //
}
})
const ruleFormRef = ref<InstanceType<typeof ElForm>>()
const state = reactive<IState>({
activeNames: [],
ruleFormRef: null,
ruleForm: createEmptyApiItem()
})
@ -138,7 +137,7 @@ const showModelMoal = () => {
content: () => (
<ElForm
model={state.ruleForm}
ref={(el) => el && (state.ruleFormRef = el)}
ref={ruleFormRef}
label-width="100px"
size={'mini'}
rules={rules}
@ -202,7 +201,7 @@ const showModelMoal = () => {
),
onConfirm: () => {
return new Promise((resolve, reject) => {
state.ruleFormRef.validate((valid) => {
ruleFormRef.value?.validate((valid) => {
if (valid) {
if (isEdit.value) {
updateFetchApi(cloneDeep(state.ruleForm))

View File

@ -1,7 +1,7 @@
<!--
* @Author: 卜启缘
* @Date: 2021-06-24 18:36:03
* @LastEditTime: 2021-07-04 19:49:52
* @LastEditTime: 2021-07-07 21:55:53
* @LastEditors: 卜启缘
* @Description: 数据模型管理
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\left-aside\components\data-source\data-model.vue
@ -45,7 +45,7 @@
</template>
<script setup lang="tsx">
import { reactive, computed } from 'vue'
import { reactive, ref, computed } from 'vue'
import {
ElForm,
ElFormItem,
@ -65,7 +65,6 @@ import { useImportSwaggerJsonModal } from './utils'
interface IState {
activeNames: string[]
ruleFormRef: any
ruleForm: VisualEditorModel
}
@ -96,9 +95,10 @@ const createEmptyModel = () => ({
entitys: [createEmptyEntity()]
})
const ruleFormRef = ref<InstanceType<typeof ElForm>>()
const state = reactive<IState>({
activeNames: [],
ruleFormRef: null,
ruleForm: createEmptyModel()
})
@ -128,12 +128,7 @@ const showModelMoal = () => {
width: 600
},
content: () => (
<ElForm
model={state.ruleForm}
ref={(el) => el && (state.ruleFormRef = el)}
label-width="100px"
size={'mini'}
>
<ElForm model={state.ruleForm} ref={ruleFormRef} label-width="100px" size={'mini'}>
<ElFormItem
label="数据源名称"
prop="name"
@ -211,7 +206,7 @@ const showModelMoal = () => {
),
onConfirm: () => {
return new Promise((resolve, reject) => {
state.ruleFormRef.validate((valid) => {
ruleFormRef.value?.validate((valid) => {
if (valid) {
if (isEdit.value) {
updateModel(state.ruleForm)

View File

@ -1,13 +1,13 @@
<!--
* @Author: 卜启缘
* @Date: 2021-06-24 18:36:03
* @LastEditTime: 2021-07-04 21:36:14
* @LastEditTime: 2021-07-07 14:12:15
* @LastEditors: 卜启缘
* @Description: 数据源管理
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\left-aside\components\data-source\index.vue
-->
<template>
<el-tabs type="border-card" stretch>
<el-tabs type="border-card" stretch class="data-source">
<el-tab-pane label="数据模型" lazy>
<data-model />
</el-tab-pane>
@ -30,9 +30,16 @@ import DataFetch from './data-fetch.vue'
</script>
<style lang="scss" scoped>
::v-deep(.el-tabs__header) {
position: sticky;
top: 0;
z-index: 10;
.data-source :deep {
.el-tabs__header {
position: sticky;
top: 0;
z-index: 10;
}
.el-tabs__content {
contain: layout;
content-visibility: auto;
}
}
</style>

View File

@ -47,33 +47,14 @@
</span>
</template>
</el-tree>
<el-dialog
v-model="dialogFormVisible"
width="380px"
:title="operatePageData ? '编辑页面' : '新增页面'"
>
<el-form ref="ruleForm" :model="form" :rules="rules">
<el-form-item prop="title" label="页面标题" label-width="80px">
<el-input v-model="form.title" autocomplete="off" />
</el-form-item>
<el-form-item prop="path" label="页面路径" label-width="80px">
<el-input v-model="form.path" autocomplete="off" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogFormVisible = false"> </el-button>
<el-button type="primary" @click="onSubmit"> </el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts">
import { defineComponent, reactive, computed, toRefs } from 'vue'
<script lang="tsx">
import { defineComponent, reactive, ref, computed, toRefs } from 'vue'
import { useVisualData, createNewPage } from '@/visual-editor/hooks/useVisualData'
import { useRouter, useRoute } from 'vue-router'
import { ElMessage } from 'element-plus'
import { ElMessage, ElForm, ElFormItem, ElInput } from 'element-plus'
import { useModal } from '@/visual-editor/hooks/useModal'
const rules = {
title: [{ required: true, message: '请输入页面标题', trigger: 'blur' }],
@ -91,14 +72,14 @@ export default defineComponent({
const { jsonData, setCurrentPage, deletePage, updatePage, incrementPage } = useVisualData()
const ruleFormRef = ref<InstanceType<typeof ElForm>>()
const state = reactive({
ruleForm: null as any,
defaultProps: {
children: 'children',
label: 'title'
},
currentNodeKey: route.path,
dialogFormVisible: false, //
operatePageData: null as any, //
form: {
//
@ -120,6 +101,56 @@ export default defineComponent({
setCurrentPage(data.path)
router.push(data.path)
}
/**
* @description 显示新增/编辑模态框
*/
const showOparateModal = () =>
useModal({
title: state.operatePageData ? '编辑页面' : '新增页面',
props: {
width: 380
},
content: () => (
<ElForm ref={ruleFormRef} model={state.form} rules={rules}>
<ElFormItem prop={'title'} label={'页面标题'} labelWidth={'80px'}>
<ElInput v-model={state.form.title} />
</ElFormItem>
<ElFormItem prop={'path'} label={'页面路径'} labelWidth={'80px'}>
<ElInput v-model={state.form.path} />
</ElFormItem>
</ElForm>
),
onConfirm: () => {
return new Promise((resolve, reject) => {
ruleFormRef.value?.validate(async (valid) => {
if (valid) {
const { title, path } = state.form
if ([title.trim(), path.trim()].includes('')) {
return ElMessage.error('标题或路径不能为空!')
}
if (state.operatePageData) {
updatePage({
newPath: path,
oldPath: state.operatePageData.path || path,
page: { title }
})
await router.replace(path)
state.currentNodeKey = path
} else {
incrementPage(path, createNewPage({ title }))
}
resolve(true)
} else {
console.log('error submit!!')
reject()
return false
}
})
})
}
})
//
const addPage = () => {
state.operatePageData = null
@ -127,7 +158,7 @@ export default defineComponent({
title: '',
path: ''
}
state.dialogFormVisible = true
showOparateModal()
}
//
const editPage = (data) => {
@ -136,7 +167,7 @@ export default defineComponent({
title: data.title,
path: data.path
}
state.dialogFormVisible = true
showOparateModal()
console.log('子页面数据:', data)
}
//
@ -149,39 +180,10 @@ export default defineComponent({
console.log('设置该页面为默认页面', data)
}
//
const onSubmit = () => {
state.ruleForm?.validate(async (valid) => {
if (valid) {
const { title, path } = state.form
if (title.trim() == '' || path.trim() == '') {
return ElMessage.error('标题或路径不能为空!')
}
if (state.operatePageData) {
updatePage({
newPath: path,
oldPath: state.operatePageData.path || path,
page: { title }
})
await router.replace(path)
state.currentNodeKey = path
} else {
incrementPage(path, createNewPage({ title }))
}
state.dialogFormVisible = false
} else {
console.log('error submit!!')
return false
}
})
}
return {
...toRefs(state),
pages,
rules,
setCurrentPage,
onSubmit,
setDefaultPage,
handleNodeClick,
addPage,

View File

@ -1,7 +1,7 @@
<!--
* @Author: 卜启缘
* @Date: 2021-06-24 00:35:17
* @LastEditTime: 2021-07-04 21:44:20
* @LastEditTime: 2021-07-07 14:02:29
* @LastEditors: 卜启缘
* @Description: 左侧边栏
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\left-aside\index.vue
@ -55,6 +55,7 @@ export default defineComponent({
<style lang="scss" scoped>
.left-aside {
height: 100%;
contain: layout;
> ::v-deep(.el-tabs__header) {
margin-right: 0;

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-06-11 18:08:01
* @LastEditTime: 2021-06-25 08:52:10
* @LastEditTime: 2021-07-07 21:53:06
* @LastEditors:
* @Description:
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\animate\Animate.tsx
@ -18,7 +18,7 @@ import { useAnimate } from '@/hooks/useAnimate'
export const Animate = defineComponent({
setup() {
const { currentBlock } = useVisualData()
const target = ref(null)
const target = ref<InstanceType<typeof HTMLDivElement>>()
const state = reactive({
activeName: '',

View File

@ -1,29 +1,32 @@
/*
* @Author:
* @Date: 2021-06-10 16:23:06
* @LastEditTime: 2021-07-02 22:02:53
* @LastEditTime: 2021-07-07 19:36:45
* @LastEditors:
* @Description:
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\attr-editor\AttrEditor.tsx
*/
import { defineComponent, computed } from 'vue'
import { defineComponent, computed, watch } from 'vue'
import {
ElColorPicker,
ElForm,
ElFormItem,
ElInput,
ElInputNumber,
ElOption,
ElSelect,
ElSwitch,
ElPopover,
ElCascader
ElCascader,
ElInputNumber,
ElRadioGroup,
ElRadioButton
} from 'element-plus'
import { VisualEditorProps, VisualEditorPropsType } from '@/visual-editor/visual-editor.props'
import { TablePropEditor, CrossSortableOptionsEditor } from './components'
import { useDotProp } from '@/visual-editor/hooks/useDotProp'
import { useVisualData } from '@/visual-editor/hooks/useVisualData'
import { cloneDeep } from 'lodash'
import { FormatInputNumber } from '@/visual-editor/components/common/format-input-number'
export const AttrEditor = defineComponent({
setup() {
@ -33,6 +36,36 @@ export const AttrEditor = defineComponent({
*/
const models = computed(() => cloneDeep(jsonData.models))
const compPaddingAttrs = ['paddingTop', 'paddingLeft', 'paddingRight', 'paddingBottom']
/**
* @description padding值的变化
*/
watch(
compPaddingAttrs.map((item) => () => currentBlock.value.styles?.[item]),
(val: string[]) => {
const isSame = val.every((item) => currentBlock.value.styles?.tempPadding == item)
if (isSame || new Set(val).size === 1) {
if (Reflect.has(currentBlock.value, 'styles')) {
currentBlock.value.styles.tempPadding = val[0]
}
} else {
currentBlock.value.styles.tempPadding = ''
}
}
)
/**
* @description padding变化时进行的操作
*/
const compPadding = computed({
get: () => currentBlock.value.styles?.tempPadding,
set(val) {
compPaddingAttrs.forEach((item) => (currentBlock.value.styles[item] = val))
currentBlock.value.styles.tempPadding = val
}
})
const renderEditor = (propName: string, propConfig: VisualEditorProps) => {
const { propObj, prop } = useDotProp(currentBlock.value.props, propName)
@ -98,9 +131,7 @@ export const AttrEditor = defineComponent({
content={`你可以利用该组件ID。对该组件进行获取和设置其属性组件可用属性可在控制台输入$$refs.${currentBlock.value._vid} 进行查看`}
>
{{
reference: () => (
<i style={{ marginLeft: '6px' }} class={'el-icon-warning-outline'}></i>
)
reference: () => <i class={'el-icon-warning-outline ml-6px'}></i>
}}
</ElPopover>
</ElFormItem>
@ -117,8 +148,8 @@ export const AttrEditor = defineComponent({
propConfig.labelPosition == 'top'
? {
display: 'flex',
'flex-direction': 'column',
'align-items': 'flex-start'
flexDirection: 'column',
alignItems: 'flex-start'
}
: {}
}
@ -142,6 +173,50 @@ export const AttrEditor = defineComponent({
</>
))
)
content.push(
<ElFormItem label={'组件对齐方式'} labelWidth={'90px'}>
<ElRadioGroup v-model={currentBlock.value.styles.justifyContent} size="mini">
<ElRadioButton label="flex-start"></ElRadioButton>
<ElRadioButton label="center"></ElRadioButton>
<ElRadioButton label="flex-end"></ElRadioButton>
</ElRadioGroup>
</ElFormItem>
)
content.push(
<>
<ElFormItem class={'flex flex-col justify-start'}>
{{
label: () => (
<div class={'flex justify-between mb-2'}>
<div></div>
<FormatInputNumber v-model={compPadding.value} class={'!w-100px'} />
</div>
),
default: () => (
<div class={'grid grid-cols-3 gap-2 w-full bg-gray-100 p-20px items-center'}>
<FormatInputNumber
v-model={currentBlock.value.styles.paddingTop}
class={'!w-100px col-span-full col-start-2'}
/>
<FormatInputNumber
v-model={currentBlock.value.styles.paddingLeft}
class={'!w-100px col-span-1'}
/>
<div class={'bg-white col-span-1 h-40px'}></div>
<FormatInputNumber
v-model={currentBlock.value.styles.paddingRight}
class={'!w-100px col-span-1'}
/>
<FormatInputNumber
v-model={currentBlock.value.styles.paddingBottom}
class={'!w-100px col-span-full col-start-2'}
/>
</div>
)
}}
</ElFormItem>
</>
)
}
}
}

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-06-24 11:01:45
* @LastEditTime: 2021-07-04 19:44:10
* @LastEditTime: 2021-07-07 21:07:07
* @LastEditors:
* @Description: -
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\right-attribute-panel\components\event-action\index.tsx
@ -37,7 +37,7 @@ interface IState {
const createEmptyActionHandle = () => ({
key: generateUUID(),
name: '',
link: ''
link: []
})
/**
@ -57,7 +57,7 @@ export const EventAction = defineComponent({
* @description
*/
const isEdit = computed(() =>
currentBlock.value.actions.some((item) => item.key === state.ruleForm.key)
currentBlock.value.actions?.some((item) => item.key === state.ruleForm.key)
)
const state = reactive<IState>({
@ -105,18 +105,16 @@ export const EventAction = defineComponent({
])
/**
*
* @description
*/
const getActionPath = (link: string[]) => {
let result = ''
const maxLength = link.length - 1
link.reduce((prev, curr, index) => {
const target = prev.find((item) => item.value == curr)
const append = maxLength !== index ? ' => ' : ''
result += target?.label + append
const result: string[] = []
link.reduce((prev, curr) => {
const target = prev?.find((item) => item.value == curr)
result.push(`${target?.label}`)
return target?.children
}, actionOptions.value)
return result
return result.join(' => ')
}
/**
@ -176,7 +174,7 @@ export const EventAction = defineComponent({
rules={[{ required: true, message: '请选择事件', trigger: 'change' }]}
>
<ElSelect v-model={state.ruleForm.event} class={'w-full'}>
{currentBlock.value.events.map((eventItem) => (
{currentBlock.value.events?.map((eventItem) => (
<ElOption
key={eventItem.value}
label={eventItem.label}
@ -275,7 +273,12 @@ export const EventAction = defineComponent({
return () => (
<>
<ElButton onClick={addActionItem} type={'primary'} size={'mini'}>
<ElButton
onClick={addActionItem}
disabled={!currentBlock.value.actions}
type={'primary'}
size={'mini'}
>
</ElButton>

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-05-04 05:36:58
* @LastEditTime: 2021-07-04 17:23:02
* @LastEditTime: 2021-07-07 16:45:34
* @LastEditors:
* @Description:
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\simulator-editor\comp-render.tsx
@ -21,7 +21,7 @@ export default defineComponent({
setup(props) {
return () =>
visualConfig.componentMap[props.element.componentKey].render({
size: {},
styles: props.element.styles || {},
props: props.element.props || {},
model: {},
block: props.element,

View File

@ -259,10 +259,10 @@ export default defineComponent({
}
.simulator-editor {
width: 560px;
height: 640px;
min-width: 560px;
padding: 10px 100px;
width: 660px;
height: 740px;
min-width: 660px;
padding: 60px 150px 0;
overflow: hidden auto;
background: #fafafa;
border-radius: 5px;

View File

@ -1,7 +1,7 @@
/*
* @Author:
* @Date: 2021-06-01 09:45:21
* @LastEditTime: 2021-07-02 20:25:58
* @LastEditTime: 2021-07-07 21:45:41
* @LastEditors:
* @Description:
* @FilePath: \vite-vue3-lowcode\src\visual-editor\types\index.d.ts
@ -13,3 +13,18 @@ declare type LabelValue = {
}
declare type LabelValueOptions = OptionItem[]
declare module '@vue/runtime-core' {
export interface ComponentCustomProperties {
$$refs: any
}
}
declare module '@vue/runtime-dom' {
export interface CSSProperties {
/** 临时padding变量. */
tempPadding?: string
}
}
export {}

View File

@ -31,7 +31,7 @@ const ServiceComponent = defineComponent({
props: { option: { type: Object as PropType<DropdownServiceOption>, required: true } },
setup(props) {
const ctx = getCurrentInstance()!
const el = ref({} as HTMLDivElement)
const el = ref<InstanceType<typeof HTMLDivElement>>()
const state = reactive({
option: props.option,
@ -86,7 +86,7 @@ const ServiceComponent = defineComponent({
Object.assign(ctx.proxy, { service })
const onMousedownDocument = (e: MouseEvent) => {
if (!el.value.contains(e.target as HTMLElement)) {
if (!el.value?.contains(e.target as HTMLElement)) {
methods.hide()
}
}

View File

@ -1,5 +1,6 @@
import type { VisualEditorProps } from './visual-editor.props'
import { inject, provide } from 'vue'
import type { CSSProperties } from 'vue'
import { useDotProp } from '@/visual-editor/hooks/useDotProp'
import type { RequestEnum, ContentTypeEnum } from '@/enums/httpEnum'
@ -7,24 +8,32 @@ import type { RequestEnum, ContentTypeEnum } from '@/enums/httpEnum'
* @description
*/
export interface VisualEditorBlockData {
_vid: string // 组件id 时间戳
moduleName: keyof ComponentModules // 组件所属的模块(基础组件、容器组件)
componentKey: string // 映射 VisualEditorConfig 中 componentMap 的 component对象
label: string // 组件标签名称
top: number // 组件的top定位
left: number // 组件的left定位
adjustPosition: boolean // 是否需要调整位置
focus: boolean // 当前是否为选中状态
zIndex: number // z-index值
width: number // 组件宽度
height: number // 组件高度
hasResize: boolean // 是否调整过宽度或者高度
props: Record<string, any> // 组件的设计属性
model: Record<string, string> // 绑定的字段
slotName?: string // 组件唯一标识
animations?: Animation[] // 动画集
actions: Action[] // 组件动作集合
events: { label: string; value: string }[] // 组件事件集合
/** 组件id 时间戳, 组件唯一标识 */
_vid: string
/** 组件所属的模块(基础组件、容器组件) */
moduleName: keyof ComponentModules
/** 映射 VisualEditorConfig 中 componentMap 的 component对象 */
componentKey: string
/** 组件标签名称 */
label: string
/** 是否需要调整位置 */
adjustPosition: boolean
/** 当前是否为选中状态 */
focus: boolean
/** 当前组件的样式 */
styles: CSSProperties
/** 是否调整过宽度或者高度 */
hasResize: boolean
/** 组件的设计属性 */
props: Record<string, any>
/** 绑定的字段 */
model: Record<string, string>
/** 动画集 */
animations?: Animation[]
/** 组件动作集合 */
actions: Action[]
/** 组件事件集合 */
events: { label: string; value: string }[]
[prop: string]: any
}
/**
@ -33,7 +42,7 @@ export interface VisualEditorBlockData {
export interface ActionHandle {
key: string
name: string
link: string
link: string[]
data?: {
bind?: string
recv?: string
@ -53,18 +62,25 @@ export interface Action {
* @description
*/
export interface PageConfig {
bgImage: string // 背景图片
bgColor: string // 背景颜色
/** 背景图片 */
bgImage: string
/** 背景颜色 */
bgColor: string
}
/**
* @description
*/
export interface VisualEditorPage {
title: string // 页面标题
path: string // 页面路径
isDefault?: boolean // 404是重定向到默认页面
config: PageConfig // 页面配置
blocks: VisualEditorBlockData[] // 当前页面的所有组件
/** 页面标题 */
title: string
/** 页面路径 */
path: string
/** 404是重定向到默认页面 */
isDefault?: boolean
/** 页面配置 */
config: PageConfig
/** 当前页面的所有组件 */
blocks: VisualEditorBlockData[]
}
/**
* @description =>
@ -76,34 +92,48 @@ export interface VisualEditorPages {
* @description
*/
export type EntityType = {
key: string // 绑定的字段 输入
name: string // 实体名称 输入
type: string // 数据类型 选择
value: string // 默认值 输入
/** 绑定的字段 输入 */
key: string
/** 实体名称 输入 */
name: string
/** 数据类型 选择 */
type: string
/** 默认值 输入 */
value: string
}
/**
* @description
*/
export interface VisualEditorModel {
name: string // 数据源名称
key: string // 绑定的字段 该字段创建的时候生成
entitys: EntityType[] // 实体集合
/** 数据源名称 */
name: string
/** 绑定的字段 该字段创建的时候生成 */
key: string
/** 实体集合 */
entitys: EntityType[]
}
/**
* @description
*/
export interface FetchApiItem {
key: string // 随机生成的key
name: string // 当前api名字
/** 随机生成的key */
key: string
/** 随机生成的key */
name: string
options: {
url: string // 请求的url
method: keyof typeof RequestEnum // 请求的方法
contentType: keyof typeof ContentTypeEnum // 请求的内容类型
/** 请求的url */
url: string
/** 请求的方法 */
method: keyof typeof RequestEnum
/** 请求的内容类型 */
contentType: keyof typeof ContentTypeEnum
}
data: {
bind: string // 请求绑定对应的某个实体
recv: string // 响应的结果绑定到某个实体上
/** 请求绑定对应的某个实体 */
bind: string
/** 响应的结果绑定到某个实体上 */
recv: string
}
}
@ -124,20 +154,29 @@ export interface VisualEditorActions {
* @description
*/
export interface VisualEditorModelValue {
pages: VisualEditorPages // 页面
models: VisualEditorModel[] // 实体
actions: VisualEditorActions // 动作
/** 页面 */
pages: VisualEditorPages
/** 实体 */
models: VisualEditorModel[]
/** 动作 */
actions: VisualEditorActions
}
/**
* @description
*/
export interface Animation {
label: string // 动画名称
value: string // 动画类名
duration: number // 动画持续时间
delay: number // 动画延迟多久执行
count: number // 动画执行次数
infinite: boolean // 是否无限循环动画
/** 动画名称 */
label: string
/** 动画类名 */
value: string
/** 动画持续时间 */
duration: number
/** 动画延迟多久执行 */
delay: number
/** 动画执行次数 */
count: number
/** 是否无限循环动画 */
infinite: boolean
}
/**
* @description
@ -151,14 +190,14 @@ export interface VisualEditorComponent {
render: (data: {
props: any
model: any
styles: CSSProperties
block: VisualEditorBlockData
size: { width?: number; height?: number }
custom: Record<string, any>
}) => JSX.Element
props?: Record<string, VisualEditorProps>
animations?: Animation[] // 动画集
events?: { label: string; value: string }[] // 组件事件集合
resize?: { width?: boolean; height?: boolean }
styles?: CSSProperties
}
export interface VisualEditorMarkLines {
@ -166,29 +205,25 @@ export interface VisualEditorMarkLines {
y: { top: number; showTop: number }[]
}
export function createNewBlock({
component,
left,
top
}: {
component: VisualEditorComponent
top: number
left: number
}): VisualEditorBlockData {
export function createNewBlock(component: VisualEditorComponent): VisualEditorBlockData {
component._vid = `${component._vid}`.startsWith('vid_') ? component._vid : `vid_${component._vid}`
return {
top,
left,
_vid: component._vid!,
moduleName: component.moduleName,
componentKey: component!.key,
label: component!.label,
adjustPosition: true,
focus: false,
zIndex: 0,
width: 0,
height: 0,
styles: {
display: 'flex',
justifyContent: 'flex-start',
paddingTop: '0',
paddingRight: '0',
paddingLeft: '0',
paddingBottom: '0',
tempPadding: '0'
},
hasResize: false,
props: Object.keys(component.props || {}).reduce((prev, curr) => {
const { propObj, prop } = useDotProp(prev, curr)
@ -261,13 +296,13 @@ export function createVisualEditorConfig() {
render: (data: {
props: { [k in keyof Props]: any }
model: Partial<{ [k in keyof Model]: any }>
styles: CSSProperties
block: VisualEditorBlockData
size: { width?: number; height?: number }
custom: Record<string, any>
}) => JSX.Element
props?: Props
model?: Model
resize?: { width?: boolean; height?: boolean }
styles?: CSSProperties
}
) => {
const comp = { ...component, key, moduleName }

214
yarn.lock
View File

@ -2,7 +2,7 @@
# yarn lockfile v1
"@antfu/utils@^0.2.3":
"@antfu/utils@^0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@antfu/utils/-/utils-0.2.4.tgz#c7d33fc6faa0d3a6fcc2555673f5e9b19c0fbc15"
integrity sha512-2bZNkVfL9IZESmvE26UKi8SzyvSoaIsGXDcnbHFMtmGMqUiB1fXpAJ1ijGf+tSqKRQ5yagck2U1Qk0p+705/kw==
@ -722,73 +722,73 @@
"@types/unist" "*"
"@types/vfile-message" "*"
"@typescript-eslint/eslint-plugin@^4.28.1":
version "4.28.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.1.tgz#c045e440196ae45464e08e20c38aff5c3a825947"
integrity sha512-9yfcNpDaNGQ6/LQOX/KhUFTR1sCKH+PBr234k6hI9XJ0VP5UqGxap0AnNwBnWFk1MNyWBylJH9ZkzBXC+5akZQ==
"@typescript-eslint/eslint-plugin@^4.28.2":
version "4.28.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.2.tgz#7a8320f00141666813d0ae43b49ee8244f7cf92a"
integrity sha512-PGqpLLzHSxq956rzNGasO3GsAPf2lY9lDUBXhS++SKonglUmJypaUtcKzRtUte8CV7nruwnDxtLUKpVxs0wQBw==
dependencies:
"@typescript-eslint/experimental-utils" "4.28.1"
"@typescript-eslint/scope-manager" "4.28.1"
"@typescript-eslint/experimental-utils" "4.28.2"
"@typescript-eslint/scope-manager" "4.28.2"
debug "^4.3.1"
functional-red-black-tree "^1.0.1"
regexpp "^3.1.0"
semver "^7.3.5"
tsutils "^3.21.0"
"@typescript-eslint/experimental-utils@4.28.1":
version "4.28.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.1.tgz#3869489dcca3c18523c46018b8996e15948dbadc"
integrity sha512-n8/ggadrZ+uyrfrSEchx3jgODdmcx7MzVM2sI3cTpI/YlfSm0+9HEUaWw3aQn2urL2KYlWYMDgn45iLfjDYB+Q==
"@typescript-eslint/experimental-utils@4.28.2":
version "4.28.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.2.tgz#4ebdec06a10888e9326e1d51d81ad52a361bd0b0"
integrity sha512-MwHPsL6qo98RC55IoWWP8/opTykjTp4JzfPu1VfO2Z0MshNP0UZ1GEV5rYSSnZSUI8VD7iHvtIPVGW5Nfh7klQ==
dependencies:
"@types/json-schema" "^7.0.7"
"@typescript-eslint/scope-manager" "4.28.1"
"@typescript-eslint/types" "4.28.1"
"@typescript-eslint/typescript-estree" "4.28.1"
"@typescript-eslint/scope-manager" "4.28.2"
"@typescript-eslint/types" "4.28.2"
"@typescript-eslint/typescript-estree" "4.28.2"
eslint-scope "^5.1.1"
eslint-utils "^3.0.0"
"@typescript-eslint/parser@^4.28.1":
version "4.28.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.28.1.tgz#5181b81658414f47291452c15bf6cd44a32f85bd"
integrity sha512-UjrMsgnhQIIK82hXGaD+MCN8IfORS1CbMdu7VlZbYa8LCZtbZjJA26De4IPQB7XYZbL8gJ99KWNj0l6WD0guJg==
"@typescript-eslint/parser@^4.28.2":
version "4.28.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.28.2.tgz#6aff11bf4b91eb67ca7517962eede951e9e2a15d"
integrity sha512-Q0gSCN51eikAgFGY+gnd5p9bhhCUAl0ERMiDKrTzpSoMYRubdB8MJrTTR/BBii8z+iFwz8oihxd0RAdP4l8w8w==
dependencies:
"@typescript-eslint/scope-manager" "4.28.1"
"@typescript-eslint/types" "4.28.1"
"@typescript-eslint/typescript-estree" "4.28.1"
"@typescript-eslint/scope-manager" "4.28.2"
"@typescript-eslint/types" "4.28.2"
"@typescript-eslint/typescript-estree" "4.28.2"
debug "^4.3.1"
"@typescript-eslint/scope-manager@4.28.1":
version "4.28.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.28.1.tgz#fd3c20627cdc12933f6d98b386940d8d0ce8a991"
integrity sha512-o95bvGKfss6705x7jFGDyS7trAORTy57lwJ+VsYwil/lOUxKQ9tA7Suuq+ciMhJc/1qPwB3XE2DKh9wubW8YYA==
"@typescript-eslint/scope-manager@4.28.2":
version "4.28.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.28.2.tgz#451dce90303a3ce283750111495d34c9c204e510"
integrity sha512-MqbypNjIkJFEFuOwPWNDjq0nqXAKZvDNNs9yNseoGBB1wYfz1G0WHC2AVOy4XD7di3KCcW3+nhZyN6zruqmp2A==
dependencies:
"@typescript-eslint/types" "4.28.1"
"@typescript-eslint/visitor-keys" "4.28.1"
"@typescript-eslint/types" "4.28.2"
"@typescript-eslint/visitor-keys" "4.28.2"
"@typescript-eslint/types@4.28.1":
version "4.28.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.28.1.tgz#d0f2ecbef3684634db357b9bbfc97b94b828f83f"
integrity sha512-4z+knEihcyX7blAGi7O3Fm3O6YRCP+r56NJFMNGsmtdw+NCdpG5SgNz427LS9nQkRVTswZLhz484hakQwB8RRg==
"@typescript-eslint/types@4.28.2":
version "4.28.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.28.2.tgz#e6b9e234e0e9a66c4d25bab881661e91478223b5"
integrity sha512-Gr15fuQVd93uD9zzxbApz3wf7ua3yk4ZujABZlZhaxxKY8ojo448u7XTm/+ETpy0V0dlMtj6t4VdDvdc0JmUhA==
"@typescript-eslint/typescript-estree@4.28.1":
version "4.28.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.1.tgz#af882ae41740d1f268e38b4d0fad21e7e8d86a81"
integrity sha512-GhKxmC4sHXxHGJv8e8egAZeTZ6HI4mLU6S7FUzvFOtsk7ZIDN1ksA9r9DyOgNqowA9yAtZXV0Uiap61bIO81FQ==
"@typescript-eslint/typescript-estree@4.28.2":
version "4.28.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.2.tgz#680129b2a285289a15e7c6108c84739adf3a798c"
integrity sha512-86lLstLvK6QjNZjMoYUBMMsULFw0hPHJlk1fzhAVoNjDBuPVxiwvGuPQq3fsBMCxuDJwmX87tM/AXoadhHRljg==
dependencies:
"@typescript-eslint/types" "4.28.1"
"@typescript-eslint/visitor-keys" "4.28.1"
"@typescript-eslint/types" "4.28.2"
"@typescript-eslint/visitor-keys" "4.28.2"
debug "^4.3.1"
globby "^11.0.3"
is-glob "^4.0.1"
semver "^7.3.5"
tsutils "^3.21.0"
"@typescript-eslint/visitor-keys@4.28.1":
version "4.28.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.1.tgz#162a515ee255f18a6068edc26df793cdc1ec9157"
integrity sha512-K4HMrdFqr9PFquPu178SaSb92CaWe2yErXyPumc8cYWxFmhgJsNY9eSePmO05j0JhBvf2Cdhptd6E6Yv9HVHcg==
"@typescript-eslint/visitor-keys@4.28.2":
version "4.28.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.2.tgz#bf56a400857bb68b59b311e6d0a5fbef5c3b5130"
integrity sha512-aT2B4PLyyRDUVUafXzpZFoc0C9t0za4BJAKP5sgWIhG+jHECQZUEjuQSCIwZdiJJ4w4cgu5r3Kh20SOdtEBl0w==
dependencies:
"@typescript-eslint/types" "4.28.1"
"@typescript-eslint/types" "4.28.2"
eslint-visitor-keys "^2.0.0"
"@vant/icons@^1.6.0":
@ -808,10 +808,10 @@
dependencies:
"@popperjs/core" "^2.9.2"
"@vant/touch-emulator@^1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@vant/touch-emulator/-/touch-emulator-1.3.0.tgz#f53a7d0c5809b91d51b7fd4c24e762673bf1f679"
integrity sha512-aiaXRMTglYP2GKVq7nRd+/x2NM3IOH+6vKjEyAeotLbRNVw61oqpPZAC95d8UqKWRN+vIdDQiPkKOJavEFZmKg==
"@vant/touch-emulator@^1.3.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@vant/touch-emulator/-/touch-emulator-1.3.1.tgz#93a0c8824d47482c660b982045378d45245e07a0"
integrity sha512-7qid+kyhvFdW7qMhxn0M9ClivvZY1sf2ph5Lu7cSVlA3s+tdtnySwOiAdZc4BSVJQUejeE63XxZIn/p6e45Uvw==
"@vant/use@^1.1.2":
version "1.1.2"
@ -990,48 +990,57 @@
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.1.4.tgz#c14c461ec42ea2c1556e86f60b0354341d91adc3"
integrity sha512-6O45kZAmkLvzGLToBxEz4lR2W6kXohCtebV2UxjH9GXjd8X9AhEn68FN9eNanFtWNzvgw1hqd6HkPRVQalqf7Q==
"@vueuse/core@^5.0.3":
version "5.0.3"
resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-5.0.3.tgz#8f3170e2a51ae62fb1725c84d4cc02a7552aad0b"
integrity sha512-TMCL11EVMaj2Y5qdYosvuwA+i1aKrerFXs7fhNZiQiLCWxF8XsrNdxzoiaI2n12UcmSOXvd1xdyWs7Nss+p/Hg==
"@vueuse/core@^5.1.3":
version "5.1.3"
resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-5.1.3.tgz#a9edda9202513423a27fbac896dd7bc918d1ac6c"
integrity sha512-5CmF/epSo9L1Obz3A37UJOpDdno0BDw46zyXq0DHgvzEwL6gPb9GgJZcy4Hm5YSjQYIeQPo35uO8qsZyIjEZog==
dependencies:
"@vueuse/shared" "5.0.3"
"@vueuse/shared" "5.1.3"
vue-demi "*"
"@vueuse/integrations@^5.0.3":
version "5.0.3"
resolved "https://registry.yarnpkg.com/@vueuse/integrations/-/integrations-5.0.3.tgz#64820965d068b356b4df50ed47a87adf0141f68e"
integrity sha512-c7dy7u4XTJeSfq/NnFotoUPrbkPJv/DbWwEYVW9YXXMdDvz1IxDdXUFrOu8ElM0qzGn4CuYg6Yr37uYR13MgXg==
"@vueuse/integrations@^5.1.3":
version "5.1.3"
resolved "https://registry.yarnpkg.com/@vueuse/integrations/-/integrations-5.1.3.tgz#bf11c56d978bad5a7723c696b5ea72ae7d84e63d"
integrity sha512-eN6L+qV/DfXP3myoKVd2+zNx02GgEdAfLLR5CKJ8eFKgTzUh7Ueha/M0QNPSZfUTkehVMn6iLS3NfTkRgp/JHg==
dependencies:
"@vueuse/shared" "5.0.3"
"@vueuse/shared" "5.1.3"
vue-demi "*"
optionalDependencies:
axios "^0.21.1"
focus-trap "^6.4.0"
focus-trap "^6.6.0"
jwt-decode "^3.1.2"
nprogress "^0.2.0"
qrcode "^1.4.4"
universal-cookie "^4.0.4"
"@vueuse/shared@5.0.3":
version "5.0.3"
resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-5.0.3.tgz#31613951d5036459650ad8d47a9185e8950ea3c9"
integrity sha512-aY93WPygr8H/4RB8YuOmAD83Y+faq7zwW10Kd9i0kD9zf5ysVP+32j09rF/mZVtGCa0CSM8ambPZMsEhCkRbwQ==
"@vueuse/shared@5.1.3":
version "5.1.3"
resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-5.1.3.tgz#11faa3a1a2b4d3dc41eac7a825900a8894efe95e"
integrity sha512-p8n/69QMtSsLN5rri9c3sN5QJJXWA7cm9chgo3DowTBRYLBni1I9kGY2nz299Tur6XEFuf+63E5TvMTJVJeHHw==
dependencies:
vue-demi "*"
"@windicss/plugin-utils@1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@windicss/plugin-utils/-/plugin-utils-1.2.0.tgz#f9c657f981d7696dfa6b8e8069b311161a2ac9b4"
integrity sha512-6OAsyz2yI0VKNHACT35FjWWzMZlMEF7Z0pIiNUd9+R9jc73+qJcK1DRCZ3YxnjuGk0G76b542uXQEJgv2jL3vA==
"@windicss/config@1.2.4":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@windicss/config/-/config-1.2.4.tgz#24b36d30c1698fff14a9bacaebc93afaf2fe9019"
integrity sha512-81oah5NF7m/ltHrP2VpKu12qejP03erelNckH9ho86vuItsSd/tNehW3oJqOThZYsbuROCzIU55QDfe7MBd+Iw==
dependencies:
"@antfu/utils" "^0.2.3"
debug "^4.3.2"
fast-glob "^3.2.5"
jiti "^1.10.1"
windicss "^3.1.4"
"@windicss/plugin-utils@1.2.4":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@windicss/plugin-utils/-/plugin-utils-1.2.4.tgz#b319355d6e9b4e529c965b5a55af6d57679e417f"
integrity sha512-0G0zPx+gLfnP2isVMrsY+C0BDXASgFwtiT7g+YL+0LCTxjPxGOMnu5lCaAoYq+1LAskliPagqnu5mgKUYMyf2Q==
dependencies:
"@antfu/utils" "^0.2.4"
"@windicss/config" "1.2.4"
debug "^4.3.2"
fast-glob "^3.2.6"
magic-string "^0.25.7"
micromatch "^4.0.4"
windicss "^3.1.3"
windicss "^3.1.4"
JSONStream@^1.0.4:
version "1.3.5"
@ -1939,11 +1948,16 @@ dargs@^7.0.0:
resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc"
integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==
dayjs@1.x, dayjs@^1.10.5:
dayjs@1.x:
version "1.10.5"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.5.tgz#5600df4548fc2453b3f163ebb2abbe965ccfb986"
integrity sha512-BUFis41ikLz+65iH6LHQCDm4YPMj5r1YFLdupPIyM4SGcXMmtiLQ7U37i+hGS8urIuqe7I/ou3IS1jVc4nbN4g==
dayjs@^1.10.6:
version "1.10.6"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.6.tgz#288b2aa82f2d8418a6c9d4df5898c0737ad02a63"
integrity sha512-AztC/IOW4L1Q41A86phW5Thhcrco3xuAA+YX/BLpLWWjRcTj5TOt/QImBLmCKlrF7u7k47arTnOyL6GnbG8Hvw==
debug@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
@ -2350,15 +2364,15 @@ eslint-plugin-prettier@^3.4.0:
dependencies:
prettier-linter-helpers "^1.0.0"
eslint-plugin-vue@^7.12.1:
version "7.12.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-7.12.1.tgz#ef6499ce4fe0566659c8e12c71713f5308630a76"
integrity sha512-xHf/wCt88qmzqQerjaSteUFGASj7fPreglKD4ijnvoKRkoSJ3/H3kuJE8QFFtc+2wjw6hRDs834HH7vpuTJQzg==
eslint-plugin-vue@^7.13.0:
version "7.13.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-7.13.0.tgz#6f3d232bf1fcd0428353b0d581ebaca1c5dbc17a"
integrity sha512-u0+jL8h2MshRuMTCLslktxRsPTjlENNcNufhgHu01N982DmHVdeFniyMPoVLLRjACQOwdz3FdlsgYGBMBG+AKg==
dependencies:
eslint-utils "^2.1.0"
natural-compare "^1.4.0"
semver "^7.3.2"
vue-eslint-parser "^7.6.0"
vue-eslint-parser "^7.8.0"
eslint-scope@^5.1.1:
version "5.1.1"
@ -2738,7 +2752,7 @@ fn-name@^2.0.1:
resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-2.0.1.tgz#5214d7537a4d06a4a301c0cc262feb84188002e7"
integrity sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc=
focus-trap@^6.4.0:
focus-trap@^6.6.0:
version "6.6.0"
resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-6.6.0.tgz#7fb37679926ec1bd762d0748b056c68a64a9e8cf"
integrity sha512-2hWVR3XbBejn5v8wDW9DFzLWXcxMNaSJ/CtE3E+FJjjBCLwIYbZJwjUi2RDBfQPM58gHEt5hck0jrJgHR9/s+A==
@ -3198,10 +3212,10 @@ human-signals@^2.1.0:
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
husky@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.0.tgz#3dbd5d28e76234689ee29bb41e048f28e3e46616"
integrity sha512-xK7lO0EtSzfFPiw+oQncQVy/XqV7UVVjxBByc+Iv5iK3yhW9boDoWgvZy3OGo48QKg/hUtZkzz0hi2HXa0kn7w==
husky@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.1.tgz#579f4180b5da4520263e8713cc832942b48e1f1c"
integrity sha512-gceRaITVZ+cJH9sNHqx5tFwbzlLCVxtVZcusME8JYQ8Edy5mpGDOqD8QBCdMhpyo9a+JXddnujQ4rpY2Ff9SJA==
iconv-lite@^0.4.24:
version "0.4.24"
@ -4761,7 +4775,7 @@ postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.21, postcss@^7.0.
source-map "^0.6.1"
supports-color "^6.1.0"
postcss@^8.1.10, postcss@^8.3.4:
postcss@^8.1.10, postcss@^8.3.5:
version "8.3.5"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.5.tgz#982216b113412bc20a86289e91eb994952a5b709"
integrity sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA==
@ -6327,10 +6341,10 @@ vfile@^4.0.0, vfile@^4.0.1:
unist-util-stringify-position "^2.0.0"
vfile-message "^2.0.0"
vite-plugin-components@^0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/vite-plugin-components/-/vite-plugin-components-0.12.0.tgz#7a20ba88be63625f759902d670c1310cf7cd9d0b"
integrity sha512-LJAn25KFLFw97mNQw74fsWvGAaaFXbDNGkReFpITPtIrmdRrwWowieg23INXAniPaGJVIhspLk0ippMPi/q0qA==
vite-plugin-components@^0.12.2:
version "0.12.2"
resolved "https://registry.yarnpkg.com/vite-plugin-components/-/vite-plugin-components-0.12.2.tgz#3afc97772cfad0bd61aa709924bf06e12abe9cf1"
integrity sha512-ecGCqEQMEwPw556WfdbRwbDsdGtBWkjSkuOXw5sKbgaZzVSlybOfrXhGjiYEatR13KCUxTHzioU2eOLu1tpWVQ==
dependencies:
debug "^4.3.2"
fast-glob "^3.2.6"
@ -6348,23 +6362,23 @@ vite-plugin-style-import@^1.0.1:
es-module-lexer "^0.6.0"
magic-string "^0.25.7"
vite-plugin-windicss@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/vite-plugin-windicss/-/vite-plugin-windicss-1.2.0.tgz#6b21e76f3aae1cd2f71c548c4bfe8d87b4328ad0"
integrity sha512-3teAmQHCDDDcy7On5fOj1sYTRVo8zAwJJd4SOapeGI7EuEzO2fHy6oDS6sPXVUnstbfoPbvrng1xvc3VAqI+sg==
vite-plugin-windicss@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/vite-plugin-windicss/-/vite-plugin-windicss-1.2.4.tgz#b9ea60482dd8b6ba4fbc717ff5a9d17dedb0683b"
integrity sha512-U+mW8AiPRgC5wbUqjtvEIbZR3LzOwhNU0wnYQueT2SjjTfjlP74vcQg37yrULxycKibpdTYVHZuDuW4QkglPng==
dependencies:
"@windicss/plugin-utils" "1.2.0"
"@windicss/plugin-utils" "1.2.4"
chalk "^4.1.1"
debug "^4.3.2"
windicss "^3.1.3"
windicss "^3.1.4"
vite@2.3.8:
version "2.3.8"
resolved "https://registry.yarnpkg.com/vite/-/vite-2.3.8.tgz#42e3e03953859fd410e4e6ab3d1cca0aab2adc3c"
integrity sha512-QiEx+iqNnJntSgSF2fWRQvRey9pORIrtNJzNyBJXwc+BdzWs83FQolX84cTBo393cfhObrtWa6180dAa4NLDiQ==
vite@2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/vite/-/vite-2.4.1.tgz#2e48b8dbfc69e4edbf7f4d1c0798d621585cb8da"
integrity sha512-4BpKRis9uxIqPfIEcJ18LTBsamqnDFxTx45CXwagHjNltHa6PFEvf8Pe6OpgIHb0OyWT30OXOSSQvdOaX4OBiQ==
dependencies:
esbuild "^0.12.8"
postcss "^8.3.4"
postcss "^8.3.5"
resolve "^1.20.0"
rollup "^2.38.5"
optionalDependencies:
@ -6532,10 +6546,10 @@ vue-demi@*:
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.9.1.tgz#25d6e1ebd4d4010757ff3571e2bf6a1d7bf3de82"
integrity sha512-7s1lufRD2l369eFWPjgLvhqCRk0XzGWJsQc7K4q+0mZtixyGIvsK1Cg88P4NcaRIEiBuuN4q1NN4SZKFKwQswA==
vue-eslint-parser@^7.6.0, vue-eslint-parser@^7.7.2:
version "7.7.2"
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-7.7.2.tgz#a723080b29c27fa0b3737bedceaeebe30fd0f359"
integrity sha512-zkfxSttpwBW9SQEa+rLR+j6sFHGGhanVH3VuzHQwybCQWJsg/Yi1W619gXOW01U/zekN4D+J4/S4Zufd1sClZg==
vue-eslint-parser@^7.8.0:
version "7.8.0"
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-7.8.0.tgz#43850bf856c9a69d62c0e12769609c338423684b"
integrity sha512-ehmmrLZNYLUoKayvVW8l8HyPQIfuYZHiJoQLRP3dapDlTU7bGs4tqIKVGdAEpMuXS/b4R/PImCt7Tkj4UhX1SQ==
dependencies:
debug "^4.1.1"
eslint-scope "^5.1.1"
@ -6619,7 +6633,7 @@ widest-line@^2.0.0:
dependencies:
string-width "^2.1.1"
windicss@^3.1.3, windicss@^3.1.4:
windicss@^3.1.4:
version "3.1.4"
resolved "https://registry.yarnpkg.com/windicss/-/windicss-3.1.4.tgz#557eaf8e3c08064a309ccb5d887c82c4bce25069"
integrity sha512-3RBcANxdOy/n4dLVT8+0X409sGI+piO06ARbQ8RncxGuYgdw5Ip3hrhGIYajH67lV+tHc7xNVGxj73amOC9N0g==