Skip to content

Commit

Permalink
feat(VsChip): add vs-chip component
Browse files Browse the repository at this point in the history
  • Loading branch information
seaneez committed Dec 28, 2023
1 parent 3fcbed4 commit a04807d
Show file tree
Hide file tree
Showing 11 changed files with 470 additions and 2 deletions.
11 changes: 11 additions & 0 deletions packages/vlossom/.storybook/examples/style-set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,23 @@ import type {
VsValueTagStyleSet,
VsNoticeStyleSet,
VsProgressStyleSet,
VsChipStyleSet,
} from '@/components/types';

const vsButton: VsButtonStyleSet = {
backgroundColor: '#1e88e5',
color: 'white',
};

const vsChip: VsChipStyleSet = {
backgroundColor: '#a5d6ad',
borderRadius: '1.2rem',
color: '#304d30',
height: '3rem',
minHeight: '2rem',
padding: '0.8rem 1.5rem',
};

const vsDivider: VsDividerStyleSet = {
lineColor: '#7071e8',
lineStyle: 'double',
Expand Down Expand Up @@ -61,6 +71,7 @@ const vsProgress: VsProgressStyleSet = {

export const styleSet: StyleSet = {
VsButton: { myStyleSet: vsButton },
VsChip: { myStyleSet: vsChip },
VsDivider: { myStyleSet: vsDivider },
VsInput: { myStyleSet: vsInput },
VsNotice: { myStyleSet: vsNotice },
Expand Down
6 changes: 6 additions & 0 deletions packages/vlossom/src/assets/icons/check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
template: `
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24">
<path fill="currentColor" d="M382-240 154-468l57-57 171 171 367-367 57 57-424 424Z"/>
</svg>`,
};
4 changes: 2 additions & 2 deletions packages/vlossom/src/assets/icons/close.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export default {
template: `
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="currentColor">
<path d="M0 0h24v24H0z" fill="none"/><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24">
<path fill="currentColor" d="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z"/>
</svg>`,
};
6 changes: 6 additions & 0 deletions packages/vlossom/src/assets/icons/person.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
template: `
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24">
<path fill="currentColor" d="M480-480q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47ZM160-160v-112q0-34 17.5-62.5T224-378q62-31 126-46.5T480-440q66 0 130 15.5T736-378q29 15 46.5 43.5T800-272v112H160Zm80-80h480v-32q0-11-5.5-20T700-306q-54-27-109-40.5T480-360q-56 0-111 13.5T260-306q-9 5-14.5 14t-5.5 20v32Zm240-320q33 0 56.5-23.5T560-640q0-33-23.5-56.5T480-720q-33 0-56.5 23.5T400-640q0 33 23.5 56.5T480-560Zm0-80Zm0 400Z"/>
</svg>`,
};
1 change: 1 addition & 0 deletions packages/vlossom/src/components/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export type * from './vs-button';
export type * from './vs-chip';
export type * from './vs-container';
export type * from './vs-divider';
export type * from './vs-form';
Expand Down
85 changes: 85 additions & 0 deletions packages/vlossom/src/components/vs-chip/VsChip.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
.vs-chip {
button {
all: unset;
}

align-items: center;
background-color: var(--vs-chip-backgroundColor, var(--vs-comp-backgroundColor));
border: var(--vs-chip-outlineBorder, 1px solid var(--vs-comp-color), 0);
border-radius: var(--vs-chip-borderRadius, 1.3rem);
color: var(--vs-chip-color, var(--vs-comp-color));
display: inline-flex;
font-size: var(--vs-chip-fontSize, 0.82rem);
font-weight: var(--vs-button-fontWeight, 400);
height: var(--vs-chip-height, 1.5rem);
justify-content: center;
min-height: var(--vs-chip-minHeight, 1.2rem);
padding: 0 0.4rem;
position: relative;

&:after {
background: #ffffff;
content: '';
display: block;
height: 100%;
left: 0;
opacity: 0;
pointer-events: none;
position: absolute;
top: 0;
transition: all 0.4s ease-out;
width: 120%;
}

.vs-chip-icon {
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
}

.vs-chip-leading-icon {
overflow: hidden;
}

.vs-chip-close {
background-color: rgba(255, 255, 255, 0.7);
cursor: pointer;
height: calc(var(--vs-chip-height, 1.2rem) * 0.8);
width: calc(var(--vs-chip-height, 1.2rem) * 0.8);
}

.vs-chip-content {
padding: var(--vs-chip-padding, 0 0.2rem);
}

.vs-chip-icon + .vs-chip-content {
margin-left: 0.05rem;
}

&.noRound {
border-radius: 0.25rem;
.chip-icon {
border-radius: 0.25rem;
}
}

&.clickable {
cursor: pointer;

&:active:after {
opacity: 0.6;
transition: 0s;
width: 0%;
}
}

&.primary {
background-color: var(--vs-chip-backgroundColor, var(--vs-comp-backgroundColor-primary));
color: var(--vs-chip-color, var(--vs-comp-color-primary));
}
}

.vs-chip + .vs-chip {
margin-left: 0.2rem;
}
81 changes: 81 additions & 0 deletions packages/vlossom/src/components/vs-chip/VsChip.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<template>
<div :class="['vs-chip', `vs-${computedColorScheme}`, { ...classObj }]" :style="customProperties">
<span v-if="hasLeadingIcon" class="vs-chip-icon vs-chip-leading-icon">
<slot name="leading-icon" />
</span>

<span class="vs-chip-content">
<slot />
</span>

<button v-if="closable" type="button" class="vs-chip-icon vs-chip-close" @click.stop="$emit('close')">
<close aria-label="close" class="close-icon" />
</button>
</div>
</template>

<script lang="ts">
import { PropType, computed, defineComponent, toRefs, useAttrs } from 'vue';
import { useColorScheme, useCustomStyle } from '@/composables';
import { ColorScheme, VsComponent } from '@/declaration/types';
import Close from '@/assets/icons/close';
interface ChipStyleSet {
backgroundColor: string;
borderRadius: string;
color: string;
fontSize: string;
fontWeight: string;
height: string;
minHeight: string;
outlineBorder: string;
padding: string;
}
export type VsChipStyleSet = Partial<ChipStyleSet>;
interface SetupContextAttrs {
onClick?: () => void;
}
const name = VsComponent.VsChip;
export default defineComponent({
name,
components: { Close },
props: {
closable: { type: Boolean, default: false },
colorScheme: { type: String as PropType<ColorScheme> },
noRound: { type: Boolean, default: false },
primary: { type: Boolean, default: false },
styleSet: { type: [String, Object] as PropType<string | VsChipStyleSet>, default: '' },
},
emits: ['close'],
setup(props, { slots }) {
const { colorScheme, noRound, primary, styleSet } = toRefs(props);
const { computedColorScheme } = useColorScheme(name, colorScheme);
const { customProperties } = useCustomStyle<VsChipStyleSet>(name, styleSet);
const hasLeadingIcon = computed((): boolean => !!slots['leading-icon']);
const attrs: SetupContextAttrs = useAttrs();
const classObj = computed(() => ({
noRound: noRound.value,
primary: primary.value,
clickable: attrs.onClick ?? false,
}));
return {
hasLeadingIcon,
computedColorScheme,
customProperties,
classObj,
};
},
});
</script>

<style lang="scss" scoped src="./VsChip.scss" />
73 changes: 73 additions & 0 deletions packages/vlossom/src/components/vs-chip/__tests__/vs-chip.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { describe, expect, it, beforeEach } from 'vitest';
import { mount } from '@vue/test-utils';
import VsChip from './../VsChip.vue';

function mountComponent() {
return mount(VsChip);
}

describe('vs-chip', () => {
describe('leading-icon', () => {
it('leading-icon ์žˆ๋Š” ๊ฒฝ์šฐ leading-icon ์Šฌ๋กฏ์ด ๋ Œ๋”๋œ๋‹ค', () => {
// given
const wrapper = mount(VsChip, {
slots: {
'leading-icon': '<div>icon</div>',
},
});

// then
expect(wrapper.find('.vs-chip-leading-icon').exists()).toBe(true);
expect(wrapper.html()).toContain('<div>icon</div>');
});
it('leading-icon์ด ์—†๋Š” ๊ฒฝ์šฐ leading-icon ์Šฌ๋กฏ์ด ๋ Œ๋”๋˜์ง€ ์•Š๋Š”๋‹ค', () => {
// given
const wrapper = mount(VsChip);

// then
expect(wrapper.find('.vs-chip-leading-icon').exists()).toBe(false);
expect(wrapper.html()).not.toContain('<div>icon</div>');
});
});

describe('closable', () => {
describe('closable ์ด true ์ธ ๊ฒฝ์šฐ', () => {
let wrapper: ReturnType<typeof mountComponent>;

// given
beforeEach(() => {
wrapper = mount(VsChip, {
props: {
closable: true,
},
});
});

it('close ๋ฒ„ํŠผ์ด ๋ Œ๋”๋œ๋‹ค', () => {
// then
expect(wrapper.find('.vs-chip-close').exists()).toBe(true);
});

it('close ๋ฒ„ํŠผ์ด ๋ˆŒ๋ ธ์„ ๋•Œ close ํ•จ์ˆ˜๋ฅผ emit ํ•œ๋‹ค', async () => {
// when
const closeBtn = wrapper.find('.vs-chip-close');
await closeBtn.trigger('click');

// then
expect(wrapper.emitted()).toHaveProperty('close');
});
});

it('closable ์ด false ์ธ ๊ฒฝ์šฐ close ๋ฒ„ํŠผ์ด ๋ Œ๋”๋˜์ง€ ์•Š๋Š”๋‹ค', () => {
// given
const wrapper = mount(VsChip, {
props: {
closable: false,
},
});

// then
expect(wrapper.find('.vs-chip-close').exists()).toBe(false);
});
});
});
12 changes: 12 additions & 0 deletions packages/vlossom/src/components/vs-chip/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { VsComponent } from '@/declaration/types';
import VsChip from './VsChip.vue';
import type { VsChipStyleSet } from './VsChip.vue';

type VsChipInstance = InstanceType<typeof VsChip>;

export type { VsChipInstance, VsChipStyleSet };

export default {
name: VsComponent.VsChip,
component: VsChip,
};
Loading

0 comments on commit a04807d

Please sign in to comment.