<template>
<tiny-form label-position="left" label-width="60px" show-message :model="formData" :rules="rules">
<tiny-form-item label="事件名" prop="eventName">
<tiny-input class="event-name" v-model="formData.eventName" :placeholder="eventNameTip" @blur="changeEventName">
<template #suffix>
<tiny-popover placement="bottom-end" trigger="hover" :close-delay="0" @show="state.showPopover = true">
<template #reference>
<tiny-icon-rich-text-link :class="{ 'bind-propertys': isUpdateEvent }" />
</template>
<div class="property-list" v-show="state.showPopover">
<div class="property-list-title">
<tiny-icon-rich-text-link />
双向绑定属性
</div>
<ul class="property-list-content">
<li
v-for="(item, index) in propertys"
:key="index"
:class="{ existed: eventNameList.has(`onUpdate:${item.property}`) }"
@click="usePropertysToBeEvent(item)"
>
<div>{{ item.property }}</div>
</li>
</ul>
</div>
</tiny-popover>
</template>
</tiny-input>
</tiny-form-item>
<tiny-form-item label="标签名">
<tiny-input v-model="label"></tiny-input>
</tiny-form-item>
<tiny-form-item label="描述">
<tiny-input v-model="description"></tiny-input>
</tiny-form-item>
<div v-if="linked" class="linked-info">链接到组件: {{ linked.componentName }} 事件: {{ linked.event }}</div>
</tiny-form>
</template>
<script lang="ts">
import { computed, reactive, watch } from 'vue'
import { Input as TinyInput, Form as TinyForm, FormItem as TinyFormItem, TinyPopover } from '@opentiny/vue'
import {
REGEXP_EVENT_NAME,
REGEXP_UPDATE_EVENT_NAME,
verifyEventName
} from '@opentiny/tiny-engine-common/js/verification'
import {
getEditBlockPropertyList,
getEditBlockEvents,
getEditEvent,
getEditEventName,
renameBlockEventName
} from './js/blockSetting'
import { IconRichTextLink } from '@opentiny/vue-icon'
export default {
components: {
TinyForm,
TinyInput,
TinyFormItem,
TinyPopover,
TinyIconRichTextLink: IconRichTextLink()
},
setup() {
const propertys = computed(() => getEditBlockPropertyList())
const events = computed(() => getEditBlockEvents())
const state = reactive({
showPopover: false
})
const eventNameTip = '事件名为小写字符或onUpdate:开头的驼峰形式,例:customEvent, onUpdate:propsName'
const linked = computed(() => (getEditEvent() || {}).linked)
const eventNameList = computed(() => new Set(Object.keys(events.value)))
const label = computed({
get: () => getEditEvent()?.label?.zh_CN || '',
set(value) {
const event = getEditEvent()
if (event && event.label) {
event.label.zh_CN = value
}
}
})
const description = computed({
get: () => getEditEvent()?.description?.zh_CN || '',
set(value) {
const event = getEditEvent()
if (event && event.description) {
event.description.zh_CN = value
}
}
})
const formData = reactive({
eventName: getEditEventName() || ''
})
const isUpdateEvent = computed(() => formData.eventName.startsWith('onUpdate:'))
const usePropertysToBeEvent = (item: any) => {
if (item.label?.text?.zh_CN) label.value = item.label.text.zh_CN
renameBlockEventName(`onUpdate:${item.property}`, getEditEventName())
state.showPopover = false
}
const rules = {
eventName: [
{
validator: (_rule: any , value: string, callback: (e?: Error) => void) => {
if (isUpdateEvent.value) {
const matched = REGEXP_UPDATE_EVENT_NAME.test(value)
const propertyMatched = propertys.value.some((item) => item.property === value.replace('onUpdate:', ''))
return matched && propertyMatched
? callback()
: callback(new Error(`${value} 需要有对应的 ${value.replace('onUpdate:', '')} 在属性中定义`))
}
if (!REGEXP_EVENT_NAME.test(value)) {
callback(new Error(eventNameTip))
} else {
callback()
}
},
trigger: 'change'
}
]
}
watch(
() => getEditEventName(),
() => {
formData.eventName = getEditEventName() || ''
}
)
const changeEventName = () => {
const isEventNameValid = isUpdateEvent.value
? REGEXP_UPDATE_EVENT_NAME.test(formData.eventName) &&
propertys.value.some((item: any) => item.property === formData.eventName.replace('onUpdate:', ''))
: verifyEventName(formData.eventName)
if (formData.eventName !== getEditEventName() && isEventNameValid) {
renameBlockEventName(formData.eventName, getEditEventName())
}
}
return {
state,
propertys,
events,
rules,
label,
linked,
formData,
description,
eventNameTip,
eventNameList,
isUpdateEvent,
changeEventName,
usePropertysToBeEvent
}
}
}
</script>
<style lang="less" scoped>
.linked-info {
margin-top: 10px;
padding: 15px 0px;
border-top: 1px solid var(--te-block-event-link-border-color);
}
.event-name {
:deep(.tiny-input__inner.tiny-input__inner) {
padding-right: var(--tv-Input-suffix-padding-right);
padding-left: var(--tv-Input-suffix-padding-left);
}
.bind-propertys {
fill: var(--te-component-common-block-add-text-color);
}
}
.property-list {
.property-list-title {
display: flex;
align-items: center;
font-weight: bold;
text-align: left;
gap: 6px;
margin-bottom: 6px;
}
.property-list-content {
max-height: 200px;
overflow-y: scroll;
overflow-x: hidden;
padding-inline-start: 10px;
padding-inline-end: 10px;
}
li {
padding: 0 12px;
margin: 0 -16px;
line-height: 24px;
cursor: pointer;
&:hover {
background: var(--te-component-common-bg-color-hover);
}
}
.existed {
cursor: not-allowed;
pointer-events: none;
color: var(--te-component-common-text-color-disabled);
}
}
</style>