Skip to content

Commit a709450

Browse files
committed
feat: overlay
1 parent cb3ad2a commit a709450

File tree

14 files changed

+292
-2
lines changed

14 files changed

+292
-2
lines changed

packages/hbui-vue/docs/.vitepress/config/sidebar.ts

+4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ const sidebar = [
2727
"text": "Icon 图标",
2828
"link": "/components/icon/"
2929
},
30+
{
31+
"text": "Overlay 遮罩层",
32+
"link": "/components/overlay/"
33+
},
3034
{
3135
"text": "Status 状态",
3236
"link": "/components/status/"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Overlay 遮罩层
2+
3+
遮罩层属于基础组件,用于构建独立于当前页面布局的组件。
4+
5+
何时使用
6+
7+
### 何时使用
8+
9+
当你需要全局弹窗,或者需要元素跟随功能,便可以使用该组件。
10+
11+
### 固定遮罩层
12+
13+
:::demo
14+
15+
```vue
16+
<template>
17+
<hb-button @click="visible = !visible">显示遮罩层</hb-button>
18+
<hb-fixed-overlay v-model="visible" :lock-scroll="false" class="demo-fixed-overlay-bg">
19+
<div class="demo-fixed-overlay-container">Hello HbUI!</div>
20+
</hb-fixed-overlay>
21+
</template>
22+
23+
<script>
24+
import { defineComponent, ref } from 'vue'
25+
26+
export default defineComponent({
27+
setup() {
28+
const visible = ref(false)
29+
30+
return { visible }
31+
}
32+
})
33+
</script>
34+
35+
<style>
36+
.demo-fixed-overlay-container {
37+
display: flex;
38+
align-items: center;
39+
justify-content: center;
40+
width: 20vw;
41+
height: 20vh;
42+
background: #fff;
43+
color: #000;
44+
}
45+
46+
.demo-fixed-overlay-bg {
47+
display: flex;
48+
align-items: center;
49+
justify-content: center;
50+
}
51+
</style>
52+
```
53+
54+
:::
55+
56+
### FixedOverlay 参数
57+
58+
| 参数名 | 类型 | 默认 | 说明 | 跳转 Demo |
59+
| :--------------------- | :-------- | :---- | :----------------------- | :------------------------ |
60+
| v-model | `boolean` | false | 可选,遮罩层是否可见 | [固定遮罩层](#固定遮罩层) |
61+
| lock-scroll | `boolean` | true | 可选,是否锁定背景滚动 | |
62+
| close-on-click-overlay | `boolean` | true | 可选,是否点击遮罩层关闭 | |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { shallowMount } from '@vue/test-utils'
2+
import { expect, test, it } from 'vitest'
3+
4+
import { Overlay } from '../index'
5+
6+
test('Overlay test', () => {
7+
const wrapper = shallowMount(Overlay, {
8+
props: {}
9+
})
10+
11+
it('Overlay demo has created successfully', async () => {
12+
expect(wrapper).toBeTruthy()
13+
})
14+
})

packages/hbui-vue/ui/overlay/index.ts

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type { App } from 'vue'
2+
import { FixedOverlay } from './src/fixed-overlay'
3+
import { inBrowser } from '@utils/common-var'
4+
5+
export * from './src/fixed-overlay/fixed-overlay-types'
6+
7+
export { FixedOverlay }
8+
9+
export default {
10+
title: 'Overlay 遮罩层',
11+
category: '通用',
12+
status: '50%',
13+
install(app: App) {
14+
app.component(FixedOverlay.name, FixedOverlay)
15+
16+
if (inBrowser && !document.getElementById('hb-overlay-anchor')) {
17+
const overlayAnchor = document.createElement('div')
18+
overlayAnchor.setAttribute('id', 'hb-overlay-anchor')
19+
overlayAnchor.style.position = 'fixed'
20+
overlayAnchor.style.left = '0'
21+
overlayAnchor.style.top = '0'
22+
overlayAnchor.style.zIndex = '1000'
23+
document.body.appendChild(overlayAnchor)
24+
}
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import type { ExtractPropTypes } from 'vue'
2+
3+
export const overlayProps = {
4+
modelValue: {
5+
type: Boolean,
6+
default: false
7+
},
8+
closeOnClickOverlay: {
9+
type: Boolean,
10+
default: true
11+
}
12+
}
13+
14+
export type OverlayProps = ExtractPropTypes<typeof overlayProps>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
@import '@hbui/styles-var/index.scss';
2+
3+
.#{$hbui-prefix}-overlay {
4+
position: fixed;
5+
top: 0;
6+
right: 0;
7+
bottom: 0;
8+
left: 0;
9+
background-color: $hbui-shadow;
10+
z-index: 1050;
11+
}
12+
13+
.#{$hbui-prefix}-overlay__fade {
14+
@mixin hb-overlay-fade-animation {
15+
animation-name: hb-overlay-fade;
16+
animation-duration: 0.3s;
17+
}
18+
@keyframes hb-overlay-fade {
19+
0% {
20+
opacity: 0;
21+
}
22+
23+
100% {
24+
opacity: 1;
25+
}
26+
}
27+
28+
&-enter {
29+
opacity: 0;
30+
}
31+
32+
&-enter-active {
33+
@include hb-overlay-fade-animation;
34+
}
35+
36+
&-leave {
37+
opacity: 1;
38+
}
39+
40+
&-leave-active {
41+
@include hb-overlay-fade-animation;
42+
43+
animation-direction: reverse;
44+
}
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { defineComponent, renderSlot, Teleport, Transition } from 'vue'
2+
import type { SetupContext } from 'vue'
3+
import { OverlayProps } from './base-overlay-types'
4+
import { useNamespace } from '@hooks/use-namespace'
5+
import './base-overlay.scss'
6+
7+
export default defineComponent({
8+
name: 'HbOverlay',
9+
setup(props: OverlayProps, ctx: SetupContext) {
10+
const ns = useNamespace('overlay')
11+
12+
return () => (
13+
<Teleport to='#hb-overlay-anchor'>
14+
<Transition name={ns.e('fade')}>{renderSlot(ctx.slots, 'default')}</Transition>
15+
</Teleport>
16+
)
17+
}
18+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { ExtractPropTypes } from 'vue'
2+
3+
export const fixedOverlayProps = {
4+
modelValue: {
5+
type: Boolean,
6+
default: false
7+
},
8+
lockScroll: {
9+
type: Boolean,
10+
default: true
11+
},
12+
closeOnClickOverlay: {
13+
type: Boolean,
14+
default: true
15+
}
16+
} as const
17+
18+
export type FixedOverlayProps = ExtractPropTypes<typeof fixedOverlayProps>
19+
20+
export interface UseFixedOverlay {
21+
onClick: (e: Event) => void
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
@import '@hbui/styles-var/index.scss';
2+
3+
.#{$hbui-prefix}-fixed-overlay {
4+
position: fixed;
5+
top: 0;
6+
right: 0;
7+
bottom: 0;
8+
left: 0;
9+
background-color: $hbui-shadow;
10+
z-index: 1050;
11+
}
12+
13+
.#{$hbui-prefix}-fixed-overlay--fade-enter-active,
14+
.#{$hbui-prefix}-fixed-overlay--fade-leave-active {
15+
transition: opacity 0.1s cubic-bezier(0, 0, 1, 1);
16+
}
17+
18+
.#{$hbui-prefix}-fixed-overlay--fade-enter-from,
19+
.#{$hbui-prefix}-fixed-overlay--fade-leave-to {
20+
opacity: 0;
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { defineComponent, SetupContext, toRefs, Transition } from 'vue'
2+
import { fixedOverlayProps, FixedOverlayProps } from './fixed-overlay-types'
3+
import { useFixedOverlay } from './use-fixed-overlay'
4+
import { useNamespace } from '@hooks/use-namespace'
5+
import './fixed-overlay.scss'
6+
7+
export const FixedOverlay = defineComponent({
8+
name: 'HbFixedOverlay',
9+
inheritAttrs: false,
10+
props: fixedOverlayProps,
11+
emits: ['update:modelValue', 'click'],
12+
setup(props: FixedOverlayProps, ctx: SetupContext) {
13+
const { modelValue } = toRefs(props)
14+
const ns = useNamespace('fixed-overlay')
15+
const { onClick } = useFixedOverlay(props, ctx)
16+
17+
return () => (
18+
<Transition name={ns.m('fade')}>
19+
{modelValue.value && (
20+
<div class={ns.b()} {...ctx.attrs} onClick={onClick}>
21+
{ctx.slots.default?.()}
22+
</div>
23+
)}
24+
</Transition>
25+
)
26+
}
27+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { onUnmounted, SetupContext, watch } from 'vue'
2+
import { FixedOverlayProps, UseFixedOverlay } from './fixed-overlay-types'
3+
import { lockScroll } from '@utils/lock-scroll'
4+
5+
export function useFixedOverlay(props: FixedOverlayProps, ctx: SetupContext): UseFixedOverlay {
6+
let lockScrollCb: () => void
7+
8+
const onClick = (event: Event) => {
9+
event.preventDefault()
10+
ctx.emit('click', event)
11+
if (props.closeOnClickOverlay) {
12+
ctx.emit('update:modelValue', false)
13+
}
14+
}
15+
16+
const removeBodyAdditions = () => {
17+
lockScrollCb?.()
18+
}
19+
20+
watch(
21+
() => props.modelValue,
22+
(val) => {
23+
if (val) {
24+
props.lockScroll && (lockScrollCb = lockScroll())
25+
} else {
26+
removeBodyAdditions()
27+
}
28+
}
29+
)
30+
31+
onUnmounted(removeBodyAdditions)
32+
33+
return { onClick }
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const inBrowser = typeof window !== 'undefined'
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
export * from './common-var'
12
export * from './lock-scroll'
23
export * from './is'

packages/hbui-vue/ui/vue-hbui.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ import CardInstall, { Card } from './card'
77
import DrawerInstall, { Drawer } from './drawer'
88
import FullscreenInstall, { Fullscreen } from './fullscreen'
99
import IconInstall, { Icon } from './icon'
10+
import OverlayInstall, { FixedOverlay } from './overlay'
1011
import StatusInstall, { Status } from './status'
1112

12-
const installs = [AlertInstall, AvatarInstall, ButtonInstall, CardInstall, DrawerInstall, FullscreenInstall, IconInstall, StatusInstall]
13+
const installs = [AlertInstall, AvatarInstall, ButtonInstall, CardInstall, DrawerInstall, FullscreenInstall, IconInstall, OverlayInstall, StatusInstall]
1314

14-
export { Alert, Avatar, Button, ButtonGroup, Card, Drawer, Fullscreen, Icon, Status }
15+
export { Alert, Avatar, Button, ButtonGroup, Card, Drawer, Fullscreen, Icon, FixedOverlay, Status }
1516

1617
export default {
1718
version: '1.0.0',

0 commit comments

Comments
 (0)