Skip to content

Commit

Permalink
feat(button-group): refine styles (#222)
Browse files Browse the repository at this point in the history
Co-authored-by: Kia Ishii <kia.king.08@gmail.com>
  • Loading branch information
NozomuIkuta and kiaking committed Feb 15, 2023
1 parent 27223ff commit 06f5934
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 171 deletions.
1 change: 1 addition & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ function sidebar() {
items: [
{ text: 'SAvatar', link: '/components/avatar' },
{ text: 'SButton', link: '/components/button' },
{ text: 'SButtonGroup', link: '/components/button-group' },
{ text: 'SInputAddon', link: '/components/input-addon' },
{ text: 'SInputFile', link: '/components/input-file' },
{ text: 'SInputHMS', link: '/components/input-hms' },
Expand Down
61 changes: 61 additions & 0 deletions docs/components/button-group.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<script setup lang="ts">
import SButton from 'sefirot/components/SButton.vue'
import SButtonGroup from 'sefirot/components/SButtonGroup.vue'
</script>

# SButtonGroup

`<SButtonGroup>` is a component that groups multiple buttons together.

<Showcase
path="/components/SButtonGroup.vue"
story="/stories-components-sbuttongroup-01-playground-story-vue"
>
<SButtonGroup>
<SButton mode="mute" label="Left" />
<SButton mode="mute" label="Middle" />
<SButton mode="mute" label="Right" />
</SButtonGroup>
</Showcase>
## Usage

Wrap `<SButton>` with `<SButtonGroup>` component. Note that currently it does not support button types other than `:type="fill"`. If you pass other type buttons the style might get corrupted.

```vue
<script setup lang="ts">
import SButton from '@globalbrain/sefirot/lib/components/SButton.vue'
import SButtonGroup from '@globalbrain/sefirot/lib/components/SButtonGroup.vue'
</script>
<template>
<SButtonGroup>
<SButton mode="mute" label="Left" />
<SButton mode="mute" label="Middle" />
<SButton mode="mute" label="Right" />
</SButtonGroup>
</template>
```

## Slots

Here are the list of slots you may define within the component.

### `#default`

You may pass in any number of `<SButton>` components. The component will group them together.

```vue
<script setup lang="ts">
import SButton from '@globalbrain/sefirot/lib/components/SButton.vue'
import SButtonGroup from '@globalbrain/sefirot/lib/components/SButtonGroup.vue'
</script>
<template>
<SButtonGroup>
<SButton mode="mute" label="Left" />
<SButton mode="mute" label="Middle" />
<SButton mode="mute" label="Right" />
</SButtonGroup>
</template>
```
4 changes: 2 additions & 2 deletions lib/components/SButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ function handleClick(): void {
</component>
</template>

<style lang="postcss" scoped>
<style scoped lang="postcss">
.SButton {
position: relative;
display: inline-flex;
Expand Down Expand Up @@ -156,7 +156,7 @@ function handleClick(): void {
}
.SButton.fill {
font-weight: 600;
font-weight: 500;
&.neutral {
border-color: var(--button-fill-neutral-border-color);
Expand Down
149 changes: 9 additions & 140 deletions lib/components/SButtonGroup.vue
Original file line number Diff line number Diff line change
@@ -1,148 +1,17 @@
<script setup lang="ts">
import { PropType, computed } from 'vue'
export interface ButtonGroupItem {
label: string
value: string
mode?: Mode
}
export type Mode = 'neutral' | 'info' | 'success' | 'warning' | 'danger'
export type Size = 'mini' | 'small' | 'medium' | 'large' | 'jumbo'
const props = defineProps({
items: { type: Array as PropType<ButtonGroupItem[]>, required: true },
size: { type: String as PropType<Size>, default: 'medium' },
modelValue: { type: String, default: null }
})
const emit = defineEmits(['update:modelValue'])
const classes = computed(() => [props.size])
function getButtonClasses(button: ButtonGroupItem) {
return [
{ active: button.value === props.modelValue },
button.mode ?? 'neutral'
]
}
function handleClick(value: string) {
emit('update:modelValue', value)
}
</script>

<template>
<div class="SButtonGroup" :class="classes">
<button
v-for="item in items"
:key="item.value"
class="button"
:class="getButtonClasses(item)"
@click="handleClick(item.value)"
>
<span class="content">
{{ item.label }}
</span>
</button>
<div class="SButtonGroup">
<slot />
</div>
</template>

<style lang="postcss" scoped>
.SButtonGroup {
display: flex;
width: fit-content;
border: 1px solid var(--c-divider);
border-radius: 4px;
overflow: hidden;
}
.SButtonGroup.mini {
height: 28px;
.button {
padding: 0 8px;
height: 28px;
font-size: 12px;
font-weight: 500;
}
}
.SButtonGroup.small {
height: 32px;
.button {
padding: 0 10px;
height: 32px;
font-size: 12px;
font-weight: 500;
}
}
.SButtonGroup.medium {
height: 40px;
.button {
padding: 0 12px;
height: 40px;
font-size: 13px;
font-weight: 500;
}
}
.SButtonGroup.large {
height: 48px;
.button {
padding: 0 14px;
height: 48px;
font-size: 14px;
font-weight: 500;
}
}
.SButtonGroup.jumbo {
height: 64px;
.button {
padding: 0 24px;
height: 64px;
font-size: 14px;
font-weight: 500;
}
}
.button {
border-left: 1px solid transparent;
letter-spacing: .4px;
color: var(--c-text-2);
white-space: nowrap;
transition: color .25s, background-color .25s;
&:hover {
color: var(--c-text-1);
}
}
.button:not(:first-child) {
border-left: 1px solid var(--c-divider);
}
.button.active {
color: var(--c-text-dark-1);
}
<style scoped lang="postcss">
.SButtonGroup :slotted(.SButton) {
border-left-width: 0;
border-radius: 0;
.button.neutral.active { background-color: var(--c-black); }
.button.info.active { background-color: var(--c-info); }
.button.success.active { background-color: var(--c-success); }
.button.warning.active { background-color: var(--c-warning); }
.button.danger.active { background-color: var(--c-danger); }
&:first-child { border-left-width: 1px; }
.content {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
&:first-child { border-radius: 6px 0 0 6px; }
&:last-child { border-radius: 0 6px 6px 0; }
}
</style>
13 changes: 5 additions & 8 deletions lib/styles/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,11 @@ body {
min-width: 320px;
min-height: 100vh;
font-family: var(--font-family-base);
letter-spacing: .4px;
line-height: 24px;
font-size: 16px;
font-weight: 400;
color: var(--c-text-1);
background-color: var(--c-bg);
direction: ltr;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

blockquote,
Expand Down Expand Up @@ -103,7 +97,6 @@ iframe,
embed,
object {
display: block;
vertical-align: middle;
}

img,
Expand All @@ -119,6 +112,7 @@ select,
textarea {
border: 0;
padding: 0;
letter-spacing: inherit;
line-height: inherit;
color: inherit;
}
Expand Down Expand Up @@ -171,17 +165,20 @@ textarea {

input[type="number"] {
-moz-appearance: textfield;
appearance: textfield;
}

input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
-webkit-appearance: none;
appearance: none;
}

input[type="select"],
select {
-webkit-appearance: none;
appearance: none;
}

fieldset {
Expand Down
69 changes: 59 additions & 10 deletions stories/components/SButtonGroup.01_Playground.story.vue
Original file line number Diff line number Diff line change
@@ -1,20 +1,69 @@
<script setup lang="ts">
import SButtonGroup, { ButtonGroupItem } from 'sefirot/components/SButtonGroup.vue'
import { ref } from 'vue'
import SButton, { Mode, Size } from 'sefirot/components/SButton.vue'
import SButtonGroup from 'sefirot/components/SButtonGroup.vue'
const value = ref('button-a')
const items: ButtonGroupItem[] = [
{ label: 'Button A', value: 'button-a' },
{ label: 'Button B', value: 'button-b' },
{ label: 'Button C', value: 'button-c' }
]
function state() {
return {
size: 'medium' as Size,
mode: 'mute' as Mode,
labelA: 'Left',
labelB: 'Middle',
labelC: 'Right'
}
}
</script>

<template>
<Board
title="Components / SButtonGroup / 01. Playground"
docs="/components/button-group"
:state="state"
>
<SButtonGroup :items="items" v-model="value" />
<template #controls="{ state }">
<HstSelect
title="size"
:options="{
mini: 'mini',
small: 'small',
medium: 'medium',
large: 'large',
jumbo: 'jumbo'
}"
v-model="state.size"
/>
<HstSelect
title="mode"
:options="{
neutral: 'neutral',
mute: 'mute',
white: 'white',
black: 'black',
info: 'info',
success: 'success',
warning: 'warning',
danger: 'danger'
}"
v-model="state.mode"
/>
<HstText
title="label a"
v-model="state.labelA"
/>
<HstText
title="label b"
v-model="state.labelB"
/>
<HstText
title="label c"
v-model="state.labelC"
/>
</template>
<template #default="{ state }">
<SButtonGroup>
<SButton :size="state.size" :mode="state.mode" :label="state.labelA" />
<SButton :size="state.size" :mode="state.mode" :label="state.labelB" />
<SButton :size="state.size" :mode="state.mode" :label="state.labelC" />
</SButtonGroup>
</template>
</Board>
</template>

0 comments on commit 06f5934

Please sign in to comment.