@softize/opus 23.0.0 → 24.0.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.
Files changed (97) hide show
  1. package/CHANGELOG.md +99 -0
  2. package/bin/cli.mjs +2 -0
  3. package/bin/lib/check.mjs +241 -42
  4. package/bin/lib/copy.mjs +16 -34
  5. package/docs/adr/0023-surfaces-share-one-anatomy-and-two-layouts.md +6 -0
  6. package/docs/adr/0039-filter-presentation-is-independent-from-filter-type.md +3 -3
  7. package/docs/adr/0040-tabs-use-a-single-navigation-presentation.md +5 -6
  8. package/docs/adr/0042-toggle-group-shares-the-grouped-control-grammar.md +79 -0
  9. package/docs/adr/0043-neutral-surfaces-and-interactions-use-opaque-role-tokens.md +73 -0
  10. package/docs/adr/0044-neutral-appearance-derives-from-bounded-axes-per-mode.md +133 -0
  11. package/docs/adr/0045-surface-replaces-content-and-card.md +230 -0
  12. package/docs/adr/0046-structural-body-owns-content-rhythm.md +103 -0
  13. package/docs/adr/0047-pane-is-only-a-split-layout-unit.md +71 -0
  14. package/docs/adr/0048-modal-intro-separates-content-from-chrome.md +34 -0
  15. package/docs/adr/0049-inline-navigation-groups-with-the-heading.md +95 -0
  16. package/package.json +5 -1
  17. package/registry/skills/build-opus-ui/SKILL.md +11 -11
  18. package/registry/skills/build-opus-ui/references/evaluations.md +10 -9
  19. package/registry/skills/build-opus-ui/references/ui-patterns.md +17 -16
  20. package/registry/templates/app/src/App.tsx +24 -12
  21. package/src/ui/appearance.ts +149 -0
  22. package/src/ui/components/patterns/action-form-card.tsx +46 -33
  23. package/src/ui/components/patterns/action-list-dialog.tsx +2 -4
  24. package/src/ui/components/patterns/confirm.tsx +3 -1
  25. package/src/ui/components/patterns/fill-region.ts +8 -7
  26. package/src/ui/components/patterns/form-dialog.tsx +1 -3
  27. package/src/ui/components/patterns/form.tsx +8 -7
  28. package/src/ui/components/patterns/list.tsx +15 -19
  29. package/src/ui/components/patterns/page.tsx +15 -11
  30. package/src/ui/components/patterns/pane.tsx +9 -240
  31. package/src/ui/components/patterns/presentation.tsx +14 -14
  32. package/src/ui/components/patterns/sidebar.tsx +7 -17
  33. package/src/ui/components/patterns/split.tsx +111 -59
  34. package/src/ui/components/patterns/{surface-header.tsx → structural-header.tsx} +90 -27
  35. package/src/ui/components/patterns/structural-media.tsx +26 -0
  36. package/src/ui/components/patterns/surface-anatomy.ts +71 -61
  37. package/src/ui/components/patterns/surface-assistant.tsx +2 -4
  38. package/src/ui/components/patterns/surface.tsx +620 -0
  39. package/src/ui/components/patterns/trigger.tsx +11 -9
  40. package/src/ui/components/primitives/ask.tsx +155 -83
  41. package/src/ui/components/primitives/button.tsx +11 -9
  42. package/src/ui/components/primitives/checkbox.tsx +8 -8
  43. package/src/ui/components/primitives/command.tsx +1 -1
  44. package/src/ui/components/primitives/composer.tsx +47 -45
  45. package/src/ui/components/primitives/detail.tsx +9 -2
  46. package/src/ui/components/primitives/dialog.tsx +60 -26
  47. package/src/ui/components/primitives/drawer.tsx +58 -12
  48. package/src/ui/components/primitives/icon-picker.tsx +90 -73
  49. package/src/ui/components/primitives/input-group.tsx +35 -28
  50. package/src/ui/components/primitives/input-otp.tsx +16 -16
  51. package/src/ui/components/primitives/input.tsx +20 -10
  52. package/src/ui/components/primitives/item.tsx +9 -12
  53. package/src/ui/components/primitives/menu.tsx +44 -65
  54. package/src/ui/components/primitives/metric-card.tsx +75 -59
  55. package/src/ui/components/primitives/radio-group.tsx +9 -9
  56. package/src/ui/components/primitives/select.tsx +344 -209
  57. package/src/ui/components/primitives/switch.tsx +10 -10
  58. package/src/ui/components/primitives/table.tsx +29 -24
  59. package/src/ui/components/primitives/tabs.tsx +4 -2
  60. package/src/ui/components/primitives/textarea.tsx +6 -6
  61. package/src/ui/components/primitives/toggle-group-context.ts +24 -0
  62. package/src/ui/components/primitives/toggle-group.tsx +116 -74
  63. package/src/ui/components/primitives/toggle.tsx +82 -16
  64. package/src/ui/docs/DocBrowser.tsx +77 -69
  65. package/src/ui/docs/content/action-form-card.md +9 -9
  66. package/src/ui/docs/content/action-list.md +76 -70
  67. package/src/ui/docs/content/action-view.md +33 -18
  68. package/src/ui/docs/content/button.md +1 -1
  69. package/src/ui/docs/content/communication.md +1 -1
  70. package/src/ui/docs/content/compositions.md +479 -0
  71. package/src/ui/docs/content/customization.md +64 -11
  72. package/src/ui/docs/content/detail.md +8 -6
  73. package/src/ui/docs/content/dialog.md +105 -60
  74. package/src/ui/docs/content/drawer.md +68 -22
  75. package/src/ui/docs/content/field.md +14 -15
  76. package/src/ui/docs/content/icon-tile.md +14 -13
  77. package/src/ui/docs/content/page.md +44 -34
  78. package/src/ui/docs/content/pane.md +42 -290
  79. package/src/ui/docs/content/presentation.md +3 -3
  80. package/src/ui/docs/content/separator.md +6 -6
  81. package/src/ui/docs/content/sidebar.md +68 -266
  82. package/src/ui/docs/content/skeleton.md +20 -18
  83. package/src/ui/docs/content/split.md +14 -14
  84. package/src/ui/docs/content/surface.md +513 -0
  85. package/src/ui/docs/content/tabs.md +20 -20
  86. package/src/ui/docs/content/toggle.md +117 -65
  87. package/src/ui/docs/content/tokens.md +124 -40
  88. package/src/ui/docs/registry.tsx +10 -6
  89. package/src/ui/index.ts +30 -27
  90. package/src/ui/meta.ts +15 -27
  91. package/src/ui/react.tsx +40 -43
  92. package/src/ui/theme.css +311 -64
  93. package/src/ui/components/patterns/content-header.tsx +0 -528
  94. package/src/ui/components/patterns/surface-media.tsx +0 -69
  95. package/src/ui/components/primitives/card.tsx +0 -191
  96. package/src/ui/docs/content/card.md +0 -292
  97. package/src/ui/docs/content/content.md +0 -275
@@ -1,27 +1,27 @@
1
- import * as React from "react"
2
- import { OTPInput, OTPInputContext } from "input-otp"
3
- import { MinusIcon } from "lucide-react"
1
+ import * as React from "react";
2
+ import { OTPInput, OTPInputContext } from "input-otp";
3
+ import { MinusIcon } from "lucide-react";
4
4
 
5
- import { cn } from '../../lib/cn.ts'
5
+ import { cn } from "../../lib/cn.ts";
6
6
 
7
7
  function InputOTP({
8
8
  className,
9
9
  containerClassName,
10
10
  ...props
11
11
  }: React.ComponentProps<typeof OTPInput> & {
12
- containerClassName?: string
12
+ containerClassName?: string;
13
13
  }) {
14
14
  return (
15
15
  <OTPInput
16
16
  data-slot="input-otp"
17
17
  containerClassName={cn(
18
18
  "flex items-center gap-2 has-disabled:opacity-50",
19
- containerClassName
19
+ containerClassName,
20
20
  )}
21
21
  className={cn("disabled:cursor-not-allowed", className)}
22
22
  {...props}
23
23
  />
24
- )
24
+ );
25
25
  }
26
26
 
27
27
  function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) {
@@ -31,7 +31,7 @@ function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) {
31
31
  className={cn("flex items-center", className)}
32
32
  {...props}
33
33
  />
34
- )
34
+ );
35
35
  }
36
36
 
37
37
  function InputOTPSlot({
@@ -39,18 +39,18 @@ function InputOTPSlot({
39
39
  className,
40
40
  ...props
41
41
  }: React.ComponentProps<"div"> & {
42
- index: number
42
+ index: number;
43
43
  }) {
44
- const inputOTPContext = React.useContext(OTPInputContext)
45
- const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {}
44
+ const inputOTPContext = React.useContext(OTPInputContext);
45
+ const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
46
46
 
47
47
  return (
48
48
  <div
49
49
  data-slot="input-otp-slot"
50
50
  data-active={isActive}
51
51
  className={cn(
52
- "relative flex h-9 w-9 items-center justify-center border-y border-r border-input bg-muted/30 text-sm transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md aria-invalid:border-context-danger data-[active=true]:z-10 data-[active=true]:border-ring data-[active=true]:ring-[0.1875rem] data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:border-context-danger data-[active=true]:aria-invalid:ring-context-danger/20 dark:bg-input/30 dark:data-[active=true]:aria-invalid:ring-context-danger/40",
53
- className
52
+ "relative flex h-9 w-9 items-center justify-center border-y border-r border-input bg-control text-sm transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md aria-invalid:border-context-danger data-[active=true]:z-10 data-[active=true]:border-ring data-[active=true]:ring-[0.1875rem] data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:border-context-danger data-[active=true]:aria-invalid:ring-context-danger/20 dark:data-[active=true]:aria-invalid:ring-context-danger/40",
53
+ className,
54
54
  )}
55
55
  {...props}
56
56
  >
@@ -61,7 +61,7 @@ function InputOTPSlot({
61
61
  </div>
62
62
  )}
63
63
  </div>
64
- )
64
+ );
65
65
  }
66
66
 
67
67
  function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) {
@@ -69,7 +69,7 @@ function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) {
69
69
  <div data-slot="input-otp-separator" role="separator" {...props}>
70
70
  <MinusIcon />
71
71
  </div>
72
- )
72
+ );
73
73
  }
74
74
 
75
- export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator }
75
+ export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };
@@ -1,25 +1,32 @@
1
- import * as React from "react"
1
+ import * as React from "react";
2
2
 
3
- import { cn } from '../../lib/cn.ts'
3
+ import { cn } from "../../lib/cn.ts";
4
4
 
5
5
  export interface InputProps extends React.ComponentProps<"input"> {
6
6
  /** Ícone LEADING dentro do campo (identidade — calendário na data, prédio na filial).
7
7
  * É a MESMA prop do Select e do Alert: adorno de campo é prop, não composição à mão. */
8
- icon?: React.ReactNode
8
+ icon?: React.ReactNode;
9
9
  /** Ação TRAILING dentro do campo, no fim — um botão que age sobre o valor (limpar,
10
10
  * mostrar senha). Par do `icon`, igual ao Select. Pra addon rico (prefixo de texto,
11
11
  * adorno em bloco, múltiplos), use `InputGroup`. */
12
- trailing?: React.ReactNode
12
+ trailing?: React.ReactNode;
13
13
  }
14
14
 
15
15
  // O <input> CRU (sem adorno): ELE é o campo — borda, foco, ref e className moram nele.
16
16
  const bareInput =
17
- "h-9 w-full min-w-0 rounded-md border border-input bg-muted/30 px-3 py-1 text-sm transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 dark:bg-input/30 focus-visible:border-ring focus-visible:ring-[0.1875rem] focus-visible:ring-ring/50 aria-invalid:border-context-danger aria-invalid:ring-context-danger/20 dark:aria-invalid:ring-context-danger/40"
17
+ "h-9 w-full min-w-0 rounded-md border border-input bg-control px-3 py-1 text-sm transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 focus-visible:border-ring focus-visible:ring-[0.1875rem] focus-visible:ring-ring/50 aria-invalid:border-context-danger aria-invalid:ring-context-danger/20 dark:aria-invalid:ring-context-danger/40";
18
18
 
19
19
  function Input({ className, type, icon, trailing, ...props }: InputProps) {
20
20
  // Sem adorno: o <input> cru de sempre — retrocompatível (refs, forms, InputGroupInput).
21
21
  if (icon === undefined && trailing === undefined) {
22
- return <input type={type} data-slot="input" className={cn(bareInput, className)} {...props} />
22
+ return (
23
+ <input
24
+ type={type}
25
+ data-slot="input"
26
+ className={cn(bareInput, className)}
27
+ {...props}
28
+ />
29
+ );
23
30
  }
24
31
  // Adornado: o MESMO modelo flex do InputGroup/Select. A borda e o anel moram no WRAPPER
25
32
  // (disparados pelo `:focus-visible` do input interno — foco de teclado); o <input> fica
@@ -31,7 +38,7 @@ function Input({ className, type, icon, trailing, ...props }: InputProps) {
31
38
  <div
32
39
  data-slot="input-wrapper"
33
40
  className={cn(
34
- "flex h-9 w-full min-w-0 items-center gap-1.5 rounded-md border border-input bg-muted/30 px-3 text-sm transition-[color,box-shadow] outline-none dark:bg-input/30",
41
+ "flex h-9 w-full min-w-0 items-center gap-1.5 rounded-md border border-input bg-control px-3 text-sm transition-[color,box-shadow] outline-none",
35
42
  "has-[input:focus-visible]:border-ring has-[input:focus-visible]:ring-[0.1875rem] has-[input:focus-visible]:ring-ring/50",
36
43
  "has-[input[aria-invalid=true]]:border-context-danger has-[input[aria-invalid=true]]:ring-context-danger/20 dark:has-[input[aria-invalid=true]]:ring-context-danger/40",
37
44
  "has-[input:disabled]:pointer-events-none has-[input:disabled]:opacity-50",
@@ -60,12 +67,15 @@ function Input({ className, type, icon, trailing, ...props }: InputProps) {
60
67
  // Interativo (AÇÃO, não decoração): sem pointer-events-none. O tom muted (ação
61
68
  // secundária) mora no slot — o botão ghost herda, sem sprinklar no call site. Se o
62
69
  // trailing é botão: aproxima 0.375rem para casar o inset horizontal com o vertical.
63
- <span data-slot="input-trailing" className="flex shrink-0 items-center text-muted-foreground has-[button]:-mr-1.5">
70
+ <span
71
+ data-slot="input-trailing"
72
+ className="flex shrink-0 items-center text-muted-foreground has-[button]:-mr-1.5"
73
+ >
64
74
  {trailing}
65
75
  </span>
66
76
  )}
67
77
  </div>
68
- )
78
+ );
69
79
  }
70
80
 
71
- export { Input }
81
+ export { Input };
@@ -7,19 +7,16 @@ import type { ControlSize } from "./control.ts";
7
7
  import { iconTileVariants } from "./icon-tile.tsx";
8
8
  import { Separator } from "./separator.tsx";
9
9
 
10
- const itemGroupVariants = cva(
11
- "group/item-group flex flex-col",
12
- {
13
- variants: {
14
- variant: {
15
- plain: "",
16
- framed:
17
- "overflow-hidden rounded-xl border border-border bg-card text-card-foreground [&>[data-slot=item]]:rounded-none [&>[data-slot=item-container]>[data-slot=item]]:rounded-none",
18
- },
10
+ const itemGroupVariants = cva("group/item-group flex flex-col", {
11
+ variants: {
12
+ variant: {
13
+ plain: "",
14
+ framed:
15
+ "overflow-hidden rounded-xl border border-border bg-card text-card-foreground [&>[data-slot=item]]:rounded-none [&>[data-slot=item-container]>[data-slot=item]]:rounded-none",
19
16
  },
20
- defaultVariants: { variant: "plain" },
21
17
  },
22
- );
18
+ defaultVariants: { variant: "plain" },
19
+ });
23
20
 
24
21
  const ItemGroupContext = React.createContext(false);
25
22
  const ItemContext = React.createContext(false);
@@ -66,7 +63,7 @@ function ItemSeparator({
66
63
  }
67
64
 
68
65
  const itemVariants = cva(
69
- "group/item flex flex-wrap items-center rounded-md border border-transparent text-sm transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-[0.1875rem] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-accent/50",
66
+ "group/item flex flex-wrap items-center rounded-md border border-transparent text-sm transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-[0.1875rem] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-interaction-hover",
70
67
  {
71
68
  variants: {
72
69
  variant: {
@@ -1,15 +1,13 @@
1
- import * as React from "react"
2
- import type { UiContext } from '../../../core/ui-context.ts'
3
- import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
4
- import { DropdownMenu as MenuPrimitive } from "radix-ui"
1
+ import * as React from "react";
2
+ import type { UiContext } from "../../../core/ui-context.ts";
3
+ import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
4
+ import { DropdownMenu as MenuPrimitive } from "radix-ui";
5
5
 
6
- import { useDismissOnIframeFocus } from "../../lib/dismiss-on-iframe.ts"
7
- import { cn } from '../../lib/cn.ts'
6
+ import { useDismissOnIframeFocus } from "../../lib/dismiss-on-iframe.ts";
7
+ import { cn } from "../../lib/cn.ts";
8
8
 
9
- function Menu({
10
- ...props
11
- }: React.ComponentProps<typeof MenuPrimitive.Root>) {
12
- return <MenuPrimitive.Root data-slot="menu" {...props} />
9
+ function Menu({ ...props }: React.ComponentProps<typeof MenuPrimitive.Root>) {
10
+ return <MenuPrimitive.Root data-slot="menu" {...props} />;
13
11
  }
14
12
 
15
13
  /**
@@ -20,20 +18,13 @@ function Menu({
20
18
  function MenuPortal({
21
19
  ...props
22
20
  }: React.ComponentProps<typeof MenuPrimitive.Portal>) {
23
- return (
24
- <MenuPrimitive.Portal data-slot="menu-portal" {...props} />
25
- )
21
+ return <MenuPrimitive.Portal data-slot="menu-portal" {...props} />;
26
22
  }
27
23
 
28
24
  function MenuTrigger({
29
25
  ...props
30
26
  }: React.ComponentProps<typeof MenuPrimitive.Trigger>) {
31
- return (
32
- <MenuPrimitive.Trigger
33
- data-slot="menu-trigger"
34
- {...props}
35
- />
36
- )
27
+ return <MenuPrimitive.Trigger data-slot="menu-trigger" {...props} />;
37
28
  }
38
29
 
39
30
  function MenuContent({
@@ -42,8 +33,8 @@ function MenuContent({
42
33
  ...props
43
34
  }: React.ComponentProps<typeof MenuPrimitive.Content>) {
44
35
  // Mesma razão do Popover: clique dentro de iframe não chega aqui fora.
45
- const ref = React.useRef<HTMLDivElement>(null)
46
- useDismissOnIframeFocus(ref)
36
+ const ref = React.useRef<HTMLDivElement>(null);
37
+ useDismissOnIframeFocus(ref);
47
38
  return (
48
39
  <MenuPrimitive.Portal>
49
40
  <MenuPrimitive.Content
@@ -52,20 +43,18 @@ function MenuContent({
52
43
  sideOffset={sideOffset}
53
44
  className={cn(
54
45
  "z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[10rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md will-change-[transform,opacity] data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
55
- className
46
+ className,
56
47
  )}
57
48
  {...props}
58
49
  />
59
50
  </MenuPrimitive.Portal>
60
- )
51
+ );
61
52
  }
62
53
 
63
54
  function MenuGroup({
64
55
  ...props
65
56
  }: React.ComponentProps<typeof MenuPrimitive.Group>) {
66
- return (
67
- <MenuPrimitive.Group data-slot="menu-group" {...props} />
68
- )
57
+ return <MenuPrimitive.Group data-slot="menu-group" {...props} />;
69
58
  }
70
59
 
71
60
  function MenuItem({
@@ -74,22 +63,22 @@ function MenuItem({
74
63
  context,
75
64
  ...props
76
65
  }: React.ComponentProps<typeof MenuPrimitive.Item> & {
77
- inset?: boolean
78
- context?: Extract<UiContext, 'neutral' | 'danger'>
66
+ inset?: boolean;
67
+ context?: Extract<UiContext, "neutral" | "danger">;
79
68
  }) {
80
- const resolvedContext = context ?? 'neutral'
69
+ const resolvedContext = context ?? "neutral";
81
70
  return (
82
71
  <MenuPrimitive.Item
83
72
  data-slot="menu-item"
84
73
  data-inset={inset}
85
74
  data-context={resolvedContext}
86
75
  className={cn(
87
- "relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[context=danger]:focus:bg-context-danger-subtle data-[context=danger]:focus:text-context-danger-emphasis [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[context=danger]:focus:*:[svg]:text-context-danger-emphasis!",
88
- className
76
+ "relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-interaction-hover focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[context=danger]:focus:bg-context-danger-subtle data-[context=danger]:focus:text-context-danger-emphasis [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[context=danger]:focus:*:[svg]:text-context-danger-emphasis!",
77
+ className,
89
78
  )}
90
79
  {...props}
91
80
  />
92
- )
81
+ );
93
82
  }
94
83
 
95
84
  function MenuCheckboxItem({
@@ -102,8 +91,8 @@ function MenuCheckboxItem({
102
91
  <MenuPrimitive.CheckboxItem
103
92
  data-slot="menu-checkbox-item"
104
93
  className={cn(
105
- "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
106
- className
94
+ "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-interaction-hover focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
95
+ className,
107
96
  )}
108
97
  checked={checked}
109
98
  {...props}
@@ -115,18 +104,13 @@ function MenuCheckboxItem({
115
104
  </span>
116
105
  {children}
117
106
  </MenuPrimitive.CheckboxItem>
118
- )
107
+ );
119
108
  }
120
109
 
121
110
  function MenuRadioGroup({
122
111
  ...props
123
112
  }: React.ComponentProps<typeof MenuPrimitive.RadioGroup>) {
124
- return (
125
- <MenuPrimitive.RadioGroup
126
- data-slot="menu-radio-group"
127
- {...props}
128
- />
129
- )
113
+ return <MenuPrimitive.RadioGroup data-slot="menu-radio-group" {...props} />;
130
114
  }
131
115
 
132
116
  function MenuRadioItem({
@@ -138,8 +122,8 @@ function MenuRadioItem({
138
122
  <MenuPrimitive.RadioItem
139
123
  data-slot="menu-radio-item"
140
124
  className={cn(
141
- "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
142
- className
125
+ "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-interaction-hover focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
126
+ className,
143
127
  )}
144
128
  {...props}
145
129
  >
@@ -150,7 +134,7 @@ function MenuRadioItem({
150
134
  </span>
151
135
  {children}
152
136
  </MenuPrimitive.RadioItem>
153
- )
137
+ );
154
138
  }
155
139
 
156
140
  function MenuLabel({
@@ -158,7 +142,7 @@ function MenuLabel({
158
142
  inset,
159
143
  ...props
160
144
  }: React.ComponentProps<typeof MenuPrimitive.Label> & {
161
- inset?: boolean
145
+ inset?: boolean;
162
146
  }) {
163
147
  return (
164
148
  <MenuPrimitive.Label
@@ -166,11 +150,11 @@ function MenuLabel({
166
150
  data-inset={inset}
167
151
  className={cn(
168
152
  "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
169
- className
153
+ className,
170
154
  )}
171
155
  {...props}
172
156
  />
173
- )
157
+ );
174
158
  }
175
159
 
176
160
  function MenuSeparator({
@@ -183,29 +167,24 @@ function MenuSeparator({
183
167
  className={cn("-mx-1 my-1 h-px bg-border", className)}
184
168
  {...props}
185
169
  />
186
- )
170
+ );
187
171
  }
188
172
 
189
- function MenuShortcut({
190
- className,
191
- ...props
192
- }: React.ComponentProps<"span">) {
173
+ function MenuShortcut({ className, ...props }: React.ComponentProps<"span">) {
193
174
  return (
194
175
  <span
195
176
  data-slot="menu-shortcut"
196
177
  className={cn(
197
178
  "ml-auto text-xs tracking-widest text-muted-foreground",
198
- className
179
+ className,
199
180
  )}
200
181
  {...props}
201
182
  />
202
- )
183
+ );
203
184
  }
204
185
 
205
- function MenuSub({
206
- ...props
207
- }: React.ComponentProps<typeof MenuPrimitive.Sub>) {
208
- return <MenuPrimitive.Sub data-slot="menu-sub" {...props} />
186
+ function MenuSub({ ...props }: React.ComponentProps<typeof MenuPrimitive.Sub>) {
187
+ return <MenuPrimitive.Sub data-slot="menu-sub" {...props} />;
209
188
  }
210
189
 
211
190
  function MenuSubTrigger({
@@ -214,22 +193,22 @@ function MenuSubTrigger({
214
193
  children,
215
194
  ...props
216
195
  }: React.ComponentProps<typeof MenuPrimitive.SubTrigger> & {
217
- inset?: boolean
196
+ inset?: boolean;
218
197
  }) {
219
198
  return (
220
199
  <MenuPrimitive.SubTrigger
221
200
  data-slot="menu-sub-trigger"
222
201
  data-inset={inset}
223
202
  className={cn(
224
- "flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
225
- className
203
+ "flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-interaction-hover focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-interaction-selected data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
204
+ className,
226
205
  )}
227
206
  {...props}
228
207
  >
229
208
  {children}
230
209
  <ChevronRightIcon className="ml-auto size-4" />
231
210
  </MenuPrimitive.SubTrigger>
232
- )
211
+ );
233
212
  }
234
213
 
235
214
  function MenuSubContent({
@@ -241,11 +220,11 @@ function MenuSubContent({
241
220
  data-slot="menu-sub-content"
242
221
  className={cn(
243
222
  "z-50 min-w-[10rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md will-change-[transform,opacity] data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
244
- className
223
+ className,
245
224
  )}
246
225
  {...props}
247
226
  />
248
- )
227
+ );
249
228
  }
250
229
 
251
230
  export {
@@ -264,4 +243,4 @@ export {
264
243
  MenuSub,
265
244
  MenuSubTrigger,
266
245
  MenuSubContent,
267
- }
246
+ };