@neoptocom/neopto-ui 0.5.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,45 +1,46 @@
1
1
  import * as React from "react";
2
- import { tv, type VariantProps } from "tailwind-variants";
3
2
  import Icon from "./Icon";
4
3
 
5
- const iconButtonStyles = tv({
6
- base: [
7
- "flex items-center justify-center rounded-full flex-shrink-0",
8
- "transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
9
- "focus-visible:ring-cyan-500/40 disabled:cursor-not-allowed disabled:opacity-50"
10
- ].join(" "),
11
- variants: {
12
- variant: {
13
- ghost: "bg-transparent hover:bg-[var(--muted)] active:bg-[var(--muted)]",
14
- primary: "bg-cyan-500 text-white hover:bg-cyan-400 active:bg-cyan-600",
15
- secondary: "border border-[var(--border)] bg-[var(--surface)] hover:bg-[var(--muted)] active:bg-[var(--muted)]"
16
- },
17
- size: {
18
- sm: "w-8 h-8",
19
- md: "w-10 h-10",
20
- lg: "w-12 h-12"
21
- }
22
- },
23
- defaultVariants: {
24
- variant: "ghost",
25
- size: "md"
26
- }
27
- });
4
+ export type IconButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
5
+ /** Button visual variant */
6
+ variant?: "ghost" | "primary" | "secondary";
7
+ /** Button size */
8
+ size?: "sm" | "md" | "lg";
9
+ /** Material Symbols icon name */
10
+ icon: string;
11
+ /** Icon size (defaults to button size) */
12
+ iconSize?: "sm" | "md" | "lg";
13
+ /** Icon fill (0 = outlined, 1 = filled) */
14
+ iconFill?: 0 | 1;
15
+ /** Optional custom className for the icon */
16
+ iconClassName?: string;
17
+ };
28
18
 
29
- type IconButtonVariants = VariantProps<typeof iconButtonStyles>;
19
+ function getIconButtonClasses(
20
+ variant: IconButtonProps["variant"] = "ghost",
21
+ size: IconButtonProps["size"] = "md",
22
+ className?: string
23
+ ): string {
24
+ const base =
25
+ "flex items-center justify-center rounded-full flex-shrink-0 " +
26
+ "transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 " +
27
+ "focus-visible:ring-cyan-500/40 disabled:cursor-not-allowed disabled:opacity-50";
30
28
 
31
- export type IconButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> &
32
- IconButtonVariants & {
33
- /** Material Symbols icon name */
34
- icon: string;
35
- /** Icon size (defaults to button size) */
36
- iconSize?: "sm" | "md" | "lg";
37
- /** Icon fill (0 = outlined, 1 = filled) */
38
- iconFill?: 0 | 1;
39
- /** Optional custom className for the icon */
40
- iconClassName?: string;
29
+ const variants = {
30
+ ghost: "bg-transparent hover:bg-[var(--muted)] active:bg-[var(--muted)]",
31
+ primary: "bg-cyan-500 text-white hover:bg-cyan-400 active:bg-cyan-600",
32
+ secondary: "border border-[var(--border)] bg-[var(--surface)] hover:bg-[var(--muted)] active:bg-[var(--muted)]"
41
33
  };
42
34
 
35
+ const sizes = {
36
+ sm: "w-8 h-8",
37
+ md: "w-10 h-10",
38
+ lg: "w-12 h-12"
39
+ };
40
+
41
+ return [base, variants[variant], sizes[size], className].filter(Boolean).join(" ");
42
+ }
43
+
43
44
  export const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(
44
45
  (
45
46
  {
@@ -71,7 +72,7 @@ export const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(
71
72
  return (
72
73
  <button
73
74
  ref={ref}
74
- className={iconButtonStyles({ variant, size, className })}
75
+ className={getIconButtonClasses(variant, size, className)}
75
76
  {...props}
76
77
  >
77
78
  <Icon
@@ -1,5 +1,4 @@
1
1
  import * as React from "react";
2
- import { tv, type VariantProps } from "tailwind-variants";
3
2
 
4
3
  export type TypoVariant =
5
4
  | "display-lg" | "display-md" | "display-sm"
@@ -11,41 +10,48 @@ export type TypoVariant =
11
10
 
12
11
  export type TypoWeight = "normal" | "medium" | "semibold" | "bold";
13
12
 
14
- const styles = tv({
15
- base: "text-current",
16
- variants: {
17
- variant: {
18
- "display-lg": "text-5xl leading-tight",
19
- "display-md": "text-4xl leading-tight",
20
- "display-sm": "text-4xl leading-tight",
21
- "headline-lg": "text-3xl leading-tight",
22
- "headline-md": "text-3xl leading-tight",
23
- "headline-sm": "text-3xl leading-tight",
24
- "title-lg": "text-xl leading-tight",
25
- "title-md": "text-lg leading-tight",
26
- "title-sm": "text-base leading-tight",
27
- "label-lg": "text-sm leading-tight",
28
- "label-md": "text-xs leading-tight",
29
- "label-sm": "text-xs leading-tight",
30
- "body-lg": "text-base leading-relaxed",
31
- "body-md": "text-sm leading-relaxed",
32
- "body-sm": "text-xs leading-relaxed",
33
- "button": "text-base leading-normal"
34
- },
35
- weight: {
36
- normal: "font-normal",
37
- medium: "font-medium",
38
- semibold: "font-semibold",
39
- bold: "font-bold"
40
- },
41
- muted: {
42
- true: "text-[var(--muted-fg)]"
43
- }
44
- },
45
- defaultVariants: {
46
- weight: "normal"
47
- }
48
- });
13
+ function getTypoClasses(
14
+ variant: TypoVariant,
15
+ weight: TypoWeight = "normal",
16
+ muted?: boolean,
17
+ className?: string
18
+ ): string {
19
+ const base = "text-current";
20
+
21
+ const variants: Record<TypoVariant, string> = {
22
+ "display-lg": "text-5xl leading-tight",
23
+ "display-md": "text-4xl leading-tight",
24
+ "display-sm": "text-4xl leading-tight",
25
+ "headline-lg": "text-3xl leading-tight",
26
+ "headline-md": "text-3xl leading-tight",
27
+ "headline-sm": "text-3xl leading-tight",
28
+ "title-lg": "text-xl leading-tight",
29
+ "title-md": "text-lg leading-tight",
30
+ "title-sm": "text-base leading-tight",
31
+ "label-lg": "text-sm leading-tight",
32
+ "label-md": "text-xs leading-tight",
33
+ "label-sm": "text-xs leading-tight",
34
+ "body-lg": "text-base leading-relaxed",
35
+ "body-md": "text-sm leading-relaxed",
36
+ "body-sm": "text-xs leading-relaxed",
37
+ "button": "text-base leading-normal"
38
+ };
39
+
40
+ const weights: Record<TypoWeight, string> = {
41
+ normal: "font-normal",
42
+ medium: "font-medium",
43
+ semibold: "font-semibold",
44
+ bold: "font-bold"
45
+ };
46
+
47
+ return [
48
+ base,
49
+ variants[variant],
50
+ weights[weight],
51
+ muted ? "text-[var(--muted-fg)]" : "",
52
+ className
53
+ ].filter(Boolean).join(" ");
54
+ }
49
55
 
50
56
  export type TypoProps<T extends React.ElementType = "span"> = {
51
57
  /**
@@ -83,7 +89,7 @@ export default function Typo<T extends React.ElementType = "span">({
83
89
 
84
90
  return (
85
91
  <Component
86
- className={styles({ variant, weight: bold, muted, className })}
92
+ className={getTypoClasses(variant, bold, muted, className)}
87
93
  style={{ fontFamily: getFontFamily(variant) }}
88
94
  {...props}
89
95
  >