Skip to content

Commit 942bf31

Browse files
authored
feat(b-avatar): add size classes for sm and lg sizes (closes #5592) (#5768)
* feat(b-avatar): add size classes for `sm` and `lg` * Update avatar.js * Update avatar.js * Update avatar.js * Update avatar-group.spec.js
1 parent 7ec2205 commit 942bf31

File tree

5 files changed

+85
-39
lines changed

5 files changed

+85
-39
lines changed

src/_variables.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,14 @@ $b-popover-bg-level: $alert-bg-level !default;
153153
$b-popover-border-level: $alert-border-level !default;
154154
$b-popover-color-level: $alert-color-level !default;
155155

156+
// --- Avatar ---
157+
158+
$b-avatar-size: 2.5rem !default;
159+
$b-avatar-size-sm: 1.5rem !default;
160+
$b-avatar-size-lg: 3.5rem !default;
161+
$b-avatar-font-size-scale: 0.4 !default;
162+
$b-avatar-badge-font-size-scale: $b-avatar-font-size-scale * 0.7 !default;
163+
156164
// --- Skeleton ---
157165

158166
$b-skeleton-background-color: rgba(0, 0, 0, 0.12) !default;

src/components/avatar/_avatar.scss

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
align-items: center;
66
justify-content: center;
77
vertical-align: middle;
8+
width: $b-avatar-size;
9+
height: $b-avatar-size;
810
font-size: inherit;
911
font-weight: 400;
1012
line-height: 1;
@@ -100,6 +102,32 @@
100102
}
101103
}
102104

105+
.b-avatar-sm {
106+
width: $b-avatar-size-sm;
107+
height: $b-avatar-size-sm;
108+
109+
.b-avatar-text {
110+
font-size: calc(#{$b-avatar-size-sm * $b-avatar-font-size-scale});
111+
}
112+
113+
.b-avatar-badge {
114+
font-size: calc(#{$b-avatar-size-sm * $b-avatar-badge-font-size-scale});
115+
}
116+
}
117+
118+
.b-avatar-lg {
119+
width: $b-avatar-size-lg;
120+
height: $b-avatar-size-lg;
121+
122+
.b-avatar-text {
123+
font-size: calc(#{$b-avatar-size-lg * $b-avatar-font-size-scale});
124+
}
125+
126+
.b-avatar-badge {
127+
font-size: calc(#{$b-avatar-size-lg * $b-avatar-badge-font-size-scale});
128+
}
129+
}
130+
103131
.b-avatar-group {
104132
.b-avatar-group-inner {
105133
display: flex;

src/components/avatar/avatar-group.spec.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,20 @@ describe('avatar-group', () => {
5555

5656
wrapper.destroy()
5757
})
58+
59+
it('overlap props work', async () => {
60+
const wrapper = mount(BAvatarGroup, {
61+
propsData: {
62+
overlap: 0.65
63+
}
64+
})
65+
66+
expect(wrapper.vm).toBeDefined()
67+
await waitNT(wrapper.vm)
68+
69+
expect(wrapper.vm.overlap).toBe(0.65)
70+
expect(wrapper.vm.overlapScale).toBe(0.325)
71+
72+
wrapper.destroy()
73+
})
5874
})

src/components/avatar/avatar.js

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Vue from '../../utils/vue'
22
import { getComponentConfig } from '../../utils/config'
3-
import { isNumber, isString, isUndefinedOrNull } from '../../utils/inspect'
3+
import { isNumber, isString } from '../../utils/inspect'
44
import { toFloat } from '../../utils/number'
55
import { omit } from '../../utils/object'
66
import { pluckProps } from '../../utils/props'
@@ -15,17 +15,13 @@ import normalizeSlotMixin from '../../mixins/normalize-slot'
1515
const NAME = 'BAvatar'
1616
const CLASS_NAME = 'b-avatar'
1717

18+
const SIZES = ['sm', null, 'lg']
19+
1820
const RX_NUMBER = /^[0-9]*\.?[0-9]+$/
1921

2022
const FONT_SIZE_SCALE = 0.4
2123
const BADGE_FONT_SIZE_SCALE = FONT_SIZE_SCALE * 0.7
2224

23-
const DEFAULT_SIZES = {
24-
sm: '1.5em',
25-
md: '2.5em',
26-
lg: '3.5em'
27-
}
28-
2925
// --- Props ---
3026
const linkProps = omit(BLinkProps, ['active', 'event', 'routerTag'])
3127

@@ -99,18 +95,10 @@ const props = {
9995

10096
// --- Utility methods ---
10197
export const computeSize = value => {
102-
// Default to `md` size when `null`, or parse to
103-
// number when value is a float-like string
104-
value =
105-
isUndefinedOrNull(value) || value === ''
106-
? 'md'
107-
: isString(value) && RX_NUMBER.test(value)
108-
? toFloat(value, 0)
109-
: value
98+
// Parse to number when value is a float-like string
99+
value = isString(value) && RX_NUMBER.test(value) ? toFloat(value, 0) : value
110100
// Convert all numbers to pixel values
111-
// Handle default sizes when `sm`, `md` or `lg`
112-
// Or use value as is
113-
return isNumber(value) ? `${value}px` : DEFAULT_SIZES[value] || value
101+
return isNumber(value) ? `${value}px` : value || null
114102
}
115103

116104
// --- Main component ---
@@ -130,36 +118,35 @@ export const BAvatar = /*#__PURE__*/ Vue.extend({
130118
computed: {
131119
computedSize() {
132120
// Always use the avatar group size
133-
return computeSize(this.bvAvatarGroup ? this.bvAvatarGroup.size : this.size)
121+
const { bvAvatarGroup } = this
122+
return computeSize(bvAvatarGroup ? bvAvatarGroup.size : this.size)
134123
},
135124
computedVariant() {
136-
// Prefer avatar-group variant if provided
137-
const avatarGroup = this.bvAvatarGroup
138-
return avatarGroup && avatarGroup.variant ? avatarGroup.variant : this.variant
125+
const { bvAvatarGroup } = this
126+
return bvAvatarGroup && bvAvatarGroup.variant ? bvAvatarGroup.variant : this.variant
139127
},
140128
computedRounded() {
141-
const avatarGroup = this.bvAvatarGroup
142-
const square = avatarGroup && avatarGroup.square ? true : this.square
143-
const rounded = avatarGroup && avatarGroup.rounded ? avatarGroup.rounded : this.rounded
129+
const { bvAvatarGroup } = this
130+
const square = bvAvatarGroup && bvAvatarGroup.square ? true : this.square
131+
const rounded = bvAvatarGroup && bvAvatarGroup.rounded ? bvAvatarGroup.rounded : this.rounded
144132
return square ? '0' : rounded === '' ? true : rounded || 'circle'
145133
},
146134
fontStyle() {
147-
let fontSize = this.computedSize
148-
fontSize = fontSize ? `calc(${fontSize} * ${FONT_SIZE_SCALE})` : null
135+
const { computedSize: size } = this
136+
const fontSize = SIZES.indexOf(size) === -1 ? `calc(${size} * ${FONT_SIZE_SCALE})` : null
149137
return fontSize ? { fontSize } : {}
150138
},
151139
marginStyle() {
152-
const avatarGroup = this.bvAvatarGroup
153-
const overlapScale = avatarGroup ? avatarGroup.overlapScale : 0
154-
const size = this.computedSize
140+
const { computedSize: size, bvAvatarGroup } = this
141+
const overlapScale = bvAvatarGroup ? bvAvatarGroup.overlapScale : 0
155142
const value = size && overlapScale ? `calc(${size} * -${overlapScale})` : null
156143
return value ? { marginLeft: value, marginRight: value } : {}
157144
},
158145
badgeStyle() {
159146
const { computedSize: size, badgeTop, badgeLeft, badgeOffset } = this
160147
const offset = badgeOffset || '0px'
161148
return {
162-
fontSize: size ? `calc(${size} * ${BADGE_FONT_SIZE_SCALE} )` : null,
149+
fontSize: SIZES.indexOf(size) === -1 ? `calc(${size} * ${BADGE_FONT_SIZE_SCALE} )` : null,
163150
top: badgeTop ? offset : null,
164151
bottom: badgeTop ? null : offset,
165152
left: badgeLeft ? offset : null,
@@ -246,6 +233,8 @@ export const BAvatar = /*#__PURE__*/ Vue.extend({
246233
const componentData = {
247234
staticClass: CLASS_NAME,
248235
class: {
236+
// Apply size class
237+
[`${CLASS_NAME}-${size}`]: size && SIZES.indexOf(size) !== -1,
249238
// We use badge styles for theme variants when not rendering `BButton`
250239
[`badge-${variant}`]: !button && variant,
251240
// Rounding/Square
@@ -254,7 +243,7 @@ export const BAvatar = /*#__PURE__*/ Vue.extend({
254243
// Other classes
255244
disabled
256245
},
257-
style: { width: size, height: size, ...marginStyle },
246+
style: { ...marginStyle, width: size, height: size },
258247
attrs: { 'aria-label': ariaLabel || null },
259248
props: button ? { variant, disabled, type } : link ? pluckProps(linkProps, this) : {},
260249
on: button || link ? { click: this.onClick } : {}

src/components/avatar/avatar.spec.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -180,19 +180,22 @@ describe('avatar', () => {
180180

181181
it('`size` prop should work as expected', async () => {
182182
const wrapper1 = mount(BAvatar)
183-
expect(wrapper1.attributes('style')).toEqual('width: 2.5em; height: 2.5em;')
183+
expect(wrapper1.attributes('style')).toEqual(undefined)
184184
wrapper1.destroy()
185185

186186
const wrapper2 = mount(BAvatar, { propsData: { size: 'sm' } })
187-
expect(wrapper2.attributes('style')).toEqual('width: 1.5em; height: 1.5em;')
187+
expect(wrapper2.attributes('style')).toEqual(undefined)
188+
expect(wrapper2.classes()).toContain('b-avatar-sm')
188189
wrapper2.destroy()
189190

190191
const wrapper3 = mount(BAvatar, { propsData: { size: 'md' } })
191-
expect(wrapper3.attributes('style')).toEqual('width: 2.5em; height: 2.5em;')
192+
expect(wrapper3.attributes('style')).toEqual(undefined)
193+
expect(wrapper3.classes()).not.toContain('b-avatar-md')
192194
wrapper3.destroy()
193195

194196
const wrapper4 = mount(BAvatar, { propsData: { size: 'lg' } })
195-
expect(wrapper4.attributes('style')).toEqual('width: 3.5em; height: 3.5em;')
197+
expect(wrapper4.attributes('style')).toEqual(undefined)
198+
expect(wrapper4.classes()).toContain('b-avatar-lg')
196199
wrapper4.destroy()
197200

198201
const wrapper5 = mount(BAvatar, { propsData: { size: 20 } })
@@ -255,7 +258,8 @@ describe('avatar', () => {
255258
expect(wrapper1.element.tagName).toBe('SPAN')
256259
expect(wrapper1.classes()).toContain('b-avatar')
257260
expect(wrapper1.classes()).toContain('badge-secondary')
258-
expect(wrapper1.attributes('style')).toContain('width: 2.5em; height: 2.5em;')
261+
// Uses avatar group size (default)
262+
expect(wrapper1.attributes('style')).toBe(undefined)
259263

260264
wrapper1.destroy()
261265

@@ -272,7 +276,8 @@ describe('avatar', () => {
272276
expect(wrapper2.classes()).toContain('b-avatar')
273277
expect(wrapper2.classes()).toContain('badge-danger')
274278
expect(wrapper2.classes()).not.toContain('badge-secondary')
275-
expect(wrapper2.attributes('style')).toContain('width: 2.5em; height: 2.5em;')
279+
// Uses avatar group size (default)
280+
expect(wrapper2.attributes('style')).toBe(undefined)
276281

277282
wrapper2.destroy()
278283
})
@@ -293,7 +298,7 @@ describe('avatar', () => {
293298
expect(wrapper1.classes()).toContain('b-avatar')
294299
expect(wrapper1.classes()).toContain('badge-secondary')
295300
// Uses avatar group size (default)
296-
expect(wrapper1.attributes('style')).toContain('width: 2.5em; height: 2.5em;')
301+
expect(wrapper1.attributes('style')).toBe(undefined)
297302

298303
wrapper1.destroy()
299304

0 commit comments

Comments
 (0)