@motor-hero/ui-kit 0.36.3 → 0.37.1

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@motor-hero/ui-kit",
3
- "version": "0.36.3",
3
+ "version": "0.37.1",
4
4
  "description": "Componentes React reutilizáveis para o ecossistema MotorHero — shadcn/ui + Tailwind CSS v4",
5
5
  "author": "MotorHero",
6
6
  "license": "UNLICENSED",
@@ -60,6 +60,7 @@
60
60
  "@radix-ui/react-dropdown-menu": "^2.1.0",
61
61
  "@radix-ui/react-popover": "^1.1.16",
62
62
  "@radix-ui/react-slot": "^1.1.0",
63
+ "@radix-ui/react-toggle-group": "^1.1.0",
63
64
  "@react-input/mask": "^2.0.4",
64
65
  "class-variance-authority": "^0.7.0",
65
66
  "cmdk": "^1.1.1",
@@ -31,7 +31,7 @@ export function FormField({ label, htmlFor, error, required, children, className
31
31
  <div className={`space-y-2 ${className ?? ""}`}>
32
32
  <label
33
33
  htmlFor={htmlFor}
34
- className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
34
+ className="block text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
35
35
  >
36
36
  {label}
37
37
  {required && <span className="ml-1 text-destructive">*</span>}
@@ -0,0 +1,99 @@
1
+ import * as ToggleGroup from "@radix-ui/react-toggle-group"
2
+ import { Star } from "lucide-react"
3
+ import { cn } from "../lib/utils"
4
+
5
+ const MAX_STARS = 5
6
+
7
+ const sizeClasses = {
8
+ sm: "h-4 w-4",
9
+ md: "h-5 w-5",
10
+ lg: "h-6 w-6",
11
+ } as const
12
+
13
+ export interface RatingProps {
14
+ value?: number
15
+ onChange?: (value: number) => void
16
+ readOnly?: boolean
17
+ size?: "sm" | "md" | "lg"
18
+ className?: string
19
+ "aria-label"?: string
20
+ }
21
+
22
+ function defaultLabel(value: number) {
23
+ return value > 0
24
+ ? `Avaliação: ${value} de ${MAX_STARS} estrelas`
25
+ : "Avaliação: sem nota"
26
+ }
27
+
28
+ export function Rating({
29
+ value = 0,
30
+ onChange,
31
+ readOnly = false,
32
+ size = "md",
33
+ className,
34
+ "aria-label": ariaLabel,
35
+ }: RatingProps) {
36
+ const clamped = Math.min(MAX_STARS, Math.max(0, value))
37
+ const label = ariaLabel ?? defaultLabel(clamped)
38
+
39
+ if (readOnly) {
40
+ return (
41
+ <div
42
+ role="img"
43
+ aria-label={label}
44
+ className={cn("inline-flex items-center gap-0.5", className)}
45
+ >
46
+ {Array.from({ length: MAX_STARS }, (_, index) => (
47
+ <Star
48
+ key={index}
49
+ aria-hidden
50
+ className={cn(
51
+ sizeClasses[size],
52
+ index < clamped
53
+ ? "fill-amber-400 text-amber-400"
54
+ : "text-muted-foreground",
55
+ )}
56
+ />
57
+ ))}
58
+ </div>
59
+ )
60
+ }
61
+
62
+ return (
63
+ <ToggleGroup.Root
64
+ type="single"
65
+ value={clamped > 0 ? String(clamped) : ""}
66
+ onValueChange={(next) => {
67
+ // Radix emite "" ao clicar de novo na estrela já selecionada;
68
+ // mantemos a nota atual em vez de zerar (onChange é sempre 1-5).
69
+ if (next) onChange?.(Number(next))
70
+ }}
71
+ aria-label={label}
72
+ className={cn("inline-flex items-center gap-0.5", className)}
73
+ >
74
+ {Array.from({ length: MAX_STARS }, (_, index) => {
75
+ const starValue = index + 1
76
+ const filled = starValue <= clamped
77
+ return (
78
+ <ToggleGroup.Item
79
+ key={starValue}
80
+ value={String(starValue)}
81
+ aria-label={`${starValue} ${starValue === 1 ? "estrela" : "estrelas"}`}
82
+ className="inline-flex cursor-pointer items-center justify-center rounded-sm bg-transparent p-0.5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
83
+ >
84
+ <Star
85
+ aria-hidden
86
+ className={cn(
87
+ sizeClasses[size],
88
+ "transition-colors",
89
+ filled
90
+ ? "fill-amber-400 text-amber-400"
91
+ : "text-muted-foreground hover:text-amber-400",
92
+ )}
93
+ />
94
+ </ToggleGroup.Item>
95
+ )
96
+ })}
97
+ </ToggleGroup.Root>
98
+ )
99
+ }
package/src/index.ts CHANGED
@@ -8,6 +8,8 @@ export type { BaseDialogProps, BaseDialogSize } from "./components/base-dialog";
8
8
  export { BaseDialog } from "./components/base-dialog";
9
9
  export type { ColorPickerProps } from "./components/color-picker";
10
10
  export { ColorPicker } from "./components/color-picker";
11
+ export { Rating } from "./components/rating"
12
+ export type { RatingProps } from "./components/rating"
11
13
  export type { ComboboxOption, ComboboxProps } from "./components/combobox";
12
14
  export { Combobox } from "./components/combobox";
13
15
  export { ConfirmDialog } from "./components/confirm-dialog";