Skip to content

Commit

Permalink
feat(Button): Allow custom variants with type safety
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisGV04 committed Nov 24, 2023
1 parent 1f789f0 commit 502efdb
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 59 deletions.
17 changes: 17 additions & 0 deletions docs/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,22 @@ export default defineAppConfig({
container: {
constrained: "max-w-2xl",
},

button: {
variant: {
"primary-solid":
"bg-primary-500 text-white shadow-sm hover:bg-primary-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500 disabled:bg-primary-500",
"primary-soft":
"bg-primary-50 text-primary-600 hover:bg-primary-100 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 disabled:bg-primary-50",
"primary-ghost":
"text-primary-500 hover:bg-primary-50 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 disabled:bg-transparent",
"primary-link":
"text-primary-500 underline-offset-4 hover:text-primary-600 hover:underline focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 disabled:text-primary-500",
},

default: {
variant: "primary-solid",
},
},
},
});
30 changes: 15 additions & 15 deletions docs/pages/button.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,31 @@ import { UiButton, UiContainer } from "#components";

<div class="mt-2 flex items-center gap-4">
<UiButton label="Solid" />
<UiButton label="Soft" variant="soft" />
<UiButton label="Ghost" variant="ghost" />
<UiButton label="Link" variant="link" />
<UiButton label="Soft" variant="primary-soft" />
<UiButton label="Ghost" variant="primary-ghost" />
<UiButton label="Link" variant="primary-link" />
</div>
</div>

<div class="demo-category-container mt-4">
<span class="demo-category-title">White</span>

<div class="mt-2 flex items-center p-4 bg-gray-900 rounded-md gap-4">
<UiButton label="Solid" color="white" />
<UiButton label="Soft" color="white" variant="soft" />
<UiButton label="Ghost" color="white" variant="ghost" />
<UiButton label="Link" color="white" variant="link" />
<UiButton label="Solid" variant="white-solid" />
<UiButton label="Soft" variant="white-soft" />
<UiButton label="Ghost" variant="white-ghost" />
<UiButton label="Link" variant="white-link" />
</div>
</div>

<div class="demo-category-container mt-4">
<span class="demo-category-title">Black</span>

<div class="mt-2 flex items-center gap-4">
<UiButton label="Solid" color="black" />
<UiButton label="Soft" color="black" variant="soft" />
<UiButton label="Ghost" color="black" variant="ghost" />
<UiButton label="Link" color="black" variant="link" />
<UiButton label="Solid" variant="black-solid" />
<UiButton label="Soft" variant="black-soft" />
<UiButton label="Ghost" variant="black-ghost" />
<UiButton label="Link" variant="black-link" />
</div>
</div>

Expand All @@ -49,11 +49,11 @@ import { UiButton, UiContainer } from "#components";
leading-icon="i-heroicons-lock-closed-20-solid"
/>
<UiButton
color="white"
label="Trailing"
variant="white-solid"
leading-icon="i-heroicons-lock-closed-20-solid"
/>
<UiButton loading color="black" label="Loading" />
<UiButton loading variant="black-solid" label="Loading" />
</div>
</div>

Expand All @@ -62,8 +62,8 @@ import { UiButton, UiContainer } from "#components";

<div class="mt-2 flex items-center gap-4">
<UiButton disabled label="Primary" />
<UiButton disabled label="White" color="white" />
<UiButton disabled label="Black" color="black" />
<UiButton disabled label="White" variant="white-solid" />
<UiButton disabled label="Black" variant="black-solid" />
</div>
</div>

Expand Down
14 changes: 2 additions & 12 deletions src/runtime/components/elements/Button.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,7 @@ import { twJoin, twMerge } from "tailwind-merge";
import type { PropType } from "vue";
import { computed, defineComponent, toRef } from "vue";
import { useUI } from "../../composables/useUI";
import type {
Button,
ButtonColor,
ButtonSize,
ButtonVariant,
Strategy,
} from "../../types";
import type { Button, ButtonSize, ButtonVariant, Strategy } from "../../types";
import { button } from "../../ui.config";
import { mergeConfig } from "../../utils";
import UiIcon from "../elements/Icon.vue";
Expand Down Expand Up @@ -46,10 +40,6 @@ export default defineComponent<Button>({
type: String as PropType<ButtonSize>,
default: () => config.default.size,
},
color: {
type: String as PropType<ButtonColor>,
default: () => config.default.color,
},
variant: {
type: String as PropType<ButtonVariant>,
default: () => config.default.variant,
Expand Down Expand Up @@ -83,7 +73,7 @@ export default defineComponent<Button>({
ui.value.size[props.size!],
ui.value.gap[props.size!],
props.padded && ui.value.padding[props.size!],
ui.value.color[props.color!][props.variant!],
ui.value.variant[props.variant!],
props.block
? "w-full flex justify-center items-center"
: "inline-flex items-center",
Expand Down
14 changes: 9 additions & 5 deletions src/runtime/types/button.d.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import type { AppConfig } from "nuxt/schema";
import { button } from "../ui.config";
import type { Link } from "./link";
import type { DeepPartial, Strategy } from "./utils";
import type { DeepPartial, ExtractDeepKey, Strategy } from "./utils";

export type ButtonSize = keyof typeof button.size;
export type ButtonColor = "primary" | "white" | "black";
export type ButtonVariant = "solid" | "soft" | "ghost" | "link";
export type ButtonSize =
| keyof typeof button.size
| ExtractDeepKey<AppConfig, ["ui", "button", "size"]>;

export type ButtonVariant =
| keyof typeof button.variant
| ExtractDeepKey<AppConfig, ["ui", "button", "variant"]>;

export interface Button extends Link {
label?: string;
Expand All @@ -18,7 +23,6 @@ export interface Button extends Link {
block?: boolean;
padded?: boolean;
size?: ButtonSize;
color?: ButtonColor;
variant?: ButtonVariant;
ui?: DeepPartial<typeof button & { strategy?: Strategy }>;
class?: any;
Expand Down
46 changes: 19 additions & 27 deletions src/runtime/ui.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,31 +135,24 @@ export const button = {
sm: "px-4 py-2",
md: "px-5 py-2.5",
},
color: {
primary: {
solid:
"bg-primary-500 text-white shadow-sm hover:bg-primary-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500 disabled:bg-primary-500",
soft: "bg-primary-50 text-primary-600 hover:bg-primary-100 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 disabled:bg-primary-50",
ghost:
"text-primary-500 hover:bg-primary-50 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 disabled:bg-transparent",
link: "text-primary-500 underline-offset-4 hover:text-primary-600 hover:underline focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 disabled:text-primary-500",
},
white: {
solid:
"bg-white text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-400 disabled:bg-white",
soft: "bg-white/20 text-white hover:bg-white/30 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 disabled:bg-white/10",
ghost:
"text-white hover:bg-white/30 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 disabled:bg-transparent",
link: "text-white underline-offset-4 hover:underline focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-400 disabled:text-white",
},
black: {
solid:
"bg-gray-900 text-white shadow-sm hover:bg-gray-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-400 disabled:bg-gray-900",
soft: "bg-gray-100 text-gray-700 hover:bg-gray-200 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 disabled:bg-gray-50",
ghost:
"text-gray-700 hover:bg-gray-200 hover:text-gray-900 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 disabled:bg-transparent",
link: "text-gray-900 underline-offset-4 hover:underline focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 disabled:text-gray-900",
},
variant: {
"white-solid":
"bg-white text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-400 disabled:bg-white",
"white-soft":
"bg-white/20 text-white hover:bg-white/30 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 disabled:bg-white/10",
"white-ghost":
"text-white hover:bg-white/30 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 disabled:bg-transparent",
"white-link":
"text-white underline-offset-4 hover:underline focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-400 disabled:text-white",

"black-solid":
"bg-gray-900 text-white shadow-sm hover:bg-gray-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-400 disabled:bg-gray-900",
"black-soft":
"bg-gray-100 text-gray-700 hover:bg-gray-200 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 disabled:bg-gray-50",
"black-ghost":
"text-gray-700 hover:bg-gray-200 hover:text-gray-900 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 disabled:bg-transparent",
"black-link":
"text-gray-900 underline-offset-4 hover:underline focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 disabled:text-gray-900",
},
icon: {
base: "flex-shrink-0",
Expand All @@ -171,8 +164,7 @@ export const button = {
},
default: {
size: "sm",
color: "primary",
variant: "solid",
variant: "black-solid",
loadingIcon: "i-heroicons-arrow-path-20-solid",
},
};
Expand Down

0 comments on commit 502efdb

Please sign in to comment.