Skip to content

Commit

Permalink
feat(ui): add button-group component
Browse files Browse the repository at this point in the history
  • Loading branch information
Makisuo committed Apr 19, 2024
1 parent 2a572e2 commit d930579
Show file tree
Hide file tree
Showing 15 changed files with 208 additions and 54 deletions.
20 changes: 14 additions & 6 deletions apps/docs/content/components/button-group.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,28 @@ description: Displays a button group.

slug: button-group

primaryTag: WIP
---

<ComponentPreview name="button-group/preview" />

## Variants

### Examples
### Solid

<ComponentPreview name="button-group/preview" />
<ComponentPreview name="button-group/solid" />

### Outline

<ComponentPreview name="button-group/outline" />

### Ghost

<ComponentPreview name="button-group/ghost" />

### Variants
### Link

<ComponentPreview name="button-group/variants" />
<ComponentPreview name="button-group/link" />

### Orientation
## Orientation

<ComponentPreview name="button-group/orientation" />
11 changes: 11 additions & 0 deletions apps/docs/src/examples/button-group/ghost.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Button, ButtonGroup } from "@pixelshades/ui/components"

export default function Example() {
return (
<ButtonGroup variant="ghost">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>
)
}
11 changes: 11 additions & 0 deletions apps/docs/src/examples/button-group/link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Button, ButtonGroup } from "@pixelshades/ui/components"

export default function Example() {
return (
<ButtonGroup variant="link">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>
)
}
30 changes: 25 additions & 5 deletions apps/docs/src/examples/button-group/orientation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,30 @@ import { Button, ButtonGroup } from "@pixelshades/ui/components"

export default function Example() {
return (
<ButtonGroup orientation="vertical">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>
<div className="flex flex-row gap-layout-sm">
<ButtonGroup orientation="vertical">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>

<ButtonGroup orientation="vertical" variant="outline">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>

<ButtonGroup orientation="vertical" variant="ghost">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>

<ButtonGroup orientation="vertical" variant="link">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>
</div>
)
}
11 changes: 11 additions & 0 deletions apps/docs/src/examples/button-group/outline.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Button, ButtonGroup } from "@pixelshades/ui/components"

export default function Example() {
return (
<ButtonGroup variant="outline">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>
)
}
11 changes: 11 additions & 0 deletions apps/docs/src/examples/button-group/solid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Button, ButtonGroup } from "@pixelshades/ui/components"

export default function Example() {
return (
<ButtonGroup variant="solid">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>
)
}
82 changes: 81 additions & 1 deletion apps/docs/src/examples/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,36 @@ export function Example() {
export function Example() {
return <Button variant="subtle">Button</Button>
}
`,
},
"button-group/ghost": {
component: lazy(() => import("~/examples/button-group/ghost.tsx")),
code: `import { Button, ButtonGroup } from "@pixelshades/ui/components"
export function Example() {
return (
<ButtonGroup variant="ghost">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>
)
}
`,
},
"button-group/link": {
component: lazy(() => import("~/examples/button-group/link.tsx")),
code: `import { Button, ButtonGroup } from "@pixelshades/ui/components"
export function Example() {
return (
<ButtonGroup variant="link">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>
)
}
`,
},
"button-group/orientation": {
Expand All @@ -132,7 +162,42 @@ export function Example() {
export function Example() {
return (
<ButtonGroup orientation="vertical">
<div className="flex flex-row gap-layout-sm">
<ButtonGroup orientation="vertical">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>
<ButtonGroup orientation="vertical" variant="outline">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>
<ButtonGroup orientation="vertical" variant="ghost">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>
<ButtonGroup orientation="vertical" variant="link">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>
</div>
)
}
`,
},
"button-group/outline": {
component: lazy(() => import("~/examples/button-group/outline.tsx")),
code: `import { Button, ButtonGroup } from "@pixelshades/ui/components"
export function Example() {
return (
<ButtonGroup variant="outline">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
Expand All @@ -154,6 +219,21 @@ export function Example() {
</ButtonGroup>
)
}
`,
},
"button-group/solid": {
component: lazy(() => import("~/examples/button-group/solid.tsx")),
code: `import { Button, ButtonGroup } from "@pixelshades/ui/components"
export function Example() {
return (
<ButtonGroup variant="solid">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>
)
}
`,
},
"button-group/variants": {
Expand Down
Binary file modified bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions packages/styles/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
},
"devDependencies": {
"@pixelshades/typescript-config": "workspace:*",
"@pixelshades/ui": "workspace:*",
"@types/node": "^20.12.7",
"@types/react": "^18.2.79",
"@types/react-dom": "^18.2.25",
Expand Down
38 changes: 10 additions & 28 deletions packages/styles/src/components/button-group/variants.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,24 @@
import { tv } from "tailwind-variants"
import { buttonVariants } from "../button"
import { buttonVariants } from "../button/variants"

export const buttonGroupVariants = tv({
slots: {
buttonGroup: "flex items-center",
...buttonVariants.slots,
button: "",
// button: cn(
// buttonVariants.slots.button,
// "first:rounded-r-none first:rounded-l-md last:rounded-r-md last:rounded-l-none",
// ),
},
defaultVariants: {
orientation: "horizontal",
gap: 0,
...buttonVariants.defaultVariants,
},
variants: {
...buttonVariants.variants,
variant: {
...buttonVariants.variants.variant,
},
orientation: {
horizontal: { buttonGroup: "flex-row" },
vertical: { buttonGroup: "flex-col" },
},
gap: {
0: { buttonGroup: "gap-0" },
1: { buttonGroup: "gap-1" },
2: { buttonGroup: "gap-2" },
3: { buttonGroup: "gap-3" },
4: { buttonGroup: "gap-4" },
5: { buttonGroup: "gap-5" },
6: { buttonGroup: "gap-6" },
7: { buttonGroup: "gap-7" },
8: { buttonGroup: "gap-8" },
9: { buttonGroup: "gap-9" },
10: { buttonGroup: "gap-10" },
horizontal: {
buttonGroup: "flex-row",
button: "first:!rounded-r-none last:rounded-l-none [&:not(:first-child):not(:last-child)]:rounded-none [&:not(:first-child):not(:last-child)]:border-x-0",
},
vertical: {
buttonGroup: "flex-col",
button: "first:!rounded-b-none last:rounded-t-none [&:not(:first-child):not(:last-child)]:rounded-none [&:not(:first-child):not(:last-child)]:border-y-0 w-full",
},
},
},
extend: buttonVariants,
})
4 changes: 2 additions & 2 deletions packages/styles/tailwind.config.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { Config } from "tailwindcss"

import { dvPlugin } from "./src/tailwind"
import { pixelShadesPlugin } from "@pixelshades/ui/tailwind"

const config: Config = {
darkMode: ["class"],
content: ["app/**/*.{ts,tsx}", "components/**/*.{ts,tsx}"],

plugins: [dvPlugin],
plugins: [pixelShadesPlugin],
}

export default config
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface ButtonGroupProps {
const { withProvider } = buttonGroupContext

/** Displays a group of buttons with matching styles. */
const UnstyledButtonGroup = ({ children, className, ...props }: ButtonGroupProps) => {
const UnstyledButtonGroup = ({ children, ...props }: ButtonGroupProps) => {
return <div {...props}>{children}</div>
}

Expand Down
30 changes: 21 additions & 9 deletions packages/ui/src/components/ui/button/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@ import type { VariantProps } from "tailwind-variants"

import { buttonVariants } from "@pixelshades/styles/components/button"

import { Button as AriaButton, type ButtonProps as AriaButtonProps } from "react-aria-components"
import {
Button as AriaButton,
type ButtonProps as AriaButtonProps,
type ButtonRenderProps,
} from "react-aria-components"
import { RenderSlot } from "../../../utils/jsx"
import { If } from "../../utils"
import { buttonGroupContext } from "../button-group/button-group-context"

type ButtonVariantProps = VariantProps<typeof buttonVariants>

Expand All @@ -20,19 +25,26 @@ const { button, icon } = buttonVariants()

const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ size, variant, className, children, before, after, withRing, ...props }, ref) => {
return (
<AriaButton
className={(values) =>
button({
const buttonGroupState = buttonGroupContext.useStyleContext()

/* If Button is in Button Group apply Button Group Styles, this can still be overwritten on button layer **/
const buttonStyles = (values: ButtonRenderProps) =>
buttonGroupState
? buttonGroupState.button({
variant,
withRing,
size,
className: typeof className === "function" ? className(values) : className,
})
}
ref={ref}
{...props}
>
: button({
variant,
withRing,
size,
className: typeof className === "function" ? className(values) : className,
})

return (
<AriaButton className={buttonStyles} ref={ref} {...props}>
<>
<If condition={before}>
<RenderSlot item={before!} className={icon({ variant, withRing, size })} />
Expand Down
7 changes: 7 additions & 0 deletions packages/ui/src/utils/create-style-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,15 @@ export const createStyleContext = <StylesFunction extends Recipe, Slot extends k
return Comp
}

const useStyleContext = () => {
const context = useContext(StyleContext)

return context
}

return {
withProvider,
withContext,
useStyleContext,
}
}
4 changes: 2 additions & 2 deletions packages/ui/tailwind.config.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { Config } from "tailwindcss"

import { dvPlugin } from "./src/tailwind"
import { pixelShadesPlugin } from "./src/tailwind"

const config: Config = {
darkMode: ["class"],
content: ["app/**/*.{ts,tsx}", "components/**/*.{ts,tsx}"],

plugins: [dvPlugin],
plugins: [pixelShadesPlugin],
}

export default config

0 comments on commit d930579

Please sign in to comment.