Skip to content

Commit

Permalink
feat(component): add button group component (#167)
Browse files Browse the repository at this point in the history
* refactor: update the pseudo element content setting

* feat(component): add button group component

* chore: add example for button group

* docs: update button group doc
  • Loading branch information
wzc520pyfm committed Apr 5, 2023
1 parent 5d15696 commit ecd9e00
Show file tree
Hide file tree
Showing 19 changed files with 264 additions and 23 deletions.
28 changes: 24 additions & 4 deletions docs/components/button.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,11 @@ Use the `icon` slots or `icon` property to add icon.

## Button Group

TODO
Displayed as a button group, can be used to group a series of similar operations.

Use tag `<o-button-group>` to group your buttons.

<demo src="../example/button/group.vue"></demo>

## Loading Button

Expand All @@ -80,7 +84,9 @@ Use attribute `size` to set additional sizes with `xs`, `sm`,`md`,`lg`.

<demo src="../example/button/size.vue"></demo>

## Button Props
## Button API

### Button Props
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| type | `'primary' \| 'secondary' \| 'success' \| 'warning' \| 'error' \| 'info'` | `'primary'` | Button type. |
Expand All @@ -94,10 +100,24 @@ Use attribute `size` to set additional sizes with `xs`, `sm`,`md`,`lg`.
| disabled | `boolean` | `false` | Disable the button. |



## Button Slots
### Button Slots

| Name | Parameters | Description |
| --- | --- | --- |
| default | `()` | Customize default content. |
| icon | `()` | Customize icon component. |

## Button Group API

### Button Group Props
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| type | `'primary' \| 'secondary' \| 'success' \| 'warning' \| 'error' \| 'info'` | `''` | Control the size of buttons in this button-group. |
| size | `'xs' \| 'sm' \| 'md' \| 'lg'` | `''` | Control the size of buttons in this button-group. |
| spacer | `boolean` | `false` | The dividing line between groups of buttons. |

### Button Group Slots

| Name | Parameters | Description |
| --- | --- | --- |
| default | `Button` | Customize button group content. |
51 changes: 51 additions & 0 deletions docs/example/button/group.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<template>
<div space-y-2>
<div fscw gap-2>
<o-button-group>
<o-button type="primary">
Previous Page
<template #icon>
<div i-carbon-chevron-left />
</template>
</o-button>
<o-button type="secondary" class="align-bottom">
Next Page <div i-carbon-chevron-right />
</o-button>
</o-button-group>
<o-button-group>
<OButton>
<template #icon>
<div i-carbon-asleep />
</template>
</OButton>
<OButton>
<template #icon>
<div i-carbon-basketball />
</template>
</OButton>
<OButton>
<template #icon>
<div i-carbon-ai-status-rejected />
</template>
</OButton>
</o-button-group>
<o-button-group spacer>
<OButton rounded-full type="primary">
<template #icon>
<div i-carbon-asleep />
</template>
</OButton>
<OButton rounded-full type="primary">
<template #icon>
<div i-carbon-basketball />
</template>
</OButton>
<OButton rounded-full type="primary">
<template #icon>
<div i-carbon-ai-status-rejected />
</template>
</OButton>
</o-button-group>
</div>
</div>
</template>
47 changes: 47 additions & 0 deletions example/src/components/TheButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,53 @@ const startLoading = () => {
<template>
<OCard title="Button">
<div space-y-2>
<div fsc gap-2>
<o-button-group>
<OButton type="primary">
Previous Page
<template #icon>
<div i-carbon-chevron-left />
</template>
</OButton>
<OButton type="secondary" class="align-bottom">
Next Page <div i-carbon-chevron-right />
</OButton>
</o-button-group>
<o-button-group>
<OButton>
<template #icon>
<div i-carbon-asleep />
</template>
</OButton>
<OButton>
<template #icon>
<div i-carbon-basketball />
</template>
</OButton>
<OButton>
<template #icon>
<div i-carbon-ai-status-rejected />
</template>
</OButton>
</o-button-group>
<o-button-group spacer>
<OButton rounded-full type="primary">
<template #icon>
<div i-carbon-asleep />
</template>
</OButton>
<OButton rounded-full type="primary">
<template #icon>
<div i-carbon-basketball />
</template>
</OButton>
<OButton rounded-full type="primary">
<template #icon>
<div i-carbon-ai-status-rejected />
</template>
</OButton>
</o-button-group>
</div>
<div fsc gap-2>
<OButton o="primary">
Primary
Expand Down
7 changes: 7 additions & 0 deletions packages/components/button-group/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { withInstall } from '@onu-ui/utils'
import ButtonGroup from '../button/src/button-group.vue'

export const OButtonGroup = withInstall(ButtonGroup)
export default OButtonGroup

export * from '../button/src/button-group'
5 changes: 3 additions & 2 deletions packages/components/button/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { withInstall } from '@onu-ui/utils'
import Button from './src/index.vue'
import Button from './src/button.vue'

export const OButton = withInstall(Button)
export default OButton

export * from './src/props'
export * from './src/button'
export * from './src/constants'
10 changes: 10 additions & 0 deletions packages/components/button/src/button-group.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { ExtractPropTypes } from 'vue'
import { buttonProps } from './button'

export const buttonGroupProps = {
type: buttonProps.type,
size: buttonProps.size,
spacer: Boolean,
}

export type OButtonGroupProps = ExtractPropTypes<typeof buttonGroupProps>
47 changes: 47 additions & 0 deletions packages/components/button/src/button-group.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<script setup lang="ts" name="OButtonGroup">
import { buttonGroupProps } from './button-group'
import { buttonGroupContextKey } from './constants'
const props = defineProps(buttonGroupProps)
provide(
buttonGroupContextKey,
reactive({
size: toRef(props, 'size'),
type: toRef(props, 'type'),
}),
)
</script>

<template>
<div class="o-button-group o-button-group-clearfix inline-block align-middle o-button-group-children" :class="[spacer && 'spacer']">
<slot />
</div>
</template>

<style scope>
.o-button-group > .o-button-base + .o-button-base {
margin-left: 0;
}
.o-button-group > .o-button-base:first-child:not(:last-child) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.o-button-group > .o-button-base:last-child:not(:first-child) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.o-button-group > .o-button-base:not(:first-child):not(:last-child) {
border-radius: 0;
}
.o-button-group > .o-button-base:not(:last-child) {
/* margin-right: -1px; */
border-right: none;
}
.o-button-group.spacer > .o-button-base:not(:first-child) {
border-left-color: white;
}
.o-button-group > .o-button-base:hover, .o-button-group > .o-button-base:focus, .o-button-group > .o-button-base:active {
z-index: 1;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ import type { SizeType, ThemeType } from '../../types'

export const buttonProps = {
type: {
type: String as PropType<ThemeType | 'default'>,
default: 'default',
type: String as PropType<ThemeType | 'default' | ''>,
default: '',
},
to: String,
shadow: Boolean,
light: Boolean,
dashed: Boolean,
text: Boolean,
size: {
type: String as PropType<SizeType>,
default: 'md',
type: String as PropType<SizeType | ''>,
default: '',
},
disabled: Boolean,
loading: Boolean,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
<script setup lang="ts" name="OButton">
import { buttonProps } from './props'
import { buttonProps } from './button'
import { buttonGroupContextKey } from './constants'
const props = defineProps(buttonProps)
const buttonGroupContext = inject(buttonGroupContextKey, undefined)
// todo: The property should follow this inheritance rule: component props > custom group rule > formItem props > form props > global size > default
const _type = computed(() => props.type || buttonGroupContext?.type || 'default')
const _size = computed(() => props.size || buttonGroupContext?.size || 'md')
const isDisabled = computed(() => props.loading || props.disabled)
const typeBtn = computed(() => props.type !== 'default' && !props.light)
const typeLight = computed(() => props.type !== 'default' && props.light)
const defaultLight = computed(() => props.type === 'default' && props.light)
const defaultText = computed(() => props.type === 'default' && props.text)
const typeBtn = computed(() => _type.value !== 'default' && !props.light)
const typeLight = computed(() => _type.value !== 'default' && props.light)
const defaultLight = computed(() => _type.value === 'default' && props.light)
const defaultText = computed(() => _type.value === 'default' && props.text)
const slots = useSlots()
const onlyIcon = computed(() => (slots.icon || props.icon) && !slots.default)
const binds = Object.assign({}, useAttrs(), props.to ? { href: props.to } : {})
Expand All @@ -21,10 +28,10 @@ const binds = Object.assign({}, useAttrs(), props.to ? { href: props.to } : {})
class="o-button-base"
:class="[
isDisabled ? 'o-disabled' : 'o-hover-active-base',
`o-${type}`,
`o-button-${size}`,
`o-${_type}`,
`o-button-${_size}`,
onlyIcon && 'aspect-square px-0',
typeBtn && `o-solid ${isDisabled ? '' : `hover-border-${type}BorderHover hover-bg-${type}LightHover hover-text-white active-text-white active-border-${type}BorderActive active-bg-${type}LightActive`} `,
typeBtn && `o-solid ${isDisabled ? '' : `hover-border-${_type}BorderHover hover-bg-${_type}LightHover hover-text-white active-text-white active-border-${_type}BorderActive active-bg-${_type}LightActive`} `,
typeLight && `${isDisabled ? 'o-button-light-disable' : 'o-button-light'}`,
text && `${isDisabled ? 'o-button-text-disable' : 'o-button-text'}`,
shadow ? 'shadow-context:50' : 'shadow-transparent',
Expand Down
11 changes: 11 additions & 0 deletions packages/components/button/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { InjectionKey } from 'vue'
import type { OButtonProps } from './button'

export interface OButtonGroupContext {
size?: OButtonProps['size']
type?: OButtonProps['type']
}

export const buttonGroupContextKey: InjectionKey<OButtonGroupContext> = Symbol(
'buttonGroupContextKey',
)
2 changes: 1 addition & 1 deletion packages/components/card/src/index.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts" setup name="OCard">
import OButton from '../../button/src/index.vue'
import OButton from '../../button/src/button.vue'
import type { ShadowType } from '../../types'
import { cardProps } from './props'
Expand Down
1 change: 1 addition & 0 deletions packages/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'uno.css'

export * from './avatar'
export * from './button'
export * from './button-group'
export * from './icon'
export * from './card'
export * from './switch'
Expand Down
4 changes: 2 additions & 2 deletions packages/components/radio/src/radio.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ function handleChange() {
@blur="isFocus = false"
@change="handleChange"
>
<!-- use `o-after:aftc-DEFAULT` to set `::after{ content: '' }` -->
<!-- use `o-after:psdc-DEFAULT` to set `::after{ content: '' }` -->
<span
class="o-radio-inner-base o-after:aftc-DEFAULT o-radio-inner-after"
class="o-radio-inner-base o-after:psdc-DEFAULT o-radio-inner-after"
:class="[
isDisabled && `o-disabled after:cursor-not-allowed`,
`o-radio-inner-${size}`,
Expand Down
2 changes: 2 additions & 0 deletions packages/onu-ui/src/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
OBacktop,
OBadge,
OButton,
OButtonGroup,
OCard,
OCheckbox,
OCollapse,
Expand All @@ -32,6 +33,7 @@ export default [
OAvatar,
OAvatarGroup,
OButton,
OButtonGroup,
OIcon,
OCard,
OAlert,
Expand Down
2 changes: 1 addition & 1 deletion packages/preset/src/rules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ export default [
['o-dashed', { 'border-style': 'dashed' }],
['o-solid', { 'background-color': 'rgba(var(--onu-c-context), 1) !important', 'border-color': 'rgba(var(--onu-c-context), 1)', 'color': 'white !important' }],
['o-bg-clip-half', { 'clip-path': 'polygon(0% 0%, 50% 0, 50% 50%, 50% 100%, 0% 100%)' }],
[/^aftc-(.*)$/, ([, s]: string[]) => ({ content: `'${s === 'DEFAULT' ? '' : s}'` })],
[/^psdc-(.*)$/, ([, s]: string[]) => ({ content: `'${s === 'DEFAULT' ? '' : s}'` })], // set content for pseudo element
] as Rule<Theme>[]
5 changes: 5 additions & 0 deletions packages/preset/src/shortcuts/button-group.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const buttonGroupShortcuts: Record<string, string> = {
// button group
'o-button-group-clearfix': 'o-after:psdc-DEFAULT after:clear-both after:table o-before:psdc-DEFAULT before:table',
'o-button-group-children': 'o-children:[.o-button-base]:left o-children:[.o-button-base]:relative',
}
2 changes: 2 additions & 0 deletions packages/preset/src/shortcuts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { alertShortcuts } from './alert'
import { avatarDynamicShortcuts, avatarShortcuts } from './avatar'
import { badgeShortcuts } from './badge'
import { buttonShortcuts } from './button'
import { buttonGroupShortcuts } from './button-group'
import { cardShortcuts } from './card'
import { checkboxShortcuts } from './checkbox'
import { collapseShortcuts } from './collapse'
Expand Down Expand Up @@ -33,6 +34,7 @@ export default [
badgeShortcuts,
// button
buttonShortcuts,
buttonGroupShortcuts,
// card
cardShortcuts,
// checkbox
Expand Down
2 changes: 1 addition & 1 deletion packages/preset/src/shortcuts/progress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export const progressShortcuts: Record<string, string> = {
'o-progress-base': 'relative leading-none flex items-center',
'o-progress-bar': 'flex-grow box-border',
'o-progress-bar-outer': 'h-6px rounded-[100px] overflow-hidden relative align-middle',
'o-progress-bar-inner': 'absolute left-0 top-0 h-full text-right rounded-[100px] leading-none whitespace-nowrap o-after:aftc-DEFAULT after:inline-block after:h-full after:align-middle',
'o-progress-bar-inner': 'absolute left-0 top-0 h-full text-right rounded-[100px] leading-none whitespace-nowrap o-after:psdc-DEFAULT after:inline-block after:h-full after:align-middle',
'o-progress-bar-inner-text': 'inline-block align-middle text-white text-12px m-[0_5px]',
'o-progress-indeterminate': 'translate-z-0 animate-indeterminate',
'o-progress-text': 'text-14px min-w-50px leading-none',
Expand Down
Loading

0 comments on commit ecd9e00

Please sign in to comment.