Skip to content

Commit

Permalink
Merge pull request #256 from josemarluedke/feat/button-group
Browse files Browse the repository at this point in the history
feat: Add ButtonGroup component to buttons pkg
  • Loading branch information
josemarluedke committed Jan 14, 2024
2 parents d0761ee + 7a3e852 commit 85a2068
Show file tree
Hide file tree
Showing 35 changed files with 4,614 additions and 10,214 deletions.
1 change: 1 addition & 0 deletions packages/buttons/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
"type": "addon",
"main": "addon-main.js",
"app-js": {
"./components/button-group.js": "./dist/_app_/components/button-group.js",
"./components/button.js": "./dist/_app_/components/button.js",
"./components/chip.js": "./dist/_app_/components/chip.js",
"./components/toggle-button.js": "./dist/_app_/components/toggle-button.js"
Expand Down
1 change: 1 addition & 0 deletions packages/buttons/rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default {
'components/**/*.js',
'helpers/**/*.js',
'utils/**/*.js',
'index.js',
'template-registry.js'
]),

Expand Down
43 changes: 43 additions & 0 deletions packages/buttons/src/components/button-group.gts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import Component from '@glimmer/component';
import { hash } from '@ember/helper';
import { useStyles } from '@frontile/theme';
import Button from './button';
import type { ButtonArgs } from './button';
import ToggleButton from './toggle-button';
import type { WithBoundArgs } from '@glint/template';

export interface ButtonGroupArgs
extends Pick<ButtonArgs, 'appearance' | 'intent' | 'size' | 'class'> {}

export interface ButtonGroupSignature {
Args: ButtonGroupArgs;
Blocks: {
default: [
{
Button: WithBoundArgs<typeof Button, 'isInGroup'>;
ToggleButton: WithBoundArgs<typeof ToggleButton, 'isInGroup'>;
}
];
};
Element: HTMLDivElement;
}

export default class ButtonGroup extends Component<ButtonGroupSignature> {
get classNames(): string {
const { buttonGroup } = useStyles();

return buttonGroup({
class: this.args.class
});
}

<template>
<div class={{this.classNames}} role="group" ...attributes>
{{yield (hash
Button=(component Button isInGroup=true appearance=@appearance intent=@intent size=@size)
ToggleButton=(component ToggleButton isInGroup=true intent=@intent size=@size)
)
}}
</div>
</template>
}
104 changes: 104 additions & 0 deletions packages/buttons/src/components/button-group.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# ButtonGroup

A button group is used to group buttons whose actions are related.


## Import

```js
import { ButtonGroup } from '@frontile/buttons';
```

## Using with Button

```gjs preview
import { ButtonGroup } from '@frontile/buttons';
<template>
<ButtonGroup as |g|>
<g.Button>First</g.Button>
<g.Button>Second</g.Button>
<g.Button>Third</g.Button>
</ButtonGroup>
</template>
```

## Using with ToggleButton

```gts preview
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { fn } from '@ember/helper';
import { ButtonGroup } from '@frontile/buttons';
export default class Example extends Component {
@tracked
isSelected = {
first: false,
second: false,
third: false
};
@action
onChange(ty: keyof typeof this.isSelected, value: boolean): void {
this.isSelected[ty] = value;
this.isSelected = { ...this.isSelected };
}
<template>
<ButtonGroup @size="sm" @intent="primary" as |g|>
{{#each-in this.isSelected as |key val|}}
<g.ToggleButton
@isSelected={{val}}
@onChange={{(fn this.onChange key)}}
>
{{key}}
</g.ToggleButton>
{{/each-in}}
</ButtonGroup>
</template>
}
```

## ButtonGroup use case

A common use case for `ButtonGroup` is to create a split button.


```gjs preview
import { ButtonGroup } from '@frontile/buttons';
<template>
<ButtonGroup @size="sm" @intent="primary" as |g|>
<g.Button>Create a merge commit</g.Button>
<g.Button @class="border-l-primary-400"><Icon/></g.Button>
</ButtonGroup>
</template>
const Icon = <template>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
</svg>
</template>
```

## Arguments

You pass pass arguments to `ButtonGroup` and they will be passed in to each of the yielded component.
You can overwrite at the specific component as well.

```gjs preview
import { ButtonGroup } from '@frontile/buttons';
<template>
<ButtonGroup @size="sm" @intent="primary" as |g|>
<g.Button>First</g.Button>
<g.Button>Second</g.Button>
<g.Button @intent="danger">Third</g.Button>
</ButtonGroup>
</template>
```

## API

6 changes: 6 additions & 0 deletions packages/buttons/src/components/button.gts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ export interface ButtonArgs {
* Custom class name, it will override the default ones using Tailwind Merge library.
*/
class?: string;

/**
* @internal
*/
isInGroup?: boolean;
}

export interface ButtonSignature {
Expand All @@ -61,6 +66,7 @@ export default class Button extends Component<ButtonSignature> {
intent: this.args.intent || 'default',
size: this.args.size,
appearance: this.args.appearance || 'default',
isInGroup: this.args.isInGroup,
class: this.args.class
});
}
Expand Down
144 changes: 91 additions & 53 deletions packages/buttons/src/components/button.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,79 @@

The Button component can be used to trigger an action, such as submitting a form, opening a modal, and more.

## Import

```js
import { Button } from '@frontile/buttons';
```

## Usage

```hbs preview-template
<Button>Button</Button>
```gjs preview
import { Button } from '@frontile/buttons';
<template>
<Button>Button</Button>
</template>
```

## Button Appearances

```hbs preview-template
<div>
<Button>Default</Button>
<Button @appearance='outlined'>Outlined</Button>
<Button @appearance='minimal'>Minimal</Button>
<Button @appearance='custom'>Custom</Button>
</div>
<div class='mt-4'>
<Button disabled>Default</Button>
<Button @appearance='outlined' disabled>Outlined</Button>
<Button @appearance='minimal' disabled>Minimal</Button>
<Button @appearance='custom' disabled>Custom</Button>
</div>
```gjs preview
import { Button } from '@frontile/buttons';
<template>
<div>
<Button>Default</Button>
<Button @appearance='outlined'>Outlined</Button>
<Button @appearance='minimal'>Minimal</Button>
<Button @appearance='custom'>Custom</Button>
</div>
<div class='mt-4'>
<Button disabled>Default</Button>
<Button @appearance='outlined' disabled>Outlined</Button>
<Button @appearance='minimal' disabled>Minimal</Button>
<Button @appearance='custom' disabled>Custom</Button>
</div>
</template>
```

The `custom` appearance is available for the cases where you might want to fully customize the appearance of the button.
The default styles are mainly structural. Intent colors are applied as `color`.

## Button Intents

```hbs preview-template
<div>
<Button @intent='primary'>Button</Button>
<Button @intent='success'>Button</Button>
<Button @intent='warning'>Button</Button>
<Button @intent='danger'>Button</Button>
</div>
<div class='mt-4'>
<Button @intent='primary' disabled>Button</Button>
<Button @intent='success' disabled>Button</Button>
<Button @intent='warning' disabled>Button</Button>
<Button @intent='danger' disabled>Button</Button>
</div>
```gjs preview
import { Button } from '@frontile/buttons';
<template>
<div>
<Button @intent='primary'>Button</Button>
<Button @intent='success'>Button</Button>
<Button @intent='warning'>Button</Button>
<Button @intent='danger'>Button</Button>
</div>
<div class='mt-4'>
<Button @intent='primary' disabled>Button</Button>
<Button @intent='success' disabled>Button</Button>
<Button @intent='warning' disabled>Button</Button>
<Button @intent='danger' disabled>Button</Button>
</div>
</template>
```

## Button Sizes

```hbs preview-template
<Button @size='xs'>Button</Button>
<Button @size='sm'>Button</Button>
<Button>Button</Button>
<Button @size='lg'>Button</Button>
<Button @size='xl'>Button</Button>
```gjs preview
import { Button } from '@frontile/buttons';
<template>
<Button @size='xs'>Button</Button>
<Button @size='sm'>Button</Button>
<Button>Button</Button>
<Button @size='lg'>Button</Button>
<Button @size='xl'>Button</Button>
</template>
```

## Renderless Button
Expand All @@ -61,39 +83,55 @@ Sometimes a button element is not ideal for a given case, but the same styles ar
Frontile provides the option to disable rendering the `button` element, but instead it yields back an object with
the class names it would use.

```hbs preview-template
<Button @isRenderless={{true}} as |btn|>
<a href='javascript:void(0)' class={{btn.classNames}}>My Link</a>
</Button>
```gjs preview
import { Button } from '@frontile/buttons';
<template>
<Button @isRenderless={{true}} as |btn|>
<a href='javascript:void(0)' class={{btn.classNames}}>My Link</a>
</Button>
</template>
```

## Composition

You can compose appearance with intents and more to create the button that best fits your needs.

```hbs preview-template
<Button @appearance='outlined' @intent='primary'>Button</Button>
<Button @appearance='minimal' @intent='warning'>Button</Button>
<Button @size='xs' @intent='danger'>Button</Button>
```gjs preview
import { Button } from '@frontile/buttons';
<template>
<Button @appearance='outlined' @intent='primary'>Button</Button>
<Button @appearance='minimal' @intent='warning'>Button</Button>
<Button @size='xs' @intent='danger'>Button</Button>
</template>
```

You can also use TailwindCSS classes to customize even further.

```hbs preview-template
<Button @appearance='outlined' @intent='primary' @class='px-20 py-2 italic'>
Button
</Button>
```gjs preview
import { Button } from '@frontile/buttons';
<template>
<Button @appearance='outlined' @intent='primary' @class='px-20 py-2 italic'>
Button
</Button>
</template>
```

Here is another example using TailwindCSS classes with the `custom` appearance.

```hbs preview-template
<Button
@appearance='custom'
class='bg-teal-100 hover:bg-teal-200 hover:text-teal-600 border-teal-600 rounded-none border-dashed'
>
Button
</Button>
```gjs preview
import { Button } from '@frontile/buttons';
<template>
<Button
@appearance='custom'
class='bg-teal-100 hover:bg-teal-200 hover:text-teal-600 border-teal-600 rounded-none border-dashed'
>
Button
</Button>
</template>
```

Note that here we used the HTML attribute `class`, instead of the argument `@class`.
Expand Down
Loading

0 comments on commit 85a2068

Please sign in to comment.