From 1954b9d625e809eb7e223a39e697b95cca998f93 Mon Sep 17 00:00:00 2001
From: Charis Lam <26616127+charislam@users.noreply.github.com>
Date: Wed, 18 Mar 2026 13:15:33 -0400
Subject: [PATCH] spike: agnostic ui + non-nextjs test app
---
apps/ui-vite-test/index.html | 12 +
apps/ui-vite-test/package.json | 28 +++
apps/ui-vite-test/src/App.css | 72 ++++++
apps/ui-vite-test/src/App.tsx | 191 +++++++++++++++
apps/ui-vite-test/src/globals.d.ts | 11 +
apps/ui-vite-test/src/main.tsx | 15 ++
apps/ui-vite-test/tsconfig.json | 17 ++
apps/ui-vite-test/vite.config.ts | 7 +
packages/ui/.gitignore | 1 +
packages/ui/base.tsx | 304 ++++++++++++++++++++++++
packages/ui/index.tsx | 309 +------------------------
packages/ui/package.json | 19 ++
packages/ui/postcss.config.js | 10 +
packages/ui/postcss.lib.config.js | 7 +
packages/ui/scripts/build-merge-css.js | 93 ++++++++
packages/ui/src/base-styles.css | 21 ++
packages/ui/tailwind.lib.config.js | 8 +
packages/ui/vite.lib.config.ts | 38 +++
pnpm-lock.yaml | 64 ++++-
turbo.json | 11 +
20 files changed, 926 insertions(+), 312 deletions(-)
create mode 100644 apps/ui-vite-test/index.html
create mode 100644 apps/ui-vite-test/package.json
create mode 100644 apps/ui-vite-test/src/App.css
create mode 100644 apps/ui-vite-test/src/App.tsx
create mode 100644 apps/ui-vite-test/src/globals.d.ts
create mode 100644 apps/ui-vite-test/src/main.tsx
create mode 100644 apps/ui-vite-test/tsconfig.json
create mode 100644 apps/ui-vite-test/vite.config.ts
create mode 100644 packages/ui/base.tsx
create mode 100644 packages/ui/postcss.config.js
create mode 100644 packages/ui/postcss.lib.config.js
create mode 100644 packages/ui/scripts/build-merge-css.js
create mode 100644 packages/ui/src/base-styles.css
create mode 100644 packages/ui/tailwind.lib.config.js
create mode 100644 packages/ui/vite.lib.config.ts
diff --git a/apps/ui-vite-test/index.html b/apps/ui-vite-test/index.html
new file mode 100644
index 00000000000..86f6028e2fb
--- /dev/null
+++ b/apps/ui-vite-test/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ UI Base — Vite Validation
+
+
+
+
+
+
diff --git a/apps/ui-vite-test/package.json b/apps/ui-vite-test/package.json
new file mode 100644
index 00000000000..d9e1e87de29
--- /dev/null
+++ b/apps/ui-vite-test/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "ui-vite-test",
+ "version": "0.0.0",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "preinstall": "npx only-allow pnpm",
+ "dev": "vite",
+ "build": "tsc --noEmit && vite build",
+ "preview": "vite preview",
+ "typecheck": "tsc --noEmit"
+ },
+ "dependencies": {
+ "lucide-react": "^0.436.0",
+ "next-themes": "^0.3.0",
+ "react": "catalog:",
+ "react-dom": "catalog:",
+ "sonner": "^1.5.0",
+ "ui": "workspace:*"
+ },
+ "devDependencies": {
+ "@types/react": "catalog:",
+ "@types/react-dom": "catalog:",
+ "@vitejs/plugin-react": "^4.3.4",
+ "typescript": "catalog:",
+ "vite": "catalog:"
+ }
+}
diff --git a/apps/ui-vite-test/src/App.css b/apps/ui-vite-test/src/App.css
new file mode 100644
index 00000000000..5a8c247ce39
--- /dev/null
+++ b/apps/ui-vite-test/src/App.css
@@ -0,0 +1,72 @@
+/* Layout styles for the ui-vite-test demo page shell.
+ Component styles come from ui/base.css — this file only covers
+ the page wrapper and section spacing used in App.tsx. */
+
+.demo-page {
+ min-height: 100vh;
+ padding: 4rem 3.5rem;
+ max-width: 56rem;
+ margin: 0 auto;
+}
+
+.demo-page h1 {
+ margin-bottom: 0.75rem;
+}
+
+.demo-subtitle {
+ margin-bottom: 3.5rem;
+}
+
+.demo-section {
+ margin-bottom: 4rem;
+}
+
+.demo-section-title {
+ margin-bottom: 1.5rem;
+ padding-bottom: 0.75rem;
+}
+
+.demo-badges {
+ margin-bottom: 1.5rem;
+}
+
+.demo-skeletons {
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
+}
+
+.demo-form {
+ display: flex;
+ flex-direction: column;
+ gap: 1.5rem;
+ max-width: 24rem;
+}
+
+.demo-form-field {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+}
+
+.demo-form-row {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+}
+
+.demo-card {
+ max-width: 24rem;
+}
+
+.demo-alert {
+ max-width: 32rem;
+}
+
+.demo-accordion {
+ max-width: 32rem;
+}
+
+.demo-separator {
+ margin: 2.5rem 0;
+}
diff --git a/apps/ui-vite-test/src/App.tsx b/apps/ui-vite-test/src/App.tsx
new file mode 100644
index 00000000000..34130abc0d2
--- /dev/null
+++ b/apps/ui-vite-test/src/App.tsx
@@ -0,0 +1,191 @@
+import './App.css'
+import { Terminal } from 'lucide-react'
+import {
+ Alert_Shadcn_,
+ AlertDescription_Shadcn_,
+ AlertTitle_Shadcn_,
+ Accordion_Shadcn_,
+ AccordionContent_Shadcn_,
+ AccordionItem_Shadcn_,
+ AccordionTrigger_Shadcn_,
+ Badge,
+ Button,
+ Button_Shadcn_,
+ Card,
+ CardContent,
+ CardHeader,
+ CardTitle,
+ Checkbox_Shadcn_,
+ Input_Shadcn_,
+ Label_Shadcn_,
+ Select_Shadcn_,
+ SelectContent_Shadcn_,
+ SelectItem_Shadcn_,
+ SelectTrigger_Shadcn_,
+ SelectValue_Shadcn_,
+ Separator,
+ Skeleton,
+ Switch,
+ Tabs_Shadcn_,
+ TabsContent_Shadcn_,
+ TabsList_Shadcn_,
+ TabsTrigger_Shadcn_,
+ Tooltip,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger,
+ SonnerToaster,
+} from 'ui/base'
+import { toast } from 'sonner'
+
+// Proof: none of these imports touch next/image, next/link, or next/navigation.
+// If any Next.js module were reachable from ui/base, this file would fail to
+// compile in a non-Next.js environment.
+
+function Section({ title, children }: { title: string; children: React.ReactNode }) {
+ return (
+
+
+ {title}
+
+ {children}
+
+ )
+}
+
+export default function App() {
+ return (
+
+
+
UI Base — Vite Validation
+
+ All components imported from{' '}
+ ui/base{' '}
+ (pre-built, no Next.js).
+
+
+
+
+
+
+
+
+
+ Shadcn Button
+
+
+
+
+
+ Default
+ Success
+ Destructive
+ Warning
+
+
+
+
+
+
+
+
+
+
+
+ Email
+
+
+
+
+ Accept terms
+
+
+
+ Enable notifications
+
+
+
+
+
+
+ US East (N. Virginia)
+ EU West (Ireland)
+ AP Southeast (Singapore)
+
+
+
+
+
+
+
+
+ Project settings
+
+
+
+
+ General
+ Billing
+ Team
+
+
+ General settings content.
+
+
+ Billing settings content.
+
+
+ Team settings content.
+
+
+
+
+
+
+
+
+
+ Build successful
+
+ All base components render correctly without Next.js.
+
+
+
+
+
+
+
+ What is Supabase?
+
+ An open source Firebase alternative built on top of Postgres.
+
+
+
+ Is it free?
+
+ Yes — generous free tier with no credit card required.
+
+
+
+
+
+
+
+
+
+
+ Hover for tooltip
+
+
+ Rendered via Radix UI — no Next.js required.
+
+
+
+
+
+
+
+ )
+}
diff --git a/apps/ui-vite-test/src/globals.d.ts b/apps/ui-vite-test/src/globals.d.ts
new file mode 100644
index 00000000000..a7db6a2c1a1
--- /dev/null
+++ b/apps/ui-vite-test/src/globals.d.ts
@@ -0,0 +1,11 @@
+// Ambient declarations needed when TypeScript follows source files from packages/ui.
+
+declare module '*.css' {
+ const styles: Record
+ export default styles
+}
+
+declare module 'highlightjs-curl' {
+ const languageFunc: unknown
+ export = languageFunc
+}
diff --git a/apps/ui-vite-test/src/main.tsx b/apps/ui-vite-test/src/main.tsx
new file mode 100644
index 00000000000..06affa6f296
--- /dev/null
+++ b/apps/ui-vite-test/src/main.tsx
@@ -0,0 +1,15 @@
+import { StrictMode } from 'react'
+import { createRoot } from 'react-dom/client'
+import { ThemeProvider } from 'next-themes'
+// Pre-built CSS: design tokens + Tailwind utilities + component CSS modules.
+// No Tailwind config needed in this app.
+import 'ui/base.css'
+import App from './App'
+
+createRoot(document.getElementById('root')!).render(
+
+
+
+
+
+)
diff --git a/apps/ui-vite-test/tsconfig.json b/apps/ui-vite-test/tsconfig.json
new file mode 100644
index 00000000000..ef993056103
--- /dev/null
+++ b/apps/ui-vite-test/tsconfig.json
@@ -0,0 +1,17 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "compilerOptions": {
+ "target": "ES2021",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "skipLibCheck": true,
+ "strict": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "react-jsx"
+ },
+ "include": ["src"]
+}
diff --git a/apps/ui-vite-test/vite.config.ts b/apps/ui-vite-test/vite.config.ts
new file mode 100644
index 00000000000..9e039433d05
--- /dev/null
+++ b/apps/ui-vite-test/vite.config.ts
@@ -0,0 +1,7 @@
+import react from '@vitejs/plugin-react'
+import { defineConfig } from 'vite'
+
+// No Tailwind or PostCSS needed — all CSS comes pre-built from ui/base.css.
+export default defineConfig({
+ plugins: [react()],
+})
diff --git a/packages/ui/.gitignore b/packages/ui/.gitignore
index e985853ed84..4a92b4cfb88 100644
--- a/packages/ui/.gitignore
+++ b/packages/ui/.gitignore
@@ -1 +1,2 @@
.vercel
+dist/
diff --git a/packages/ui/base.tsx b/packages/ui/base.tsx
new file mode 100644
index 00000000000..522a1a8db13
--- /dev/null
+++ b/packages/ui/base.tsx
@@ -0,0 +1,304 @@
+// Next.js-agnostic entry point for packages/ui.
+// This is the source of truth for the base bundle.
+//
+// The following components are intentionally excluded because they import from next/*:
+// - src/lib/Markdown (imports next/image)
+// - src/components/Image (imports next/image)
+// - src/components/TextLink (imports next/link)
+// - src/layout/banners (imports next/navigation)
+//
+// New exports should be added here by default.
+// Only add to index.tsx if the component requires Next.js APIs.
+
+// GENERAL
+
+export * from './src/components/Button'
+export * from './src/components/Icon/IconBackground'
+
+// DISPLAYS
+
+export { Card as Card_legacy_ } from './src/components/Card'
+export * from './src/components/Tabs'
+export * from './src/components/Alert'
+export * from './src/components/Accordion'
+export * from './src/components/Collapsible'
+export * from './src/components/CodeBlock'
+export * from './src/components/SimpleCodeBlock'
+export * from './src/components/Mermaid'
+
+// NAV
+
+export * from './src/components/Menu'
+export * from './src/components/NavMenu'
+
+// OVERLAYS
+
+export * from './src/components/Modal'
+export * from './src/components/SidePanel'
+export * from './src/components/Popover'
+
+// HTML
+
+export { Heading } from './src/components/CustomHTMLElements'
+
+// UTILITIES
+
+export * from './src/components/Space'
+export * from './src/components/Loading'
+export * from './src/components/LogoLoader'
+export * from './src/components/AnimatedCounter'
+export * from './src/lib/utils'
+
+// DATA ENTRY
+
+export * from './src/components/Select'
+export * from './src/components/Listbox'
+export * from './src/components/Checkbox'
+export * from './src/components/Input'
+export * from './src/components/InputNumber'
+export * from './src/components/Radio'
+export * from './src/components/Toggle'
+export * from './src/components/Form'
+export * from './src/components/ExpandingTextArea'
+
+export * from './src/components/PrePostTab'
+
+// layout
+export * from './src/components/LoadingLine'
+
+// ai icon
+export * from './src/layout/ai-icon-animation'
+
+// theme switcher
+export * from './src/components/ThemeProvider/themes'
+export * from './src/components/ThemeProvider/singleThemes'
+
+// shadcn
+export * from './src/components/shadcn/ui/dropdown-menu'
+export * from './src/components/shadcn/ui/sonner'
+export * from './src/components/shadcn/ui/sonner-progress'
+export * from './src/components/shadcn/ui/separator'
+export * from './src/components/shadcn/ui/sheet'
+export * from './src/components/shadcn/ui/badge'
+export * from './src/components/shadcn/ui/input-otp'
+export * from './src/components/shadcn/ui/alert-dialog'
+export * from './src/components/shadcn/ui/avatar'
+export * from './src/components/shadcn/ui/drawer'
+export * from './src/components/shadcn/ui/menubar'
+export * from './src/components/shadcn/ui/navigation-menu'
+export * from './src/components/shadcn/ui/progress'
+export * from './src/components/shadcn/ui/skeleton'
+export * from './src/components/shadcn/ui/slider'
+export * from './src/components/shadcn/ui/textarea'
+export * from './src/components/shadcn/ui/toggle-group'
+
+export { Toggle as Toggle_Shadcn_ } from './src/components/shadcn/ui/toggle'
+
+export * from './src/components/shadcn/ui/card'
+
+export {
+ Command as Command_Shadcn_,
+ CommandDialog as CommandDialog,
+ CommandInput as CommandInput_Shadcn_,
+ CommandList as CommandList_Shadcn_,
+ CommandEmpty as CommandEmpty_Shadcn_,
+ CommandGroup as CommandGroup_Shadcn_,
+ CommandItem as CommandItem_Shadcn_,
+ CommandShortcut as CommandShortcut_Shadcn_,
+ CommandSeparator as CommandSeparator_Shadcn_,
+} from './src/components/shadcn/ui/command'
+
+export {
+ ContextMenu as ContextMenu_Shadcn_,
+ ContextMenuTrigger as ContextMenuTrigger_Shadcn_,
+ ContextMenuContent as ContextMenuContent_Shadcn_,
+ ContextMenuItem as ContextMenuItem_Shadcn_,
+ ContextMenuSeparator as ContextMenuSeparator_Shadcn_,
+ ContextMenuLabel as ContextMenuLabel_Shadcn_,
+ ContextMenuRadioGroup as ContextMenuRadioGroup_Shadcn_,
+ ContextMenuRadioItem as ContextMenuRadioItem_Shadcn_,
+ ContextMenuShortcut as ContextMenuShortcut_Shadcn_,
+ ContextMenuSub as ContextMenuSub_Shadcn_,
+ ContextMenuSubContent as ContextMenuSubContent_Shadcn_,
+ ContextMenuSubTrigger as ContextMenuSubTrigger_Shadcn_,
+ ContextMenuCheckboxItem as ContextMenuCheckboxItem_Shadcn_,
+ ContextMenuGroup as ContextMenuGroup_Shadcn_,
+ ContextMenuPortal as ContextMenuPortal_Shadcn_,
+} from './src/components/shadcn/ui/context-menu'
+
+export * from './src/components/shadcn/ui/dialog'
+
+export {
+ Alert as Alert_Shadcn_,
+ AlertTitle as AlertTitle_Shadcn_,
+ AlertDescription as AlertDescription_Shadcn_,
+} from './src/components/shadcn/ui/alert'
+
+export * from './src/components/AlertCollapsible'
+
+export {
+ Field as Field_Shadcn_,
+ FieldContent as FieldContent_Shadcn_,
+ FieldDescription as FieldDescription_Shadcn_,
+ FieldError as FieldError_Shadcn_,
+ FieldGroup as FieldGroup_Shadcn_,
+ FieldLabel as FieldLabel_Shadcn_,
+ FieldLegend as FieldLegend_Shadcn_,
+ FieldSeparator as FieldSeparator_Shadcn_,
+ FieldSet as FieldSet_Shadcn_,
+ FieldTitle as FieldTitle_Shadcn_,
+} from './src/components/shadcn/ui/field'
+
+export {
+ useFormField as useFormField_Shadcn_,
+ Form as Form_Shadcn_,
+ FormItem as FormItem_Shadcn_,
+ FormLabel as FormLabel_Shadcn_,
+ FormControl as FormControl_Shadcn_,
+ FormDescription as FormDescription_Shadcn_,
+ FormMessage as FormMessage_Shadcn_,
+ FormField as FormField_Shadcn_,
+ useWatch as useWatch_Shadcn_,
+} from './src/components/shadcn/ui/form'
+
+export {
+ Popover as Popover_Shadcn_,
+ PopoverTrigger as PopoverTrigger_Shadcn_,
+ PopoverContent as PopoverContent_Shadcn_,
+ PopoverAnchor as PopoverAnchor_Shadcn_,
+ PopoverSeparator as PopoverSeparator_Shadcn_,
+} from './src/components/shadcn/ui/popover'
+
+export {
+ Accordion as Accordion_Shadcn_,
+ AccordionItem as AccordionItem_Shadcn_,
+ AccordionTrigger as AccordionTrigger_Shadcn_,
+ AccordionContent as AccordionContent_Shadcn_,
+} from './src/components/shadcn/ui/accordion'
+
+export {
+ Select as Select_Shadcn_,
+ SelectContent as SelectContent_Shadcn_,
+ SelectGroup as SelectGroup_Shadcn_,
+ SelectItem as SelectItem_Shadcn_,
+ SelectLabel as SelectLabel_Shadcn_,
+ SelectSeparator as SelectSeparator_Shadcn_,
+ SelectTrigger as SelectTrigger_Shadcn_,
+ SelectValue as SelectValue_Shadcn_,
+ SelectScrollUpButton as SelectScrollUpButton_Shadcn_,
+ SelectScrollDownButton as SelectScrollDownButton_Shadcn_,
+} from './src/components/shadcn/ui/select'
+
+export {
+ RadioGroup as RadioGroup_Shadcn_,
+ RadioGroupItem as RadioGroupItem_Shadcn_,
+ RadioGroupLargeItem as RadioGroupLargeItem_Shadcn_,
+} from './src/components/shadcn/ui/radio-group'
+
+export { Slider as Slider_Shadcn_ } from './src/components/shadcn/ui/slider'
+
+export { Input as Input_Shadcn_ } from './src/components/shadcn/ui/input'
+
+export { Button as Button_Shadcn_ } from './src/components/shadcn/ui/button'
+
+export { ButtonGroup, ButtonGroupItem } from './src/components/shadcn/ui/button-group'
+
+export {
+ Breadcrumb as Breadcrumb_Shadcn_,
+ BreadcrumbItem as BreadcrumbItem_Shadcn_,
+ BreadcrumbLink as BreadcrumbLink_Shadcn_,
+ BreadcrumbList as BreadcrumbList_Shadcn_,
+ BreadcrumbEllipsis as BreadcrumbEllipsis_Shadcn_,
+ BreadcrumbPage as BreadcrumbPage_Shadcn_,
+ BreadcrumbSeparator as BreadcrumbSeparator_Shadcn_,
+} from './src/components/shadcn/ui/breadcrumb'
+
+export { TextArea as TextArea_Shadcn_ } from './src/components/shadcn/ui/text-area'
+
+export { Label as Label_Shadcn_ } from './src/components/shadcn/ui/label'
+
+export * from './src/components/shadcn/ui/switch'
+
+export { Checkbox as Checkbox_Shadcn_ } from './src/components/shadcn/ui/checkbox'
+
+export * from './src/components/shadcn/ui/scroll-area'
+
+export * from './src/components/shadcn/ui/hover-card'
+
+export * from './src/components/shadcn/ui/aspect-ratio'
+
+export * from './src/components/shadcn/ui/table'
+export * from './src/components/ShadowScrollArea'
+
+export {
+ Collapsible as Collapsible_Shadcn_,
+ CollapsibleTrigger as CollapsibleTrigger_Shadcn_,
+ CollapsibleContent as CollapsibleContent_Shadcn_,
+} from './src/components/shadcn/ui/collapsible'
+
+export {
+ Tabs as Tabs_Shadcn_,
+ TabsContent as TabsContent_Shadcn_,
+ TabsList as TabsList_Shadcn_,
+ TabsTrigger as TabsTrigger_Shadcn_,
+} from './src/components/shadcn/ui/tabs'
+
+export {
+ TooltipProvider,
+ Tooltip,
+ TooltipTrigger,
+ TooltipContent,
+ TooltipPortal,
+} from './src/components/shadcn/ui/tooltip'
+
+export {
+ HoverCard as HoverCard_Shadcn_,
+ HoverCardTrigger as HoverCardTrigger_Shadcn_,
+ HoverCardContent as HoverCardContent_Shadcn_,
+} from './src/components/shadcn/ui/hover-card'
+
+export * from './src/components/shadcn/ui/calendar'
+
+export { Toggle as Toggle_Shadcn } from './src/components/shadcn/ui/toggle'
+
+export { ScrollArea, ScrollBar, ScrollViewport } from './src/components/shadcn/ui/scroll-area'
+
+export { Separator } from './src/components/shadcn/ui/separator'
+
+export * from './src/components/shadcn/ui/resizable'
+
+export * from './src/components/radio-group-stacked'
+export * from './src/components/radio-group-card'
+
+export * from './src/components/TreeView'
+
+export * from './src/components/shadcn/ui/chart'
+export * from './src/components/shadcn/ui/sidebar'
+
+export * from './src/components/StatusIcon'
+
+// ICONS
+export * from './src/components/Icon/icons/IconBriefcase2'
+export * from './src/components/Icon/icons/IconBroadcast'
+export * from './src/components/Icon/icons/IconChangelog'
+export * from './src/components/Icon/icons/IconDatabaseChanges'
+export * from './src/components/Icon/icons/IconDiscord'
+export * from './src/components/Icon/icons/IconDiscussions'
+export * from './src/components/Icon/icons/IconDocumentation'
+export * from './src/components/Icon/icons/IconGitHubSolid'
+export * from './src/components/Icon/icons/IconIntegrations'
+export * from './src/components/Icon/icons/IconLifeBuoy2'
+export * from './src/components/Icon/icons/IconLinkedinSolid'
+export * from './src/components/Icon/icons/IconMicSolid'
+export * from './src/components/Icon/icons/IconPartners'
+export * from './src/components/Icon/icons/IconPresence'
+export * from './src/components/Icon/icons/IconProductHunt'
+export * from './src/components/Icon/icons/IconTwitterX'
+export * from './src/components/Icon/icons/IconYCombinator'
+export * from './src/components/Icon/icons/IconYoutubeSolid'
+
+// Hooks
+export * from './src/lib/Hooks'
+export * from './src/components/hooks/use-mobile'
+
+export * from './src/components/KeyboardShortcut/KeyboardShortcut'
diff --git a/packages/ui/index.tsx b/packages/ui/index.tsx
index 850a633ea39..93701d2934d 100644
--- a/packages/ui/index.tsx
+++ b/packages/ui/index.tsx
@@ -1,305 +1,14 @@
-// Markdown components
+// Full export: everything in base plus Next.js-specific components.
+// Existing apps import from this entry (unchanged behaviour).
+//
+// To add a new export:
+// - If it does NOT import from next/*, add it to base.tsx
+// - If it DOES import from next/*, add it here only
+export * from './base'
+
+// Next.js-specific components
export * from './src/lib/Markdown'
-
-// GENERAL
-
-export * from './src/components/Button'
-export * from './src/components/Icon/IconBackground'
export * from './src/components/Image'
-
-// DISPLAYS
-
-export { Card as Card_legacy_ } from './src/components/Card'
-export * from './src/components/Tabs'
-export * from './src/components/Alert'
-export * from './src/components/Accordion'
-export * from './src/components/Collapsible'
-export * from './src/components/CodeBlock'
-export * from './src/components/SimpleCodeBlock'
-export * from './src/components/Mermaid'
-
-// NAV
-
-export * from './src/components/Menu'
-export * from './src/components/NavMenu'
-
-// OVERLAYS
-
-export * from './src/components/Modal'
-export * from './src/components/SidePanel'
-export * from './src/components/Popover'
-
-// HTML
-
-export { Heading } from './src/components/CustomHTMLElements'
-
-// UTILITIES
-
-export * from './src/components/Space'
-export * from './src/components/Loading'
-export * from './src/components/LogoLoader'
-export * from './src/components/AnimatedCounter'
-export * from './src/lib/utils'
-
-// DATA ENTRY
-
-export * from './src/components/Select'
-export * from './src/components/Listbox'
-export * from './src/components/Checkbox'
-export * from './src/components/Input'
-export * from './src/components/InputNumber'
-export * from './src/components/Radio'
-export * from './src/components/Toggle'
-export * from './src/components/Form'
-export * from './src/components/ExpandingTextArea'
-
-export * from './src/components/PrePostTab'
-
-// layout
-export * from './src/components/LoadingLine'
-
-// ai icon
-export * from './src/layout/ai-icon-animation'
-
-// theme switcher
-export * from './src/components/ThemeProvider/themes'
-export * from './src/components/ThemeProvider/singleThemes'
-
-// shadcn
-export * from './src/components/shadcn/ui/dropdown-menu'
-export * from './src/components/shadcn/ui/sonner'
-export * from './src/components/shadcn/ui/sonner-progress'
-export * from './src/components/shadcn/ui/separator'
-export * from './src/components/shadcn/ui/sheet'
-export * from './src/components/shadcn/ui/badge'
-export * from './src/components/shadcn/ui/input-otp'
-export * from './src/components/shadcn/ui/alert-dialog'
-export * from './src/components/shadcn/ui/avatar'
-export * from './src/components/shadcn/ui/drawer'
-export * from './src/components/shadcn/ui/menubar'
-export * from './src/components/shadcn/ui/navigation-menu'
-export * from './src/components/shadcn/ui/progress'
-export * from './src/components/shadcn/ui/skeleton'
-export * from './src/components/shadcn/ui/slider'
-export * from './src/components/shadcn/ui/textarea'
-export * from './src/components/shadcn/ui/toggle-group'
-
-export { Toggle as Toggle_Shadcn_ } from './src/components/shadcn/ui/toggle'
-
-export * from './src/components/shadcn/ui/card'
-
-export {
- Command as Command_Shadcn_,
- CommandDialog as CommandDialog,
- CommandInput as CommandInput_Shadcn_,
- CommandList as CommandList_Shadcn_,
- CommandEmpty as CommandEmpty_Shadcn_,
- CommandGroup as CommandGroup_Shadcn_,
- CommandItem as CommandItem_Shadcn_,
- CommandShortcut as CommandShortcut_Shadcn_,
- CommandSeparator as CommandSeparator_Shadcn_,
-} from './src/components/shadcn/ui/command'
-
-export {
- ContextMenu as ContextMenu_Shadcn_,
- ContextMenuTrigger as ContextMenuTrigger_Shadcn_,
- ContextMenuContent as ContextMenuContent_Shadcn_,
- ContextMenuItem as ContextMenuItem_Shadcn_,
- ContextMenuSeparator as ContextMenuSeparator_Shadcn_,
- ContextMenuLabel as ContextMenuLabel_Shadcn_,
- ContextMenuRadioGroup as ContextMenuRadioGroup_Shadcn_,
- ContextMenuRadioItem as ContextMenuRadioItem_Shadcn_,
- ContextMenuShortcut as ContextMenuShortcut_Shadcn_,
- ContextMenuSub as ContextMenuSub_Shadcn_,
- ContextMenuSubContent as ContextMenuSubContent_Shadcn_,
- ContextMenuSubTrigger as ContextMenuSubTrigger_Shadcn_,
- ContextMenuCheckboxItem as ContextMenuCheckboxItem_Shadcn_,
- ContextMenuGroup as ContextMenuGroup_Shadcn_,
- ContextMenuPortal as ContextMenuPortal_Shadcn_,
-} from './src/components/shadcn/ui/context-menu'
-
-export * from './src/components/shadcn/ui/dialog'
-
-export {
- Alert as Alert_Shadcn_,
- AlertTitle as AlertTitle_Shadcn_,
- AlertDescription as AlertDescription_Shadcn_,
-} from './src/components/shadcn/ui/alert'
-
-export * from './src/components/AlertCollapsible'
-
-export {
- Field as Field_Shadcn_,
- FieldContent as FieldContent_Shadcn_,
- FieldDescription as FieldDescription_Shadcn_,
- FieldError as FieldError_Shadcn_,
- FieldGroup as FieldGroup_Shadcn_,
- FieldLabel as FieldLabel_Shadcn_,
- FieldLegend as FieldLegend_Shadcn_,
- FieldSeparator as FieldSeparator_Shadcn_,
- FieldSet as FieldSet_Shadcn_,
- FieldTitle as FieldTitle_Shadcn_,
-} from './src/components/shadcn/ui/field'
-
-export {
- useFormField as useFormField_Shadcn_,
- Form as Form_Shadcn_,
- FormItem as FormItem_Shadcn_,
- FormLabel as FormLabel_Shadcn_,
- FormControl as FormControl_Shadcn_,
- FormDescription as FormDescription_Shadcn_,
- FormMessage as FormMessage_Shadcn_,
- FormField as FormField_Shadcn_,
- useWatch as useWatch_Shadcn_,
-} from './src/components/shadcn/ui/form'
-
-export {
- Popover as Popover_Shadcn_,
- PopoverTrigger as PopoverTrigger_Shadcn_,
- PopoverContent as PopoverContent_Shadcn_,
- PopoverAnchor as PopoverAnchor_Shadcn_,
- PopoverSeparator as PopoverSeparator_Shadcn_,
-} from './src/components/shadcn/ui/popover'
-
-export {
- Accordion as Accordion_Shadcn_,
- AccordionItem as AccordionItem_Shadcn_,
- AccordionTrigger as AccordionTrigger_Shadcn_,
- AccordionContent as AccordionContent_Shadcn_,
-} from './src/components/shadcn/ui/accordion'
-
-export {
- Select as Select_Shadcn_,
- SelectContent as SelectContent_Shadcn_,
- SelectGroup as SelectGroup_Shadcn_,
- SelectItem as SelectItem_Shadcn_,
- SelectLabel as SelectLabel_Shadcn_,
- SelectSeparator as SelectSeparator_Shadcn_,
- SelectTrigger as SelectTrigger_Shadcn_,
- SelectValue as SelectValue_Shadcn_,
- SelectScrollUpButton as SelectScrollUpButton_Shadcn_,
- SelectScrollDownButton as SelectScrollDownButton_Shadcn_,
-} from './src/components/shadcn/ui/select'
-
-export {
- RadioGroup as RadioGroup_Shadcn_,
- RadioGroupItem as RadioGroupItem_Shadcn_,
- RadioGroupLargeItem as RadioGroupLargeItem_Shadcn_,
-} from './src/components/shadcn/ui/radio-group'
-
-export { Slider as Slider_Shadcn_ } from './src/components/shadcn/ui/slider'
-
-export { Input as Input_Shadcn_ } from './src/components/shadcn/ui/input'
-
-export { Button as Button_Shadcn_ } from './src/components/shadcn/ui/button'
-
-export { ButtonGroup, ButtonGroupItem } from './src/components/shadcn/ui/button-group'
-
-export {
- Breadcrumb as Breadcrumb_Shadcn_,
- BreadcrumbItem as BreadcrumbItem_Shadcn_,
- BreadcrumbLink as BreadcrumbLink_Shadcn_,
- BreadcrumbList as BreadcrumbList_Shadcn_,
- BreadcrumbEllipsis as BreadcrumbEllipsis_Shadcn_,
- BreadcrumbPage as BreadcrumbPage_Shadcn_,
- BreadcrumbSeparator as BreadcrumbSeparator_Shadcn_,
-} from './src/components/shadcn/ui/breadcrumb'
-
-export { TextArea as TextArea_Shadcn_ } from './src/components/shadcn/ui/text-area'
-
-export { Label as Label_Shadcn_ } from './src/components/shadcn/ui/label'
-
-export * from './src/components/shadcn/ui/switch'
-
-export { Checkbox as Checkbox_Shadcn_ } from './src/components/shadcn/ui/checkbox'
-
-export * from './src/components/shadcn/ui/scroll-area'
-
-export * from './src/components/shadcn/ui/hover-card'
-
-export * from './src/components/shadcn/ui/aspect-ratio'
-
-export * from './src/components/shadcn/ui/table'
-export * from './src/components/ShadowScrollArea'
-
-export {
- Collapsible as Collapsible_Shadcn_,
- CollapsibleTrigger as CollapsibleTrigger_Shadcn_,
- CollapsibleContent as CollapsibleContent_Shadcn_,
-} from './src/components/shadcn/ui/collapsible'
-
-export {
- Tabs as Tabs_Shadcn_,
- TabsContent as TabsContent_Shadcn_,
- TabsList as TabsList_Shadcn_,
- TabsTrigger as TabsTrigger_Shadcn_,
-} from './src/components/shadcn/ui/tabs'
-
-export {
- TooltipProvider,
- Tooltip,
- TooltipTrigger,
- TooltipContent,
- TooltipPortal,
-} from './src/components/shadcn/ui/tooltip'
-
-export {
- HoverCard as HoverCard_Shadcn_,
- HoverCardTrigger as HoverCardTrigger_Shadcn_,
- HoverCardContent as HoverCardContent_Shadcn_,
-} from './src/components/shadcn/ui/hover-card'
-
-export * from './src/components/shadcn/ui/calendar'
-
-export { Toggle as Toggle_Shadcn } from './src/components/shadcn/ui/toggle'
-
-export { ScrollArea, ScrollBar, ScrollViewport } from './src/components/shadcn/ui/scroll-area'
-
-export { Separator } from './src/components/shadcn/ui/separator'
-
-export * from './src/components/shadcn/ui/resizable'
-
-export * from './src/components/radio-group-stacked'
-export * from './src/components/radio-group-card'
-
-export * from './src/components/TreeView'
-
-export * from './src/components/shadcn/ui/chart'
-export * from './src/components/shadcn/ui/sidebar'
-
-// links
-
export * from './src/components/TextLink'
-
-// used for LW
export * from './src/layout/banners'
-
-export * from './src/components/StatusIcon'
-
-// ICONS
-// export icons
-export * from './src/components/Icon/icons/IconBriefcase2'
-export * from './src/components/Icon/icons/IconBroadcast'
-export * from './src/components/Icon/icons/IconChangelog'
-export * from './src/components/Icon/icons/IconDatabaseChanges'
-export * from './src/components/Icon/icons/IconDiscord'
-export * from './src/components/Icon/icons/IconDiscussions'
-export * from './src/components/Icon/icons/IconDocumentation'
-export * from './src/components/Icon/icons/IconGitHubSolid'
-export * from './src/components/Icon/icons/IconIntegrations'
-export * from './src/components/Icon/icons/IconLifeBuoy2'
-export * from './src/components/Icon/icons/IconLinkedinSolid'
-export * from './src/components/Icon/icons/IconMicSolid'
-export * from './src/components/Icon/icons/IconPartners'
-export * from './src/components/Icon/icons/IconPresence'
-export * from './src/components/Icon/icons/IconProductHunt'
-export * from './src/components/Icon/icons/IconTwitterX'
-export * from './src/components/Icon/icons/IconYCombinator'
-export * from './src/components/Icon/icons/IconYoutubeSolid'
-
-// Export hooks
-export * from './src/lib/Hooks'
-export * from './src/components/hooks/use-mobile'
-
-export * from './src/components/KeyboardShortcut/KeyboardShortcut'
diff --git a/packages/ui/package.json b/packages/ui/package.json
index 91f3b5dc16e..a98747bc92e 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -3,10 +3,23 @@
"version": "0.0.0",
"main": "./index.tsx",
"types": "./index.tsx",
+ "exports": {
+ ".": {
+ "types": "./index.tsx",
+ "default": "./index.tsx"
+ },
+ "./base": {
+ "types": "./base.tsx",
+ "import": "./dist/base.js"
+ },
+ "./base.css": "./dist/base.css",
+ "./src/*": "./src/*"
+ },
"license": "MIT",
"sideEffects": false,
"scripts": {
"preinstall": "npx only-allow pnpm",
+ "build": "vite build --config vite.lib.config.ts && tailwindcss -c tailwind.lib.config.js -i src/base-styles.css -o dist/base-tw.css && node scripts/build-merge-css.js",
"typecheck": "tsc --noEmit",
"generate-demo-tailwind-classes": "node internals/tokens/generate-demo-tailwind-classes.js",
"cleanse-css-for-tailwind": "node internals/tokens/cleanse-css-for-tailwind.js",
@@ -80,7 +93,13 @@
"tailwindcss": "catalog:",
"vaul": "^0.9.9"
},
+ "peerDependenciesMeta": {
+ "next": {
+ "optional": true
+ }
+ },
"devDependencies": {
+ "@vitejs/plugin-react": "^4.3.4",
"@ctrl/tinycolor": "^3.4.0",
"@testing-library/jest-dom": "^6.6.0",
"@testing-library/react": "^16.0.0",
diff --git a/packages/ui/postcss.config.js b/packages/ui/postcss.config.js
new file mode 100644
index 00000000000..b96175def0a
--- /dev/null
+++ b/packages/ui/postcss.config.js
@@ -0,0 +1,10 @@
+// PostCSS config for packages/ui.
+// Used by both:
+// - `pnpm build` (vite.lib.config.ts): expands @apply in CSS modules for the
+// pre-built base bundle, and generates Tailwind utilities for base-styles.css
+// - `pnpm test` (vitest): expands @apply so CSS modules compile correctly in jsdom
+module.exports = {
+ plugins: {
+ tailwindcss: { config: './tailwind.lib.config.js' },
+ },
+}
diff --git a/packages/ui/postcss.lib.config.js b/packages/ui/postcss.lib.config.js
new file mode 100644
index 00000000000..3750e011892
--- /dev/null
+++ b/packages/ui/postcss.lib.config.js
@@ -0,0 +1,7 @@
+// PostCSS config used exclusively by vite.lib.config.ts during the library build.
+// Tailwind processes @apply directives in CSS modules using the lib content paths.
+module.exports = {
+ plugins: {
+ tailwindcss: { config: './tailwind.lib.config.js' },
+ },
+}
diff --git a/packages/ui/scripts/build-merge-css.js b/packages/ui/scripts/build-merge-css.js
new file mode 100644
index 00000000000..db048d61dff
--- /dev/null
+++ b/packages/ui/scripts/build-merge-css.js
@@ -0,0 +1,93 @@
+// Merges the two intermediate CSS files produced during the library build into
+// the final dist/base.css that consumers import.
+//
+// Build pipeline:
+// 1. vite build → dist/base-components.css (CSS modules, @apply expanded)
+// 2. tailwindcss → dist/base-tw.css (Tailwind utilities + design tokens)
+// 3. this script → dist/base.css (font-face + combined, intermediates deleted)
+//
+// Order: font-face first, then utilities, then component-specific rules.
+
+const fs = require('fs')
+const path = require('path')
+
+const dist = path.resolve(__dirname, '../dist')
+const srcFonts = path.resolve(__dirname, '../src/fonts')
+const distFonts = path.join(dist, 'fonts')
+
+// Copy font files to dist/fonts/ so the @font-face urls resolve correctly.
+if (!fs.existsSync(distFonts)) fs.mkdirSync(distFonts, { recursive: true })
+for (const file of fs.readdirSync(srcFonts)) {
+ fs.copyFileSync(path.join(srcFonts, file), path.join(distFonts, file))
+}
+
+// @font-face declarations — URLs are relative to dist/base.css.
+const fontFaceCss = `@font-face {
+ font-family: 'custom-font';
+ src: url('./fonts/CustomFont-Book.woff2') format('woff2');
+ font-weight: 400;
+ font-style: normal;
+ font-display: swap;
+}
+@font-face {
+ font-family: 'custom-font';
+ src: url('./fonts/CustomFont-BookItalic.woff2') format('woff2');
+ font-weight: 400;
+ font-style: italic;
+ font-display: swap;
+}
+@font-face {
+ font-family: 'custom-font';
+ src: url('./fonts/CustomFont-Medium.woff2') format('woff2');
+ font-weight: 500;
+ font-style: normal;
+ font-display: swap;
+}
+@font-face {
+ font-family: 'custom-font';
+ src: url('./fonts/CustomFont-Bold.woff2') format('woff2');
+ font-weight: 700;
+ font-style: normal;
+ font-display: swap;
+}
+@font-face {
+ font-family: 'custom-font';
+ src: url('./fonts/CustomFont-BoldItalic.woff2') format('woff2');
+ font-weight: 700;
+ font-style: italic;
+ font-display: swap;
+}
+@font-face {
+ font-family: 'custom-font';
+ src: url('./fonts/CustomFont-Black.woff2') format('woff2');
+ font-weight: 800;
+ font-style: normal;
+ font-display: swap;
+}
+@font-face {
+ font-family: 'custom-font';
+ src: url('./fonts/CustomFont-BlackItalic.woff2') format('woff2');
+ font-weight: 800;
+ font-style: italic;
+ font-display: swap;
+}
+/* Activate fonts via CSS variables, matching the design-system app's next/font setup. */
+:root {
+ --font-custom: 'custom-font', Circular, 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ --font-source-code-pro: 'Source Code Pro', 'Office Code Pro', Menlo, monospace;
+}
+`
+
+const twPath = path.join(dist, 'base-tw.css')
+const componentsPath = path.join(dist, 'base-components.css')
+const outputPath = path.join(dist, 'base.css')
+
+const tw = fs.existsSync(twPath) ? fs.readFileSync(twPath, 'utf8') : ''
+const components = fs.existsSync(componentsPath) ? fs.readFileSync(componentsPath, 'utf8') : ''
+
+fs.writeFileSync(outputPath, fontFaceCss + '\n' + tw + (components ? '\n' + components : ''))
+
+if (fs.existsSync(twPath)) fs.rmSync(twPath)
+if (fs.existsSync(componentsPath)) fs.rmSync(componentsPath)
+
+console.log('dist/base.css written (%d bytes)', fs.statSync(outputPath).size)
diff --git a/packages/ui/src/base-styles.css b/packages/ui/src/base-styles.css
new file mode 100644
index 00000000000..4f4587ad288
--- /dev/null
+++ b/packages/ui/src/base-styles.css
@@ -0,0 +1,21 @@
+/* Design tokens — CSS custom properties for the Supabase design system */
+@import '../build/css/source/global.css';
+@import '../build/css/themes/dark.css';
+@import '../build/css/themes/light.css';
+
+/* Tailwind layers — utilities are generated by scanning src/** during build */
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@layer base {
+ * {
+ @apply border-border;
+ }
+ body {
+ font-synthesis-weight: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ }
+}
diff --git a/packages/ui/tailwind.lib.config.js b/packages/ui/tailwind.lib.config.js
new file mode 100644
index 00000000000..824e777ca13
--- /dev/null
+++ b/packages/ui/tailwind.lib.config.js
@@ -0,0 +1,8 @@
+// Tailwind config for the pre-built base bundle.
+// Scans all base component source files so every utility class used in JSX
+// or via @apply in CSS modules is included in dist/base.css.
+const config = require('config/tailwind.config')
+
+module.exports = config({
+ content: ['./src/**/*.{tsx,ts,js}', './base.tsx'],
+})
diff --git a/packages/ui/vite.lib.config.ts b/packages/ui/vite.lib.config.ts
new file mode 100644
index 00000000000..6d499b5bda1
--- /dev/null
+++ b/packages/ui/vite.lib.config.ts
@@ -0,0 +1,38 @@
+import { resolve } from 'path'
+import react from '@vitejs/plugin-react'
+import { defineConfig } from 'vite'
+
+// Types are served from the source base.tsx file directly (via exports["./base"].types).
+// No separate .d.ts generation is needed.
+
+export default defineConfig({
+ plugins: [react()],
+
+ css: {
+ // Point Vite at the package directory so it finds postcss.config.js here.
+ // This ensures @apply directives in CSS modules are expanded by Tailwind
+ // during the lib build.
+ postcss: resolve(__dirname, '.'),
+ },
+
+ build: {
+ lib: {
+ entry: resolve(__dirname, 'base.tsx'),
+ formats: ['es'],
+ fileName: () => 'base.js',
+ },
+ rollupOptions: {
+ // Externalize every package-level import so the bundle only contains
+ // the UI component code itself. All runtime deps are provided by the
+ // consuming app (resolved via pnpm workspace hoisting).
+ external: (id) =>
+ !id.startsWith('.') && !id.startsWith('/') && !id.startsWith('\0'),
+ output: {
+ // Name the extracted CSS distinctly so the merge script can find it.
+ assetFileNames: 'base-components[extname]',
+ },
+ },
+ // All CSS (CSS modules + any imported CSS) lands in a single file.
+ cssCodeSplit: false,
+ },
+})
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index cc3f6b1da7b..b0cf5c5495b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -833,7 +833,7 @@ importers:
version: 1.1.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@sentry/nextjs':
specifier: 'catalog:'
- version: 10.27.0(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@16.1.7(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1)(supports-color@8.1.1)(webpack@5.94.0)
+ version: 10.27.0(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@16.1.7(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1)(supports-color@8.1.1)(webpack@5.94.0)
'@std/path':
specifier: npm:@jsr/std__path@^1.0.8
version: '@jsr/std__path@1.0.8'
@@ -983,13 +983,13 @@ importers:
version: 0.52.2
next:
specifier: ~16.1.7
- version: 16.1.7(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4)
+ version: 16.1.7(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4)
next-themes:
specifier: ^0.3.0
version: 0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
nuqs:
specifier: 2.7.1
- version: 2.7.1(@tanstack/react-router@1.158.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(next@16.1.7(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react-router@7.12.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
+ version: 2.7.1(@tanstack/react-router@1.158.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(next@16.1.7(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react-router@7.12.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
openai:
specifier: ^4.75.1
version: 4.104.0(encoding@0.1.13)(ws@8.18.3)(zod@3.25.76)
@@ -1254,7 +1254,7 @@ importers:
version: 2.11.3(@types/node@22.13.14)(typescript@5.9.2)
next-router-mock:
specifier: ^0.9.13
- version: 0.9.13(next@16.1.7(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1)
+ version: 0.9.13(next@16.1.7(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1)
node-mocks-http:
specifier: ^1.17.2
version: 1.17.2(@types/node@22.13.14)
@@ -1587,6 +1587,43 @@ importers:
specifier: 'catalog:'
version: 7.1.11(@types/node@22.13.14)(jiti@2.5.1)(sass@1.77.4)(terser@5.39.0)(tsx@4.20.3)(yaml@2.8.1)
+ apps/ui-vite-test:
+ dependencies:
+ lucide-react:
+ specifier: ^0.436.0
+ version: 0.436.0(react@18.3.1)
+ next-themes:
+ specifier: ^0.3.0
+ version: 0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ react:
+ specifier: 'catalog:'
+ version: 18.3.1
+ react-dom:
+ specifier: 'catalog:'
+ version: 18.3.1(react@18.3.1)
+ sonner:
+ specifier: ^1.5.0
+ version: 1.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ ui:
+ specifier: workspace:*
+ version: link:../../packages/ui
+ devDependencies:
+ '@types/react':
+ specifier: 'catalog:'
+ version: 18.3.3
+ '@types/react-dom':
+ specifier: 'catalog:'
+ version: 18.3.0
+ '@vitejs/plugin-react':
+ specifier: ^4.3.4
+ version: 4.3.4(supports-color@8.1.1)(vite@7.1.11(@types/node@22.13.14)(jiti@2.5.1)(sass@1.77.4)(terser@5.39.0)(tsx@4.20.3)(yaml@2.8.1))
+ typescript:
+ specifier: 'catalog:'
+ version: 5.9.2
+ vite:
+ specifier: 'catalog:'
+ version: 7.1.11(@types/node@22.13.14)(jiti@2.5.1)(sass@1.77.4)(terser@5.39.0)(tsx@4.20.3)(yaml@2.8.1)
+
apps/www:
dependencies:
'@bsmnt/scrollytelling':
@@ -2201,7 +2238,7 @@ importers:
version: 18.3.0
next-router-mock:
specifier: ^0.9.13
- version: 0.9.13(next@16.1.7(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1)
+ version: 0.9.13(next@16.1.7(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1)
tsconfig:
specifier: workspace:*
version: link:../tsconfig
@@ -2569,6 +2606,9 @@ importers:
'@types/react-syntax-highlighter':
specifier: ^15.5.13
version: 15.5.13
+ '@vitejs/plugin-react':
+ specifier: ^4.3.4
+ version: 4.3.4(supports-color@8.1.1)(vite@7.1.11(@types/node@22.13.14)(jiti@2.5.1)(sass@1.77.4)(terser@5.39.0)(tsx@4.20.3)(yaml@2.8.1))
'@vitest/coverage-v8':
specifier: ^3.2.0
version: 3.2.4(supports-color@8.1.1)(vitest@3.2.4)
@@ -25208,7 +25248,7 @@ snapshots:
- supports-color
- webpack
- '@sentry/nextjs@10.27.0(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@16.1.7(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1)(supports-color@8.1.1)(webpack@5.94.0)':
+ '@sentry/nextjs@10.27.0(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@16.1.7(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1)(supports-color@8.1.1)(webpack@5.94.0)':
dependencies:
'@opentelemetry/api': 1.9.0
'@opentelemetry/semantic-conventions': 1.38.0
@@ -25221,7 +25261,7 @@ snapshots:
'@sentry/react': 10.27.0(react@18.3.1)
'@sentry/vercel-edge': 10.27.0
'@sentry/webpack-plugin': 4.6.1(encoding@0.1.13)(supports-color@8.1.1)(webpack@5.94.0)
- next: 16.1.7(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4)
+ next: 16.1.7(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4)
resolve: 1.22.8
rollup: 4.59.0
stacktrace-parser: 0.1.10
@@ -33431,9 +33471,9 @@ snapshots:
next: 15.5.13(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4)
react: 18.3.1
- next-router-mock@0.9.13(next@16.1.7(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1):
+ next-router-mock@0.9.13(next@16.1.7(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1):
dependencies:
- next: 16.1.7(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4)
+ next: 16.1.7(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4)
react: 18.3.1
next-seo@6.5.0(next@15.5.13(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
@@ -33475,7 +33515,7 @@ snapshots:
- '@babel/core'
- babel-plugin-macros
- next@16.1.7(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4):
+ next@16.1.7(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4):
dependencies:
'@next/env': 16.1.7
'@swc/helpers': 0.5.15
@@ -33818,13 +33858,13 @@ snapshots:
mitt: 3.0.1
next: 15.5.13(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4)
- nuqs@2.7.1(@tanstack/react-router@1.158.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(next@16.1.7(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react-router@7.12.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1):
+ nuqs@2.7.1(@tanstack/react-router@1.158.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(next@16.1.7(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react-router@7.12.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1):
dependencies:
'@standard-schema/spec': 1.0.0
react: 18.3.1
optionalDependencies:
'@tanstack/react-router': 1.158.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- next: 16.1.7(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4)
+ next: 16.1.7(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4)
react-router: 7.12.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
nuqs@2.8.1(@tanstack/react-router@1.158.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(next@15.5.13(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react-router@7.12.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1):
diff --git a/turbo.json b/turbo.json
index 050e48bbb24..6206ec49ec6 100644
--- a/turbo.json
+++ b/turbo.json
@@ -6,6 +6,17 @@
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**", "!.next/cache/**/*", "!.next/dev/**/*"]
},
+ "ui#build": {
+ "dependsOn": ["^build"],
+ "outputs": ["dist/**"]
+ },
+ "ui-vite-test#dev": {
+ "dependsOn": ["ui#build"],
+ "cache": false
+ },
+ "ui-vite-test#build": {
+ "dependsOn": ["ui#build"]
+ },
"design-system#build": {
"dependsOn": ["^build"],
"env": [