Skip to content
This repository was archived by the owner on Jan 8, 2025. It is now read-only.

Commit 2ca9973

Browse files
authored
feat: add component bottom-navigation (#56)
* test(ui/loading): add test case and snapshots * test(ui/collapse): add test case and snapshots * test(ui/collapse): add test case and snapshots * feat: handle pnpm-lock * chore: handle pnpm-lock * test(ui/index-bar): add test case and snapshots * fix: undo merge Code changes * test: Merge branch 'dev' from upstream * test(ui/lazy): add test case and snapshots * fix: remove test code * test(ui/action-sheet): add test case and snapshots * test(ui/date-picker): add test case and snaps * test(ui/date-picker): fix .at error * test(ui/date-picker): fix .at error * test(ui/counter): add test case * refactor: code optimize * feat: add component bottom-navigation
1 parent 01650e1 commit 2ca9973

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1873
-202
lines changed

packages/varlet-vue2-cli/src/commands/changelog.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { resolve as resolvePath } from 'path'
55
import { CWD } from '../shared/constant'
66

77
interface ChangelogCommandOptions {
8-
file?: string;
9-
releaseCount?: number;
8+
file?: string
9+
releaseCount?: number
1010
}
1111

1212
export function changelog({ releaseCount = 0, file = 'CHANGELOG.md' }: ChangelogCommandOptions = {}): Promise<void> {

packages/varlet-vue2-cli/src/commands/jest.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import { runCLI } from 'jest'
33
import { CWD, JEST_CONFIG } from '../shared/constant'
44

55
interface JestCommandOptions {
6-
watch?: boolean;
7-
watchAll?: boolean;
8-
component?: string;
9-
clearCache?: boolean;
6+
watch?: boolean
7+
watchAll?: boolean
8+
component?: string
9+
clearCache?: boolean
1010
}
1111

1212
export async function jest(cmd: JestCommandOptions) {
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<template>
2+
<button
3+
class="var-bottom-navigation-item"
4+
ref="bottomNavigationItem"
5+
v-ripple
6+
:style="{
7+
color: computeColorStyle(),
8+
}"
9+
@click="handleClick"
10+
>
11+
<var-icon
12+
v-if="icon && !$slots.icon"
13+
:name="icon"
14+
:namespace="namespace"
15+
class="var-bottom-navigation-item__icon"
16+
/>
17+
<slot name="icon" :active="isActive"></slot>
18+
<var-badge v-if="badge" v-bind="badgeProps" class="var-bottom-navigation-item__badge" />
19+
<span class="var-bottom-navigation-item__label">
20+
<template v-if="!$slots.default">
21+
{{ label }}
22+
</template>
23+
<slot></slot>
24+
</span>
25+
</button>
26+
</template>
27+
28+
<script>
29+
import Ripple from '../ripple'
30+
import VarBadge from '../badge'
31+
import VarIcon from '../icon'
32+
import { defineComponent } from '../utils/create'
33+
import { props } from './props'
34+
import { createChildrenMixin } from '../utils/mixins/relation'
35+
36+
const defaultBadgeProps = {
37+
type: 'danger',
38+
dot: true,
39+
}
40+
41+
export default defineComponent({
42+
name: 'VarBottomNavigationItem',
43+
components: {
44+
VarBadge,
45+
VarIcon,
46+
},
47+
directives: { Ripple },
48+
49+
mixins: [
50+
createChildrenMixin('bottomNavigation', { parentKey: 'bottomNavigation', childrenKey: 'bottomNavigationItems' }),
51+
],
52+
53+
inheritAttrs: false,
54+
props,
55+
56+
data: () => ({
57+
isActive: false,
58+
badgeProps: {},
59+
}),
60+
61+
mounted() {
62+
this.isActive = this.name === this.bottomNavigation.active || this.index === this.bottomNavigation.active
63+
64+
if (this.isActive) {
65+
this.$refs.bottomNavigationItem.classList.add('var-bottom-navigation-item--active')
66+
}
67+
},
68+
69+
watch: {
70+
badge: {
71+
handler(newValue) {
72+
this.badgeProps = newValue === true ? defaultBadgeProps : this.badge
73+
},
74+
immediate: true,
75+
},
76+
},
77+
78+
methods: {
79+
computeColorStyle() {
80+
const { activeColor, inactiveColor } = this.bottomNavigation
81+
82+
return this.isActive ? activeColor : inactiveColor
83+
},
84+
setCurrent(value) {
85+
const _isActive = value === this.index || value === this.name
86+
87+
if (_isActive === this.isActive) {
88+
return
89+
}
90+
91+
this.isActive = _isActive
92+
93+
if (this.isActive) {
94+
this.$refs.bottomNavigationItem.classList.add('var-bottom-navigation-item--active')
95+
} else {
96+
this.$refs.bottomNavigationItem.classList.remove('var-bottom-navigation-item--active')
97+
}
98+
},
99+
handleClick() {
100+
const { name, getListeners, index } = this
101+
const active = name ?? index
102+
103+
getListeners().onClick?.(active)
104+
this.bottomNavigation.onToggle(active)
105+
},
106+
},
107+
})
108+
</script>
109+
110+
<style lang="less">
111+
@import '../styles/common';
112+
@import '../ripple/ripple';
113+
@import '../badge/badge';
114+
@import '../icon/icon';
115+
@import './bottomNavigationItem';
116+
</style>
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
@bottom-navigation-item-font-size: var(--font-size-sm);
2+
@bottom-navigation-item-inactive-color: #646566;
3+
@bottom-navigation-item-active-color: var(--color-primary);
4+
@bottom-navigation-item-active-background-color: #fff;
5+
@bottom-navigation-item-line-height: 1;
6+
@bottom-navigation-item-icon-size: 22px;
7+
@bottom-navigation-item-icon-margin-bottom: 5px;
8+
9+
:root {
10+
--bottom-navigation-item-font-size: @bottom-navigation-item-font-size;
11+
--bottom-navigation-item-inactive-color: @bottom-navigation-item-inactive-color;
12+
--bottom-navigation-item-active-color: @bottom-navigation-item-active-color;
13+
--bottom-navigation-item-active-background-color: @bottom-navigation-item-active-background-color;
14+
--bottom-navigation-item-line-height: @bottom-navigation-item-line-height;
15+
--bottom-navigation-item-icon-size: @bottom-navigation-item-icon-size;
16+
--bottom-navigation-item-icon-margin-bottom: @bottom-navigation-item-icon-margin-bottom;
17+
}
18+
19+
.var-bottom-navigation-item {
20+
height: 100%;
21+
padding: 6px 12px 8px;
22+
position: relative;
23+
display: inline-flex;
24+
flex: 1 1 0%;
25+
flex-direction: column;
26+
align-items: center;
27+
justify-content: center;
28+
line-height: var(--bottom-navigation-item-line-height);
29+
color: var(--bottom-navigation-item-inactive-color);
30+
cursor: pointer;
31+
user-select: none;
32+
vertical-align: middle;
33+
appearance: none;
34+
text-decoration: none;
35+
background-color: transparent;
36+
outline: 0;
37+
border: 0;
38+
transition: color 250ms, margin 250ms;
39+
40+
&--active {
41+
color: var(--bottom-navigation-item-active-color);
42+
background-color: var(--bottom-navigation-item-active-background-color);
43+
transition: background-color 250ms;
44+
45+
.var-bottom-navigation-item__label {
46+
font-size: calc(var(--bottom-navigation-item-font-size) * 1.16);
47+
}
48+
}
49+
50+
&--right-half-space {
51+
margin-right: calc(var(--bottom-navigation-height) / 2);
52+
}
53+
54+
&--left-half-space {
55+
margin-left: calc(var(--bottom-navigation-height) / 2);
56+
}
57+
58+
&--right-space {
59+
margin-right: calc(var(--bottom-navigation-height) + var(--bottom-navigation-fab-offset));
60+
}
61+
62+
&__icon {
63+
font-size: var(--bottom-navigation-item-icon-size);
64+
}
65+
66+
&__badge {
67+
position: absolute;
68+
left: 40px;
69+
transform: translateY(-16px);
70+
}
71+
72+
&__label {
73+
margin-top: var(--bottom-navigation-item-icon-margin-bottom);
74+
font-size: var(--bottom-navigation-item-font-size);
75+
transition: font-size 0.2s ease 0.1s;
76+
white-space: nowrap;
77+
}
78+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
## API
2+
3+
### 属性
4+
5+
|参数 | 说明 | 类型 | 默认值 |
6+
| ---- | ---- | ---- | ---- |
7+
| `name` | 标签名称,作为匹配的标识符 | _string_ | `-` |
8+
| `icon` | 图标名称,等同于 Icon 组件的 [name 属性](/#/zh-CN/icon) | _string_ | `-` |
9+
| `label` | 标签文字内容 | _string_ | - |
10+
| `namespace` | 图标的命名空间, 可扩展自定义图标库,等同于 Icon 组件的 [namespace 属性](/#/zh-CN/icon) | _string_ | `var-icon` |
11+
| `badge` | 图标右上角徽标 | _boolean \| BadgeProps_ | `false` |
12+
13+
### 事件
14+
15+
|事件名 | 说明 | 回调参数 |
16+
| ---- | ---- | ---- |
17+
| `click` | 点击时触发 | `active: number \| string` |
18+
19+
### 插槽
20+
21+
| 名称 | 说明 | 参数 |
22+
| ---- | ---- | ----|
23+
| `default` | 自定义标签文字内容,会覆盖 `label` 的内容 | `-` |
24+
| `icon` | 自定义图标 | `active: boolean` |
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import type { VueConstructor } from 'vue'
2+
import BottomNavigationItem from './BottomNavigationItem.vue'
3+
4+
BottomNavigationItem.install = function (app: VueConstructor) {
5+
app.component(BottomNavigationItem.name, BottomNavigationItem)
6+
}
7+
8+
export const _BottomNavigationItemComponent = BottomNavigationItem
9+
10+
export default BottomNavigationItem
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import type { PropType } from 'vue'
2+
import type { BadgeProps } from '../../types'
3+
4+
export const props = {
5+
name: {
6+
type: String,
7+
},
8+
icon: {
9+
type: String,
10+
},
11+
label: {
12+
type: String,
13+
},
14+
namespace: {
15+
type: String,
16+
default: 'var-icon',
17+
},
18+
badge: {
19+
type: [Boolean, Object] as PropType<boolean | Partial<BadgeProps>>,
20+
default: false,
21+
},
22+
onClick: {
23+
type: Function as PropType<(active: number | string) => void>,
24+
},
25+
}

0 commit comments

Comments
 (0)