@adea-ai/ui 0.12.0 → 0.12.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 (90) hide show
  1. package/dist/components/account-drawer.d.ts +1 -1
  2. package/dist/components/account-drawer.js +12 -12
  3. package/dist/components/on-screen-controls.js +12 -12
  4. package/dist/components/scene-settings.d.ts +3 -3
  5. package/dist/components/scene-settings.js +11 -11
  6. package/dist/components/theme-provider.d.ts +1 -1
  7. package/dist/components/theme-provider.js +2 -2
  8. package/dist/components/theme-toggle.js +8 -8
  9. package/dist/components/ui/badge.d.ts +3 -3
  10. package/dist/components/ui/badge.js +15 -15
  11. package/dist/components/ui/button.d.ts +2 -2
  12. package/dist/components/ui/button.js +19 -19
  13. package/dist/components/ui/card.d.ts +1 -1
  14. package/dist/components/ui/card.js +3 -3
  15. package/dist/components/ui/dialog.d.ts +4 -4
  16. package/dist/components/ui/dialog.js +10 -10
  17. package/dist/components/ui/drawer.d.ts +5 -5
  18. package/dist/components/ui/drawer.js +26 -26
  19. package/dist/components/ui/dropdown-menu.d.ts +5 -5
  20. package/dist/components/ui/dropdown-menu.js +12 -12
  21. package/dist/components/ui/empty.d.ts +7 -7
  22. package/dist/components/ui/empty.js +11 -11
  23. package/dist/components/ui/field.d.ts +12 -12
  24. package/dist/components/ui/field.js +22 -22
  25. package/dist/components/ui/input.d.ts +2 -2
  26. package/dist/components/ui/input.js +3 -3
  27. package/dist/components/ui/label.d.ts +2 -2
  28. package/dist/components/ui/label.js +3 -3
  29. package/dist/components/ui/radio-group.d.ts +2 -2
  30. package/dist/components/ui/radio-group.js +6 -6
  31. package/dist/components/ui/separator.d.ts +1 -1
  32. package/dist/components/ui/separator.js +5 -5
  33. package/dist/components/ui/skeleton.d.ts +1 -1
  34. package/dist/components/ui/skeleton.js +2 -2
  35. package/dist/components/ui/spinner.d.ts +2 -2
  36. package/dist/components/ui/spinner.js +3 -3
  37. package/dist/components/ui/switch.d.ts +2 -2
  38. package/dist/components/ui/switch.js +5 -5
  39. package/dist/components/ui/tabs.d.ts +2 -2
  40. package/dist/components/ui/tabs.js +13 -13
  41. package/dist/components/ui/toggle-group.d.ts +6 -6
  42. package/dist/components/ui/toggle-group.js +13 -13
  43. package/dist/components/ui/toggle.d.ts +2 -2
  44. package/dist/components/ui/toggle.js +11 -11
  45. package/dist/components/ui/tooltip.d.ts +3 -3
  46. package/dist/components/ui/tooltip.js +5 -5
  47. package/dist/components/version-dialog.d.ts +1 -1
  48. package/dist/components/version-dialog.js +33 -33
  49. package/dist/components/workspace-brand.js +1 -1
  50. package/dist/components/workspace-logo.d.ts +1 -1
  51. package/dist/index.d.ts +19 -19
  52. package/dist/index.js +19 -19
  53. package/dist/lib/utils.d.ts +1 -1
  54. package/dist/lib/utils.js +2 -2
  55. package/dist/lib/version-notes.js +18 -18
  56. package/package.json +9 -9
  57. package/src/components/account-drawer.tsx +27 -27
  58. package/src/components/on-screen-controls.tsx +45 -45
  59. package/src/components/scene-settings.tsx +55 -55
  60. package/src/components/theme-provider.tsx +7 -7
  61. package/src/components/theme-toggle.tsx +20 -20
  62. package/src/components/ui/badge.tsx +20 -20
  63. package/src/components/ui/button.tsx +24 -24
  64. package/src/components/ui/card.tsx +6 -6
  65. package/src/components/ui/dialog.tsx +24 -24
  66. package/src/components/ui/drawer.tsx +55 -55
  67. package/src/components/ui/dropdown-menu.tsx +39 -39
  68. package/src/components/ui/empty.tsx +25 -25
  69. package/src/components/ui/field.tsx +55 -55
  70. package/src/components/ui/input.tsx +7 -7
  71. package/src/components/ui/label.tsx +7 -7
  72. package/src/components/ui/radio-group.tsx +9 -9
  73. package/src/components/ui/separator.tsx +7 -7
  74. package/src/components/ui/skeleton.tsx +5 -5
  75. package/src/components/ui/spinner.tsx +6 -6
  76. package/src/components/ui/switch.tsx +8 -8
  77. package/src/components/ui/tabs.tsx +21 -21
  78. package/src/components/ui/toggle-group.tsx +25 -25
  79. package/src/components/ui/toggle.tsx +15 -15
  80. package/src/components/ui/tooltip.tsx +13 -13
  81. package/src/components/version-dialog.tsx +113 -113
  82. package/src/components/workspace-brand.tsx +4 -4
  83. package/src/components/workspace-logo.tsx +2 -2
  84. package/src/index.tsx +19 -19
  85. package/src/lib/utils.ts +3 -3
  86. package/src/lib/version-notes.ts +23 -23
  87. package/src/styles/conventional-workspace.css +26 -26
  88. package/src/styles/globals.css +2 -2
  89. package/src/styles/theme.css +1 -1
  90. package/src/styles/workspace-shell.css +2 -2
@@ -1,68 +1,68 @@
1
- "use client";
1
+ 'use client'
2
2
 
3
- import { useCallback, useEffect, useRef } from "react";
4
- import type { PointerEvent, ReactNode } from "react";
5
- import { ZoomIn, ZoomOut } from "lucide-react";
6
- import { Button } from "#components/ui/button";
7
- import { cn } from "#lib/utils";
3
+ import { useCallback, useEffect, useRef } from 'react'
4
+ import type { PointerEvent, ReactNode } from 'react'
5
+ import { ZoomIn, ZoomOut } from 'lucide-react'
6
+ import { Button } from '#components/ui/button'
7
+ import { cn } from '#lib/utils'
8
8
  type ControlButtonProps = {
9
- code: string;
10
- label: string;
11
- children: ReactNode;
12
- className?: string;
13
- };
9
+ code: string
10
+ label: string
11
+ children: ReactNode
12
+ className?: string
13
+ }
14
14
 
15
- function sendKeyEvent(type: "keydown" | "keyup", code: string): void {
15
+ function sendKeyEvent(type: 'keydown' | 'keyup', code: string): void {
16
16
  window.dispatchEvent(
17
17
  new KeyboardEvent(type, { bubbles: true, cancelable: true, code, key: code })
18
- );
18
+ )
19
19
  }
20
20
 
21
21
  function ControlButton({ code, label, children, className }: ControlButtonProps) {
22
- const pressed = useRef(false);
23
- const pressedPointer = useRef<number | null>(null);
22
+ const pressed = useRef(false)
23
+ const pressedPointer = useRef<number | null>(null)
24
24
 
25
25
  const release = useCallback(() => {
26
- if (!pressed.current) return;
27
- pressed.current = false;
28
- pressedPointer.current = null;
29
- sendKeyEvent("keyup", code);
30
- }, [code]);
26
+ if (!pressed.current) return
27
+ pressed.current = false
28
+ pressedPointer.current = null
29
+ sendKeyEvent('keyup', code)
30
+ }, [code])
31
31
 
32
32
  // Self-heal: release the key if the pointerup lands elsewhere (e.g. the
33
33
  // scene DOM changes mid-teleport) or the window loses focus. PointerId
34
34
  // matching preserves multi-touch.
35
35
  useEffect(() => {
36
36
  const onWindowPointerUp = (event: globalThis.PointerEvent) => {
37
- if (pressedPointer.current === event.pointerId) release();
38
- };
39
- const onBlur = () => release();
40
- window.addEventListener("pointerup", onWindowPointerUp);
41
- window.addEventListener("blur", onBlur);
37
+ if (pressedPointer.current === event.pointerId) release()
38
+ }
39
+ const onBlur = () => release()
40
+ window.addEventListener('pointerup', onWindowPointerUp)
41
+ window.addEventListener('blur', onBlur)
42
42
  return () => {
43
- window.removeEventListener("pointerup", onWindowPointerUp);
44
- window.removeEventListener("blur", onBlur);
45
- };
46
- }, [release]);
43
+ window.removeEventListener('pointerup', onWindowPointerUp)
44
+ window.removeEventListener('blur', onBlur)
45
+ }
46
+ }, [release])
47
47
 
48
48
  const press = useCallback(
49
49
  (event: PointerEvent<HTMLButtonElement>) => {
50
- event.preventDefault();
51
- if (pressed.current) return;
52
- pressed.current = true;
53
- pressedPointer.current = event.pointerId;
54
- event.currentTarget.setPointerCapture(event.pointerId);
55
- sendKeyEvent("keydown", code);
50
+ event.preventDefault()
51
+ if (pressed.current) return
52
+ pressed.current = true
53
+ pressedPointer.current = event.pointerId
54
+ event.currentTarget.setPointerCapture(event.pointerId)
55
+ sendKeyEvent('keydown', code)
56
56
  },
57
57
  [code]
58
- );
58
+ )
59
59
 
60
60
  return (
61
61
  <button
62
62
  type="button"
63
63
  aria-label={label}
64
64
  className={cn(
65
- "flex size-14 touch-none select-none items-center justify-center rounded-2xl border border-white/25 bg-slate-950/65 p-2 text-white shadow-lg backdrop-blur-sm transition active:scale-95 [-webkit-touch-callout:none] [-webkit-user-select:none]",
65
+ 'flex size-14 touch-none select-none items-center justify-center rounded-2xl border border-white/25 bg-slate-950/65 p-2 text-white shadow-lg backdrop-blur-sm transition active:scale-95 [-webkit-touch-callout:none] [-webkit-user-select:none]',
66
66
  className
67
67
  )}
68
68
  onContextMenu={(event) => event.preventDefault()}
@@ -73,15 +73,15 @@ function ControlButton({ code, label, children, className }: ControlButtonProps)
73
73
  >
74
74
  {children}
75
75
  </button>
76
- );
76
+ )
77
77
  }
78
78
 
79
79
  export type OnScreenControlsProps = {
80
- onZoomIn?: () => void;
81
- onZoomOut?: () => void;
82
- showMovementControls?: boolean;
83
- showJumpControl?: boolean;
84
- };
80
+ onZoomIn?: () => void
81
+ onZoomOut?: () => void
82
+ showMovementControls?: boolean
83
+ showJumpControl?: boolean
84
+ }
85
85
 
86
86
  export function OnScreenControls({
87
87
  onZoomIn,
@@ -89,7 +89,7 @@ export function OnScreenControls({
89
89
  showMovementControls = true,
90
90
  showJumpControl = true,
91
91
  }: OnScreenControlsProps = {}) {
92
- const showZoomControls = Boolean(onZoomIn && onZoomOut);
92
+ const showZoomControls = Boolean(onZoomIn && onZoomOut)
93
93
 
94
94
  return (
95
95
  <div
@@ -152,5 +152,5 @@ export function OnScreenControls({
152
152
  ) : null}
153
153
  </div>
154
154
  </div>
155
- );
155
+ )
156
156
  }
@@ -1,54 +1,54 @@
1
- "use client";
1
+ 'use client'
2
2
 
3
- import { createPortal } from "react-dom";
4
- import { useEffect, useState, type ReactNode } from "react";
5
- import { Box, Camera, Focus, Grid3X3, UserRoundPen } from "lucide-react";
6
- import { AccountDrawer } from "./account-drawer";
7
- import { Button } from "#components/ui/button";
3
+ import { createPortal } from 'react-dom'
4
+ import { useEffect, useState, type ReactNode } from 'react'
5
+ import { Box, Camera, Focus, Grid3X3, UserRoundPen } from 'lucide-react'
6
+ import { AccountDrawer } from './account-drawer'
7
+ import { Button } from '#components/ui/button'
8
8
 
9
9
  export type SceneSettingsProps = {
10
- cameraViewMode: "perspective" | "orthographic";
11
- onCameraViewModeChange: (value: "perspective" | "orthographic") => void;
12
- allowCameraViewModeChange?: boolean;
10
+ cameraViewMode: 'perspective' | 'orthographic'
11
+ onCameraViewModeChange: (value: 'perspective' | 'orthographic') => void
12
+ allowCameraViewModeChange?: boolean
13
13
  /** Standalone character selection and customization menu toggle. */
14
- characterDesignerEnabled?: boolean;
15
- onCharacterDesignerChange?: (value: boolean) => void;
14
+ characterDesignerEnabled?: boolean
15
+ onCharacterDesignerChange?: (value: boolean) => void
16
16
  /** DOM target for the character designer control in an app shell toolbar. */
17
- characterDesignerTargetId?: string;
17
+ characterDesignerTargetId?: string
18
18
  /** Open the scene-specific room layout and interior prop designer. */
19
- onOpenRoomDesigner?: () => void;
19
+ onOpenRoomDesigner?: () => void
20
20
  /** DOM target for the account drawer trigger in an app shell toolbar. */
21
- accountTargetId?: string;
22
- accountLabel?: string;
23
- accountAuthenticated?: boolean;
24
- accountBusy?: boolean;
25
- accountMusicControl?: ReactNode;
26
- onAccountSignIn?: () => void;
27
- onAccountSignOut?: () => void;
28
- showAccountDrawer?: boolean;
21
+ accountTargetId?: string
22
+ accountLabel?: string
23
+ accountAuthenticated?: boolean
24
+ accountBusy?: boolean
25
+ accountMusicControl?: ReactNode
26
+ onAccountSignIn?: () => void
27
+ onAccountSignOut?: () => void
28
+ showAccountDrawer?: boolean
29
29
  /** DOM target for the compact camera controls in an app shell toolbar. */
30
- cameraTargetId?: string;
30
+ cameraTargetId?: string
31
31
  /** DOM target for the room designer control in an app shell toolbar. */
32
- roomDesignerTargetId?: string;
32
+ roomDesignerTargetId?: string
33
33
  /** DOM target for the development scene editor control in an app shell toolbar. */
34
- sceneEditorTargetId?: string;
34
+ sceneEditorTargetId?: string
35
35
  /** Development-only scene editor toggle, available in perspective view. */
36
- sceneEditorEnabled?: boolean;
37
- onSceneEditorChange?: (value: boolean) => void;
38
- };
36
+ sceneEditorEnabled?: boolean
37
+ onSceneEditorChange?: (value: boolean) => void
38
+ }
39
39
 
40
40
  function usePortalTarget(targetId?: string) {
41
- const [target, setTarget] = useState<HTMLElement | null>(null);
41
+ const [target, setTarget] = useState<HTMLElement | null>(null)
42
42
 
43
43
  useEffect(() => {
44
- setTarget(targetId ? document.getElementById(targetId) : null);
45
- }, [targetId]);
44
+ setTarget(targetId ? document.getElementById(targetId) : null)
45
+ }, [targetId])
46
46
 
47
- return target;
47
+ return target
48
48
  }
49
49
 
50
50
  function renderInTarget(content: ReactNode, target: HTMLElement | null) {
51
- return target ? createPortal(content, target) : content;
51
+ return target ? createPortal(content, target) : content
52
52
  }
53
53
 
54
54
  /** Compact scene controls shared by the HQ shell and other scene hosts. */
@@ -74,22 +74,22 @@ export function SceneSettings({
74
74
  sceneEditorEnabled,
75
75
  onSceneEditorChange,
76
76
  }: SceneSettingsProps) {
77
- const cameraTarget = usePortalTarget(cameraTargetId);
78
- const characterDesignerTarget = usePortalTarget(characterDesignerTargetId);
79
- const roomDesignerTarget = usePortalTarget(roomDesignerTargetId);
80
- const sceneEditorTarget = usePortalTarget(sceneEditorTargetId);
77
+ const cameraTarget = usePortalTarget(cameraTargetId)
78
+ const characterDesignerTarget = usePortalTarget(characterDesignerTargetId)
79
+ const roomDesignerTarget = usePortalTarget(roomDesignerTargetId)
80
+ const sceneEditorTarget = usePortalTarget(sceneEditorTargetId)
81
81
 
82
82
  const cameraControl = (
83
83
  <div className="workspace-camera-control" role="group" aria-label="Camera view">
84
84
  <Button
85
85
  type="button"
86
86
  size="sm"
87
- variant={cameraViewMode === "perspective" ? "default" : "outline"}
87
+ variant={cameraViewMode === 'perspective' ? 'default' : 'outline'}
88
88
  className="workspace-camera-button"
89
89
  aria-label="Perspective camera"
90
90
  title="Perspective camera"
91
- aria-pressed={cameraViewMode === "perspective"}
92
- onClick={() => onCameraViewModeChange("perspective")}
91
+ aria-pressed={cameraViewMode === 'perspective'}
92
+ onClick={() => onCameraViewModeChange('perspective')}
93
93
  >
94
94
  <Camera aria-hidden="true" />
95
95
  Perspective
@@ -97,34 +97,34 @@ export function SceneSettings({
97
97
  <Button
98
98
  type="button"
99
99
  size="sm"
100
- variant={cameraViewMode === "orthographic" ? "default" : "outline"}
100
+ variant={cameraViewMode === 'orthographic' ? 'default' : 'outline'}
101
101
  className="workspace-camera-button"
102
102
  aria-label="Top-down camera"
103
103
  title="Top-down camera"
104
- aria-pressed={cameraViewMode === "orthographic"}
105
- onClick={() => onCameraViewModeChange("orthographic")}
104
+ aria-pressed={cameraViewMode === 'orthographic'}
105
+ onClick={() => onCameraViewModeChange('orthographic')}
106
106
  >
107
107
  <Focus aria-hidden="true" />
108
108
  Top-down
109
109
  </Button>
110
110
  </div>
111
- );
111
+ )
112
112
 
113
113
  const characterDesignerControl = (
114
114
  <Button
115
115
  type="button"
116
- variant={characterDesignerEnabled ? "default" : "outline"}
116
+ variant={characterDesignerEnabled ? 'default' : 'outline'}
117
117
  size="sm"
118
118
  aria-haspopup="dialog"
119
- aria-label={characterDesignerEnabled ? "Close character designer" : "Open character designer"}
120
- title={characterDesignerEnabled ? "Close character designer" : "Open character designer"}
119
+ aria-label={characterDesignerEnabled ? 'Close character designer' : 'Open character designer'}
120
+ title={characterDesignerEnabled ? 'Close character designer' : 'Open character designer'}
121
121
  aria-pressed={characterDesignerEnabled}
122
122
  onClick={() => onCharacterDesignerChange?.(!characterDesignerEnabled)}
123
123
  >
124
124
  <UserRoundPen className="size-4" aria-hidden="true" />
125
125
  <span className="workspace-character-designer-label">Character</span>
126
126
  </Button>
127
- );
127
+ )
128
128
 
129
129
  const roomDesignerControl = (
130
130
  <Button
@@ -139,23 +139,23 @@ export function SceneSettings({
139
139
  <Grid3X3 className="size-4" aria-hidden="true" />
140
140
  <span className="workspace-room-designer-label">Room designer</span>
141
141
  </Button>
142
- );
142
+ )
143
143
 
144
144
  const sceneEditorControl = (
145
145
  <Button
146
146
  type="button"
147
- variant={sceneEditorEnabled ? "default" : "outline"}
147
+ variant={sceneEditorEnabled ? 'default' : 'outline'}
148
148
  size="sm"
149
149
  aria-haspopup="dialog"
150
- aria-label={sceneEditorEnabled ? "Close scene editor" : "Open scene editor"}
151
- title={sceneEditorEnabled ? "Close scene editor" : "Open scene editor"}
150
+ aria-label={sceneEditorEnabled ? 'Close scene editor' : 'Open scene editor'}
151
+ title={sceneEditorEnabled ? 'Close scene editor' : 'Open scene editor'}
152
152
  aria-pressed={sceneEditorEnabled}
153
153
  onClick={() => onSceneEditorChange?.(!sceneEditorEnabled)}
154
154
  >
155
155
  <Box className="size-4" aria-hidden="true" />
156
156
  <span className="workspace-scene-editor-label">Scene editor</span>
157
157
  </Button>
158
- );
158
+ )
159
159
 
160
160
  return (
161
161
  <>
@@ -180,7 +180,7 @@ export function SceneSettings({
180
180
  <div className="fixed right-4 top-16 z-40">{characterDesignerControl}</div>
181
181
  )
182
182
  ) : null}
183
- {onOpenRoomDesigner && cameraViewMode === "orthographic" ? (
183
+ {onOpenRoomDesigner && cameraViewMode === 'orthographic' ? (
184
184
  roomDesignerTarget ? (
185
185
  createPortal(roomDesignerControl, roomDesignerTarget)
186
186
  ) : (
@@ -190,7 +190,7 @@ export function SceneSettings({
190
190
  {sceneEditorEnabled != null &&
191
191
  !sceneEditorEnabled &&
192
192
  onSceneEditorChange &&
193
- cameraViewMode === "perspective" ? (
193
+ cameraViewMode === 'perspective' ? (
194
194
  sceneEditorTarget ? (
195
195
  createPortal(sceneEditorControl, sceneEditorTarget)
196
196
  ) : (
@@ -198,5 +198,5 @@ export function SceneSettings({
198
198
  )
199
199
  ) : null}
200
200
  </>
201
- );
201
+ )
202
202
  }
@@ -1,19 +1,19 @@
1
- "use client";
1
+ 'use client'
2
2
 
3
- import { ThemeProvider as NextThemesProvider } from "next-themes";
4
- import type { ComponentProps, ReactElement, ReactNode } from "react";
3
+ import { ThemeProvider as NextThemesProvider } from 'next-themes'
4
+ import type { ComponentProps, ReactElement, ReactNode } from 'react'
5
5
 
6
6
  // Bun 1.4 can resolve next-themes against a separate React type instance. The
7
7
  // runtime component is compatible, but TypeScript then drops `children` from
8
8
  // its JSX props. Keep the shared provider's public contract stable by
9
9
  // normalizing the third-party component's props at this boundary.
10
10
  type CompatibleNextThemesProviderProps = ComponentProps<typeof NextThemesProvider> & {
11
- children?: ReactNode;
12
- };
11
+ children?: ReactNode
12
+ }
13
13
 
14
14
  const CompatibleNextThemesProvider = NextThemesProvider as unknown as (
15
15
  props: CompatibleNextThemesProviderProps
16
- ) => ReactElement;
16
+ ) => ReactElement
17
17
 
18
18
  /** Shared theme provider used by each Next app in the workspace. */
19
19
  export function ThemeProvider({ children }: { children: ReactNode }) {
@@ -26,5 +26,5 @@ export function ThemeProvider({ children }: { children: ReactNode }) {
26
26
  >
27
27
  {children}
28
28
  </CompatibleNextThemesProvider>
29
- );
29
+ )
30
30
  }
@@ -1,32 +1,32 @@
1
- "use client";
1
+ 'use client'
2
2
 
3
- import { useSyncExternalStore } from "react";
4
- import { Monitor, Moon, Sun } from "lucide-react";
5
- import { useTheme } from "next-themes";
6
- import { Button } from "#components/ui/button";
7
- import { cn } from "#lib/utils";
3
+ import { useSyncExternalStore } from 'react'
4
+ import { Monitor, Moon, Sun } from 'lucide-react'
5
+ import { useTheme } from 'next-themes'
6
+ import { Button } from '#components/ui/button'
7
+ import { cn } from '#lib/utils'
8
8
 
9
9
  /**
10
10
  * Compact sun/moon theme selector. Wired to the next-themes provider so the
11
11
  * choice persists across the app (localStorage) and applies to every scene.
12
12
  */
13
13
  export function ThemeToggle({ className }: { className?: string }) {
14
- const { theme, setTheme } = useTheme();
14
+ const { theme, setTheme } = useTheme()
15
15
  const mounted = useSyncExternalStore(
16
16
  () => () => undefined,
17
17
  () => true,
18
18
  () => false
19
- );
19
+ )
20
20
 
21
21
  // next-themes resolves the saved/system theme after mount. Use the stable
22
22
  // light presentation for both SSR and the first client render so the
23
23
  // aria/class attributes cannot mismatch during hydration.
24
- const selectedTheme = mounted ? theme : "system";
24
+ const selectedTheme = mounted ? theme : 'system'
25
25
 
26
26
  return (
27
27
  <div
28
28
  className={cn(
29
- "inline-flex items-center gap-1.5 rounded-full border border-input bg-background p-1.5",
29
+ 'inline-flex items-center gap-1.5 rounded-full border border-input bg-background p-1.5',
30
30
  className
31
31
  )}
32
32
  role="radiogroup"
@@ -35,11 +35,11 @@ export function ThemeToggle({ className }: { className?: string }) {
35
35
  <Button
36
36
  type="button"
37
37
  role="radio"
38
- aria-checked={selectedTheme === "system"}
38
+ aria-checked={selectedTheme === 'system'}
39
39
  aria-label="System theme"
40
- variant={selectedTheme === "system" ? "default" : "ghost"}
40
+ variant={selectedTheme === 'system' ? 'default' : 'ghost'}
41
41
  size="icon-sm"
42
- onClick={() => setTheme("system")}
42
+ onClick={() => setTheme('system')}
43
43
  className="rounded-full"
44
44
  >
45
45
  <Monitor className="size-4" aria-hidden="true" />
@@ -47,11 +47,11 @@ export function ThemeToggle({ className }: { className?: string }) {
47
47
  <Button
48
48
  type="button"
49
49
  role="radio"
50
- aria-checked={selectedTheme === "light"}
50
+ aria-checked={selectedTheme === 'light'}
51
51
  aria-label="Light theme"
52
- variant={selectedTheme === "light" ? "default" : "ghost"}
52
+ variant={selectedTheme === 'light' ? 'default' : 'ghost'}
53
53
  size="icon-sm"
54
- onClick={() => setTheme("light")}
54
+ onClick={() => setTheme('light')}
55
55
  className="rounded-full"
56
56
  >
57
57
  <Sun className="size-4" aria-hidden="true" />
@@ -59,15 +59,15 @@ export function ThemeToggle({ className }: { className?: string }) {
59
59
  <Button
60
60
  type="button"
61
61
  role="radio"
62
- aria-checked={selectedTheme === "dark"}
62
+ aria-checked={selectedTheme === 'dark'}
63
63
  aria-label="Dark theme"
64
- variant={selectedTheme === "dark" ? "default" : "ghost"}
64
+ variant={selectedTheme === 'dark' ? 'default' : 'ghost'}
65
65
  size="icon-sm"
66
- onClick={() => setTheme("dark")}
66
+ onClick={() => setTheme('dark')}
67
67
  className="rounded-full"
68
68
  >
69
69
  <Moon className="size-4" aria-hidden="true" />
70
70
  </Button>
71
71
  </div>
72
- );
72
+ )
73
73
  }
@@ -1,38 +1,38 @@
1
- import { mergeProps } from "@base-ui/react/merge-props";
2
- import { useRender } from "@base-ui/react/use-render";
3
- import { cva, type VariantProps } from "class-variance-authority";
1
+ import { mergeProps } from '@base-ui/react/merge-props'
2
+ import { useRender } from '@base-ui/react/use-render'
3
+ import { cva, type VariantProps } from 'class-variance-authority'
4
4
 
5
- import { cn } from "#lib/utils";
5
+ import { cn } from '#lib/utils'
6
6
 
7
7
  const badgeVariants = cva(
8
- "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!",
8
+ 'group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!',
9
9
  {
10
10
  variants: {
11
11
  variant: {
12
- default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
13
- secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
12
+ default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80',
13
+ secondary: 'bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80',
14
14
  destructive:
15
- "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
16
- outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
17
- ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
18
- link: "text-primary underline-offset-4 hover:underline",
15
+ 'bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20',
16
+ outline: 'border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground',
17
+ ghost: 'hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50',
18
+ link: 'text-primary underline-offset-4 hover:underline',
19
19
  },
20
20
  },
21
21
  defaultVariants: {
22
- variant: "default",
22
+ variant: 'default',
23
23
  },
24
24
  }
25
- );
25
+ )
26
26
 
27
27
  function Badge({
28
28
  className,
29
- variant = "default",
29
+ variant = 'default',
30
30
  render,
31
31
  ...props
32
- }: useRender.ComponentProps<"span"> & VariantProps<typeof badgeVariants>) {
32
+ }: useRender.ComponentProps<'span'> & VariantProps<typeof badgeVariants>) {
33
33
  return useRender({
34
- defaultTagName: "span",
35
- props: mergeProps<"span">(
34
+ defaultTagName: 'span',
35
+ props: mergeProps<'span'>(
36
36
  {
37
37
  className: cn(badgeVariants({ variant }), className),
38
38
  },
@@ -40,10 +40,10 @@ function Badge({
40
40
  ),
41
41
  render,
42
42
  state: {
43
- slot: "badge",
43
+ slot: 'badge',
44
44
  variant,
45
45
  },
46
- });
46
+ })
47
47
  }
48
48
 
49
- export { Badge, badgeVariants };
49
+ export { Badge, badgeVariants }
@@ -1,51 +1,51 @@
1
- import { Button as ButtonPrimitive } from "@base-ui/react/button";
2
- import { cva, type VariantProps } from "class-variance-authority";
1
+ import { Button as ButtonPrimitive } from '@base-ui/react/button'
2
+ import { cva, type VariantProps } from 'class-variance-authority'
3
3
 
4
- import { cn } from "#lib/utils";
4
+ import { cn } from '#lib/utils'
5
5
 
6
6
  const buttonVariants = cva(
7
7
  "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
8
8
  {
9
9
  variants: {
10
10
  variant: {
11
- default: "bg-primary text-primary-foreground hover:bg-primary/80",
11
+ default: 'bg-primary text-primary-foreground hover:bg-primary/80',
12
12
  outline:
13
- "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
13
+ 'border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50',
14
14
  secondary:
15
- "bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
15
+ 'bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground',
16
16
  ghost:
17
- "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
17
+ 'hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50',
18
18
  destructive:
19
- "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
19
+ 'bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40',
20
20
  success:
21
- "bg-[#1a7f37]/10 text-[#1a7f37] hover:bg-[#1a7f37]/20 focus-visible:border-[#1a7f37]/40 focus-visible:ring-[#1a7f37]/20 dark:bg-[#3fb950]/20 dark:text-[#7ee787] dark:hover:bg-[#3fb950]/30 dark:focus-visible:ring-[#3fb950]/40",
22
- link: "text-primary underline-offset-4 hover:underline",
21
+ 'bg-[#1a7f37]/10 text-[#1a7f37] hover:bg-[#1a7f37]/20 focus-visible:border-[#1a7f37]/40 focus-visible:ring-[#1a7f37]/20 dark:bg-[#3fb950]/20 dark:text-[#7ee787] dark:hover:bg-[#3fb950]/30 dark:focus-visible:ring-[#3fb950]/40',
22
+ link: 'text-primary underline-offset-4 hover:underline',
23
23
  },
24
24
  size: {
25
25
  default:
26
- "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
26
+ 'h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',
27
27
  xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
28
28
  sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
29
- lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
30
- icon: "size-8",
31
- "icon-xs":
29
+ lg: 'h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',
30
+ icon: 'size-8',
31
+ 'icon-xs':
32
32
  "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
33
- "icon-sm":
34
- "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
35
- "icon-lg": "size-9",
33
+ 'icon-sm':
34
+ 'size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg',
35
+ 'icon-lg': 'size-9',
36
36
  },
37
37
  },
38
38
  defaultVariants: {
39
- variant: "default",
40
- size: "default",
39
+ variant: 'default',
40
+ size: 'default',
41
41
  },
42
42
  }
43
- );
43
+ )
44
44
 
45
45
  function Button({
46
46
  className,
47
- variant = "default",
48
- size = "default",
47
+ variant = 'default',
48
+ size = 'default',
49
49
  ...props
50
50
  }: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
51
51
  return (
@@ -54,7 +54,7 @@ function Button({
54
54
  className={cn(buttonVariants({ variant, size, className }))}
55
55
  {...props}
56
56
  />
57
- );
57
+ )
58
58
  }
59
59
 
60
- export { Button, buttonVariants };
60
+ export { Button, buttonVariants }