@adea-ai/ui 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/LICENSE +201 -0
  2. package/dist/components/account-drawer.d.ts +1 -1
  3. package/dist/components/account-drawer.js +12 -12
  4. package/dist/components/on-screen-controls.js +12 -12
  5. package/dist/components/scene-settings.d.ts +3 -3
  6. package/dist/components/scene-settings.js +11 -11
  7. package/dist/components/theme-provider.d.ts +1 -1
  8. package/dist/components/theme-provider.js +2 -2
  9. package/dist/components/theme-toggle.js +8 -8
  10. package/dist/components/ui/badge.d.ts +3 -3
  11. package/dist/components/ui/badge.js +15 -15
  12. package/dist/components/ui/button.d.ts +2 -2
  13. package/dist/components/ui/button.js +19 -19
  14. package/dist/components/ui/card.d.ts +1 -1
  15. package/dist/components/ui/card.js +3 -3
  16. package/dist/components/ui/dialog.d.ts +4 -4
  17. package/dist/components/ui/dialog.js +10 -10
  18. package/dist/components/ui/drawer.d.ts +5 -5
  19. package/dist/components/ui/drawer.js +26 -26
  20. package/dist/components/ui/dropdown-menu.d.ts +5 -5
  21. package/dist/components/ui/dropdown-menu.js +12 -12
  22. package/dist/components/ui/empty.d.ts +7 -7
  23. package/dist/components/ui/empty.js +11 -11
  24. package/dist/components/ui/field.d.ts +12 -12
  25. package/dist/components/ui/field.js +22 -22
  26. package/dist/components/ui/input.d.ts +2 -2
  27. package/dist/components/ui/input.js +3 -3
  28. package/dist/components/ui/label.d.ts +2 -2
  29. package/dist/components/ui/label.js +3 -3
  30. package/dist/components/ui/radio-group.d.ts +2 -2
  31. package/dist/components/ui/radio-group.js +6 -6
  32. package/dist/components/ui/separator.d.ts +1 -1
  33. package/dist/components/ui/separator.js +5 -5
  34. package/dist/components/ui/skeleton.d.ts +1 -1
  35. package/dist/components/ui/skeleton.js +2 -2
  36. package/dist/components/ui/spinner.d.ts +2 -2
  37. package/dist/components/ui/spinner.js +3 -3
  38. package/dist/components/ui/switch.d.ts +2 -2
  39. package/dist/components/ui/switch.js +5 -5
  40. package/dist/components/ui/tabs.d.ts +2 -2
  41. package/dist/components/ui/tabs.js +13 -13
  42. package/dist/components/ui/toggle-group.d.ts +6 -6
  43. package/dist/components/ui/toggle-group.js +13 -13
  44. package/dist/components/ui/toggle.d.ts +2 -2
  45. package/dist/components/ui/toggle.js +11 -11
  46. package/dist/components/ui/tooltip.d.ts +3 -3
  47. package/dist/components/ui/tooltip.js +5 -5
  48. package/dist/components/version-dialog.d.ts +1 -1
  49. package/dist/components/version-dialog.js +33 -33
  50. package/dist/components/workspace-brand.js +1 -1
  51. package/dist/components/workspace-logo.d.ts +1 -1
  52. package/dist/index.d.ts +19 -19
  53. package/dist/index.js +19 -19
  54. package/dist/lib/utils.d.ts +1 -1
  55. package/dist/lib/utils.js +2 -2
  56. package/dist/lib/version-notes.js +18 -18
  57. package/package.json +24 -9
  58. package/src/components/account-drawer.tsx +27 -27
  59. package/src/components/on-screen-controls.tsx +45 -45
  60. package/src/components/scene-settings.tsx +55 -55
  61. package/src/components/theme-provider.tsx +7 -7
  62. package/src/components/theme-toggle.tsx +20 -20
  63. package/src/components/ui/badge.tsx +20 -20
  64. package/src/components/ui/button.tsx +24 -24
  65. package/src/components/ui/card.tsx +6 -6
  66. package/src/components/ui/dialog.tsx +24 -24
  67. package/src/components/ui/drawer.tsx +55 -55
  68. package/src/components/ui/dropdown-menu.tsx +39 -39
  69. package/src/components/ui/empty.tsx +25 -25
  70. package/src/components/ui/field.tsx +55 -55
  71. package/src/components/ui/input.tsx +7 -7
  72. package/src/components/ui/label.tsx +7 -7
  73. package/src/components/ui/radio-group.tsx +9 -9
  74. package/src/components/ui/separator.tsx +7 -7
  75. package/src/components/ui/skeleton.tsx +5 -5
  76. package/src/components/ui/spinner.tsx +6 -6
  77. package/src/components/ui/switch.tsx +8 -8
  78. package/src/components/ui/tabs.tsx +21 -21
  79. package/src/components/ui/toggle-group.tsx +25 -25
  80. package/src/components/ui/toggle.tsx +15 -15
  81. package/src/components/ui/tooltip.tsx +13 -13
  82. package/src/components/version-dialog.tsx +113 -113
  83. package/src/components/workspace-brand.tsx +4 -4
  84. package/src/components/workspace-logo.tsx +2 -2
  85. package/src/index.tsx +19 -19
  86. package/src/lib/utils.ts +3 -3
  87. package/src/lib/version-notes.ts +23 -23
  88. package/src/styles/conventional-workspace.css +26 -26
  89. package/src/styles/globals.css +2 -2
  90. package/src/styles/theme.css +1 -1
  91. package/src/styles/workspace-shell.css +2 -2
@@ -1,20 +1,20 @@
1
1
  export function plainTextFromMarkdown(markdown) {
2
2
  return markdown
3
- .replace(/\r\n/g, "\n")
4
- .replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1")
5
- .replace(/\[([^\]]+)\]\([^)]*\)/g, "$1")
6
- .replace(/^[ \t]*#{1,6}[ \t]*/gm, "")
7
- .replace(/^[ \t]*>[ \t]?/gm, "")
8
- .replace(/^[ \t]*---+[ \t]*$/gm, "")
9
- .replace(/^[ \t]*[-*+][ \t]+/gm, "• ")
10
- .replace(/^[ \t]*\d+\.[ \t]+/gm, "")
11
- .replace(/```[^\n]*\n?/g, "")
12
- .replace(/`([^`]+)`/g, "$1")
13
- .replace(/\*\*([^*]+)\*\*/g, "$1")
14
- .replace(/__([^_]+)__/g, "$1")
15
- .replace(/\*([^*]+)\*/g, "$1")
16
- .replace(/_([^_]+)_/g, "$1")
17
- .replace(/\n{3,}/g, "\n\n")
3
+ .replace(/\r\n/g, '\n')
4
+ .replace(/!\[([^\]]*)\]\([^)]*\)/g, '$1')
5
+ .replace(/\[([^\]]+)\]\([^)]*\)/g, '$1')
6
+ .replace(/^[ \t]*#{1,6}[ \t]*/gm, '')
7
+ .replace(/^[ \t]*>[ \t]?/gm, '')
8
+ .replace(/^[ \t]*---+[ \t]*$/gm, '')
9
+ .replace(/^[ \t]*[-*+][ \t]+/gm, '• ')
10
+ .replace(/^[ \t]*\d+\.[ \t]+/gm, '')
11
+ .replace(/```[^\n]*\n?/g, '')
12
+ .replace(/`([^`]+)`/g, '$1')
13
+ .replace(/\*\*([^*]+)\*\*/g, '$1')
14
+ .replace(/__([^_]+)__/g, '$1')
15
+ .replace(/\*([^*]+)\*/g, '$1')
16
+ .replace(/_([^_]+)_/g, '$1')
17
+ .replace(/\n{3,}/g, '\n\n')
18
18
  .trim();
19
19
  }
20
20
  export function formatReleaseDate(value) {
@@ -24,8 +24,8 @@ export function formatReleaseDate(value) {
24
24
  if (Number.isNaN(date.getTime()))
25
25
  return value;
26
26
  return new Intl.DateTimeFormat(undefined, {
27
- day: "numeric",
28
- month: "short",
29
- year: "numeric",
27
+ day: 'numeric',
28
+ month: 'short',
29
+ year: 'numeric',
30
30
  }).format(date);
31
31
  }
package/package.json CHANGED
@@ -1,9 +1,21 @@
1
1
  {
2
2
  "name": "@adea-ai/ui",
3
- "version": "0.12.0",
4
- "type": "module",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
3
+ "version": "0.13.0",
4
+ "description": "Shared UI kit for Adea: Base UI-backed shadcn primitives, workspace shells, and theme styles.",
5
+ "keywords": [
6
+ "base-ui",
7
+ "components",
8
+ "react",
9
+ "shadcn",
10
+ "tailwind",
11
+ "workspace"
12
+ ],
13
+ "license": "Apache-2.0",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/adea-ai/adea.git",
17
+ "directory": "packages/ui"
18
+ },
7
19
  "files": [
8
20
  "dist",
9
21
  "src",
@@ -11,6 +23,13 @@
11
23
  "tsconfig.json",
12
24
  "README.md"
13
25
  ],
26
+ "type": "module",
27
+ "main": "dist/index.js",
28
+ "types": "dist/index.d.ts",
29
+ "imports": {
30
+ "#components/*": "./src/components/*.tsx",
31
+ "#lib/*": "./src/lib/*.ts"
32
+ },
14
33
  "exports": {
15
34
  ".": {
16
35
  "types": "./dist/index.d.ts",
@@ -33,12 +52,8 @@
33
52
  "./theme.css": "./src/styles/theme.css",
34
53
  "./workspace-shell.css": "./src/styles/workspace-shell.css"
35
54
  },
36
- "imports": {
37
- "#components/*": "./src/components/*.tsx",
38
- "#lib/*": "./src/lib/*.ts"
39
- },
40
55
  "scripts": {
41
- "lint": "eslint .",
56
+ "lint": "oxlint",
42
57
  "build": "tsc -p tsconfig.json",
43
58
  "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput",
44
59
  "typecheck": "tsc -p tsconfig.json --noEmit"
@@ -1,9 +1,9 @@
1
- "use client";
1
+ 'use client'
2
2
 
3
- import { createPortal } from "react-dom";
4
- import { useEffect, useState, type ReactNode } from "react";
5
- import { UserRound } from "lucide-react";
6
- import { Button } from "#components/ui/button";
3
+ import { createPortal } from 'react-dom'
4
+ import { useEffect, useState, type ReactNode } from 'react'
5
+ import { UserRound } from 'lucide-react'
6
+ import { Button } from '#components/ui/button'
7
7
  import {
8
8
  Drawer,
9
9
  DrawerClose,
@@ -12,21 +12,21 @@ import {
12
12
  DrawerHeader,
13
13
  DrawerTitle,
14
14
  DrawerTrigger,
15
- } from "#components/ui/drawer";
16
- import { ThemeToggle } from "./theme-toggle";
15
+ } from '#components/ui/drawer'
16
+ import { ThemeToggle } from './theme-toggle'
17
17
 
18
18
  export type AccountDrawerProps = {
19
- accountLabel?: string;
20
- authenticated?: boolean;
21
- busy?: boolean;
22
- musicControl?: ReactNode;
23
- triggerTargetId?: string;
24
- onSignIn?: () => void;
25
- onSignOut?: () => void;
26
- };
19
+ accountLabel?: string
20
+ authenticated?: boolean
21
+ busy?: boolean
22
+ musicControl?: ReactNode
23
+ triggerTargetId?: string
24
+ onSignIn?: () => void
25
+ onSignOut?: () => void
26
+ }
27
27
 
28
28
  export function AccountDrawer({
29
- accountLabel = "Sign in",
29
+ accountLabel = 'Sign in',
30
30
  authenticated = false,
31
31
  busy = false,
32
32
  musicControl,
@@ -34,11 +34,11 @@ export function AccountDrawer({
34
34
  onSignIn,
35
35
  onSignOut,
36
36
  }: AccountDrawerProps) {
37
- const [triggerTarget, setTriggerTarget] = useState<HTMLElement | null>(null);
37
+ const [triggerTarget, setTriggerTarget] = useState<HTMLElement | null>(null)
38
38
 
39
39
  useEffect(() => {
40
- setTriggerTarget(triggerTargetId ? document.getElementById(triggerTargetId) : null);
41
- }, [triggerTargetId]);
40
+ setTriggerTarget(triggerTargetId ? document.getElementById(triggerTargetId) : null)
41
+ }, [triggerTargetId])
42
42
 
43
43
  const trigger = (
44
44
  <DrawerTrigger
@@ -55,7 +55,7 @@ export function AccountDrawer({
55
55
  <UserRound aria-hidden="true" />
56
56
  <span>{accountLabel}</span>
57
57
  </DrawerTrigger>
58
- );
58
+ )
59
59
 
60
60
  return (
61
61
  <Drawer swipeDirection="right">
@@ -75,8 +75,8 @@ export function AccountDrawer({
75
75
  <DrawerTitle className="truncate">{accountLabel}</DrawerTitle>
76
76
  <DrawerDescription>
77
77
  {authenticated
78
- ? "Signed in · workspace saved"
79
- : "Guest workspace · sign in anytime"}
78
+ ? 'Signed in · workspace saved'
79
+ : 'Guest workspace · sign in anytime'}
80
80
  </DrawerDescription>
81
81
  </div>
82
82
  </div>
@@ -108,8 +108,8 @@ export function AccountDrawer({
108
108
  </h2>
109
109
  <p className="text-sm text-muted-foreground">
110
110
  {authenticated
111
- ? "Sign out on this device without removing your saved workspace."
112
- : "Sign in or create an account to keep this workspace across devices."}
111
+ ? 'Sign out on this device without removing your saved workspace.'
112
+ : 'Sign in or create an account to keep this workspace across devices.'}
113
113
  </p>
114
114
  </div>
115
115
  <DrawerClose
@@ -117,17 +117,17 @@ export function AccountDrawer({
117
117
  <Button
118
118
  type="button"
119
119
  className="shrink-0"
120
- variant={authenticated ? "outline" : "default"}
120
+ variant={authenticated ? 'outline' : 'default'}
121
121
  disabled={busy}
122
122
  onClick={authenticated ? onSignOut : onSignIn}
123
123
  />
124
124
  }
125
125
  >
126
- {authenticated ? "Sign out" : "Sign in"}
126
+ {authenticated ? 'Sign out' : 'Sign in'}
127
127
  </DrawerClose>
128
128
  </section>
129
129
  </div>
130
130
  </DrawerContent>
131
131
  </Drawer>
132
- );
132
+ )
133
133
  }
@@ -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
  }