@fluencypassdevs/cycle 0.7.1 → 0.7.3

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/README.md CHANGED
@@ -5,7 +5,22 @@ Design System da [Fluencypass](https://fluencypass.com), construido sobre shadcn
5
5
  ## Instalacao
6
6
 
7
7
  ```bash
8
- npm install @fluencypassdevs/cycle
8
+ npm install @fluencypassdevs/cycle geist
9
+ ```
10
+
11
+ No `src/app/layout.tsx`, configurar a fonte Geist:
12
+
13
+ ```tsx
14
+ import { GeistSans } from "geist/font/sans"
15
+ import { GeistMono } from "geist/font/mono"
16
+
17
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
18
+ return (
19
+ <html lang="pt-BR" className={`${GeistSans.variable} ${GeistMono.variable}`}>
20
+ <body>{children}</body>
21
+ </html>
22
+ )
23
+ }
9
24
  ```
10
25
 
11
26
  No `globals.css`:
package/bin/mcp.mjs CHANGED
@@ -531,6 +531,28 @@ cycleToast.info("Nova mensagem recebida")`,
531
531
  <Button disabled><Spinner size="xs" /> Salvando...</Button>`,
532
532
  keywords: ["spinner", "loading", "carregando", "aguarde", "loader", "spin", "indicador"],
533
533
  },
534
+ {
535
+ name: "Fab",
536
+ import: `import { Fab } from "@fluencypassdevs/cycle"`,
537
+ description: "Floating Action Button — botao circular flutuante para acao principal. 3 sizes (sm=40px, default=48px, lg=56px), 3 variants (default, secondary, outline). Modo extended (pill com icone + texto). Shadow-lg, posicao fixa configuravel.",
538
+ props: [
539
+ { name: "variant", type: '"default" | "secondary" | "outline"', default: '"default"' },
540
+ { name: "size", type: '"sm" | "default" | "lg"', default: '"default"' },
541
+ { name: "extended", type: "boolean", default: "false" },
542
+ { name: "position", type: '"bottom-right" | "bottom-left" | "bottom-center" | "none"', default: '"bottom-right"' },
543
+ { name: "asChild", type: "boolean", default: "false" },
544
+ ],
545
+ example: `<Fab position="none" aria-label="Adicionar">
546
+ <CycleIcon icon={Plus} decorative />
547
+ </Fab>
548
+ <Fab extended position="none">
549
+ <CycleIcon icon={Pencil} decorative /> Editar
550
+ </Fab>
551
+ <Fab variant="secondary" position="bottom-right" aria-label="Chat">
552
+ <CycleIcon icon={MessageCircle} decorative />
553
+ </Fab>`,
554
+ keywords: ["fab", "floating", "action", "button", "botao", "flutuante", "circular", "shadow"],
555
+ },
534
556
  {
535
557
  name: "FluencypassLogo",
536
558
  import: `import { FluencypassLogo, FluencypassIcon } from "@fluencypassdevs/cycle"`,
@@ -742,10 +764,29 @@ import { Home } from "lucide-react" // PROIBIDO
742
764
 
743
765
  ## 1. Instalar o pacote:
744
766
  \`\`\`bash
745
- npm install @fluencypassdevs/cycle
767
+ npm install @fluencypassdevs/cycle geist
768
+ \`\`\`
769
+
770
+ ## 2. Configurar a fonte Geist (OBRIGATORIO):
771
+
772
+ No \`src/app/layout.tsx\`:
773
+
774
+ \`\`\`tsx
775
+ import { GeistSans } from "geist/font/sans"
776
+ import { GeistMono } from "geist/font/mono"
777
+
778
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
779
+ return (
780
+ <html lang="pt-BR" className={\`\${GeistSans.variable} \${GeistMono.variable}\`}>
781
+ <body>{children}</body>
782
+ </html>
783
+ )
784
+ }
746
785
  \`\`\`
747
786
 
748
- ## 2. Configurar CSS (globals.css):
787
+ > Sem isso, todos os textos usam a fonte do sistema em vez da Geist.
788
+
789
+ ## 3. Configurar CSS (globals.css):
749
790
 
750
791
  \`\`\`css
751
792
  @import "tailwindcss";
@@ -754,26 +795,24 @@ npm install @fluencypassdevs/cycle
754
795
 
755
796
  So isso! O \`@source\` do Tailwind v4 ja esta embutido dentro do CSS do pacote — nao precisa adicionar manualmente.
756
797
 
757
- > Se o projeto tinha \`@source "../../node_modules/@fluencypassdevs/cycle/dist"\` no globals.css, pode remover (a partir da v0.7.0 e automatico).
758
-
759
- ## 3. Importar componentes:
798
+ ## 4. Importar componentes:
760
799
  \`\`\`tsx
761
800
  import { Button, Input, Badge } from "@fluencypassdevs/cycle"
762
801
  \`\`\`
763
802
 
764
- ## 4. Importar icones (OBRIGATORIO via Cycle):
803
+ ## 5. Importar icones (OBRIGATORIO via Cycle):
765
804
  \`\`\`tsx
766
805
  import { CycleIcon } from "@fluencypassdevs/cycle"
767
806
  import { Home } from "@fluencypassdevs/cycle/icons/lucide"
768
807
  // NUNCA: import { Home } from "lucide-react" ❌
769
808
  \`\`\`
770
809
 
771
- ## 5. Utilidades:
810
+ ## 6. Utilidades:
772
811
  \`\`\`tsx
773
812
  import { cn } from "@fluencypassdevs/cycle/lib/utils"
774
813
  \`\`\`
775
814
 
776
- ## 6. Configurar regras para IA (opcional):
815
+ ## 7. Configurar regras para IA (opcional):
777
816
  \`\`\`bash
778
817
  npx cycle init
779
818
  \`\`\`
@@ -17,6 +17,31 @@ import { CycleIcon } from "@fluencypassdevs/cycle/icons"
17
17
  import { cn } from "@fluencypassdevs/cycle/lib/utils"
18
18
  ```
19
19
 
20
+ ## Fonte Geist (OBRIGATORIO)
21
+
22
+ O Cycle usa a fonte **Geist**. Instalar junto com o pacote:
23
+
24
+ ```bash
25
+ npm install @fluencypassdevs/cycle geist
26
+ ```
27
+
28
+ No `src/app/layout.tsx`:
29
+
30
+ ```tsx
31
+ import { GeistSans } from "geist/font/sans"
32
+ import { GeistMono } from "geist/font/mono"
33
+
34
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
35
+ return (
36
+ <html lang="pt-BR" className={`${GeistSans.variable} ${GeistMono.variable}`}>
37
+ <body>{children}</body>
38
+ </html>
39
+ )
40
+ }
41
+ ```
42
+
43
+ > Sem isso, todos os textos usam a fonte do sistema em vez da Geist.
44
+
20
45
  ## CSS (globals.css)
21
46
 
22
47
  O `globals.css` DEVE conter:
@@ -31,9 +56,10 @@ O `globals.css` DEVE conter:
31
56
  ### Troubleshooting: Componentes sem estilo
32
57
 
33
58
  Se componentes Cycle aparecem sem estilo, verifique:
34
- 1. O `@import "@fluencypassdevs/cycle/styles.css";` esta presente no globals.css?
35
- 2. O pacote esta instalado? `npm list @fluencypassdevs/cycle`
36
- 3. Versao >= 0.7.0? O @source automatico so existe a partir desta versao.
59
+ 1. A fonte Geist esta configurada no layout.tsx?
60
+ 2. O `@import "@fluencypassdevs/cycle/styles.css";` esta presente no globals.css?
61
+ 3. O pacote esta instalado? `npm list @fluencypassdevs/cycle`
62
+ 4. Versao >= 0.7.2? Fixes criticos de CSS nesta versao.
37
63
 
38
64
  ## Regras para IA (IMPORTANTE)
39
65
 
@@ -124,6 +150,7 @@ Todos importados de `@fluencypassdevs/cycle`:
124
150
  | Empty | Estado vazio |
125
151
  | Skeleton | Placeholder de carregamento |
126
152
  | Spinner | Indicador de carregamento animado (5 sizes) |
153
+ | Fab | Floating Action Button circular/pill (3 sizes, 3 variants) |
127
154
  | Dialog | Modal dialog |
128
155
  | FluencypassLogo, FluencypassIcon | Logo e icone da Fluencypass |
129
156
  | ProductLogo, ClassLogo, PrivateTalkLogo, GroupTalkLogo | Logos dos produtos |
@@ -6,7 +6,7 @@ import { cva } from 'class-variance-authority';
6
6
  import { jsx } from 'react/jsx-runtime';
7
7
 
8
8
  var checkboxVariants = cva(
9
- "peer shrink-0 border border-neutral-input shadow-xs transition-shadow outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:bg-neutral-input/30 dark:aria-invalid:ring-destructive/40 dark:data-[state=checked]:bg-primary",
9
+ "peer shrink-0 border border-neutral-border shadow-xs transition-shadow outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:bg-neutral-input/30 dark:aria-invalid:ring-destructive/40 dark:data-[state=checked]:bg-primary",
10
10
  {
11
11
  variants: {
12
12
  size: {
@@ -57,5 +57,5 @@ function Checkbox(_a) {
57
57
  }
58
58
 
59
59
  export { Checkbox, checkboxVariants };
60
- //# sourceMappingURL=chunk-IJTNFN6N.js.map
61
- //# sourceMappingURL=chunk-IJTNFN6N.js.map
60
+ //# sourceMappingURL=chunk-5BNTQSCS.js.map
61
+ //# sourceMappingURL=chunk-5BNTQSCS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/ui/checkbox.tsx"],"names":["CheckboxPrimitive"],"mappings":";;;;;;;AASA,IAAM,gBAAA,GAAmB,GAAA;AAAA,EACvB,yeAAA;AAAA,EACA;AAAA,IACE,QAAA,EAAU;AAAA,MACR,IAAA,EAAM;AAAA,QACJ,EAAA,EAAI,yBAAA;AAAA,QACJ,OAAA,EAAS,yBAAA;AAAA,QACT,EAAA,EAAI;AAAA,OACN;AAAA,MACA,OAAA,EAAS;AAAA,QACP,OAAA,EAAS,eAAA;AAAA,QACT,QAAA,EAAU;AAAA;AACZ,KACF;AAAA,IACA,eAAA,EAAiB;AAAA,MACf,IAAA,EAAM,SAAA;AAAA,MACN,OAAA,EAAS;AAAA;AACX;AAEJ;AASA,SAAS,SAAS,EAAA,EAMA;AANA,EAAA,IAAA,EAAA,GAAA,EAAA,EAChB;AAAA,IAAA,SAAA;AAAA,IACA,IAAA,GAAO,SAAA;AAAA,IACP,OAAA,GAAU,SAAA;AAAA,IACV;AAAA,GAzCF,GAqCkB,EAAA,EAKb,KAAA,GAAA,SAAA,CALa,EAAA,EAKb;AAAA,IAJH,WAAA;AAAA,IACA,MAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GAAA,CAAA;AAGA,EAAA,uBACE,GAAA;AAAA,IAACA,UAAA,CAAkB,IAAA;AAAA,IAAlB,aAAA,CAAA,cAAA,CAAA;AAAA,MACC,WAAA,EAAU,UAAA;AAAA,MACV,cAAA,EAAc,OAAA;AAAA,MACd,SAAA,EAAW,GAAG,KAAA,EAAO,gBAAA,CAAiB,EAAE,IAAA,EAAM,OAAA,EAAS,CAAA,EAAG,SAAS;AAAA,KAAA,EAC/D,KAAA,CAAA,EAJL;AAAA,MAMC,QAAA,kBAAA,GAAA;AAAA,QAACA,UAAA,CAAkB,SAAA;AAAA,QAAlB;AAAA,UACC,WAAA,EAAU,oBAAA;AAAA,UACV,SAAA,EAAU,wDAAA;AAAA,UAEV,8BAAC,SAAA,EAAA,EAAU;AAAA;AAAA;AACb,KAAA;AAAA,GACF;AAEJ","file":"chunk-5BNTQSCS.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { CheckIcon } from \"lucide-react\"\nimport { Checkbox as CheckboxPrimitive } from \"radix-ui\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst checkboxVariants = cva(\n \"peer shrink-0 border border-neutral-border shadow-xs transition-shadow outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:bg-neutral-input/30 dark:aria-invalid:ring-destructive/40 dark:data-[state=checked]:bg-primary\",\n {\n variants: {\n size: {\n sm: \"size-3.5 [&_svg]:size-3\",\n default: \"size-4 [&_svg]:size-3.5\",\n lg: \"size-5 [&_svg]:size-4\",\n },\n variant: {\n default: \"rounded-[4px]\",\n circular: \"rounded-full\",\n },\n },\n defaultVariants: {\n size: \"default\",\n variant: \"default\",\n },\n }\n)\n\nexport interface CheckboxProps\n extends React.ComponentProps<typeof CheckboxPrimitive.Root>,\n VariantProps<typeof checkboxVariants> {\n /** Classe de tema aplicada apenas no estado checked (ex: \"theme-class\") */\n theme?: string\n}\n\nfunction Checkbox({\n className,\n size = \"default\",\n variant = \"default\",\n theme,\n ...props\n}: CheckboxProps) {\n return (\n <CheckboxPrimitive.Root\n data-slot=\"checkbox\"\n data-variant={variant}\n className={cn(theme, checkboxVariants({ size, variant }), className)}\n {...props}\n >\n <CheckboxPrimitive.Indicator\n data-slot=\"checkbox-indicator\"\n className=\"grid place-content-center text-current transition-none\"\n >\n <CheckIcon />\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n )\n}\n\nexport { Checkbox, checkboxVariants }\n"]}
@@ -0,0 +1,91 @@
1
+ import { cn } from './chunk-TYCPXAXF.js';
2
+ import { __objRest, __spreadValues } from './chunk-YINJ5YZ5.js';
3
+ import { cva } from 'class-variance-authority';
4
+ import { Slot } from 'radix-ui';
5
+ import { jsx } from 'react/jsx-runtime';
6
+
7
+ var fabVariants = cva(
8
+ "inline-flex shrink-0 items-center justify-center rounded-full whitespace-nowrap transition-all outline-none cursor-pointer shadow-lg hover:shadow-xl focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-primary/90",
9
+ {
10
+ variants: {
11
+ size: {
12
+ sm: "size-10 [&_svg:not([class*='size-'])]:size-4 [&_svg]:stroke-[1.5]",
13
+ default: "size-12 [&_svg:not([class*='size-'])]:size-5 [&_svg]:stroke-[1.5]",
14
+ lg: "size-14 [&_svg:not([class*='size-'])]:size-6 [&_svg]:stroke-[1.5]"
15
+ },
16
+ variant: {
17
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
18
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
19
+ outline: "border border-border bg-background text-foreground hover:bg-accent hover:text-accent-foreground"
20
+ }
21
+ },
22
+ defaultVariants: {
23
+ size: "default",
24
+ variant: "default"
25
+ }
26
+ }
27
+ );
28
+ var fabExtendedVariants = cva(
29
+ "rounded-full gap-2 button-md",
30
+ {
31
+ variants: {
32
+ size: {
33
+ sm: "h-10 px-4 button-sm [&_svg:not([class*='size-'])]:size-4 [&_svg]:stroke-[1.5]",
34
+ default: "h-12 px-5 button-md [&_svg:not([class*='size-'])]:size-5 [&_svg]:stroke-[1.5]",
35
+ lg: "h-14 px-6 button-lg [&_svg:not([class*='size-'])]:size-6 [&_svg]:stroke-[1.5]"
36
+ }
37
+ },
38
+ defaultVariants: {
39
+ size: "default"
40
+ }
41
+ }
42
+ );
43
+ var positionClasses = {
44
+ "bottom-right": "fixed bottom-6 right-6 z-50",
45
+ "bottom-left": "fixed bottom-6 left-6 z-50",
46
+ "bottom-center": "fixed bottom-6 left-1/2 -translate-x-1/2 z-50",
47
+ none: ""
48
+ };
49
+ function Fab(_a) {
50
+ var _b = _a, {
51
+ className,
52
+ size = "default",
53
+ variant = "default",
54
+ asChild = false,
55
+ extended = false,
56
+ position = "bottom-right"
57
+ } = _b, props = __objRest(_b, [
58
+ "className",
59
+ "size",
60
+ "variant",
61
+ "asChild",
62
+ "extended",
63
+ "position"
64
+ ]);
65
+ const Comp = asChild ? Slot.Root : "button";
66
+ return /* @__PURE__ */ jsx(
67
+ Comp,
68
+ __spreadValues({
69
+ "data-slot": "fab",
70
+ "data-variant": variant,
71
+ "data-size": size,
72
+ className: cn(
73
+ // Base styles shared between icon and extended
74
+ "inline-flex shrink-0 items-center justify-center rounded-full whitespace-nowrap transition-all outline-none cursor-pointer shadow-lg hover:shadow-xl focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
75
+ // Variant colors
76
+ variant === "default" && "bg-primary text-primary-foreground hover:bg-primary/90",
77
+ variant === "secondary" && "bg-secondary text-secondary-foreground hover:bg-secondary/80",
78
+ variant === "outline" && "border border-border bg-background text-foreground hover:bg-accent hover:text-accent-foreground",
79
+ // Size: icon-only (square) vs extended (pill)
80
+ extended ? fabExtendedVariants({ size }) : fabVariants({ size }),
81
+ // Position
82
+ positionClasses[position != null ? position : "bottom-right"],
83
+ className
84
+ )
85
+ }, props)
86
+ );
87
+ }
88
+
89
+ export { Fab, fabVariants };
90
+ //# sourceMappingURL=chunk-7NFHHOAE.js.map
91
+ //# sourceMappingURL=chunk-7NFHHOAE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/ui/fab.tsx"],"names":[],"mappings":";;;;;;AAQA,IAAM,WAAA,GAAc,GAAA;AAAA,EAClB,+VAAA;AAAA,EACA;AAAA,IACE,QAAA,EAAU;AAAA,MACR,IAAA,EAAM;AAAA,QACJ,EAAA,EAAI,mEAAA;AAAA,QACJ,OAAA,EAAS,mEAAA;AAAA,QACT,EAAA,EAAI;AAAA,OACN;AAAA,MACA,OAAA,EAAS;AAAA,QACP,OAAA,EAAS,wDAAA;AAAA,QACT,SAAA,EAAW,8DAAA;AAAA,QACX,OAAA,EAAS;AAAA;AACX,KACF;AAAA,IACA,eAAA,EAAiB;AAAA,MACf,IAAA,EAAM,SAAA;AAAA,MACN,OAAA,EAAS;AAAA;AACX;AAEJ;AAEA,IAAM,mBAAA,GAAsB,GAAA;AAAA,EAC1B,8BAAA;AAAA,EACA;AAAA,IACE,QAAA,EAAU;AAAA,MACR,IAAA,EAAM;AAAA,QACJ,EAAA,EAAI,+EAAA;AAAA,QACJ,OAAA,EAAS,+EAAA;AAAA,QACT,EAAA,EAAI;AAAA;AACN,KACF;AAAA,IACA,eAAA,EAAiB;AAAA,MACf,IAAA,EAAM;AAAA;AACR;AAEJ,CAAA;AAaA,IAAM,eAAA,GAAkB;AAAA,EACtB,cAAA,EAAgB,6BAAA;AAAA,EAChB,aAAA,EAAe,4BAAA;AAAA,EACf,eAAA,EAAiB,+CAAA;AAAA,EACjB,IAAA,EAAM;AACR,CAAA;AAEA,SAAS,IAAI,EAAA,EAQA;AARA,EAAA,IAAA,EAAA,GAAA,EAAA,EACX;AAAA,IAAA,SAAA;AAAA,IACA,IAAA,GAAO,SAAA;AAAA,IACP,OAAA,GAAU,SAAA;AAAA,IACV,OAAA,GAAU,KAAA;AAAA,IACV,QAAA,GAAW,KAAA;AAAA,IACX,QAAA,GAAW;AAAA,GAtEb,GAgEa,EAAA,EAOR,KAAA,GAAA,SAAA,CAPQ,EAAA,EAOR;AAAA,IANH,WAAA;AAAA,IACA,MAAA;AAAA,IACA,SAAA;AAAA,IACA,SAAA;AAAA,IACA,UAAA;AAAA,IACA;AAAA,GAAA,CAAA;AAGA,EAAA,MAAM,IAAA,GAAO,OAAA,GAAU,IAAA,CAAK,IAAA,GAAO,QAAA;AAEnC,EAAA,uBACE,GAAA;AAAA,IAAC,IAAA;AAAA,IAAA,cAAA,CAAA;AAAA,MACC,WAAA,EAAU,KAAA;AAAA,MACV,cAAA,EAAc,OAAA;AAAA,MACd,WAAA,EAAW,IAAA;AAAA,MACX,SAAA,EAAW,EAAA;AAAA;AAAA,QAET,wSAAA;AAAA;AAAA,QAEA,YAAY,SAAA,IAAa,wDAAA;AAAA,QACzB,YAAY,WAAA,IAAe,8DAAA;AAAA,QAC3B,YAAY,SAAA,IAAa,iGAAA;AAAA;AAAA,QAEzB,QAAA,GAAW,oBAAoB,EAAE,IAAA,EAAM,CAAA,GAAI,WAAA,CAAY,EAAE,IAAA,EAAM,CAAA;AAAA;AAAA,QAE/D,eAAA,CAAgB,8BAAY,cAAc,CAAA;AAAA,QAC1C;AAAA;AACF,KAAA,EACI,KAAA;AAAA,GACN;AAEJ","file":"chunk-7NFHHOAE.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { Slot } from \"radix-ui\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst fabVariants = cva(\n \"inline-flex shrink-0 items-center justify-center rounded-full whitespace-nowrap transition-all outline-none cursor-pointer shadow-lg hover:shadow-xl focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-primary/90\",\n {\n variants: {\n size: {\n sm: \"size-10 [&_svg:not([class*='size-'])]:size-4 [&_svg]:stroke-[1.5]\",\n default: \"size-12 [&_svg:not([class*='size-'])]:size-5 [&_svg]:stroke-[1.5]\",\n lg: \"size-14 [&_svg:not([class*='size-'])]:size-6 [&_svg]:stroke-[1.5]\",\n },\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n secondary: \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n outline: \"border border-border bg-background text-foreground hover:bg-accent hover:text-accent-foreground\",\n },\n },\n defaultVariants: {\n size: \"default\",\n variant: \"default\",\n },\n }\n)\n\nconst fabExtendedVariants = cva(\n \"rounded-full gap-2 button-md\",\n {\n variants: {\n size: {\n sm: \"h-10 px-4 button-sm [&_svg:not([class*='size-'])]:size-4 [&_svg]:stroke-[1.5]\",\n default: \"h-12 px-5 button-md [&_svg:not([class*='size-'])]:size-5 [&_svg]:stroke-[1.5]\",\n lg: \"h-14 px-6 button-lg [&_svg:not([class*='size-'])]:size-6 [&_svg]:stroke-[1.5]\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n }\n)\n\nexport interface FabProps\n extends React.ComponentProps<\"button\">,\n VariantProps<typeof fabVariants> {\n /** Render as child element (Slot) */\n asChild?: boolean\n /** Extended mode: pill shape with icon + label. Pass a string or ReactNode for the label. */\n extended?: boolean\n /** Position preset. \"none\" disables fixed positioning. Default: \"bottom-right\" */\n position?: \"bottom-right\" | \"bottom-left\" | \"bottom-center\" | \"none\"\n}\n\nconst positionClasses = {\n \"bottom-right\": \"fixed bottom-6 right-6 z-50\",\n \"bottom-left\": \"fixed bottom-6 left-6 z-50\",\n \"bottom-center\": \"fixed bottom-6 left-1/2 -translate-x-1/2 z-50\",\n none: \"\",\n} as const\n\nfunction Fab({\n className,\n size = \"default\",\n variant = \"default\",\n asChild = false,\n extended = false,\n position = \"bottom-right\",\n ...props\n}: FabProps) {\n const Comp = asChild ? Slot.Root : \"button\"\n\n return (\n <Comp\n data-slot=\"fab\"\n data-variant={variant}\n data-size={size}\n className={cn(\n // Base styles shared between icon and extended\n \"inline-flex shrink-0 items-center justify-center rounded-full whitespace-nowrap transition-all outline-none cursor-pointer shadow-lg hover:shadow-xl focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n // Variant colors\n variant === \"default\" && \"bg-primary text-primary-foreground hover:bg-primary/90\",\n variant === \"secondary\" && \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n variant === \"outline\" && \"border border-border bg-background text-foreground hover:bg-accent hover:text-accent-foreground\",\n // Size: icon-only (square) vs extended (pill)\n extended ? fabExtendedVariants({ size }) : fabVariants({ size }),\n // Position\n positionClasses[position ?? \"bottom-right\"],\n className\n )}\n {...props}\n />\n )\n}\n\nexport { Fab, fabVariants }\n"]}
@@ -5,8 +5,8 @@ import { cn } from './chunk-TYCPXAXF.js';
5
5
  import { __objRest, __spreadProps, __spreadValues } from './chunk-YINJ5YZ5.js';
6
6
  import * as React from 'react';
7
7
  import { cva } from 'class-variance-authority';
8
- import { ThumbsUp, ThumbsDown, X } from 'lucide-react';
9
- import { jsxs, jsx } from 'react/jsx-runtime';
8
+ import { ThumbsUp, ThumbsDown, Check, X } from 'lucide-react';
9
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
10
10
 
11
11
  var likeDislikeVariants = cva("inline-flex flex-col", {
12
12
  variants: {
@@ -48,6 +48,8 @@ function LikeDislike(_a) {
48
48
  feedbackPlaceholder = "O que voce nao gostou?",
49
49
  feedbackSubmitLabel = "Enviar",
50
50
  onFeedbackSubmit,
51
+ feedbackSuccessMessage = "Obrigado pelo feedback!",
52
+ feedbackAutoCloseDelay = 2e3,
51
53
  burstTheme = "theme-brand",
52
54
  disabled = false
53
55
  } = _b, props = __objRest(_b, [
@@ -60,6 +62,8 @@ function LikeDislike(_a) {
60
62
  "feedbackPlaceholder",
61
63
  "feedbackSubmitLabel",
62
64
  "onFeedbackSubmit",
65
+ "feedbackSuccessMessage",
66
+ "feedbackAutoCloseDelay",
63
67
  "burstTheme",
64
68
  "disabled"
65
69
  ]);
@@ -69,6 +73,8 @@ function LikeDislike(_a) {
69
73
  const [feedbackText, setFeedbackText] = React.useState("");
70
74
  const [isBursting, setIsBursting] = React.useState(false);
71
75
  const [feedbackDismissed, setFeedbackDismissed] = React.useState(false);
76
+ const [feedbackStatus, setFeedbackStatus] = React.useState("idle");
77
+ const autoCloseTimerRef = React.useRef(null);
72
78
  const s = sizeConfig[size != null ? size : "default"];
73
79
  function handleClick(target) {
74
80
  if (disabled) return;
@@ -76,6 +82,9 @@ function LikeDislike(_a) {
76
82
  if (!isControlled) setInternalValue(next);
77
83
  onValueChange == null ? void 0 : onValueChange(next);
78
84
  setFeedbackDismissed(false);
85
+ setFeedbackStatus("idle");
86
+ setFeedbackText("");
87
+ if (autoCloseTimerRef.current) clearTimeout(autoCloseTimerRef.current);
79
88
  if (target === "like" && next === "like") {
80
89
  setIsBursting(true);
81
90
  }
@@ -83,11 +92,27 @@ function LikeDislike(_a) {
83
92
  function handleBurstEnd() {
84
93
  setIsBursting(false);
85
94
  }
86
- function handleFeedbackSubmit(e) {
95
+ React.useEffect(() => {
96
+ return () => {
97
+ if (autoCloseTimerRef.current) clearTimeout(autoCloseTimerRef.current);
98
+ };
99
+ }, []);
100
+ async function handleFeedbackSubmit(e) {
87
101
  e.preventDefault();
88
- if (feedbackText.trim()) {
89
- onFeedbackSubmit == null ? void 0 : onFeedbackSubmit(feedbackText.trim());
102
+ if (!feedbackText.trim() || feedbackStatus === "submitting") return;
103
+ setFeedbackStatus("submitting");
104
+ try {
105
+ await (onFeedbackSubmit == null ? void 0 : onFeedbackSubmit(feedbackText.trim()));
106
+ setFeedbackStatus("submitted");
90
107
  setFeedbackText("");
108
+ if (feedbackAutoCloseDelay > 0) {
109
+ autoCloseTimerRef.current = setTimeout(() => {
110
+ setFeedbackDismissed(true);
111
+ setFeedbackStatus("idle");
112
+ }, feedbackAutoCloseDelay);
113
+ }
114
+ } catch (e2) {
115
+ setFeedbackStatus("idle");
91
116
  }
92
117
  }
93
118
  const isLiked = currentValue === "like";
@@ -175,49 +200,58 @@ function LikeDislike(_a) {
175
200
  }
176
201
  )
177
202
  ] }),
178
- showFeedbackPanel && /* @__PURE__ */ jsxs("div", { className: "absolute left-0 top-full z-50 mt-2 w-72 rounded-lg border border-border bg-background p-3 shadow-md animate-in fade-in-0 zoom-in-95 slide-in-from-top-2", children: [
179
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
180
- /* @__PURE__ */ jsx("p", { className: cn("font-medium text-foreground", s.text), children: feedbackPlaceholder }),
181
- /* @__PURE__ */ jsx(
182
- "button",
183
- {
184
- type: "button",
185
- onClick: () => setFeedbackDismissed(true),
186
- className: "inline-flex size-6 items-center justify-center rounded-md text-muted-foreground hover:bg-muted hover:text-foreground transition-colors cursor-pointer",
187
- "aria-label": "Fechar",
188
- children: /* @__PURE__ */ jsx(CycleIcon, { icon: X, size: "xs", decorative: true })
189
- }
190
- )
191
- ] }),
192
- /* @__PURE__ */ jsxs("form", { onSubmit: handleFeedbackSubmit, className: "flex flex-col gap-2", children: [
193
- /* @__PURE__ */ jsx(
194
- Textarea,
195
- {
196
- textareaSize: "sm",
197
- value: feedbackText,
198
- onChange: (e) => setFeedbackText(e.target.value),
199
- placeholder: "Conte-nos mais...",
200
- disabled,
201
- className: "resize-none min-h-[60px]",
202
- "aria-label": "Feedback"
203
- }
204
- ),
205
- /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(
206
- Button,
207
- {
208
- type: "submit",
209
- size: "sm",
210
- disabled: disabled || !feedbackText.trim(),
211
- children: feedbackSubmitLabel
212
- }
213
- ) })
203
+ showFeedbackPanel && /* @__PURE__ */ jsx("div", { className: "absolute left-0 top-full z-50 mt-2 w-72 rounded-lg border border-border bg-background p-3 shadow-md animate-in fade-in-0 zoom-in-95 slide-in-from-top-2", children: feedbackStatus === "submitted" ? (
204
+ /* --- Success state --- */
205
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 py-2", children: [
206
+ /* @__PURE__ */ jsx("span", { className: "inline-flex size-5 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground", children: /* @__PURE__ */ jsx(CycleIcon, { icon: Check, size: "xs", decorative: true }) }),
207
+ /* @__PURE__ */ jsx("p", { className: cn("text-foreground", s.text), children: feedbackSuccessMessage })
214
208
  ] })
215
- ] })
209
+ ) : (
210
+ /* --- Form state --- */
211
+ /* @__PURE__ */ jsxs(Fragment, { children: [
212
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
213
+ /* @__PURE__ */ jsx("p", { className: cn("font-medium text-foreground", s.text), children: feedbackPlaceholder }),
214
+ /* @__PURE__ */ jsx(
215
+ "button",
216
+ {
217
+ type: "button",
218
+ onClick: () => setFeedbackDismissed(true),
219
+ className: "inline-flex size-6 items-center justify-center rounded-md text-muted-foreground hover:bg-muted hover:text-foreground transition-colors cursor-pointer",
220
+ "aria-label": "Fechar",
221
+ children: /* @__PURE__ */ jsx(CycleIcon, { icon: X, size: "xs", decorative: true })
222
+ }
223
+ )
224
+ ] }),
225
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleFeedbackSubmit, className: "flex flex-col gap-2", children: [
226
+ /* @__PURE__ */ jsx(
227
+ Textarea,
228
+ {
229
+ textareaSize: "sm",
230
+ value: feedbackText,
231
+ onChange: (e) => setFeedbackText(e.target.value),
232
+ placeholder: "Conte-nos mais...",
233
+ disabled: disabled || feedbackStatus === "submitting",
234
+ className: "resize-none min-h-[60px]",
235
+ "aria-label": "Feedback"
236
+ }
237
+ ),
238
+ /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(
239
+ Button,
240
+ {
241
+ type: "submit",
242
+ size: "sm",
243
+ disabled: disabled || !feedbackText.trim() || feedbackStatus === "submitting",
244
+ children: feedbackStatus === "submitting" ? "Enviando..." : feedbackSubmitLabel
245
+ }
246
+ ) })
247
+ ] })
248
+ ] })
249
+ ) })
216
250
  ]
217
251
  })
218
252
  );
219
253
  }
220
254
 
221
255
  export { LikeDislike, likeDislikeVariants };
222
- //# sourceMappingURL=chunk-57NRP7HJ.js.map
223
- //# sourceMappingURL=chunk-57NRP7HJ.js.map
256
+ //# sourceMappingURL=chunk-MSFBYHUF.js.map
257
+ //# sourceMappingURL=chunk-MSFBYHUF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/ui/like-dislike.tsx"],"names":["e"],"mappings":"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","file":"chunk-MSFBYHUF.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { ThumbsUp, ThumbsDown, X, Check } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { CycleIcon } from \"@/components/icons\"\nimport { Button } from \"@/components/ui/button\"\nimport { Textarea } from \"@/components/ui/textarea\"\n\n/* ---------------------------------- CVA ---------------------------------- */\n\nconst likeDislikeVariants = cva(\"inline-flex flex-col\", {\n variants: {\n size: {\n default: \"gap-2\",\n xs: \"gap-1.5\",\n sm: \"gap-1.5\",\n lg: \"gap-3\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n})\n\n/** Maps component size → toggle button dimensions + icon size + burst ray size */\nconst sizeConfig = {\n xs: { iconBtn: \"size-6\", icon: \"xs\" as const, text: \"text-xs\", rayH: \"h-1\", rayW: \"w-[2px]\" },\n sm: { iconBtn: \"size-8\", icon: \"xs\" as const, text: \"text-xs\", rayH: \"h-1.5\", rayW: \"w-[2px]\" },\n default: { iconBtn: \"size-10\", icon: \"sm\" as const, text: \"text-sm\", rayH: \"h-2\", rayW: \"w-[2px]\" },\n lg: { iconBtn: \"size-12\", icon: \"sm\" as const, text: \"text-base\", rayH: \"h-2.5\", rayW: \"w-[3px]\" },\n} as const\n\n/** Angles and colors for the burst rays */\nconst BURST_RAYS = [\n { angle: 0, delay: \"0ms\" },\n { angle: 45, delay: \"30ms\" },\n { angle: 90, delay: \"60ms\" },\n { angle: 135, delay: \"20ms\" },\n { angle: 180, delay: \"50ms\" },\n { angle: 225, delay: \"10ms\" },\n { angle: 270, delay: \"40ms\" },\n { angle: 315, delay: \"25ms\" },\n]\n\n/* -------------------------------- Types --------------------------------- */\n\nexport type LikeDislikeValue = \"like\" | \"dislike\" | null\n\nexport interface LikeDislikeProps\n extends Omit<React.ComponentProps<\"div\">, \"onChange\" | \"defaultValue\">,\n VariantProps<typeof likeDislikeVariants> {\n /** Current value — controlled */\n value?: LikeDislikeValue\n /** Default value — uncontrolled */\n defaultValue?: LikeDislikeValue\n /** Called when the value changes */\n onValueChange?: (value: LikeDislikeValue) => void\n /** Show feedback textarea when dislike is selected */\n showFeedback?: boolean\n /** Placeholder for the feedback textarea */\n feedbackPlaceholder?: string\n /** Label for the feedback submit button */\n feedbackSubmitLabel?: string\n /** Called when feedback is submitted. Can return a Promise for async handling. */\n onFeedbackSubmit?: (feedback: string) => void | Promise<void>\n /** Message shown after feedback is submitted */\n feedbackSuccessMessage?: string\n /** Delay in ms before auto-closing after submit. Default: 2000. Set 0 to disable. */\n feedbackAutoCloseDelay?: number\n /** Theme class for the burst animation rays (e.g. \"theme-brand\"). Default: \"theme-brand\" */\n burstTheme?: string\n /** Disabled state */\n disabled?: boolean\n}\n\n/* ------------------------------ Component ------------------------------- */\n\nfunction LikeDislike({\n className,\n size = \"default\",\n value: valueProp,\n defaultValue = null,\n onValueChange,\n showFeedback = false,\n feedbackPlaceholder = \"O que voce nao gostou?\",\n feedbackSubmitLabel = \"Enviar\",\n onFeedbackSubmit,\n feedbackSuccessMessage = \"Obrigado pelo feedback!\",\n feedbackAutoCloseDelay = 2000,\n burstTheme = \"theme-brand\",\n disabled = false,\n ...props\n}: LikeDislikeProps) {\n /* --- State --- */\n const isControlled = valueProp !== undefined\n const [internalValue, setInternalValue] = React.useState<LikeDislikeValue>(defaultValue)\n const currentValue = isControlled ? valueProp : internalValue\n\n const [feedbackText, setFeedbackText] = React.useState(\"\")\n const [isBursting, setIsBursting] = React.useState(false)\n const [feedbackDismissed, setFeedbackDismissed] = React.useState(false)\n const [feedbackStatus, setFeedbackStatus] = React.useState<\"idle\" | \"submitting\" | \"submitted\">(\"idle\")\n const autoCloseTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(null)\n\n const s = sizeConfig[size ?? \"default\"]\n\n /* --- Handlers --- */\n function handleClick(target: \"like\" | \"dislike\") {\n if (disabled) return\n const next: LikeDislikeValue = currentValue === target ? null : target\n\n if (!isControlled) setInternalValue(next)\n onValueChange?.(next)\n setFeedbackDismissed(false)\n setFeedbackStatus(\"idle\")\n setFeedbackText(\"\")\n if (autoCloseTimerRef.current) clearTimeout(autoCloseTimerRef.current)\n\n // Trigger burst animation when transitioning TO like\n if (target === \"like\" && next === \"like\") {\n setIsBursting(true)\n }\n }\n\n function handleBurstEnd() {\n setIsBursting(false)\n }\n\n // Cleanup auto-close timer\n React.useEffect(() => {\n return () => {\n if (autoCloseTimerRef.current) clearTimeout(autoCloseTimerRef.current)\n }\n }, [])\n\n async function handleFeedbackSubmit(e: React.FormEvent) {\n e.preventDefault()\n if (!feedbackText.trim() || feedbackStatus === \"submitting\") return\n\n setFeedbackStatus(\"submitting\")\n try {\n await onFeedbackSubmit?.(feedbackText.trim())\n setFeedbackStatus(\"submitted\")\n setFeedbackText(\"\")\n\n // Auto-close after delay\n if (feedbackAutoCloseDelay > 0) {\n autoCloseTimerRef.current = setTimeout(() => {\n setFeedbackDismissed(true)\n setFeedbackStatus(\"idle\")\n }, feedbackAutoCloseDelay)\n }\n } catch {\n // If the callback throws, reset to idle so the user can retry\n setFeedbackStatus(\"idle\")\n }\n }\n\n const isLiked = currentValue === \"like\"\n const isDisliked = currentValue === \"dislike\"\n const showFeedbackPanel = isDisliked && showFeedback && !feedbackDismissed\n\n /* --- Shared button classes --- */\n const btnBase = cn(\n \"relative inline-flex shrink-0 items-center justify-center rounded-lg transition-[color,box-shadow,background-color] outline-none cursor-pointer\",\n \"hover:bg-muted hover:text-muted-foreground\",\n \"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50\",\n \"disabled:pointer-events-none disabled:opacity-50\",\n \"[&_svg]:pointer-events-none [&_svg]:shrink-0\",\n s.iconBtn\n )\n\n return (\n <div\n data-slot=\"like-dislike\"\n className={cn(\"relative inline-flex\", className)}\n {...props}\n >\n {/* Button row */}\n <div className=\"inline-flex items-center gap-1\" role=\"group\" aria-label=\"Avaliar conteudo\">\n {/* Like */}\n <button\n type=\"button\"\n aria-pressed={isLiked}\n aria-label=\"Gostei\"\n disabled={disabled}\n onClick={() => handleClick(\"like\")}\n className={cn(\n btnBase,\n isLiked && \"bg-accent text-accent-foreground [&_svg]:fill-current\"\n )}\n >\n {/* Burst rays (behind the icon) */}\n {isBursting && (\n <span\n className={cn(\"absolute inset-0 z-0 pointer-events-none\", burstTheme)}\n aria-hidden=\"true\"\n >\n {BURST_RAYS.map(({ angle, delay }) => (\n <span\n key={angle}\n className=\"absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2\"\n style={{ rotate: `${angle}deg` }}\n >\n <span\n className={cn(\n \"block rounded-full bg-primary opacity-0 animate-like-burst\",\n s.rayW, s.rayH\n )}\n style={{ animationDelay: delay }}\n />\n </span>\n ))}\n </span>\n )}\n\n {/* Icon with pop animation (above rays) */}\n <span\n className={cn(\"relative z-10\", isBursting && \"animate-like-pop\")}\n onAnimationEnd={handleBurstEnd}\n >\n <CycleIcon icon={ThumbsUp} size={s.icon} decorative />\n </span>\n </button>\n\n {/* Dislike */}\n <button\n type=\"button\"\n aria-pressed={isDisliked}\n aria-label=\"Nao gostei\"\n disabled={disabled}\n onClick={() => handleClick(\"dislike\")}\n className={cn(\n btnBase,\n isDisliked && \"bg-accent text-accent-foreground [&_svg]:fill-current\"\n )}\n >\n <CycleIcon icon={ThumbsDown} size={s.icon} decorative />\n </button>\n </div>\n\n {/* Floating feedback panel */}\n {showFeedbackPanel && (\n <div className=\"absolute left-0 top-full z-50 mt-2 w-72 rounded-lg border border-border bg-background p-3 shadow-md animate-in fade-in-0 zoom-in-95 slide-in-from-top-2\">\n {feedbackStatus === \"submitted\" ? (\n /* --- Success state --- */\n <div className=\"flex items-center gap-2 py-2\">\n <span className=\"inline-flex size-5 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground\">\n <CycleIcon icon={Check} size=\"xs\" decorative />\n </span>\n <p className={cn(\"text-foreground\", s.text)}>\n {feedbackSuccessMessage}\n </p>\n </div>\n ) : (\n /* --- Form state --- */\n <>\n <div className=\"flex items-center justify-between mb-2\">\n <p className={cn(\"font-medium text-foreground\", s.text)}>\n {feedbackPlaceholder}\n </p>\n <button\n type=\"button\"\n onClick={() => setFeedbackDismissed(true)}\n className=\"inline-flex size-6 items-center justify-center rounded-md text-muted-foreground hover:bg-muted hover:text-foreground transition-colors cursor-pointer\"\n aria-label=\"Fechar\"\n >\n <CycleIcon icon={X} size=\"xs\" decorative />\n </button>\n </div>\n <form onSubmit={handleFeedbackSubmit} className=\"flex flex-col gap-2\">\n <Textarea\n textareaSize=\"sm\"\n value={feedbackText}\n onChange={(e) => setFeedbackText(e.target.value)}\n placeholder=\"Conte-nos mais...\"\n disabled={disabled || feedbackStatus === \"submitting\"}\n className=\"resize-none min-h-[60px]\"\n aria-label=\"Feedback\"\n />\n <div className=\"flex justify-end\">\n <Button\n type=\"submit\"\n size=\"sm\"\n disabled={disabled || !feedbackText.trim() || feedbackStatus === \"submitting\"}\n >\n {feedbackStatus === \"submitting\" ? \"Enviando...\" : feedbackSubmitLabel}\n </Button>\n </div>\n </form>\n </>\n )}\n </div>\n )}\n </div>\n )\n}\n\nexport { LikeDislike, likeDislikeVariants }\n"]}
@@ -6,7 +6,7 @@ import { cva } from 'class-variance-authority';
6
6
  import { jsx } from 'react/jsx-runtime';
7
7
 
8
8
  var radioVariants = cva(
9
- "aspect-square rounded-full border border-neutral-input bg-neutral-bg shadow-xs transition-shadow outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=checked]:border-primary data-[state=checked]:text-foreground dark:aria-invalid:ring-destructive/40",
9
+ "aspect-square rounded-full border border-neutral-border bg-neutral-bg shadow-xs transition-shadow outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=checked]:border-primary data-[state=checked]:text-foreground dark:aria-invalid:ring-destructive/40",
10
10
  {
11
11
  variants: {
12
12
  size: {
@@ -59,5 +59,5 @@ function RadioGroupItem(_a) {
59
59
  }
60
60
 
61
61
  export { RadioGroup, RadioGroupItem, radioVariants };
62
- //# sourceMappingURL=chunk-K567KZD5.js.map
63
- //# sourceMappingURL=chunk-K567KZD5.js.map
62
+ //# sourceMappingURL=chunk-X4IBONFB.js.map
63
+ //# sourceMappingURL=chunk-X4IBONFB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/ui/radio-group.tsx"],"names":["RadioGroupPrimitive"],"mappings":";;;;;;;AASA,IAAM,aAAA,GAAgB,GAAA;AAAA,EACpB,8ZAAA;AAAA,EACA;AAAA,IACE,QAAA,EAAU;AAAA,MACR,IAAA,EAAM;AAAA,QACJ,EAAA,EAAI,yBAAA;AAAA,QACJ,OAAA,EAAS,yBAAA;AAAA,QACT,EAAA,EAAI;AAAA;AACN,KACF;AAAA,IACA,eAAA,EAAiB;AAAA,MACf,IAAA,EAAM;AAAA;AACR;AAEJ;AAKA,SAAS,WAAW,EAAA,EAA0C;AAA1C,EAAA,IAAA,EAAA,GAAA,EAAA,EAAE,EAAA,SAAA,EA5BtB,GA4BoB,EAAA,EAAgB,KAAA,GAAA,SAAA,CAAhB,IAAgB,CAAd,WAAA,CAAA,CAAA;AACpB,EAAA,uBACE,GAAA;AAAA,IAACA,YAAA,CAAoB,IAAA;AAAA,IAApB,cAAA,CAAA;AAAA,MACC,WAAA,EAAU,aAAA;AAAA,MACV,SAAA,EAAW,EAAA,CAAG,YAAA,EAAc,SAAS;AAAA,KAAA,EACjC,KAAA;AAAA,GACN;AAEJ;AASA,SAAS,eAAe,EAAA,EAKA;AALA,EAAA,IAAA,EAAA,GAAA,EAAA,EACtB;AAAA,IAAA,SAAA;AAAA,IACA,IAAA,GAAO,SAAA;AAAA,IACP;AAAA,GAhDF,GA6CwB,EAAA,EAInB,KAAA,GAAA,SAAA,CAJmB,EAAA,EAInB;AAAA,IAHH,WAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GAAA,CAAA;AAGA,EAAA,uBACE,GAAA;AAAA,IAACA,YAAA,CAAoB,IAAA;AAAA,IAApB,aAAA,CAAA,cAAA,CAAA;AAAA,MACC,WAAA,EAAU,kBAAA;AAAA,MACV,SAAA,EAAW,GAAG,KAAA,EAAO,aAAA,CAAc,EAAE,IAAA,EAAM,GAAG,SAAS;AAAA,KAAA,EACnD,KAAA,CAAA,EAHL;AAAA,MAKC,QAAA,kBAAA,GAAA;AAAA,QAACA,YAAA,CAAoB,SAAA;AAAA,QAApB;AAAA,UACC,WAAA,EAAU,uBAAA;AAAA,UACV,SAAA,EAAU,wCAAA;AAAA,UAEV,QAAA,kBAAA,GAAA,CAAC,UAAA,EAAA,EAAW,SAAA,EAAU,cAAA,EAAe;AAAA;AAAA;AACvC,KAAA;AAAA,GACF;AAEJ","file":"chunk-X4IBONFB.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { CircleIcon } from \"lucide-react\"\nimport { RadioGroup as RadioGroupPrimitive } from \"radix-ui\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst radioVariants = cva(\n \"aspect-square rounded-full border border-neutral-border bg-neutral-bg shadow-xs transition-shadow outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=checked]:border-primary data-[state=checked]:text-foreground dark:aria-invalid:ring-destructive/40\",\n {\n variants: {\n size: {\n sm: \"size-3.5 [&_svg]:size-2\",\n default: \"size-4 [&_svg]:size-2.5\",\n lg: \"size-5 [&_svg]:size-3\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n }\n)\n\nexport interface RadioGroupProps\n extends React.ComponentProps<typeof RadioGroupPrimitive.Root> {}\n\nfunction RadioGroup({ className, ...props }: RadioGroupProps) {\n return (\n <RadioGroupPrimitive.Root\n data-slot=\"radio-group\"\n className={cn(\"grid gap-3\", className)}\n {...props}\n />\n )\n}\n\nexport interface RadioGroupItemProps\n extends React.ComponentProps<typeof RadioGroupPrimitive.Item>,\n VariantProps<typeof radioVariants> {\n /** Classe de tema aplicada apenas no estado checked (ex: \"theme-class\") */\n theme?: string\n}\n\nfunction RadioGroupItem({\n className,\n size = \"default\",\n theme,\n ...props\n}: RadioGroupItemProps) {\n return (\n <RadioGroupPrimitive.Item\n data-slot=\"radio-group-item\"\n className={cn(theme, radioVariants({ size }), className)}\n {...props}\n >\n <RadioGroupPrimitive.Indicator\n data-slot=\"radio-group-indicator\"\n className=\"grid place-content-center text-current\"\n >\n <CircleIcon className=\"fill-current\" />\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n )\n}\n\nexport { RadioGroup, RadioGroupItem, radioVariants }\n"]}
package/dist/index.d.ts CHANGED
@@ -38,6 +38,7 @@ export { ResizableHandle, ResizablePanel, ResizablePanelGroup } from './ui/resiz
38
38
  export { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from './ui/empty.js';
39
39
  export { Skeleton } from './ui/skeleton.js';
40
40
  export { Spinner, SpinnerProps } from './ui/spinner.js';
41
+ export { Fab, FabProps, fabVariants } from './ui/fab.js';
41
42
  export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from './ui/dialog.js';
42
43
  import 'clsx';
43
44
  import 'react';
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ export { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTi
3
3
  export { Skeleton } from './chunk-2EKU7RP4.js';
4
4
  export { Spinner } from './chunk-5XNYJECW.js';
5
5
  export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from './chunk-TZ7BEYQ7.js';
6
+ export { Fab, fabVariants } from './chunk-7NFHHOAE.js';
6
7
  export { FluencypassIcon, FluencypassLogo } from './chunk-5LZHXNBV.js';
7
8
  export { ClassLogo, GroupTalkLogo, PrivateTalkLogo, ProductLogo } from './chunk-XVBX263W.js';
8
9
  export { AudioPlayer } from './chunk-UAHCRXAG.js';
@@ -18,15 +19,15 @@ export { ProgressDot, dotVariants, progressDotVariants } from './chunk-ZTANTDKS.
18
19
  export { FileCard, fileCardVariants } from './chunk-JMNMW54C.js';
19
20
  export { ChatPanel } from './chunk-WUZODCC2.js';
20
21
  export { ChatBubble, chatBubbleVariants } from './chunk-HZJRM5EK.js';
21
- export { LikeDislike, likeDislikeVariants } from './chunk-57NRP7HJ.js';
22
+ export { LikeDislike, likeDislikeVariants } from './chunk-MSFBYHUF.js';
22
23
  export { Achievement, Answer, Badge as BadgeIcon, Certificate, Chat as ChatIcon, Checkpoint, Completion, Conversation, Course, Deadline, Dialogue, Dictionary, Diploma, DotLive, Exercise, Feedback, Flashcard, Fluency, Goal, Grammar, GroupClass, Highlight, Language, Lesson, Listening, Live, MemoryCard, Milestone, Module, Presentation, PrivateClass, Progress as ProgressIcon, Question, Quiz, Ray, Reading, Recap, RecordedClass, Recurring, Repetition, Required, Schedule, Sentence, Streak, Task, Translate, Unit, Vocabulary, Whiteboard } from './chunk-D4QCYBCD.js';
23
24
  export { LiveWaiting } from './chunk-FPXSUEJO.js';
24
25
  export { Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage } from './chunk-MSLQRGSP.js';
25
26
  export { CycleIcon, ICON_SIZES } from './chunk-V7M2NHUO.js';
26
27
  export { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger } from './chunk-QZVQPUVT.js';
27
28
  export { ScrollArea, ScrollBar } from './chunk-3LXU5C35.js';
28
- export { Checkbox, checkboxVariants } from './chunk-IJTNFN6N.js';
29
- export { RadioGroup, RadioGroupItem, radioVariants } from './chunk-K567KZD5.js';
29
+ export { Checkbox, checkboxVariants } from './chunk-5BNTQSCS.js';
30
+ export { RadioGroup, RadioGroupItem, radioVariants } from './chunk-X4IBONFB.js';
30
31
  export { Switch, switchVariants } from './chunk-NVA4ZJOS.js';
31
32
  export { Slider, sliderVariants } from './chunk-AL2ALTBH.js';
32
33
  export { Toggle, toggleVariants } from './chunk-CIM6KJH5.js';
@@ -685,3 +685,96 @@
685
685
  line-height: 3.75rem; /* 60px */
686
686
  letter-spacing: -0.05em;
687
687
  }
688
+
689
+ /* --- Display --- */
690
+ @utility display-md {
691
+ font-family: var(--font-sans);
692
+ font-size: 4rem; /* 64px */
693
+ font-weight: 700;
694
+ line-height: 5.125rem; /* 82px */
695
+ letter-spacing: -0.05em;
696
+ }
697
+
698
+ @utility display-md-light {
699
+ font-family: var(--font-sans);
700
+ font-size: 4rem; /* 64px */
701
+ font-weight: 300;
702
+ line-height: 5.125rem; /* 82px */
703
+ letter-spacing: -0.05em;
704
+ }
705
+
706
+ @utility display-lg {
707
+ font-family: var(--font-sans);
708
+ font-size: 4.5rem; /* 72px */
709
+ font-weight: 700;
710
+ line-height: 5.625rem; /* 90px */
711
+ letter-spacing: -0.05em;
712
+ }
713
+
714
+ @utility display-lg-light {
715
+ font-family: var(--font-sans);
716
+ font-size: 4.5rem; /* 72px */
717
+ font-weight: 300;
718
+ line-height: 5.625rem; /* 90px */
719
+ letter-spacing: -0.05em;
720
+ }
721
+
722
+ /* --- Button --- */
723
+ @utility button-sm {
724
+ font-family: var(--font-sans);
725
+ font-size: 0.75rem; /* 12px */
726
+ font-weight: 500;
727
+ line-height: 0.75rem; /* 12px — 1:1 ratio */
728
+ letter-spacing: 0em;
729
+ }
730
+
731
+ @utility button-md {
732
+ font-family: var(--font-sans);
733
+ font-size: 0.875rem; /* 14px */
734
+ font-weight: 500;
735
+ line-height: 0.875rem; /* 14px — 1:1 ratio */
736
+ letter-spacing: 0em;
737
+ }
738
+
739
+ @utility button-lg {
740
+ font-family: var(--font-sans);
741
+ font-size: 1rem; /* 16px */
742
+ font-weight: 500;
743
+ line-height: 1rem; /* 16px — 1:1 ratio */
744
+ letter-spacing: 0em;
745
+ }
746
+
747
+ /* --- UI --- */
748
+ @utility ui-label {
749
+ font-family: var(--font-sans);
750
+ font-size: 0.875rem; /* 14px */
751
+ font-weight: 500;
752
+ line-height: 0.875rem; /* 14px */
753
+ letter-spacing: 0em;
754
+ }
755
+
756
+ @utility ui-caption {
757
+ font-family: var(--font-sans);
758
+ font-size: 0.75rem; /* 12px */
759
+ font-weight: 400;
760
+ line-height: 1rem; /* 16px */
761
+ letter-spacing: 0em;
762
+ }
763
+
764
+ @utility ui-overline {
765
+ font-family: var(--font-sans);
766
+ font-size: 0.75rem; /* 12px */
767
+ font-weight: 500;
768
+ line-height: 1rem; /* 16px */
769
+ letter-spacing: 0.025em;
770
+ text-transform: uppercase;
771
+ }
772
+
773
+ /* --- Animations --- */
774
+ @utility animate-like-pop {
775
+ animation: like-pop 350ms cubic-bezier(0.22, 1, 0.36, 1);
776
+ }
777
+
778
+ @utility animate-like-burst {
779
+ animation: like-burst 500ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
780
+ }
@@ -1,4 +1,4 @@
1
- export { Checkbox, checkboxVariants } from '../chunk-IJTNFN6N.js';
1
+ export { Checkbox, checkboxVariants } from '../chunk-5BNTQSCS.js';
2
2
  import '../chunk-TYCPXAXF.js';
3
3
  import '../chunk-YINJ5YZ5.js';
4
4
  //# sourceMappingURL=checkbox.js.map
@@ -0,0 +1,20 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as class_variance_authority_types from 'class-variance-authority/types';
3
+ import * as React from 'react';
4
+ import { VariantProps } from 'class-variance-authority';
5
+
6
+ declare const fabVariants: (props?: ({
7
+ size?: "sm" | "lg" | "default" | null | undefined;
8
+ variant?: "default" | "outline" | "secondary" | null | undefined;
9
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
10
+ interface FabProps extends React.ComponentProps<"button">, VariantProps<typeof fabVariants> {
11
+ /** Render as child element (Slot) */
12
+ asChild?: boolean;
13
+ /** Extended mode: pill shape with icon + label. Pass a string or ReactNode for the label. */
14
+ extended?: boolean;
15
+ /** Position preset. "none" disables fixed positioning. Default: "bottom-right" */
16
+ position?: "bottom-right" | "bottom-left" | "bottom-center" | "none";
17
+ }
18
+ declare function Fab({ className, size, variant, asChild, extended, position, ...props }: FabProps): react_jsx_runtime.JSX.Element;
19
+
20
+ export { Fab, type FabProps, fabVariants };
package/dist/ui/fab.js ADDED
@@ -0,0 +1,5 @@
1
+ export { Fab, fabVariants } from '../chunk-7NFHHOAE.js';
2
+ import '../chunk-TYCPXAXF.js';
3
+ import '../chunk-YINJ5YZ5.js';
4
+ //# sourceMappingURL=fab.js.map
5
+ //# sourceMappingURL=fab.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"fab.js"}
@@ -20,13 +20,17 @@ interface LikeDislikeProps extends Omit<React.ComponentProps<"div">, "onChange"
20
20
  feedbackPlaceholder?: string;
21
21
  /** Label for the feedback submit button */
22
22
  feedbackSubmitLabel?: string;
23
- /** Called when feedback is submitted */
24
- onFeedbackSubmit?: (feedback: string) => void;
23
+ /** Called when feedback is submitted. Can return a Promise for async handling. */
24
+ onFeedbackSubmit?: (feedback: string) => void | Promise<void>;
25
+ /** Message shown after feedback is submitted */
26
+ feedbackSuccessMessage?: string;
27
+ /** Delay in ms before auto-closing after submit. Default: 2000. Set 0 to disable. */
28
+ feedbackAutoCloseDelay?: number;
25
29
  /** Theme class for the burst animation rays (e.g. "theme-brand"). Default: "theme-brand" */
26
30
  burstTheme?: string;
27
31
  /** Disabled state */
28
32
  disabled?: boolean;
29
33
  }
30
- declare function LikeDislike({ className, size, value: valueProp, defaultValue, onValueChange, showFeedback, feedbackPlaceholder, feedbackSubmitLabel, onFeedbackSubmit, burstTheme, disabled, ...props }: LikeDislikeProps): react_jsx_runtime.JSX.Element;
34
+ declare function LikeDislike({ className, size, value: valueProp, defaultValue, onValueChange, showFeedback, feedbackPlaceholder, feedbackSubmitLabel, onFeedbackSubmit, feedbackSuccessMessage, feedbackAutoCloseDelay, burstTheme, disabled, ...props }: LikeDislikeProps): react_jsx_runtime.JSX.Element;
31
35
 
32
36
  export { LikeDislike, type LikeDislikeProps, type LikeDislikeValue, likeDislikeVariants };
@@ -1,4 +1,4 @@
1
- export { LikeDislike, likeDislikeVariants } from '../chunk-57NRP7HJ.js';
1
+ export { LikeDislike, likeDislikeVariants } from '../chunk-MSFBYHUF.js';
2
2
  import '../chunk-D4QCYBCD.js';
3
3
  import '../chunk-V7M2NHUO.js';
4
4
  import '../chunk-7UMEJDC3.js';
@@ -1,4 +1,4 @@
1
- export { RadioGroup, RadioGroupItem, radioVariants } from '../chunk-K567KZD5.js';
1
+ export { RadioGroup, RadioGroupItem, radioVariants } from '../chunk-X4IBONFB.js';
2
2
  import '../chunk-TYCPXAXF.js';
3
3
  import '../chunk-YINJ5YZ5.js';
4
4
  //# sourceMappingURL=radio-group.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluencypassdevs/cycle",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "description": "Cycle Design System — UI component library by Fluencypass",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/ui/like-dislike.tsx"],"names":[],"mappings":";;;;;;;;;;AAaA,IAAM,mBAAA,GAAsB,IAAI,sBAAA,EAAwB;AAAA,EACtD,QAAA,EAAU;AAAA,IACR,IAAA,EAAM;AAAA,MACJ,OAAA,EAAS,OAAA;AAAA,MACT,EAAA,EAAI,SAAA;AAAA,MACJ,EAAA,EAAI,SAAA;AAAA,MACJ,EAAA,EAAI;AAAA;AACN,GACF;AAAA,EACA,eAAA,EAAiB;AAAA,IACf,IAAA,EAAM;AAAA;AAEV,CAAC;AAGD,IAAM,UAAA,GAAa;AAAA,EACjB,EAAA,EAAI,EAAE,OAAA,EAAS,QAAA,EAAU,IAAA,EAAM,IAAA,EAAe,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,KAAA,EAAO,IAAA,EAAM,SAAA,EAAU;AAAA,EAC5F,EAAA,EAAI,EAAE,OAAA,EAAS,QAAA,EAAU,IAAA,EAAM,IAAA,EAAe,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,OAAA,EAAS,IAAA,EAAM,SAAA,EAAU;AAAA,EAC9F,OAAA,EAAS,EAAE,OAAA,EAAS,SAAA,EAAW,IAAA,EAAM,IAAA,EAAe,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,KAAA,EAAO,IAAA,EAAM,SAAA,EAAU;AAAA,EAClG,EAAA,EAAI,EAAE,OAAA,EAAS,SAAA,EAAW,IAAA,EAAM,IAAA,EAAe,IAAA,EAAM,WAAA,EAAa,IAAA,EAAM,OAAA,EAAS,IAAA,EAAM,SAAA;AACzF,CAAA;AAGA,IAAM,UAAA,GAAa;AAAA,EACjB,EAAE,KAAA,EAAO,CAAA,EAAG,KAAA,EAAO,KAAA,EAAM;AAAA,EACzB,EAAE,KAAA,EAAO,EAAA,EAAI,KAAA,EAAO,MAAA,EAAO;AAAA,EAC3B,EAAE,KAAA,EAAO,EAAA,EAAI,KAAA,EAAO,MAAA,EAAO;AAAA,EAC3B,EAAE,KAAA,EAAO,GAAA,EAAK,KAAA,EAAO,MAAA,EAAO;AAAA,EAC5B,EAAE,KAAA,EAAO,GAAA,EAAK,KAAA,EAAO,MAAA,EAAO;AAAA,EAC5B,EAAE,KAAA,EAAO,GAAA,EAAK,KAAA,EAAO,MAAA,EAAO;AAAA,EAC5B,EAAE,KAAA,EAAO,GAAA,EAAK,KAAA,EAAO,MAAA,EAAO;AAAA,EAC5B,EAAE,KAAA,EAAO,GAAA,EAAK,KAAA,EAAO,MAAA;AACvB,CAAA;AA+BA,SAAS,YAAY,EAAA,EAaA;AAbA,EAAA,IAAA,EAAA,GAAA,EAAA,EACnB;AAAA,IAAA,SAAA;AAAA,IACA,IAAA,GAAO,SAAA;AAAA,IACP,KAAA,EAAO,SAAA;AAAA,IACP,YAAA,GAAe,IAAA;AAAA,IACf,aAAA;AAAA,IACA,YAAA,GAAe,KAAA;AAAA,IACf,mBAAA,GAAsB,wBAAA;AAAA,IACtB,mBAAA,GAAsB,QAAA;AAAA,IACtB,gBAAA;AAAA,IACA,UAAA,GAAa,aAAA;AAAA,IACb,QAAA,GAAW;AAAA,GAvFb,GA4EqB,EAAA,EAYhB,KAAA,GAAA,SAAA,CAZgB,EAAA,EAYhB;AAAA,IAXH,WAAA;AAAA,IACA,MAAA;AAAA,IACA,OAAA;AAAA,IACA,cAAA;AAAA,IACA,eAAA;AAAA,IACA,cAAA;AAAA,IACA,qBAAA;AAAA,IACA,qBAAA;AAAA,IACA,kBAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA,GAAA,CAAA;AAIA,EAAA,MAAM,eAAe,SAAA,KAAc,MAAA;AACnC,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAU,eAA2B,YAAY,CAAA;AACvF,EAAA,MAAM,YAAA,GAAe,eAAe,SAAA,GAAY,aAAA;AAEhD,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAU,eAAS,EAAE,CAAA;AACzD,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAU,eAAS,KAAK,CAAA;AACxD,EAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,CAAA,GAAU,eAAS,KAAK,CAAA;AAEtE,EAAA,MAAM,CAAA,GAAI,UAAA,CAAW,IAAA,IAAA,IAAA,GAAA,IAAA,GAAQ,SAAS,CAAA;AAGtC,EAAA,SAAS,YAAY,MAAA,EAA4B;AAC/C,IAAA,IAAI,QAAA,EAAU;AACd,IAAA,MAAM,IAAA,GAAyB,YAAA,KAAiB,MAAA,GAAS,IAAA,GAAO,MAAA;AAEhE,IAAA,IAAI,CAAC,YAAA,EAAc,gBAAA,CAAiB,IAAI,CAAA;AACxC,IAAA,aAAA,IAAA,IAAA,GAAA,MAAA,GAAA,aAAA,CAAgB,IAAA,CAAA;AAChB,IAAA,oBAAA,CAAqB,KAAK,CAAA;AAG1B,IAAA,IAAI,MAAA,KAAW,MAAA,IAAU,IAAA,KAAS,MAAA,EAAQ;AACxC,MAAA,aAAA,CAAc,IAAI,CAAA;AAAA,IACpB;AAAA,EACF;AAEA,EAAA,SAAS,cAAA,GAAiB;AACxB,IAAA,aAAA,CAAc,KAAK,CAAA;AAAA,EACrB;AAEA,EAAA,SAAS,qBAAqB,CAAA,EAAoB;AAChD,IAAA,CAAA,CAAE,cAAA,EAAe;AACjB,IAAA,IAAI,YAAA,CAAa,MAAK,EAAG;AACvB,MAAA,gBAAA,IAAA,IAAA,GAAA,MAAA,GAAA,gBAAA,CAAmB,aAAa,IAAA,EAAK,CAAA;AACrC,MAAA,eAAA,CAAgB,EAAE,CAAA;AAAA,IACpB;AAAA,EACF;AAEA,EAAA,MAAM,UAAU,YAAA,KAAiB,MAAA;AACjC,EAAA,MAAM,aAAa,YAAA,KAAiB,SAAA;AACpC,EAAA,MAAM,iBAAA,GAAoB,UAAA,IAAc,YAAA,IAAgB,CAAC,iBAAA;AAGzD,EAAA,MAAM,OAAA,GAAU,EAAA;AAAA,IACd,iJAAA;AAAA,IACA,4CAAA;AAAA,IACA,+EAAA;AAAA,IACA,kDAAA;AAAA,IACA,8CAAA;AAAA,IACA,CAAA,CAAE;AAAA,GACJ;AAEA,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA,aAAA,CAAA,cAAA,CAAA;AAAA,MACC,WAAA,EAAU,cAAA;AAAA,MACV,SAAA,EAAW,EAAA,CAAG,sBAAA,EAAwB,SAAS;AAAA,KAAA,EAC3C,KAAA,CAAA,EAHL;AAAA,MAMC,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,SAAI,SAAA,EAAU,gCAAA,EAAiC,IAAA,EAAK,OAAA,EAAQ,cAAW,kBAAA,EAEtE,QAAA,EAAA;AAAA,0BAAA,IAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,cAAA,EAAc,OAAA;AAAA,cACd,YAAA,EAAW,QAAA;AAAA,cACX,QAAA;AAAA,cACA,OAAA,EAAS,MAAM,WAAA,CAAY,MAAM,CAAA;AAAA,cACjC,SAAA,EAAW,EAAA;AAAA,gBACT,OAAA;AAAA,gBACA,OAAA,IAAW;AAAA,eACb;AAAA,cAGC,QAAA,EAAA;AAAA,gBAAA,UAAA,oBACC,GAAA;AAAA,kBAAC,MAAA;AAAA,kBAAA;AAAA,oBACC,SAAA,EAAW,EAAA,CAAG,0CAAA,EAA4C,UAAU,CAAA;AAAA,oBACpE,aAAA,EAAY,MAAA;AAAA,oBAEX,qBAAW,GAAA,CAAI,CAAC,EAAE,KAAA,EAAO,OAAM,qBAC9B,GAAA;AAAA,sBAAC,MAAA;AAAA,sBAAA;AAAA,wBAEC,SAAA,EAAU,6DAAA;AAAA,wBACV,KAAA,EAAO,EAAE,MAAA,EAAQ,CAAA,EAAG,KAAK,CAAA,GAAA,CAAA,EAAM;AAAA,wBAE/B,QAAA,kBAAA,GAAA;AAAA,0BAAC,MAAA;AAAA,0BAAA;AAAA,4BACC,SAAA,EAAW,EAAA;AAAA,8BACT,4DAAA;AAAA,8BACA,CAAA,CAAE,IAAA;AAAA,8BAAM,CAAA,CAAE;AAAA,6BACZ;AAAA,4BACA,KAAA,EAAO,EAAE,cAAA,EAAgB,KAAA;AAAM;AAAA;AACjC,uBAAA;AAAA,sBAVK;AAAA,qBAYR;AAAA;AAAA,iBACH;AAAA,gCAIF,GAAA;AAAA,kBAAC,MAAA;AAAA,kBAAA;AAAA,oBACC,SAAA,EAAW,EAAA,CAAG,eAAA,EAAiB,UAAA,IAAc,kBAAkB,CAAA;AAAA,oBAC/D,cAAA,EAAgB,cAAA;AAAA,oBAEhB,QAAA,kBAAA,GAAA,CAAC,aAAU,IAAA,EAAM,QAAA,EAAU,MAAM,CAAA,CAAE,IAAA,EAAM,YAAU,IAAA,EAAC;AAAA;AAAA;AACtD;AAAA;AAAA,WACF;AAAA,0BAGA,GAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,cAAA,EAAc,UAAA;AAAA,cACd,YAAA,EAAW,YAAA;AAAA,cACX,QAAA;AAAA,cACA,OAAA,EAAS,MAAM,WAAA,CAAY,SAAS,CAAA;AAAA,cACpC,SAAA,EAAW,EAAA;AAAA,gBACT,OAAA;AAAA,gBACA,UAAA,IAAc;AAAA,eAChB;AAAA,cAEA,QAAA,kBAAA,GAAA,CAAC,aAAU,IAAA,EAAM,UAAA,EAAY,MAAM,CAAA,CAAE,IAAA,EAAM,YAAU,IAAA,EAAC;AAAA;AAAA;AACxD,SAAA,EACF,CAAA;AAAA,QAGC,iBAAA,oBACC,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yJAAA,EACb,QAAA,EAAA;AAAA,0BAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,wCAAA,EACb,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,OAAE,SAAA,EAAW,EAAA,CAAG,+BAA+B,CAAA,CAAE,IAAI,GACnD,QAAA,EAAA,mBAAA,EACH,CAAA;AAAA,4BACA,GAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAK,QAAA;AAAA,gBACL,OAAA,EAAS,MAAM,oBAAA,CAAqB,IAAI,CAAA;AAAA,gBACxC,SAAA,EAAU,uJAAA;AAAA,gBACV,YAAA,EAAW,QAAA;AAAA,gBAEX,8BAAC,SAAA,EAAA,EAAU,IAAA,EAAM,GAAG,IAAA,EAAK,IAAA,EAAK,YAAU,IAAA,EAAC;AAAA;AAAA;AAC3C,WAAA,EACF,CAAA;AAAA,0BACA,IAAA,CAAC,MAAA,EAAA,EAAK,QAAA,EAAU,oBAAA,EAAsB,WAAU,qBAAA,EAC9C,QAAA,EAAA;AAAA,4BAAA,GAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBACC,YAAA,EAAa,IAAA;AAAA,gBACb,KAAA,EAAO,YAAA;AAAA,gBACP,UAAU,CAAC,CAAA,KAAM,eAAA,CAAgB,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,gBAC/C,WAAA,EAAY,mBAAA;AAAA,gBACZ,QAAA;AAAA,gBACA,SAAA,EAAU,0BAAA;AAAA,gBACV,YAAA,EAAW;AAAA;AAAA,aACb;AAAA,4BACA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,kBAAA,EACb,QAAA,kBAAA,GAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAK,QAAA;AAAA,gBACL,IAAA,EAAK,IAAA;AAAA,gBACL,QAAA,EAAU,QAAA,IAAY,CAAC,YAAA,CAAa,IAAA,EAAK;AAAA,gBAExC,QAAA,EAAA;AAAA;AAAA,aACH,EACF;AAAA,WAAA,EACF;AAAA,SAAA,EACF;AAAA;AAAA,KAAA;AAAA,GAEJ;AAEJ","file":"chunk-57NRP7HJ.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { ThumbsUp, ThumbsDown, X } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { CycleIcon } from \"@/components/icons\"\nimport { Button } from \"@/components/ui/button\"\nimport { Textarea } from \"@/components/ui/textarea\"\n\n/* ---------------------------------- CVA ---------------------------------- */\n\nconst likeDislikeVariants = cva(\"inline-flex flex-col\", {\n variants: {\n size: {\n default: \"gap-2\",\n xs: \"gap-1.5\",\n sm: \"gap-1.5\",\n lg: \"gap-3\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n})\n\n/** Maps component size → toggle button dimensions + icon size + burst ray size */\nconst sizeConfig = {\n xs: { iconBtn: \"size-6\", icon: \"xs\" as const, text: \"text-xs\", rayH: \"h-1\", rayW: \"w-[2px]\" },\n sm: { iconBtn: \"size-8\", icon: \"xs\" as const, text: \"text-xs\", rayH: \"h-1.5\", rayW: \"w-[2px]\" },\n default: { iconBtn: \"size-10\", icon: \"sm\" as const, text: \"text-sm\", rayH: \"h-2\", rayW: \"w-[2px]\" },\n lg: { iconBtn: \"size-12\", icon: \"sm\" as const, text: \"text-base\", rayH: \"h-2.5\", rayW: \"w-[3px]\" },\n} as const\n\n/** Angles and colors for the burst rays */\nconst BURST_RAYS = [\n { angle: 0, delay: \"0ms\" },\n { angle: 45, delay: \"30ms\" },\n { angle: 90, delay: \"60ms\" },\n { angle: 135, delay: \"20ms\" },\n { angle: 180, delay: \"50ms\" },\n { angle: 225, delay: \"10ms\" },\n { angle: 270, delay: \"40ms\" },\n { angle: 315, delay: \"25ms\" },\n]\n\n/* -------------------------------- Types --------------------------------- */\n\nexport type LikeDislikeValue = \"like\" | \"dislike\" | null\n\nexport interface LikeDislikeProps\n extends Omit<React.ComponentProps<\"div\">, \"onChange\" | \"defaultValue\">,\n VariantProps<typeof likeDislikeVariants> {\n /** Current value — controlled */\n value?: LikeDislikeValue\n /** Default value — uncontrolled */\n defaultValue?: LikeDislikeValue\n /** Called when the value changes */\n onValueChange?: (value: LikeDislikeValue) => void\n /** Show feedback textarea when dislike is selected */\n showFeedback?: boolean\n /** Placeholder for the feedback textarea */\n feedbackPlaceholder?: string\n /** Label for the feedback submit button */\n feedbackSubmitLabel?: string\n /** Called when feedback is submitted */\n onFeedbackSubmit?: (feedback: string) => void\n /** Theme class for the burst animation rays (e.g. \"theme-brand\"). Default: \"theme-brand\" */\n burstTheme?: string\n /** Disabled state */\n disabled?: boolean\n}\n\n/* ------------------------------ Component ------------------------------- */\n\nfunction LikeDislike({\n className,\n size = \"default\",\n value: valueProp,\n defaultValue = null,\n onValueChange,\n showFeedback = false,\n feedbackPlaceholder = \"O que voce nao gostou?\",\n feedbackSubmitLabel = \"Enviar\",\n onFeedbackSubmit,\n burstTheme = \"theme-brand\",\n disabled = false,\n ...props\n}: LikeDislikeProps) {\n /* --- State --- */\n const isControlled = valueProp !== undefined\n const [internalValue, setInternalValue] = React.useState<LikeDislikeValue>(defaultValue)\n const currentValue = isControlled ? valueProp : internalValue\n\n const [feedbackText, setFeedbackText] = React.useState(\"\")\n const [isBursting, setIsBursting] = React.useState(false)\n const [feedbackDismissed, setFeedbackDismissed] = React.useState(false)\n\n const s = sizeConfig[size ?? \"default\"]\n\n /* --- Handlers --- */\n function handleClick(target: \"like\" | \"dislike\") {\n if (disabled) return\n const next: LikeDislikeValue = currentValue === target ? null : target\n\n if (!isControlled) setInternalValue(next)\n onValueChange?.(next)\n setFeedbackDismissed(false)\n\n // Trigger burst animation when transitioning TO like\n if (target === \"like\" && next === \"like\") {\n setIsBursting(true)\n }\n }\n\n function handleBurstEnd() {\n setIsBursting(false)\n }\n\n function handleFeedbackSubmit(e: React.FormEvent) {\n e.preventDefault()\n if (feedbackText.trim()) {\n onFeedbackSubmit?.(feedbackText.trim())\n setFeedbackText(\"\")\n }\n }\n\n const isLiked = currentValue === \"like\"\n const isDisliked = currentValue === \"dislike\"\n const showFeedbackPanel = isDisliked && showFeedback && !feedbackDismissed\n\n /* --- Shared button classes --- */\n const btnBase = cn(\n \"relative inline-flex shrink-0 items-center justify-center rounded-lg transition-[color,box-shadow,background-color] outline-none cursor-pointer\",\n \"hover:bg-muted hover:text-muted-foreground\",\n \"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50\",\n \"disabled:pointer-events-none disabled:opacity-50\",\n \"[&_svg]:pointer-events-none [&_svg]:shrink-0\",\n s.iconBtn\n )\n\n return (\n <div\n data-slot=\"like-dislike\"\n className={cn(\"relative inline-flex\", className)}\n {...props}\n >\n {/* Button row */}\n <div className=\"inline-flex items-center gap-1\" role=\"group\" aria-label=\"Avaliar conteudo\">\n {/* Like */}\n <button\n type=\"button\"\n aria-pressed={isLiked}\n aria-label=\"Gostei\"\n disabled={disabled}\n onClick={() => handleClick(\"like\")}\n className={cn(\n btnBase,\n isLiked && \"bg-accent text-accent-foreground [&_svg]:fill-current\"\n )}\n >\n {/* Burst rays (behind the icon) */}\n {isBursting && (\n <span\n className={cn(\"absolute inset-0 z-0 pointer-events-none\", burstTheme)}\n aria-hidden=\"true\"\n >\n {BURST_RAYS.map(({ angle, delay }) => (\n <span\n key={angle}\n className=\"absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2\"\n style={{ rotate: `${angle}deg` }}\n >\n <span\n className={cn(\n \"block rounded-full bg-primary opacity-0 animate-like-burst\",\n s.rayW, s.rayH\n )}\n style={{ animationDelay: delay }}\n />\n </span>\n ))}\n </span>\n )}\n\n {/* Icon with pop animation (above rays) */}\n <span\n className={cn(\"relative z-10\", isBursting && \"animate-like-pop\")}\n onAnimationEnd={handleBurstEnd}\n >\n <CycleIcon icon={ThumbsUp} size={s.icon} decorative />\n </span>\n </button>\n\n {/* Dislike */}\n <button\n type=\"button\"\n aria-pressed={isDisliked}\n aria-label=\"Nao gostei\"\n disabled={disabled}\n onClick={() => handleClick(\"dislike\")}\n className={cn(\n btnBase,\n isDisliked && \"bg-accent text-accent-foreground [&_svg]:fill-current\"\n )}\n >\n <CycleIcon icon={ThumbsDown} size={s.icon} decorative />\n </button>\n </div>\n\n {/* Floating feedback panel */}\n {showFeedbackPanel && (\n <div className=\"absolute left-0 top-full z-50 mt-2 w-72 rounded-lg border border-border bg-background p-3 shadow-md animate-in fade-in-0 zoom-in-95 slide-in-from-top-2\">\n <div className=\"flex items-center justify-between mb-2\">\n <p className={cn(\"font-medium text-foreground\", s.text)}>\n {feedbackPlaceholder}\n </p>\n <button\n type=\"button\"\n onClick={() => setFeedbackDismissed(true)}\n className=\"inline-flex size-6 items-center justify-center rounded-md text-muted-foreground hover:bg-muted hover:text-foreground transition-colors cursor-pointer\"\n aria-label=\"Fechar\"\n >\n <CycleIcon icon={X} size=\"xs\" decorative />\n </button>\n </div>\n <form onSubmit={handleFeedbackSubmit} className=\"flex flex-col gap-2\">\n <Textarea\n textareaSize=\"sm\"\n value={feedbackText}\n onChange={(e) => setFeedbackText(e.target.value)}\n placeholder=\"Conte-nos mais...\"\n disabled={disabled}\n className=\"resize-none min-h-[60px]\"\n aria-label=\"Feedback\"\n />\n <div className=\"flex justify-end\">\n <Button\n type=\"submit\"\n size=\"sm\"\n disabled={disabled || !feedbackText.trim()}\n >\n {feedbackSubmitLabel}\n </Button>\n </div>\n </form>\n </div>\n )}\n </div>\n )\n}\n\nexport { LikeDislike, likeDislikeVariants }\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/ui/checkbox.tsx"],"names":["CheckboxPrimitive"],"mappings":";;;;;;;AASA,IAAM,gBAAA,GAAmB,GAAA;AAAA,EACvB,weAAA;AAAA,EACA;AAAA,IACE,QAAA,EAAU;AAAA,MACR,IAAA,EAAM;AAAA,QACJ,EAAA,EAAI,yBAAA;AAAA,QACJ,OAAA,EAAS,yBAAA;AAAA,QACT,EAAA,EAAI;AAAA,OACN;AAAA,MACA,OAAA,EAAS;AAAA,QACP,OAAA,EAAS,eAAA;AAAA,QACT,QAAA,EAAU;AAAA;AACZ,KACF;AAAA,IACA,eAAA,EAAiB;AAAA,MACf,IAAA,EAAM,SAAA;AAAA,MACN,OAAA,EAAS;AAAA;AACX;AAEJ;AASA,SAAS,SAAS,EAAA,EAMA;AANA,EAAA,IAAA,EAAA,GAAA,EAAA,EAChB;AAAA,IAAA,SAAA;AAAA,IACA,IAAA,GAAO,SAAA;AAAA,IACP,OAAA,GAAU,SAAA;AAAA,IACV;AAAA,GAzCF,GAqCkB,EAAA,EAKb,KAAA,GAAA,SAAA,CALa,EAAA,EAKb;AAAA,IAJH,WAAA;AAAA,IACA,MAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GAAA,CAAA;AAGA,EAAA,uBACE,GAAA;AAAA,IAACA,UAAA,CAAkB,IAAA;AAAA,IAAlB,aAAA,CAAA,cAAA,CAAA;AAAA,MACC,WAAA,EAAU,UAAA;AAAA,MACV,cAAA,EAAc,OAAA;AAAA,MACd,SAAA,EAAW,GAAG,KAAA,EAAO,gBAAA,CAAiB,EAAE,IAAA,EAAM,OAAA,EAAS,CAAA,EAAG,SAAS;AAAA,KAAA,EAC/D,KAAA,CAAA,EAJL;AAAA,MAMC,QAAA,kBAAA,GAAA;AAAA,QAACA,UAAA,CAAkB,SAAA;AAAA,QAAlB;AAAA,UACC,WAAA,EAAU,oBAAA;AAAA,UACV,SAAA,EAAU,wDAAA;AAAA,UAEV,8BAAC,SAAA,EAAA,EAAU;AAAA;AAAA;AACb,KAAA;AAAA,GACF;AAEJ","file":"chunk-IJTNFN6N.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { CheckIcon } from \"lucide-react\"\nimport { Checkbox as CheckboxPrimitive } from \"radix-ui\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst checkboxVariants = cva(\n \"peer shrink-0 border border-neutral-input shadow-xs transition-shadow outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:bg-neutral-input/30 dark:aria-invalid:ring-destructive/40 dark:data-[state=checked]:bg-primary\",\n {\n variants: {\n size: {\n sm: \"size-3.5 [&_svg]:size-3\",\n default: \"size-4 [&_svg]:size-3.5\",\n lg: \"size-5 [&_svg]:size-4\",\n },\n variant: {\n default: \"rounded-[4px]\",\n circular: \"rounded-full\",\n },\n },\n defaultVariants: {\n size: \"default\",\n variant: \"default\",\n },\n }\n)\n\nexport interface CheckboxProps\n extends React.ComponentProps<typeof CheckboxPrimitive.Root>,\n VariantProps<typeof checkboxVariants> {\n /** Classe de tema aplicada apenas no estado checked (ex: \"theme-class\") */\n theme?: string\n}\n\nfunction Checkbox({\n className,\n size = \"default\",\n variant = \"default\",\n theme,\n ...props\n}: CheckboxProps) {\n return (\n <CheckboxPrimitive.Root\n data-slot=\"checkbox\"\n data-variant={variant}\n className={cn(theme, checkboxVariants({ size, variant }), className)}\n {...props}\n >\n <CheckboxPrimitive.Indicator\n data-slot=\"checkbox-indicator\"\n className=\"grid place-content-center text-current transition-none\"\n >\n <CheckIcon />\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n )\n}\n\nexport { Checkbox, checkboxVariants }\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/ui/radio-group.tsx"],"names":["RadioGroupPrimitive"],"mappings":";;;;;;;AASA,IAAM,aAAA,GAAgB,GAAA;AAAA,EACpB,6ZAAA;AAAA,EACA;AAAA,IACE,QAAA,EAAU;AAAA,MACR,IAAA,EAAM;AAAA,QACJ,EAAA,EAAI,yBAAA;AAAA,QACJ,OAAA,EAAS,yBAAA;AAAA,QACT,EAAA,EAAI;AAAA;AACN,KACF;AAAA,IACA,eAAA,EAAiB;AAAA,MACf,IAAA,EAAM;AAAA;AACR;AAEJ;AAKA,SAAS,WAAW,EAAA,EAA0C;AAA1C,EAAA,IAAA,EAAA,GAAA,EAAA,EAAE,EAAA,SAAA,EA5BtB,GA4BoB,EAAA,EAAgB,KAAA,GAAA,SAAA,CAAhB,IAAgB,CAAd,WAAA,CAAA,CAAA;AACpB,EAAA,uBACE,GAAA;AAAA,IAACA,YAAA,CAAoB,IAAA;AAAA,IAApB,cAAA,CAAA;AAAA,MACC,WAAA,EAAU,aAAA;AAAA,MACV,SAAA,EAAW,EAAA,CAAG,YAAA,EAAc,SAAS;AAAA,KAAA,EACjC,KAAA;AAAA,GACN;AAEJ;AASA,SAAS,eAAe,EAAA,EAKA;AALA,EAAA,IAAA,EAAA,GAAA,EAAA,EACtB;AAAA,IAAA,SAAA;AAAA,IACA,IAAA,GAAO,SAAA;AAAA,IACP;AAAA,GAhDF,GA6CwB,EAAA,EAInB,KAAA,GAAA,SAAA,CAJmB,EAAA,EAInB;AAAA,IAHH,WAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GAAA,CAAA;AAGA,EAAA,uBACE,GAAA;AAAA,IAACA,YAAA,CAAoB,IAAA;AAAA,IAApB,aAAA,CAAA,cAAA,CAAA;AAAA,MACC,WAAA,EAAU,kBAAA;AAAA,MACV,SAAA,EAAW,GAAG,KAAA,EAAO,aAAA,CAAc,EAAE,IAAA,EAAM,GAAG,SAAS;AAAA,KAAA,EACnD,KAAA,CAAA,EAHL;AAAA,MAKC,QAAA,kBAAA,GAAA;AAAA,QAACA,YAAA,CAAoB,SAAA;AAAA,QAApB;AAAA,UACC,WAAA,EAAU,uBAAA;AAAA,UACV,SAAA,EAAU,wCAAA;AAAA,UAEV,QAAA,kBAAA,GAAA,CAAC,UAAA,EAAA,EAAW,SAAA,EAAU,cAAA,EAAe;AAAA;AAAA;AACvC,KAAA;AAAA,GACF;AAEJ","file":"chunk-K567KZD5.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { CircleIcon } from \"lucide-react\"\nimport { RadioGroup as RadioGroupPrimitive } from \"radix-ui\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst radioVariants = cva(\n \"aspect-square rounded-full border border-neutral-input bg-neutral-bg shadow-xs transition-shadow outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=checked]:border-primary data-[state=checked]:text-foreground dark:aria-invalid:ring-destructive/40\",\n {\n variants: {\n size: {\n sm: \"size-3.5 [&_svg]:size-2\",\n default: \"size-4 [&_svg]:size-2.5\",\n lg: \"size-5 [&_svg]:size-3\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n }\n)\n\nexport interface RadioGroupProps\n extends React.ComponentProps<typeof RadioGroupPrimitive.Root> {}\n\nfunction RadioGroup({ className, ...props }: RadioGroupProps) {\n return (\n <RadioGroupPrimitive.Root\n data-slot=\"radio-group\"\n className={cn(\"grid gap-3\", className)}\n {...props}\n />\n )\n}\n\nexport interface RadioGroupItemProps\n extends React.ComponentProps<typeof RadioGroupPrimitive.Item>,\n VariantProps<typeof radioVariants> {\n /** Classe de tema aplicada apenas no estado checked (ex: \"theme-class\") */\n theme?: string\n}\n\nfunction RadioGroupItem({\n className,\n size = \"default\",\n theme,\n ...props\n}: RadioGroupItemProps) {\n return (\n <RadioGroupPrimitive.Item\n data-slot=\"radio-group-item\"\n className={cn(theme, radioVariants({ size }), className)}\n {...props}\n >\n <RadioGroupPrimitive.Indicator\n data-slot=\"radio-group-indicator\"\n className=\"grid place-content-center text-current\"\n >\n <CircleIcon className=\"fill-current\" />\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n )\n}\n\nexport { RadioGroup, RadioGroupItem, radioVariants }\n"]}