Skip to content

Commit a26cfc2

Browse files
committed
Allow adding labels to ipl-button through its default slot
1 parent 1206ecd commit a26cfc2

File tree

7 files changed

+156
-38
lines changed

7 files changed

+156
-38
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# 3.1.0
2+
3+
- Allow adding labels to ipl-button through its default slot
4+
- For example, this can be used to make a button's label contain an icon and text simultaneously.
5+
- Allow disabling text capitalization on ipl-button
6+
17
# 3.0.1
28

39
- Fix content within the header-extra slot of ipl-expanding-space sometimes being invisible
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<template>
2+
<div class="width-capped-content vertical-layout">
3+
<!-- #region example -->
4+
<ipl-button
5+
:disabled="disabled"
6+
:small="small"
7+
>
8+
<font-awesome-icon
9+
icon="file"
10+
class="icon"
11+
/>
12+
Custom Content
13+
</ipl-button>
14+
15+
<ipl-button
16+
v-slot="{ state }"
17+
requires-confirmation
18+
:disabled="disabled"
19+
:small="small"
20+
>
21+
<font-awesome-icon
22+
icon="file"
23+
class="icon"
24+
/>
25+
{{ state === 'confirm' ? 'Confirm?' : 'Requires Confirmation' }}
26+
</ipl-button>
27+
28+
<ipl-button
29+
v-slot="{ state }"
30+
async
31+
:disabled="disabled"
32+
:small="small"
33+
@click="asyncSuccess"
34+
>
35+
<template v-if="state === 'idle'">
36+
Async
37+
</template>
38+
<template v-else-if="state === 'loading'">
39+
Working...
40+
</template>
41+
<template v-else-if="state === 'success'">
42+
Done!
43+
</template>
44+
<template v-else-if="state === 'error'">
45+
Error!
46+
</template>
47+
</ipl-button>
48+
<!-- #endregion example -->
49+
</div>
50+
<div class="horizontal-layout">
51+
<ipl-checkbox
52+
v-model="disabled"
53+
label="Disabled"
54+
/>
55+
<ipl-checkbox
56+
v-model="small"
57+
label="Small"
58+
/>
59+
</div>
60+
</template>
61+
62+
<script setup lang="ts">
63+
import IplButton from '../../src/components/iplButton.vue';
64+
import IplCheckbox from '../../src/components/iplCheckbox.vue';
65+
import { ref } from 'vue';
66+
import { library } from '@fortawesome/fontawesome-svg-core';
67+
import { faFile } from '@fortawesome/free-solid-svg-icons';
68+
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
69+
70+
library.add(faFile);
71+
72+
const disabled = ref(false);
73+
const small = ref(false);
74+
75+
async function asyncSuccess() {
76+
return new Promise(resolve => {
77+
setTimeout(resolve, 2500);
78+
});
79+
}
80+
</script>

docs/examples/ButtonExample.vue

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
<template>
2-
<div class="width-capped-content">
2+
<div class="width-capped-content vertical-layout">
33
<!-- #region example -->
44
<ipl-button
55
label="Button"
66
:disabled="disabled"
77
:small="small"
88
/>
9+
<ipl-button
10+
label="Button"
11+
:disabled="disabled"
12+
:small="small"
13+
class="no-text-transform"
14+
/>
915
<!-- #endregion example -->
1016
</div>
1117
<div class="horizontal-layout">

docs/ipl-button.md

+4
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,7 @@ title: ipl-button
3333
## Transparent
3434

3535
::: demo ButtonTransparentExample
36+
37+
## Custom Content
38+
39+
::: demo ButtonCustomContentExample

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@iplsplatoon/vue-components",
3-
"version": "3.0.1",
3+
"version": "3.1.0",
44
"description": "Vue components for internal Inkling Performance Labs utilities.",
55
"homepage": "https://github.com/IPLSplatoon/vue-components",
66
"repository": "https://github.com/IPLSplatoon/vue-components",

src/components/__tests__/iplButton.test.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ describe('iplButton', () => {
1818
expect(wrapper.find('span.label').text()).toEqual('Button');
1919
});
2020

21+
it('applies content from default slot', () => {
22+
const wrapper = shallowMount(IplButton, {
23+
slots: {
24+
default: () => 'test default slot'
25+
}
26+
});
27+
28+
expect(wrapper.find('span.label').text()).toEqual('test default slot');
29+
});
30+
2131
it('applies given href to button if present', () => {
2232
const wrapper = shallowMount(IplButton, { props: { label: 'Button', href: 'https://google.com/' } });
2333

@@ -30,10 +40,10 @@ describe('iplButton', () => {
3040
expect(wrapper.find('font-awesome-icon-stub.icon').attributes().icon).toEqual('cool-icon');
3141
});
3242

33-
it('does not create label element if icon is given', () => {
43+
it('creates icon element if icon is provided', () => {
3444
const wrapper = shallowMount(IplButton, { props: { icon: 'cool-icon', label: 'something' } });
3545

36-
expect(wrapper.find('span.label').exists()).toEqual(false);
46+
expect(wrapper.find('span.label').text()).toEqual('');
3747
expect(wrapper.find('font-awesome-icon-stub.icon').exists()).toEqual(true);
3848
});
3949

src/components/iplButton.vue

+46-34
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,36 @@
1919
@click="handleClick"
2020
@contextmenu="$emit('rightClick', $event)"
2121
>
22-
<span
23-
v-if="!isIconButton"
24-
class="label"
25-
>
26-
{{ labelInternal }}
22+
<span class="label">
23+
<slot :state="labelState">
24+
<span
25+
v-if="!isIconButton"
26+
class="default-label"
27+
>
28+
<template v-if="labelState === 'idle'">
29+
{{ label }}
30+
</template>
31+
<template v-else-if="labelState === 'confirm'">
32+
{{ shortConfirmationMessage ? 'Confirm?' : 'Are you sure?' }}
33+
</template>
34+
<template v-else-if="labelState === 'error'">
35+
Error!
36+
</template>
37+
<template v-else-if="labelState === 'loading'">
38+
Loading...
39+
</template>
40+
<template v-else-if="labelState === 'success'">
41+
{{ successMessage }}
42+
</template>
43+
</span>
44+
<font-awesome-icon
45+
v-else
46+
:icon="icon"
47+
class="icon"
48+
fixed-width
49+
/>
50+
</slot>
2751
</span>
28-
<font-awesome-icon
29-
v-else
30-
:icon="icon"
31-
class="icon"
32-
fixed-width
33-
/>
3452
</component>
3553
</template>
3654

@@ -110,10 +128,6 @@ export default defineComponent({
110128
emits: [ 'click', 'rightClick' ],
111129
112130
setup(props, { emit }) {
113-
if (props.icon == null && isBlank(props.label)) {
114-
console.warn('ipl-button requires an icon or label to be provided.');
115-
}
116-
117131
const instance = getCurrentInstance();
118132
let resetTimeout: number | null = null;
119133
let confirmationResetTimeout: number | null = null;
@@ -210,22 +224,13 @@ export default defineComponent({
210224
buttonState,
211225
isIconButton: computed(() => props.icon != null),
212226
disabledInternal,
213-
labelInternal: computed(() => {
227+
labelState: computed<'idle' | 'error' | 'success' | 'loading' | 'confirm'>(() => {
214228
if (props.requiresConfirmation && isClicked.value) {
215-
return props.shortConfirmationMessage ? 'Confirm?' : 'Are you sure?';
216-
}
217-
if (!props.async && !props.disableOnSuccess) return props.label;
218-
219-
switch (buttonState.value) {
220-
case 'error':
221-
return 'Error!';
222-
case 'loading':
223-
return props.progressMessage;
224-
case 'success':
225-
return props.successMessage;
226-
default:
227-
return props.label;
229+
return 'confirm';
228230
}
231+
if (!props.async && !props.disableOnSuccess) return 'idle';
232+
233+
return buttonState.value;
229234
}),
230235
isBlank,
231236
hasLink
@@ -239,7 +244,6 @@ export default defineComponent({
239244
240245
.ipl-button {
241246
text-decoration: none !important;
242-
text-transform: uppercase;
243247
font-size: 1em;
244248
font-weight: 700;
245249
font-family: constants.$body-font;
@@ -274,21 +278,29 @@ export default defineComponent({
274278
width: 2.4em;
275279
min-width: 2.4em;
276280
padding: 0.4em;
281+
282+
:deep(.icon) {
283+
height: 100%;
284+
width: 100%;
285+
}
277286
}
278287
279288
&.small {
280289
font-size: 0.75em;
281290
}
282291
283-
.label, .icon {
292+
.label, :deep(.icon) {
284293
z-index: 3;
285294
position: relative;
286295
user-select: none;
287296
}
288297
289-
.icon {
290-
height: 100%;
291-
width: 100%;
298+
.default-label {
299+
text-transform: uppercase;
300+
}
301+
302+
&.no-text-transform .default-label {
303+
text-transform: none;
292304
}
293305
294306
&.disabled {

0 commit comments

Comments
 (0)