未验证 提交 3bdb469b 编辑于 作者: cyole's avatar cyole
浏览文件

chore: initialize zui demo project

上级
import { createStyleSheet } from '../../../_utils/jss'
export const styles = createStyleSheet({
root: {
'padding': 0,
'border': 0,
'background': 'transparent',
'color': '#1677ff',
'cursor': 'pointer',
'&:hover': {
color: '#4096ff',
},
},
})
<template>
<div>
<span>上方内容</span>
<ZDivider />
<span>下方内容</span>
</div>
</template>
# 分割线 Divider
TODO: 补充水平分割线、带文字分割线、虚线和垂直分割线示例。
## 演示
<!-- DEMO -->
<demo vue="divider/demos/basic.vue" />
<!-- DEMO -->
## API
<!-- API -->
TODO: 对照 `src/divider/src/interface.ts` 补充 Props 和 Slots 表格。
<!-- API -->
export { default as ZDivider } from './src/Divider.vue'
export * from './src/interface'
<script setup lang="ts">
import type { DividerSlots } from './interface'
import { computed } from 'vue'
import { dividerProps } from './interface'
import { styles } from './styles'
defineOptions({ name: 'ZDivider' })
const props = defineProps(dividerProps)
defineSlots<DividerSlots>()
const dividerClass = computed(() => [
styles.classes.root,
props.direction === 'vertical' ? styles.classes.vertical : styles.classes.horizontal,
props.dashed ? styles.classes.dashed : undefined,
])
</script>
<template>
<div
role="separator"
:class="dividerClass"
>
<span
v-if="$slots.default && direction === 'horizontal'"
:class="styles.classes.text"
>
<slot />
</span>
</div>
</template>
import type { ExtractPublicPropTypes, PropType, VNodeChild } from 'vue'
export type DividerDirection = 'horizontal' | 'vertical'
export const dividerProps = {
direction: {
type: String as PropType<DividerDirection>,
default: 'horizontal',
},
dashed: Boolean,
} as const
export type DividerProps = ExtractPublicPropTypes<typeof dividerProps>
export interface DividerSlots {
default?: () => VNodeChild
}
import { createStyleSheet } from '../../../_utils/jss'
export const styles = createStyleSheet({
root: {
borderColor: '#e5e6eb',
color: '#86909c',
},
horizontal: {
display: 'flex',
alignItems: 'center',
width: '100%',
margin: [16, 0],
borderTop: '1px solid #e5e6eb',
},
vertical: {
display: 'inline-block',
height: '1em',
margin: [0, 8],
borderLeft: '1px solid #e5e6eb',
verticalAlign: 'middle',
},
dashed: {
borderStyle: 'dashed',
},
text: {
padding: [0, 12],
background: '#fff',
transform: 'translateY(-50%)',
},
})
<template>
<ZEmpty />
</template>
# 空状态 Empty
TODO: 补充默认空状态、自定义描述、自定义图片和业务空态示例。
## 演示
<!-- DEMO -->
<demo vue="empty/demos/basic.vue" />
<!-- DEMO -->
## API
<!-- API -->
TODO: 对照 `src/empty/src/interface.ts` 补充 Props 和 Slots 表格。
<!-- API -->
export { default as ZEmpty } from './src/Empty.vue'
export * from './src/interface'
<script setup lang="ts">
import type { EmptySlots } from './interface'
import { emptyProps } from './interface'
import { styles } from './styles'
defineOptions({ name: 'ZEmpty' })
defineProps(emptyProps)
defineSlots<EmptySlots>()
</script>
<template>
<div :class="styles.classes.root">
<div :class="styles.classes.image">
<slot name="image">
<span :class="styles.classes.placeholder" />
</slot>
</div>
<div :class="styles.classes.description">
<slot>
{{ description }}
</slot>
</div>
</div>
</template>
import type { ExtractPublicPropTypes, VNodeChild } from 'vue'
export const emptyProps = {
description: {
type: String,
default: '暂无数据',
},
} as const
export type EmptyProps = ExtractPublicPropTypes<typeof emptyProps>
export interface EmptySlots {
image?: () => VNodeChild
default?: () => VNodeChild
}
import { createStyleSheet } from '../../../_utils/jss'
export const styles = createStyleSheet({
root: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
padding: 32,
color: '#86909c',
},
image: {
marginBottom: 12,
},
placeholder: {
display: 'block',
width: 64,
height: 44,
borderRadius: 8,
background: '#f2f3f5',
boxShadow: 'inset 0 -12px 0 #e5e6eb',
},
description: {
fontSize: 14,
lineHeight: '22px',
},
})
<script setup lang="ts">
function handleClick() {
console.log('example button clicked')
}
</script>
<template>
<div style="display: flex; gap: 12px; align-items: center;">
<ZExampleButton @click="handleClick">
默认按钮
</ZExampleButton>
<ZExampleButton type="primary">
主要按钮
</ZExampleButton>
<ZExampleButton type="success">
成功按钮
</ZExampleButton>
</div>
</template>
# 示例按钮 ExampleButton
用于展示组件源码、Props 类型、JSS 样式、文档示例、API 表格和单元测试的推荐写法。
## 演示
<!-- DEMO -->
<demo vue="example-button/demos/basic.vue" />
<demo vue="example-button/demos/states.vue" />
<!-- DEMO -->
## API
### ExampleButton Props
| 名称 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| type | `'default' \| 'primary' \| 'success'` | `'default'` | 按钮类型 |
| loading | `boolean` | `false` | 是否展示加载态 |
| disabled | `boolean` | `false` | 是否禁用按钮 |
### ExampleButton Events
| 名称 | 参数 | 说明 |
| --- | --- | --- |
| click | `(event: MouseEvent)` | 点击按钮时触发,禁用或加载状态下不会触发 |
### ExampleButton Slots
| 名称 | 参数 | 说明 |
| --- | --- | --- |
| default | `()` | 按钮内容 |
<template>
<div style="display: flex; gap: 12px; align-items: center;">
<ZExampleButton loading>
加载中
</ZExampleButton>
<ZExampleButton disabled>
禁用按钮
</ZExampleButton>
</div>
</template>
export { default as ZExampleButton } from './src/ExampleButton.vue'
export * from './src/interface'
<script setup lang="ts">
import type { ExampleButtonEvents, ExampleButtonSlots } from './interface'
import { computed } from 'vue'
import { exampleButtonProps } from './interface'
import { styles } from './styles'
defineOptions({ name: 'ZExampleButton' })
const props = defineProps(exampleButtonProps)
const emit = defineEmits<ExampleButtonEvents>()
defineSlots<ExampleButtonSlots>()
const typeClass = computed(() => {
return {
default: styles.classes.defaultType,
primary: styles.classes.primary,
success: styles.classes.success,
}[props.type]
})
const buttonClass = computed(() => [
styles.classes.root,
typeClass.value,
props.loading ? styles.classes.loading : undefined,
])
function handleClick(event: MouseEvent) {
if (props.disabled || props.loading)
return
emit('click', event)
}
</script>
<template>
<button
type="button"
:class="buttonClass"
:disabled="disabled || loading"
@click="handleClick"
>
<span
v-if="loading"
:class="styles.classes.spinner"
aria-hidden="true"
/>
<span :class="styles.classes.content">
<slot />
</span>
</button>
</template>
import type { ExtractPublicPropTypes, PropType, VNodeChild } from 'vue'
export type ExampleButtonType = 'default' | 'primary' | 'success'
export const exampleButtonProps = {
type: {
type: String as PropType<ExampleButtonType>,
default: 'default',
},
loading: Boolean,
disabled: Boolean,
} as const
export type ExampleButtonProps = ExtractPublicPropTypes<typeof exampleButtonProps>
export interface ExampleButtonEvents {
(e: 'click', event: MouseEvent): void
}
export interface ExampleButtonSlots {
default?: () => VNodeChild
}
import { createStyleSheet } from '../../../_utils/jss'
export const styles = createStyleSheet({
'root': {
'display': 'inline-flex',
'alignItems': 'center',
'justifyContent': 'center',
'gap': 6,
'height': 32,
'padding': [0, 14],
'border': '1px solid transparent',
'borderRadius': 6,
'fontSize': 14,
'fontWeight': 500,
'lineHeight': '20px',
'cursor': 'pointer',
'transition': 'all 0.2s ease',
'&:disabled': {
cursor: 'not-allowed',
opacity: 0.56,
},
},
'defaultType': {
'borderColor': '#d9d9d9',
'background': '#fff',
'color': '#1f2329',
'&:not(:disabled):hover': {
borderColor: '#1677ff',
color: '#1677ff',
},
},
'primary': {
'background': '#1677ff',
'color': '#fff',
'&:not(:disabled):hover': {
background: '#4096ff',
},
},
'success': {
'background': '#2f9e44',
'color': '#fff',
'&:not(:disabled):hover': {
background: '#37b24d',
},
},
'loading': {
pointerEvents: 'none',
},
'spinner': {
width: 12,
height: 12,
border: '2px solid currentColor',
borderTopColor: 'transparent',
borderRadius: '50%',
animation: '$spin 0.8s linear infinite',
},
'content': {
display: 'inline-flex',
alignItems: 'center',
},
'@keyframes spin': {
to: {
transform: 'rotate(360deg)',
},
},
})
支持 Markdown
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册