Compare commits

..
83 Commits
Author SHA1 Message Date
hanzo-dev 103b8c1f91 fix: rename turbo.json pipeline → tasks (Turbo 2.0) 2026-03-28 14:52:09 -07:00
hanzo-dev c93c0f0a98 chore: gitignore generated static API files (build artifacts) 2026-03-28 14:41:32 -07:00
hanzo-dev d4c5b88519 fix: force-static on all API routes for CF Pages export
Add dynamic=force-static + generateStaticParams to registry routes.
Replace server-only chat/search routes with static stubs.
Remove conflicting /api/registry/route.ts (dir collision).
Update next.config.mjs for CF_PAGES env.
2026-03-28 00:15:05 -07:00
hanzo-dev 98632915fe chore: add generated static registry API files 2026-03-27 21:29:16 -07:00
hanzo-dev 7f19d72d28 fix: add missing AI SDK deps for chat and search routes
The chat API route (app/api/chat/route.ts) imports @ai-sdk/openai-compatible
and ai but neither was declared in app/package.json. Also skip puppeteer
Chrome download in .npmrc since it's only used for optional screenshot
capture and its postinstall failure breaks pnpm install in CI.
2026-03-27 20:28:30 -07:00
hanzo-dev 1fcf9dce94 feat: add AI chat and search API routes for ui.hanzo.ai
- /api/chat: streaming RAG chat about UI components (zen-coder-flash)
- /api/search: proxy to Hanzo Cloud search-docs with publishable key
- lib/search.ts: search config (cloud backend, pk-hanzo-ui-search-2026)

Same pattern as docs.hanzo.ai AI search. Users can chat on the site
and ask questions about components.
2026-03-27 19:31:18 -07:00
hanzo-dev 2515b596b7 feat: add registry API routes and static build for MCP tool
Add Next.js API routes at /api/registry/ for dynamic component queries
(server mode). Add build-registry-api.mts script that generates static
JSON files at /api/registry/ for CF Pages / static hosting.

Endpoints:
- /api/registry — component list
- /api/registry/components/{name} — component with source
- /api/registry/search?q= — search
- /api/registry/index — full manifest (single payload)

Static files built during `pnpm build` step.
2026-03-27 19:15:54 -07:00
hanzo-dev 2ad4de8410 fix: add component-helpers dep to checkbox/button/list-item 2026-03-27 17:26:12 -07:00
hanzo-dev 88863caa79 fix: ALL UI deps 3.0.0->3.0.1, publish 3.0.2 2026-03-27 16:50:15 -07:00
hanzo-dev 86c312b7d4 fix: purge workspace:*, publish 3.0.1 2026-03-27 15:54:38 -07:00
hanzo-dev becf552ac5 feat: all UI packages at 3.0.0 (unified) 2026-03-27 14:52:23 -07:00
hanzo-dev 6894aac69d fix: ALL UI packages 2.0.8, internal deps point to correct published versions 2026-03-27 14:18:17 -07:00
hanzo-dev 14219cf9b5 fix: ALL UI packages 2.0.7, helpers->component-helpers in all dist 2026-03-27 13:35:34 -07:00
hanzo-dev 54447b5025 fix: button/list-item import useCurrentColor from component-helpers, bump 2.0.6 2026-03-27 12:04:16 -07:00
hanzo-dev aca5c3cd41 fix: all imports @hanzo/gui-* -> @hanzogui/*, TamaguiRoot -> GuiRoot in dist, bump 2.0.5 2026-03-26 20:27:38 -07:00
hanzo-dev 1a9f041acc fix: repair JSON formatting in package.json 2026-03-24 20:32:33 -07:00
hanzo-dev 793cf731ab fix: correct package names @hanzo/gui-* -> @hanzogui/* 2026-03-24 20:31:50 -07:00
hanzo-dev 45df2ea8b9 fix: bump UI packages to 2.0.4 with consistent deps 2026-03-24 20:31:14 -07:00
hanzo-dev 1a6cc7888b fix: resolve workspace:* to 2.0.1, bump UI packages 2026-03-24 19:22:01 -07:00
hanzo-dev 179ae0de2e docs: update LLM.md with upstream sync info and current structure 2026-03-24 19:13:53 -07:00
hanzo-dev 51c4d12dce feat: sync upstream shadcn/ui — shadcn@4.1.0, v4 app, font system, chart improvements
Upstream sync from shadcn-ui/ui (1686 commits since last merge base).

Key changes:
- packages/shadcn upgraded to 4.1.0 (CLI font transformers, scaffold from github, chart colors)
- apps/v4 replaces apps/www as the primary docs/registry app
- Font system: 25+ heading font registries, font markers utility, @supports override
- Chart improvements: recharts v3 compat, radial chart fixes
- templates/ updated with monorepo variants (astro, vite, react-router, start)
- skills/shadcn AI skill definitions added
- deprecated/ removed (auth, auth-firebase, cli, www)

Preserved Hanzo-only paths: app/, pkg/, demo/, docs/, template/next/
2026-03-24 19:04:31 -07:00
hanzo-dev 6fe7078b06 fix: update checkout client 2026-03-24 18:42:34 -07:00
hanzo-dev 3cdad07e32 feat: migrate tamagui primitives to @hanzogui/*, rename tokens/tamagui to tokens/gui 2026-03-24 18:42:34 -07:00
hanzo-dev 8a492a2d18 feat: migrate UI packages from @hanzo/gui-* to @hanzogui/* scope, purge all tamagui refs, v2.0.0 2026-03-24 18:42:34 -07:00
Darkhorse7starsandhanzo-dev fb6da37f9f fix: ESLint 10 config compatibility and cleanup temp files
- Rewrite app/eslint.config.mjs to use @typescript-eslint/parser directly
  (fixes "Class extends value undefined" error with typescript-eslint 8.x)
- Add typescript-eslint override in root package.json for ESLint 10 compat
- Remove deprecated .eslintignore (use flat config ignores instead)
- Delete temp/backup files (.bak, .old, .tmp)

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-03-23 16:55:41 -05:00
Darkhorse7starsandhanzo-dev 41d618d1d8 fix: resolve CI type check and lint failures
- Downgrade app/ react-resizable-panels to v3 (code uses v3 API names)
- Add missing @eslint/js dependency for eslint.config.mjs
- Fix TS18048 in chart-line-dots-custom.tsx (null check cx/cy)
- Fix TS7006 in ai-code.tsx (explicit any types for monaco callbacks)

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-03-23 12:41:22 -05:00
Darkhorse7starsandhanzo-dev 4cb8cac44c fix: use react-resizable-panels v3 API for compatibility
Changed imports from v4 names (Group, Separator) to v3 names
(PanelGroup, PanelResizeHandle) to fix build errors in consumers
using react-resizable-panels v3. Updated peer dep to ^3.0.0.

Bump @hanzo/ui to 5.5.1.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-03-23 12:22:29 -05:00
hanzo-dev 5aee8715d7 fix: resolve 34 missing gui workspace deps to published npm versions
The gui-* packages were imported from hanzo/gui but 34 underlying
utility/core packages (gui-build, gui-core, gui-helpers, gui-web, etc.)
were not included in the workspace. Changed their workspace:* refs to
the published 2.0.0-rc.29 versions so pnpm can resolve from registry.
2026-03-22 19:02:28 -07:00
hanzo-dev aa7f45b29d chore: brand + gui publish artifacts 2026-03-22 18:38:17 -07:00
hanzo-dev 65d32dda4c feat: add @hanzo/gui-* UI component packages from hanzo/gui rebrand 2026-03-21 13:08:01 -07:00
hanzo-dev 9ba70a4e2c chore: update all dependencies to latest 2026-03-21 11:44:34 -07:00
hanzo-dev 5850560681 chore: bump @hanzo/ui to 5.5.0 (dash components) 2026-03-18 14:52:20 -07:00
hanzo-dev 189b34971f fix: clean names — dash/layout, dash/sidebar, dash/table, dash/form, dash/crud 2026-03-18 14:49:17 -07:00
hanzo-dev e010864f26 fix: rename admin->dash in tsup build config 2026-03-18 14:47:05 -07:00
hanzo-dev e74efbab46 chore: bump @hanzo/ui to 5.4.0 (adds @hanzo/ui/dash) 2026-03-18 14:40:24 -07:00
hanzo-dev 4884736c69 feat: add @hanzo/ui/dash — shared dashboard UI (layout, data table, forms, CRUD) 2026-03-18 14:39:39 -07:00
hanzo-dev bb48d51d70 fix: update repository URL from react-sdk to ui for npm provenance 2026-03-16 22:03:53 -07:00
hanzo-dev 3d88cc75eb chore: bump @hanzo/ui to 5.3.42 2026-03-16 21:51:19 -07:00
hanzo-dev bc8945ff4e fix: rename Developer tier to Pay As You Go
"Developer" is the free/OSS tier, not a paid plan. Rename to
"Pay As You Go" to match actual billing semantics.
2026-03-16 21:50:12 -07:00
hanzo-dev 9627ebbbbc feat: move upgrade CTA to top, improve zero-usage display
- Upgrade CTA now renders first (above usage card) when not subscribed
- "No usage yet" instead of "— tokens" when zero usage
- "Credits available" with balance instead of "$0.00 API spend"
- "Start using Hanzo AI to see stats" subtitle for zero-usage state
2026-03-16 21:38:50 -07:00
hanzo-dev 80147c328f feat(navigation): expand AppSwitcher from 6 to 26 apps with grouped layout
Unified app switcher is the single source of truth for cross-app navigation.
All services now accessible from every Hanzo app via HanzoHeader.

- DEFAULT_HANZO_APPS: 26 apps across 7 groups (Core, AI, Observability,
  Infrastructure, Apps, Business, Resources)
- OrgDomains: white-label domain mapping for all 4 orgs (hanzo, lux, zoo, pars)
  expanded from 7 to 27 fields
- getAppsForOrg(): returns org-aware URLs for all 26 apps
- AppSwitcher: grouped 2-column grid with section headers, scrollable
2026-03-13 04:08:28 -07:00
hanzo-dev 29b3652711 fix: expand BillingSection type to include all billing sections 2026-03-11 18:29:53 -07:00
hanzo-dev 891818443a feat(@hanzo/ui): add billing module to dist build
Add billing/index tsup entry so @hanzo/ui/billing resolves from npm.
Update package.json export to point to dist instead of source.
Bumps to v5.3.41.
2026-03-11 17:55:00 -07:00
hanzo-dev 532d8e692c feat(@hanzo/ui): add navigation/hanzo-shell build entry
Add separate tsup entry point for navigation/hanzo-shell so the
wildcard package export ./navigation/* resolves to a real dist file.
Bumps version to 5.3.40.
2026-03-11 17:40:01 -07:00
hanzo-dev e45833b5f2 feat: add hard refresh and settings to HanzoHeader shell 2026-03-11 11:38:55 -07:00
hanzo-dev dffa6cef34 feat: add @hanzo/ui/auth package with IAMLoginButton and AuthGuard
New auth components for unified IAM integration:
- IAMLoginButton: "Sign in with Hanzo" button that initiates OAuth flow
- AuthGuard: wrapper that redirects to IAM when unauthenticated
- Re-exports useHanzoAuth, UserOrgDropdown, HanzoUser/HanzoOrg types
Adds ./auth and ./auth/* subpath exports to package.json.
2026-03-10 16:59:46 -07:00
hanzo-dev 04407e9cb5 feat(shell): org-aware app switcher, white-label domains, hanzo.space
- chat.hanzo.ai → hanzo.chat (canonical domain)
- Add hanzo.space (Storage) to DEFAULT_HANZO_APPS
- Add ORG_DOMAINS map: hanzo, lux, zoo, pars with per-org domains
- Add getAppsForOrg() for white-label app switcher URLs
- HanzoHeader now resolves org-specific domains automatically
- UserOrgDropdown Account/Billing links adapt to current org
- Export OrgDomains type and getAppsForOrg from hanzo-shell
2026-03-10 16:06:51 -07:00
hanzo-dev 9f0e37d8c3 fix(billing): export BillingSection type from @hanzo/ui/billing 2026-03-10 15:32:03 -07:00
hanzo-dev bf18ef7a35 chore: gitignore dist-test output 2026-03-03 10:43:12 -08:00
hanzo-dev edda5a41b8 feat: add UserAvatar with three-tier fallback (photo → Gravatar → generative SVG)
BeamAvatar: deterministic face-like SVG from any string, zero deps, boring-avatars beam algorithm
UserAvatar: three-tier fallback — uploaded photo, Gravatar SHA-256, generative beam SVG
UserOrgDropdown now uses UserAvatar instead of simple letter initials
2026-03-03 20:37:01 -08:00
Zach Kelling 320885b073 chore(ui): bump to v5.3.38
Published with HanzoCommandPalette component.
2026-03-03 17:35:30 -08:00
Zach Kelling d97b670580 feat(ui): add HanzoCommandPalette — shared Cmd+K command palette
Zero-dependency React component for cross-app command navigation.
Supports extensible app-specific commands, keyboard nav, search filtering.
2026-03-03 17:33:30 -08:00
Zach Kelling b8ecd6c408 fix(ci): resolve TypeScript build errors blocking deployment
- resizable.tsx: update react-resizable-panels v4 imports (PanelGroup→Group, PanelResizeHandle→Separator)
- blob.ts: wrap Buffer in Uint8Array for BlobPart compatibility
- tsconfig.build.json: exclude typo-plugin JS from type-checked build
2026-03-03 14:33:02 -08:00
Zach Kelling 4086d54305 test: add static CI test to validate all docs URLs have matching MDX files
Runs 228 tests checking that every href in docs.ts config resolves to
an actual MDX file. Catches 404s before deployment without needing a
running server. Reports orphaned MDX files not in nav config.
2026-03-03 14:25:06 -08:00
Zach Kelling 6831117b97 feat: full docs modernization — zero 404s, 585 pages, dep updates
- Enable all 15 finance component docs (from .disabled → .mdx)
- Create stock-market.mdx, 8 chart docs, 8 block docs, 2 framework docs
- Add direction.tsx component (RTL/LTR support from upstream shadcn)
- Add xs/icon-xs button sizes, data-variant/data-size attributes
- Fix build-registry.mts to handle default exports in namespace re-exports
- Add default props to order-entry, positions-list, orders-history, trading-panel
- Fix 18 navigation stubs → re-export from root implementations
- Add 44 orphaned MDX files to nav (installation, dark-mode, desktop, guides, etc)
- Migrate 6 framer-motion imports → motion/react
- Bump React 19.2.0→19.2.4, Next.js 16.0.1→16.1.6, motion→12.34.0
- Align lucide-react, sonner v2, tailwind-merge v3, postcss-selector-parser v7
- Remove framer-motion dep (superseded by motion)
- Fix @types/react-dom, TypeScript versions across workspaces
2026-03-03 07:34:51 -08:00
hanzo-dev 6ea1042d44 feat: @hanzo/shop payment popup + Square billing components
- @hanzo/shop: new embeddable 3-tab topup widget (card/crypto/bank)
  - HanzoTopup dialog, TopupButton trigger
  - CardInput (Square Web Payments SDK), CryptoInput (MPC chains), BankInput (ACH)
  - hooks: useSquareCard, useTopup
- @hanzo/commerce client: add getWalletAddress, addBankAccount, addCryptoWallet, topup
- @hanzo/ui billing: comprehensive billing dashboard components
  - OverviewDashboard, PaymentManager (Square), CreditsPanel, UsagePanel
  - InvoicesPayments, TransactionsPanel, SquareCardForm
  - CostExplorer, SpendAlerts, AccountMembers, AccountSwitcher
  - BillingSettings, SupportTiersPanel, PromotionsPanel
  - GuidedSetup, AnimatedCard, StatusBar
2026-03-02 11:09:00 -08:00
hanzo-dev d9f090bb53 feat(commerce): update commerce client SDK 2026-03-01 19:40:49 -08:00
hanzo-dev e1184390dc feat(@hanzo/commerce): extend client with checkout, coupons, referrals, affiliates
Add comprehensive commerce client methods:
- validateCoupon / applyCoupon (pre-checkout validation)
- createCheckoutSession (hosted checkout, returns checkoutUrl)
- tokenizeCard (S2S card tokenization without external SDK)
- referrals: createReferralProgram, getReferralLink, trackReferral, getReferralStats
- affiliates: registerAffiliate, getAffiliateStats, getAffiliateCommissions
- Backwards-compatible: commerceUrl still works, baseUrl preferred
- Default baseUrl: https://api.hanzo.ai
- Request timeout support (timeoutMs, default 15s)
2026-03-01 16:20:08 -08:00
hanzo-dev a42e158a07 fix(ci): add NEXT_PUBLIC_APP_URL env and coverage json-summary reporter 2026-03-01 16:01:01 -08:00
hanzo-dev 6347fe0aeb feat: remove @hanzo/auth, all auth goes through @hanzo/iam
- Move pkg/auth and pkg/auth-firebase to deprecated/ (excluded from workspace)
- Remove @hanzo/auth from commerce and checkout peerDependencies
- Remove useAuth() from payment-step-form; contact form defaults to empty strings
- Update pnpm lockfile

Production auth is now handled entirely by IAM (hanzo.id). The legacy
auth package is preserved in deprecated/ for reference.
2026-03-01 15:39:33 -08:00
hanzo-dev f08abfe55a chore: update pnpm lockfile 2026-03-01 15:27:19 -08:00
hanzo-dev fbe58782d9 chore(@hanzo/ui): bump to 5.3.37 — publish model components 2026-03-01 15:25:31 -08:00
hanzo-dev 16ffaea878 feat(@hanzo/ui): add shared model components — ModelCard, ModelTable, ModelLibrary, ZenEnso
Adds @hanzo/ui/models export with data-agnostic model UI components
that work across hanzo.ai, zen-docs, and any other Hanzo site:

- ZenModelLike/ModelFamilyLike interfaces (structural compatibility
  with @hanzo/zen-models, no cross-package dependency needed)
- ModelCard: rich clickable card with status badges, spec, action buttons
- ModelTable: static table view with pricing and context columns
- ModelLibrary: full catalog with family sections and filter toggle
- ZenEnso: animated SVG enso circle logo component

Fix ./models ESM export path (dist/models/index.mjs not dist/src/models/).
2026-03-01 15:19:28 -08:00
hanzo-dev a4f1a1c16f feat: add HanzoShell shared navigation components
New pkg/ui/src/navigation/hanzo-shell/ module:
- HanzoHeader: sticky 14px header with logo/breadcrumb/app-switcher/user-dropdown
- HanzoMark: official H-mark SVG with hover origami animation + brand context menu
  (right-click → Brand Guidelines, Press Kit, Download Logo, Copy SVG, hanzo.ai)
- AppSwitcher: 3x3-grid icon → dropdown listing all Hanzo apps
- UserOrgDropdown: avatar/initials, org switcher (from IAM groups), sign-out
- useHanzoAuth: zero-dep hook reads hanzo-auth-token from localStorage,
  fetches iam.hanzo.ai/api/userinfo, maps IAM groups to org list
- DEFAULT_HANZO_APPS: Account, Billing, Console, Chat, Platform

Design tokens: bg-[#09090b]/90, border-white/[0.07], text-[11-13px], monochrome
Exported from @hanzo/ui navigation index for use across all Hanzo properties.
2026-03-01 12:38:58 -08:00
hanzo-dev 8ed0e27d73 [cleanup] remove AI slop files 2026-02-28 12:25:38 -08:00
hanzo-dev 9958dde439 feat: add @hanzo/og programmatic OG image package
Shared package for generating OpenGraph/social images across all Hanzo
sites. Supports 6 layout variants (page, model, code, stat, split,
minimal) with inline styles for next/og ImageResponse compatibility.
Includes HANZO_AI_THEME and HANZO_INDUSTRIES_THEME brand presets.
2026-02-28 10:45:00 -08:00
hanzo-dev e64e9cdbdc perf: reduce @hanzo/ui bundle 74% by removing duplicate entries and enabling minification
- Remove duplicate tsup entries: primitives-export and primitives/index
  both compiled same primitives/index-standard.ts → save 2×436K=870K
- Enable minify:true; safe because 'use client' banner is added post-build
  via onSuccess hook, not as source directive
- Update ./primitives export in package.json to point to ./dist/index.mjs
- Result: dist 10M → 2.6M, index.mjs 436K → 314K (minified)

Published as @hanzo/ui@5.3.36
2026-02-28 10:27:43 -08:00
hanzo-dev 095773b2da chore: bump versions — @hanzo/ui@5.3.35, @hanzo/auth-firebase@1.0.0, @hanzo/commerce@7.5.1 2026-02-27 21:30:24 -08:00
hanzo-dev 926985e5ad chore: update generated registry and color files from build 2026-02-27 21:28:17 -08:00
hanzo-dev 24ace5354a fix: resolve build errors — add avatar/org to HanzoUserInfoStore, fix Zod v3/v4 type mismatch, generate d.ts files in @hanzo/ui build 2026-02-27 21:20:16 -08:00
hanzo-dev 412ee93a25 chore: untrack .claude/settings.local.json, add to gitignore 2026-02-27 20:42:26 -08:00
hanzo-dev 751111a0d7 chore: update pnpm-lock.yaml 2026-02-27 19:35:51 -08:00
hanzo-dev 8dab1688f7 Remove Firebase from @hanzo/auth and @hanzo/commerce
Firebase has been completely removed from core packages:
- @hanzo/auth v2.8.0: stub implementations replace Firebase auth/wallet
- @hanzo/commerce v7.5.0: no-op order persistence replaces Firestore
- Firebase code preserved in @hanzo/auth-firebase (optional package)
- Zero Firebase imports in auth and commerce packages
2026-02-27 19:35:51 -08:00
Zoo Queenandhanzo-dev 7887485e95 feat(commerce): add billingRefund method for correction deposits
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-02-20 19:07:18 -08:00
Zoo Queenandhanzo-dev 3e1283365a refactor: clean Commerce API client — one class, no aliases
Commerce is THE client for the Commerce API. No aliases, no backwards
compat wrappers. import { Commerce } from '@hanzo/commerce'

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-02-17 21:06:22 -08:00
Zoo Queenandhanzo-dev 8919c32d0f feat: rename BillingClient to CommerceClient, add @hanzo/commerce/client
CommerceClient is the canonical Commerce API client. @hanzo/commerce/billing
re-exports as BillingClient for backwards compat.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-02-17 21:05:35 -08:00
Zoo Queenandhanzo-dev be95271bc4 fix: update repository URLs to hanzoai/ui for npm provenance
npm provenance requires repository.url to match the publishing repo.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-02-17 21:02:20 -08:00
Zoo Queenandhanzo-dev f2752141ff feat: add BillingClient to @hanzo/commerce, fix npm-publish token
- billing.ts: canonical billing client for Commerce API
- Exports at @hanzo/commerce/billing
- Fix workspace:* peerDeps (resolve to version ranges for npm compat)
- Fix npm-publish workflow to use NPM_TOKEN secret

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-02-17 20:59:46 -08:00
Zoo Queenandhanzo-dev b6311022f3 fix: add avatar and organization fields to Firebase auth store
All HanzoUserInfo implementations must include the new fields.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-02-17 20:55:38 -08:00
Zoo Queenandhanzo-dev 07f1182d52 feat: add IAM auth service as primary auth provider
- IamAuthService: OIDC/PKCE-based auth, auto-registers when IAM config present
- Enhanced types: avatar, organization fields on HanzoUserInfo
- AuthServiceConf: IAM fields (iamServerUrl, iamClientId, etc.)
- Firebase becomes optional integration, IAM is the default
- Fix npm-publish workflow: add id-token permission for provenance

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-02-17 20:52:49 -08:00
Zoo Queenandhanzo-dev bacd545b67 fix: resolve pnpm version conflict in publish workflow
Remove explicit version to let packageManager field in package.json
control the pnpm version.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-02-17 20:47:34 -08:00
Zoo Queenandhanzo-dev d95693b61a chore: bump @hanzo/auth to 2.7.0
Adds shared OrgProjectSwitcher component for unified org/project
selection across all Hanzo apps.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-02-17 20:45:28 -08:00
Zoo Queenandhanzo-dev dce79e1309 feat: add shared OrgProjectSwitcher component to @hanzo/auth
Props-driven org/project/environment switcher used across all
Hanzo services. Supports single-org display, multi-org dropdown,
project selector, and environment badge.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-02-17 20:38:07 -08:00
2440 changed files with 97735 additions and 13536 deletions
-9
View File
@@ -1,9 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="640" viewBox="0 0 1280 640" role="img" aria-label="ui">
<rect width="1280" height="640" fill="#0A0A0A"/>
<svg x="96" y="215" width="210" height="210" viewBox="0 0 67 67"><path d="M22.21 67V44.6369H0V67H22.21Z" fill="#fff"/><path d="M66.7038 22.3184H22.2534L0.0878906 44.6367H44.4634L66.7038 22.3184Z" fill="#fff"/><path d="M22.21 0H0V22.3184H22.21V0Z" fill="#fff"/><path d="M66.7198 0H44.5098V22.3184H66.7198V0Z" fill="#fff"/><path d="M66.7198 67V44.6369H44.5098V67H66.7198Z" fill="#fff"/></svg>
<text x="378" y="276" font-family="Inter,system-ui,-apple-system,sans-serif" font-size="78" font-weight="800" letter-spacing="-2" fill="#ffffff">ui</text>
<text x="378" y="322" font-family="Inter,system-ui,sans-serif" font-size="30" fill="#ffffff" opacity=".66">React component library for AI applications</text>
<rect x="378" y="338" width="806" height="3" rx="1.5" fill="#ffffff" opacity=".9"/>
<text x="378" y="390" font-family="Inter,system-ui,sans-serif" font-size="24" font-weight="600" fill="#ffffff" opacity=".5">github.com/hanzoai</text>
<text x="1184" y="390" text-anchor="end" font-family="Inter,system-ui,sans-serif" font-size="24" font-weight="600" fill="#ffffff" opacity=".5">hanzo.ai</text>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

+1 -1
View File
@@ -4,7 +4,7 @@
import { exec } from "child_process"
import fs from "fs"
const pkgJsonPath = "pkgs/shadcn/package.json"
const pkgJsonPath = "packages/shadcn/package.json"
try {
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath))
exec("git rev-parse --short HEAD", (err, stdout) => {
+1 -1
View File
@@ -4,7 +4,7 @@
import { exec } from "child_process"
import fs from "fs"
const pkgJsonPath = "pkgs/shadcn/package.json"
const pkgJsonPath = "packages/shadcn/package.json"
try {
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath))
exec("git rev-parse --short HEAD", (err, stdout) => {
+17 -17
View File
@@ -18,7 +18,7 @@ concurrency:
jobs:
lint:
name: Lint
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -47,14 +47,14 @@ jobs:
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
run: pnpm install --frozen-lockfile
- name: Run linting
run: pnpm run lint
typecheck:
name: Type Check
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -83,19 +83,19 @@ jobs:
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
run: pnpm install --frozen-lockfile
- name: Build UI package
run: cd pkgs/ui && pnpm run build
run: cd pkg/ui && pnpm run build
- name: Run type checking
run: |
cd app && pnpm run typecheck
cd ../pkgs/ui && pnpm run tc --noEmit
cd ../pkg/ui && pnpm run tc --noEmit
build:
name: Build
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -124,10 +124,10 @@ jobs:
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
run: pnpm install --frozen-lockfile
- name: Build UI package
run: cd pkgs/ui && pnpm run build:full
run: cd pkg/ui && pnpm run build:full
- name: Build app
run: cd app && pnpm run build
@@ -140,11 +140,11 @@ jobs:
name: build-artifacts
path: |
app/.next
pkgs/ui/dist
pkg/ui/dist
test:
name: Test
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -173,10 +173,10 @@ jobs:
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
run: pnpm install --frozen-lockfile
- name: Run pkgs/ui tests
run: cd pkgs/ui && pnpm test -- --run
- name: Run pkg/ui tests
run: cd pkg/ui && pnpm test -- --run
- name: Run app tests
run: |
@@ -190,12 +190,12 @@ jobs:
if: always()
uses: codecov/codecov-action@v3
with:
files: ./pkgs/ui/coverage/lcov.info
files: ./pkg/ui/coverage/lcov.info
flags: unit
deploy-preview:
name: Deploy Preview
runs-on: hanzo-deploy-linux-amd64
runs-on: ubuntu-latest
needs: [lint, typecheck, build]
if: github.event_name == 'pull_request'
steps:
@@ -244,7 +244,7 @@ jobs:
status:
name: CI Status
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
needs: [lint, typecheck, build, test]
if: always()
steps:
+3 -3
View File
@@ -6,7 +6,7 @@ on:
jobs:
lint:
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
name: pnpm lint
steps:
- uses: actions/checkout@v3
@@ -42,7 +42,7 @@ jobs:
- run: pnpm lint
format:
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
name: pnpm format:check
steps:
- uses: actions/checkout@v3
@@ -83,7 +83,7 @@ jobs:
- run: pnpm format:check
tsc:
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
name: pnpm typecheck
steps:
- uses: actions/checkout@v3
+5 -5
View File
@@ -9,7 +9,7 @@ on:
jobs:
coverage:
name: Test Coverage
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
steps:
- name: Checkout
@@ -26,15 +26,15 @@ jobs:
version: 9
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
run: pnpm install --frozen-lockfile
- name: Run tests with coverage
run: cd pkgs/ui && pnpm test:coverage
run: cd pkg/ui && pnpm test:coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: ./pkgs/ui/coverage/lcov.info
files: ./pkg/ui/coverage/lcov.info
flags: unit
name: hanzo-ui-coverage
@@ -44,7 +44,7 @@ jobs:
with:
script: |
const fs = require('fs');
const coverage = JSON.parse(fs.readFileSync('./pkgs/ui/coverage/coverage-summary.json', 'utf8'));
const coverage = JSON.parse(fs.readFileSync('./pkg/ui/coverage/coverage-summary.json', 'utf8'));
const total = coverage.total;
const comment = `## Test Coverage Report\n\n` +
`Lines: ${total.lines.pct}%\n` +
+4 -4
View File
@@ -22,7 +22,7 @@ concurrency:
jobs:
build:
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
@@ -53,11 +53,11 @@ jobs:
- name: Install dependencies
run: |
pnpm install --no-frozen-lockfile
pnpm install --frozen-lockfile
- name: Build @hanzo/ui package
run: |
cd pkgs/ui && pnpm build
cd pkg/ui && pnpm build
- name: Capture screenshots (optional)
if: github.event.inputs.capture_screenshots == 'true'
@@ -88,7 +88,7 @@ jobs:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: hanzo-deploy-linux-amd64
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
+1 -1
View File
@@ -11,7 +11,7 @@ permissions:
jobs:
deprecated:
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
steps:
- name: Checkout PR
uses: actions/checkout@v4
+1 -1
View File
@@ -8,7 +8,7 @@ on:
jobs:
stale:
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
if: github.repository_owner == 'shadcn-ui'
steps:
- uses: actions/stale@v9
+23 -22
View File
@@ -31,7 +31,7 @@ on:
jobs:
publish:
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -43,6 +43,7 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
@@ -51,31 +52,31 @@ jobs:
- name: Build packages
run: |
if [ "${{ github.event.inputs.package }}" = "all" ] || [ "${{ github.event.inputs.package }}" = "ui" ]; then
cd pkgs/ui && pnpm build
cd pkg/ui && pnpm build
cd ../..
fi
if [ "${{ github.event.inputs.package }}" = "all" ] || [ "${{ github.event.inputs.package }}" = "ui-mcp" ]; then
cd pkgs/ui-mcp && pnpm build
cd pkg/ui-mcp && pnpm build
cd ../..
fi
if [ "${{ github.event.inputs.package }}" = "all" ] || [ "${{ github.event.inputs.package }}" = "auth" ]; then
cd pkgs/auth && pnpm build
cd pkg/auth && pnpm build
cd ../..
fi
if [ "${{ github.event.inputs.package }}" = "all" ] || [ "${{ github.event.inputs.package }}" = "commerce" ]; then
cd pkgs/commerce && pnpm build
cd pkg/commerce && pnpm build
cd ../..
fi
if [ "${{ github.event.inputs.package }}" = "all" ] || [ "${{ github.event.inputs.package }}" = "checkout" ]; then
cd pkgs/checkout && pnpm build
cd pkg/checkout && pnpm build
cd ../..
fi
if [ "${{ github.event.inputs.package }}" = "all" ] || [ "${{ github.event.inputs.package }}" = "brand" ]; then
cd pkgs/brand && pnpm build
cd pkg/brand && pnpm build
cd ../..
fi
if [ "${{ github.event.inputs.package }}" = "all" ] || [ "${{ github.event.inputs.package }}" = "react" ]; then
cd pkgs/react && pnpm build
cd pkg/react && pnpm build
cd ../..
fi
@@ -141,34 +142,34 @@ jobs:
case "${{ github.event.inputs.package }}" in
ui)
publish_package "pkgs/ui"
publish_package "pkg/ui"
;;
ui-mcp)
publish_package "pkgs/ui-mcp"
publish_package "pkg/ui-mcp"
;;
auth)
publish_package "pkgs/auth"
publish_package "pkg/auth"
;;
commerce)
publish_package "pkgs/commerce"
publish_package "pkg/commerce"
;;
checkout)
publish_package "pkgs/checkout"
publish_package "pkg/checkout"
;;
brand)
publish_package "pkgs/brand"
publish_package "pkg/brand"
;;
react)
publish_package "pkgs/react"
publish_package "pkg/react"
;;
all)
publish_package "pkgs/ui"
publish_package "pkgs/ui-mcp"
publish_package "pkgs/auth"
publish_package "pkgs/commerce"
publish_package "pkgs/checkout"
publish_package "pkgs/brand"
publish_package "pkgs/react"
publish_package "pkg/ui"
publish_package "pkg/ui-mcp"
publish_package "pkg/auth"
publish_package "pkg/commerce"
publish_package "pkg/checkout"
publish_package "pkg/brand"
publish_package "pkg/react"
;;
esac
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
if: |
github.repository_owner == 'shadcn-ui' &&
${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
name: Write comment to the PR
steps:
- name: "Comment on PR"
+4 -3
View File
@@ -18,7 +18,7 @@ jobs:
github.repository_owner == 'shadcn-ui' &&
contains(github.event.pull_request.labels.*.name, '🚀 autorelease')
name: Build & Publish a beta release to NPM
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
environment: Preview
steps:
@@ -37,6 +37,7 @@ jobs:
with:
node-version: 20
registry-url: "https://registry.npmjs.org"
cache: "pnpm"
- name: Update npm for OIDC support
run: npm install -g npm@latest
@@ -54,10 +55,10 @@ jobs:
id: package-version
uses: martinbeentjes/npm-get-version-action@main
with:
path: pkgs/shadcn
path: packages/shadcn
- name: Upload packaged artifact
uses: actions/upload-artifact@v4
with:
name: npm-package-shadcn@${{ steps.package-version.outputs.current-version }}-pr-${{ github.event.number }} # encode the PR number into the artifact name
path: pkgs/shadcn/dist/index.js
path: packages/shadcn/dist/index.js
+22 -18
View File
@@ -8,7 +8,7 @@ on:
jobs:
test:
name: Run Tests
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -20,27 +20,29 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
run: pnpm install --frozen-lockfile
- name: Build packages
run: |
cd pkgs/ui && pnpm build && cd ../..
cd pkgs/commerce && pnpm build && cd ../..
cd pkgs/brand && pnpm build && cd ../..
cd pkgs/react && pnpm build && cd ../..
cd pkg/ui && pnpm build && cd ../..
cd pkg/auth && pnpm build && cd ../..
cd pkg/commerce && pnpm build && cd ../..
cd pkg/brand && pnpm build && cd ../..
cd pkg/react && pnpm build && cd ../..
- name: Run tests
run: |
cd pkgs/ui && pnpm test
cd pkg/ui && pnpm test
cd ../react && pnpm test
cd ../..
publish:
name: Publish to NPM
needs: test
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
@@ -55,28 +57,30 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
run: pnpm install --frozen-lockfile
- name: Build all packages
run: |
cd pkgs/ui && pnpm build && cd ../..
cd pkgs/commerce && pnpm build && cd ../..
cd pkgs/brand && pnpm build && cd ../..
cd pkgs/react && pnpm build && cd ../..
cd pkg/ui && pnpm build && cd ../..
cd pkg/auth && pnpm build && cd ../..
cd pkg/commerce && pnpm build && cd ../..
cd pkg/brand && pnpm build && cd ../..
cd pkg/react && pnpm build && cd ../..
- name: Configure npm authentication
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
run: |
npm config set //registry.npmjs.org/:_authToken $NODE_AUTH_TOKEN
npm whoami
- name: Check and publish packages
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
run: |
echo "Checking all packages for unpublished versions..."
@@ -84,8 +88,8 @@ jobs:
SKIPPED_COUNT=0
PUBLISHED_PACKAGES=""
for package in ui commerce brand react; do
cd "pkgs/$package"
for package in ui auth commerce brand react; do
cd "pkg/$package"
CURRENT_VERSION=$(node -p "require('./package.json').version")
PACKAGE_NAME=$(node -p "require('./package.json').name")
@@ -142,7 +146,7 @@ jobs:
```bash
# Install latest versions
npm install @hanzo/ui @hanzo/commerce @hanzo/brand @hanzo/react
npm install @hanzo/ui @hanzo/auth @hanzo/commerce @hanzo/brand @hanzo/react
```
files: |
CHANGELOG.md
+16 -26
View File
@@ -4,12 +4,11 @@ on:
push:
branches: [main]
paths:
- 'pkgs/*/package.json'
- 'pkgs/*/package.json'
- 'pkg/*/package.json'
jobs:
detect-changes:
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
outputs:
packages: ${{ steps.changed.outputs.packages }}
steps:
@@ -20,47 +19,37 @@ jobs:
- name: Detect changed packages
id: changed
run: |
CHANGED=()
for pkg_json in pkgs/*/package.json pkgs/*/package.json; do
[ ! -f "$pkg_json" ] && continue
CHANGED_PACKAGES=()
for pkg_json in pkg/*/package.json; do
pkg_dir=$(dirname "$pkg_json")
pkg_name=$(basename "$pkg_dir")
# Skip private packages
IS_PRIVATE=$(jq -r '.private // false' "$pkg_json")
[ "$IS_PRIVATE" = "true" ] && continue
# Only publish @hanzo/* packages
PKG_NAME=$(jq -r '.name' "$pkg_json")
case "$PKG_NAME" in
@hanzo/*) ;;
*) continue ;;
esac
# Check version changed
# Check if package.json version changed
if git diff HEAD~1 HEAD --quiet "$pkg_json" 2>/dev/null; then
continue
fi
OLD=$(git show HEAD~1:"$pkg_json" 2>/dev/null | jq -r '.version' || echo "0.0.0")
NEW=$(jq -r '.version' "$pkg_json")
# Get old and new versions
OLD_VERSION=$(git show HEAD~1:"$pkg_json" 2>/dev/null | jq -r '.version' || echo "0.0.0")
NEW_VERSION=$(jq -r '.version' "$pkg_json")
if [ "$OLD" != "$NEW" ]; then
echo "Version change: $PKG_NAME ($OLD -> $NEW)"
CHANGED+=("$(basename "$pkg_dir")")
if [ "$OLD_VERSION" != "$NEW_VERSION" ]; then
echo "Version change detected: $pkg_name ($OLD_VERSION -> $NEW_VERSION)"
CHANGED_PACKAGES+=("$pkg_name")
fi
done
if [ ${#CHANGED[@]} -eq 0 ]; then
if [ ${#CHANGED_PACKAGES[@]} -eq 0 ]; then
echo "packages=[]" >> $GITHUB_OUTPUT
else
JSON=$(printf '%s\n' "${CHANGED[@]}" | jq -R . | jq -s -c .)
JSON=$(printf '%s\n' "${CHANGED_PACKAGES[@]}" | jq -R . | jq -s -c .)
echo "packages=$JSON" >> $GITHUB_OUTPUT
fi
publish:
needs: detect-changes
if: needs.detect-changes.outputs.packages != '[]'
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
strategy:
matrix:
package: ${{ fromJson(needs.detect-changes.outputs.packages) }}
@@ -73,6 +62,7 @@ jobs:
with:
node-version: 20
registry-url: 'https://registry.npmjs.org'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
+2 -1
View File
@@ -16,7 +16,7 @@ jobs:
release:
if: ${{ github.repository_owner == 'shadcn-ui' }}
name: Create a PR for release workflow
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v3
@@ -33,6 +33,7 @@ jobs:
with:
node-version: 20
registry-url: "https://registry.npmjs.org"
cache: "pnpm"
- name: Update npm for OIDC support
run: npm install -g npm@latest
+100
View File
@@ -0,0 +1,100 @@
name: Sync Forks
on:
push:
branches: [main]
workflow_dispatch:
inputs:
fork:
description: 'Fork to sync (luxfi or zoo or all)'
required: false
default: 'all'
jobs:
sync-luxfi:
if: github.event.inputs.fork == 'luxfi' || github.event.inputs.fork == 'all' || github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- name: Checkout Hanzo UI
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Git
run: |
git config --global user.name "Hanzo Bot"
git config --global user.email "bot@hanzo.ai"
- name: Clone Luxfi Fork
run: |
git clone https://github.com/luxfi/ui.git luxfi-ui
cd luxfi-ui
git remote add upstream https://github.com/hanzoai/ui.git
git fetch upstream
- name: Sync and Rebrand
run: |
cd luxfi-ui
# Merge upstream changes
git checkout main
git merge upstream/main --no-edit || true
# Run rebrand script
cp ../scripts/rebrand.sh ./
chmod +x rebrand.sh
./rebrand.sh luxfi
# Commit changes
git add -A
git commit -m "sync: Update from hanzoai/ui and rebrand for Luxfi" || true
- name: Push to Luxfi
env:
GITHUB_TOKEN: ${{ secrets.FORK_SYNC_TOKEN }}
run: |
cd luxfi-ui
git push https://$GITHUB_TOKEN@github.com/luxfi/ui.git main || true
sync-zoo:
if: github.event.inputs.fork == 'zoo' || github.event.inputs.fork == 'all' || github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- name: Checkout Hanzo UI
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Git
run: |
git config --global user.name "Hanzo Bot"
git config --global user.email "bot@hanzo.ai"
- name: Clone Zoo Fork
run: |
git clone https://github.com/zooai/ui.git zoo-ui
cd zoo-ui
git remote add upstream https://github.com/hanzoai/ui.git
git fetch upstream
- name: Sync and Rebrand
run: |
cd zoo-ui
# Merge upstream changes
git checkout main
git merge upstream/main --no-edit || true
# Run rebrand script
cp ../scripts/rebrand.sh ./
chmod +x rebrand.sh
./rebrand.sh zoo
# Commit changes
git add -A
git commit -m "sync: Update from hanzoai/ui and rebrand for Zoo" || true
- name: Push to Zoo
env:
GITHUB_TOKEN: ${{ secrets.FORK_SYNC_TOKEN }}
run: |
cd zoo-ui
git push https://$GITHUB_TOKEN@github.com/zooai/ui.git main || true
+1 -1
View File
@@ -6,7 +6,7 @@ on:
jobs:
test:
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
name: pnpm test
env:
NEXT_PUBLIC_APP_URL: http://localhost:4000
+2 -2
View File
@@ -15,7 +15,7 @@ on:
jobs:
check-registry-sync:
if: github.event_name == 'pull_request'
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
name: check-registry-sync
permissions:
contents: read
@@ -52,7 +52,7 @@ jobs:
exit 1
validate:
runs-on: hanzo-build-linux-amd64
runs-on: ubuntu-latest
name: pnpm validate:registries
permissions:
contents: read
-1
View File
@@ -5,7 +5,6 @@ node_modules
**/node_modules
.pnp
.pnp.js
/pnpm-lock.yaml
# testing
coverage
+3 -3
View File
@@ -4,8 +4,8 @@
"typescript.preferences.quoteStyle": "single",
"eslint.workingDirectories": [
{ "pattern": "apps/*/" },
{ "pattern": "pkgs/*/" },
{ "pattern": "pkgs/*/" }
{ "pattern": "packages/*/" },
{ "pattern": "pkg/*/" }
],
"tailwindCSS.classFunctions": ["cva", "cn"],
"vitest.debugExclude": [
@@ -19,6 +19,6 @@
"search.exclude": {
"apps/v4/registry/radix-*": true,
"apps/v4/public/r/*": true,
"pkgs/shadcn/test/fixtures/*": true
"packages/shadcn/test/fixtures/*": true
}
}
-190
View File
@@ -1,190 +0,0 @@
# Hanzo UI Consolidation — one library, all polish, no duplication
**Goal.** RIP the fragmentation (`@hanzo/data` vs `@hanzo/ui` vs in-console duplicates) into ONE canonical, cross-platform, presentational, clean-room library: **`@hanzo/ui`, built on `@hanzo/gui`**. Preserve every polished component + token; zero loss; no fork.
**Status.**
- **Step 1 — Audit:** complete (this document; four source trees read file-by-file).
- **Step 2 — Establish `@hanzo/ui` + migrate the stable foundation:** **DONE & GREEN** (`pkg/ui` is now a real package; `tsc --noEmit` = 0 errors, `vitest` = 12/12).
- **Step 3 — Console re-point:** **STAGED, not merged.** Gate is split (backend live, app lanes in-flight) — see [Step 3](#step-3--console-re-point-staged).
**One decision needs CTO sign-off before publish** — see [Naming / version](#naming--version--the-one-decision).
---
## Architecture — three layers, decomplected
```
@hanzo/gui (Tamagui/One) cross-platform primitives: Text, XStack/YStack, Button, Input,
│ Card, Popover, Select, Switch, Slider, Spinner, ScrollView …
@hanzo/data (pkg/data) the metadata-driven RECORD layer: fields → records → views
│ (RecordsView, DataTable, BoardView, RecordDetail, field editors)
@hanzo/ui (pkg/ui) ◄──── THE ONE LIBRARY. Two orthogonal concerns, one package:
• product/app layer → import { … } from '@hanzo/ui'
• record layer → import { … } from '@hanzo/ui/data' (re-exports @hanzo/data)
```
`@hanzo/data` stays the **source of truth** for the record layer; `@hanzo/ui` **composes** it (`export * from '@hanzo/data'` on the `./data` subpath) rather than copying — so the CMS/ERP/Help app lanes that consume `@hanzo/data` today keep working untouched, and there is exactly one home. This mirrors how the gui base wraps `hanzogui`.
Both layers own a `DataTable` (product = generic typed `<T>` list; data = field-driven record grid). Keeping the record layer on the `./data` subpath keeps each name unambiguous — no rename, no collision.
---
## The preserve-and-merge manifest
Legend: **✅ migrated** (in `pkg/ui`, GREEN) · **↪ re-exported** (composed from `@hanzo/data`) · **⏳ staged** (Step 3, after app lanes land) · **🔧 pending prop-injection** (app-coupled; decouple before it can live in a presentational lib) · **🏠 stays in console** (app glue, not a UI component).
### A. Record layer — `@hanzo/data` → `@hanzo/ui/data` ↪
Source: `pkg/data/src/*` (v1.2.0, clean-room, already published). Surfaced through `@hanzo/ui/data` and `@hanzo/ui/primitives/bases/data`. Nothing re-implemented.
| Component / module | Source | New home |
|---|---|---|
| `RecordsView` (flagship: toolbar over table⇆board, filter/sort/search/group, saved views) | `view/RecordsView.tsx`, `view/Toolbar.tsx` | `@hanzo/ui/data` |
| `DataTable` (field-driven record grid: sort headers, drag resize/reorder, row select, inline edit, pagination) | `table/DataTable.tsx` | `@hanzo/ui/data` |
| `BoardView` (kanban, optimistic drag-move) · `RecordCard` | `board/BoardView.tsx`, `table/RecordCard.tsx` | `@hanzo/ui/data` |
| `RecordDetail` / `RecordForm` | `record/RecordDetail.tsx` | `@hanzo/ui/data` |
| Field model + registry (`FieldType` ×24, `FieldDefinition`, `registerField`, routers) | `field/{types,registry,registerDefaults,FieldDisplay,FieldInput}` | `@hanzo/ui/data` |
| Field displays + **editors** (select/currency/date/relation/file/JSON/boolean/fullName/address…) | `field/{displays,inputs}.tsx` | `@hanzo/ui/data` |
| Composable primitives: `Menu`, `CheckBox`, `Toggle`, `Calendar` | `primitives/*` | `@hanzo/ui/data` |
| Pure logic: `applyView`, `sortRecords`, `filterRecords`, `searchRecords`, `paginate`, `boardColumns`, … | `{table,board,view}/logic.ts` | `@hanzo/ui/data` (+ `@hanzo/data/*/logic` subpaths for Node hosts) |
| Tokens: `tokens`, `TAG_TONES`, `tagTone` | `theme.ts` | **also top-level `@hanzo/ui`** (token surface) |
### B. Console `components/ui/*` product primitives → `@hanzo/ui/product` ✅ / 🔧
Source: `console2/src/components/ui/*`. The pure subset was ported **byte-identical** (verified by `diff`) — 100% of the polish preserved (Charts' hover tooltips/axis-ticks/honest-null, DataTable width/flex/hover-gating, Field's 6 variants, SlideOver's focus-trap + scroll-lock, ComboBox's ReDoS-safe filter).
| Component | Source (`console2/src/components/ui/`) | New home | Status |
|---|---|---|---|
| `DataTable<T>` (generic typed list) + `Column` | `DataTable.tsx` | `@hanzo/ui` (`product/DataTable`) | ✅ |
| `PageHeader` | `PageHeader.tsx` | `@hanzo/ui` | ✅ |
| `Field*` (`FieldRow/Text/TextArea/Switch/Select/Slider`) | `Field.tsx` | `@hanzo/ui` | ✅ |
| **Charts** (`Sparkline/LineChart/BarChart/Donut/BarRows`, `CHART_PALETTE`) | `Charts.tsx` | `@hanzo/ui` | ✅ |
| `Donut` (standalone dependency-free ring) | `Donut.tsx` | `@hanzo/ui` as **`DonutRing`** (alias — Charts.Donut is canonical) | ✅ |
| `StatusTag` (health verdict → pill) | `StatusTag.tsx` | `@hanzo/ui` | ✅ |
| `EmptyState` (DO/Vercel-class first-run) | `EmptyState.tsx` | `@hanzo/ui` | ✅ (**decoupled** — see §I) |
| `Metric*` (`MetricCard/MiniBars/UtilBar/LegendDot/Panel/HintButton`, `SERIES`) | `Metric.tsx` | `@hanzo/ui` (its `Sparkline` preserved as **`MetricSparkline`**) | ✅ |
| `ComboBox` + pure `filterOptions`/`isKnownOption` | `ComboBox.tsx`, `combobox/filter.ts` | `@hanzo/ui` | ✅ (+ `filter.test.ts`) |
| `PrimaryButton` · `HanzoMark` · `ProductIcon` · `ProviderLogo` | resp. files | `@hanzo/ui` | ✅ |
| `SlideOver` (a11y drawer) · `SelectMenu` · `Toast` (`useToast`) | resp. files | `@hanzo/ui` | ✅ (SlideOver import decoupled `~/…/color``./color`) |
| `Reorder<T>` (pointer DnD) · `FadeIn` · `ThemeToggle` · `color` (`asColor`/`IconLike`) | resp. files | `@hanzo/ui` | ✅ (+ `Reorder.test.ts`) |
| `DetailPane` (right-side pane over SlideOver) | `components/DetailPane.tsx` | `@hanzo/ui` | ⏳ (liftable; lands with Step 3 — depends only on SlideOver) |
| `ChunkGuard` (stale-deploy chunk-error reload) | `components/ChunkGuard.tsx` | `@hanzo/ui` | ⏳ (fully portable; lands with Step 3) |
### C. Design tokens + motion → `@hanzo/ui` ✅
The brief's premise (`globals.css` `t_dark`/`t_light` token blocks) is **corrected**: `t_dark`/`t_light` are `@hanzo/gui` (Tamagui) theme **class names**; the calm values live in three real places, all preserved:
| Polish | Source | New home |
|---|---|---|
| Calm dark-first tokens (surface, text, accent `#60a5fa`, tag tones) — raw hex, theme-config independent | `pkg/data/src/theme.ts` | `@hanzo/ui` (top-level `tokens`/`TAG_TONES`/`tagTone`) |
| OKLCH shadcn-compatible palette (soft-charcoal `oklch(0.145 0 0)`, `--radius: 0.5rem`, indigo sidebar accent) | `pkgs/ui/style/hanzo-default-colors.css`, `@hanzo/tokens` | unchanged (legacy shadcn line); the gui line uses the hex tokens above |
| **Motion vocabulary**`hz-fade-up` (FadeIn), `hz-collapse`/`hz-slide`/`hz-fade` (shell/drawer), `hz-drag-item`, `hz-skeleton`/`hz-pulse`/`hz-row-in`; all `prefers-reduced-motion`-guarded | `console2/app/globals.css` (motion section) | **`@hanzo/ui/styles/motion.css`** (verbatim) — `import '@hanzo/ui/styles/motion.css'` once at app root |
### D. Generic DocType renderer → `@hanzo/ui` ⏳ (Step 3, FINAL — active lane)
Source: `console2/src/components/doctype/*`. **Actively edited by the CMS/ERP/Help lanes (untracked).** Dependency-**injected** (`client: FrameworkClient` prop) — not `~/lib/api`-coupled — so the real move-blockers are `~/lib/framework/{types,fields}` + the `ui/*` primitives (now in `@hanzo/ui`) + `@hanzo/data` (now `@hanzo/ui/data`).
| File | Class | Step-3 disposition |
|---|---|---|
| `MediaGrid.tsx` | presentational | → `@hanzo/ui` (cleanest lift; props-only DAM gallery) |
| `DocTypeRecords.tsx` / `DocTypeDetail.tsx` | mixed (data-bound shell over `@hanzo/data` views) | shell **stays in console**; renders `@hanzo/ui/data` views (already true) |
| `CollectionsBrowser.tsx` | mixed (card grid + install/create orchestration) | presentational card-grid → `@hanzo/ui`; orchestration stays |
| `data.ts` | glue (relation loading) | stays in console |
### E. LivingOverview → `@hanzo/ui` ⏳ (Step 3 — active lane)
Source: `console2/src/components/products/overview/living/*` (untracked/modified). Pure/presentational parts portable; app-glue concentrated in `registry.ts` (live API clients).
| Part | Class | Step-3 disposition |
|---|---|---|
| `motion.ts`, `hooks.ts`, `logic.ts`, `config.ts` (types) | pure | → `@hanzo/ui` (unit-tested; count-up, poll clock, unit formatting) |
| `tiles.tsx`, `LivingOverview.tsx` | presentational (reuse `ui/Charts` verbatim) | → `@hanzo/ui` (once `config.ts`'s one `~/lib/products/registry` `ProductIcon` type is swapped for `@hanzo/ui`'s `IconLike`) |
| `adapters.ts`, `registry.ts` | glue (map REAL `/v1` sources → `OverviewData`) | **stay in console** |
### F. Framework / Base-data libs → stay in console 🏠
`src/lib/framework/*` (DocType wire contract + `FrameworkApi` client + pure `fields.ts` mapper to `@hanzo/data`) and `src/lib/base-data/*` (Base REST client + schema→field mapper) are **app data-access glue**, not UI. They stay in the console. Their pure mappers (`docTypeToFields`, `baseCollectionToFields`) could later publish as a small `@hanzo/base-data` adapter, but they are not UI components and are out of scope for `@hanzo/ui`.
### G. App-coupled console components → 🔧 pending prop-injection (NOT yet in the lib)
These import app `~/lib`/session/router/branding and must be made presentational (inject props) before they belong in a host-agnostic lib. Kept in console for now; the injection contract is specified so the eventual lift is mechanical.
| Component | Coupling | Inject to lift |
|---|---|---|
| `BackendStateCard` (`BackendState.tsx`) | `~/lib/api` `ApiError` | accept a numeric `status` (or shared error shape) instead of `ApiError` |
| `BrandLogo` | session + live IAM `organization()` + `~/config` + branding | `orgName`, `logoUrl` (or a `loadOrgLogo` loader), brand mark/name as props |
| `Breadcrumbs` | `next/navigation` + catalog lookups | `crumbs[]` (or `pathname` + resolver) + `onNavigate` |
| `Loader` / `BrandMark` | `~/config` + brand logo pkgs | `brand`/`brandName` + the animated-SVG getter |
| `States` (`ErrorState`, `OperatorAccessRequired`) | `~/lib/api` + session + branding | the error, the account identity, brand strings |
---
## What this pass built (Step 2)
New in **`pkg/ui`** (was a bare `src/` staging dir — no package):
- `package.json``@hanzo/ui` `8.0.0`, source-published (`files: ["src"]`, exports map to `.ts`), peers `@hanzo/gui >=7.2.2`, `@hanzo/data >=1.2.0`, `react >=19`; BSD-3-Clause. Exports: `.`, `./product`, `./data`, `./primitives/bases/data`, `./styles/motion.css`.
- `src/index.ts` — top-level barrel (product layer + tokens).
- `src/product/index.ts` — product barrel; **collision-free** (Charts `Sparkline`/`Donut` canonical; Metric's → `MetricSparkline`; standalone ring → `DonutRing`; `ComboOption` from the one filter module) — **zero loss**.
- `src/data.ts``export * from '@hanzo/data'` (the record layer, one home).
- `src/styles/hanzo-motion.css` — the motion vocabulary, verbatim.
- `tsconfig.json`, `vitest.config.ts`, `gui.config.ts`, `gui.d.ts`, `.npmignore`, `README.md` — mirror the proven `pkg/data` setup.
- **One decouple fix:** `product/EmptyState.tsx` no longer imports `~/lib/products/registry`; it uses the local `IconLike` type — the last host coupling in the product tree is gone.
**Green:** `tsc --noEmit` = 0 errors (strict); `vitest run` = 12/12 (`combobox/filter`, `Reorder`). Every product component is host-agnostic (imports only `react`, `@hanzo/gui`, `@hanzogui/*`, `@hanzo/data`, relative).
## Clean-room guarantee (preserved)
`pkg/data` audited for GPL/Twenty contamination: **none.** No GPL, no copied license headers/SPDX, no Twenty entity/decorator architecture. The field/record model is an independent `FieldType` union + `FieldDefinition` + runtime `Map` registry (records are plain `Record<string, unknown>`). "Twenty" appears **only as benchmark prose** ("Airtable/Twenty-class polish, clean-room"). License: BSD-3-Clause. `@hanzo/ui` inherits the same posture.
---
## Naming / version — DECIDED: `@hanzo/ui@8`, shadcn retired to `@hanzo/ui-shadcn`
**Decision:** the gui-based unified library takes the `@hanzo/ui` name **forward at `8.0.0`** (aligning with the "Hanzo Cloud 8.x" umbrella; major = breaking re-platform). The legacy shadcn/Radix line (`pkgs/ui`, v5.7.0) is **retired by renaming** to `@hanzo/ui-shadcn` (never hard-deleted) — it stays fully alive under the new name, freeing `@hanzo/ui` for v8. Precedent: `pkg/data@1.2.0` already superseded `pkgs/data@1.1.0` under the same name.
This is **DONE (repo-local):** `pkg/ui/package.json` is `@hanzo/ui@8.0.0`, GREEN. The rest is a coordinated, **sequenced** retire — because publishing `@hanzo/ui@8` (a different, gui-based API with no shadcn `Button/Card/Dialog`) under the name ~20 repos consume for shadcn primitives will BREAK any consumer that resolves to `@8`. So order matters:
**Blast radius (measured across `~/work/hanzo`).** Declared deps on `@hanzo/ui` in ~20 repos. Most pin `^5.x` (semver-safe from an `@8` bump): paas, chat, platform, app, hanzo.ai, o11y, docs, mdx, hanzobot, ui-repo `pkgs/checkout` `^5.3`, `pkgs/agent-ui` `^5.0`. **Would break on `@8`:** `hanzoai/identity/app` (`"latest"`), ui-repo `pkgs/commerce` (`>=5.0.0`); `app/` uses `workspace:^`. The `ui.hanzo.ai` docs app + `pkgs/{commerce,checkout,agent-ui}` import the shadcn line internally.
**Publish reality.** `.github/workflows/publish-on-tag.yml` publishes **`pkgs/ui`** (the shadcn line) as `@hanzo/ui` on a `v*` tag — it does not reference `pkg/ui`. So a tag push today publishes shadcn, not v8. Publishing v8 needs the workflow rewired to build/publish `pkg/ui`. `npm` is not authed locally (`npm whoami` empty) — per house rules, publish goes through **CI (self-hosted runners, canonical org `NPM_TOKEN`)**, not a local `npm publish`.
**Safe sequence to fully land v8 (each step reversible until the tag push):**
1.`pkg/ui` = `@hanzo/ui@8.0.0`, GREEN (done, committed to a branch).
2. Rename `pkgs/ui` name → `@hanzo/ui-shadcn`; update the internal ui-repo consumers (`app/`, `pkgs/{commerce,checkout,agent-ui}`) + `check-no-hanzogui`/registry scripts that reference it.
3. Migrate external consumers off `@hanzo/ui``@hanzo/ui-shadcn` (start with the break-risk ones: `identity` `latest`, `commerce` `>=5`; the `^5` pins are safe to migrate at leisure). ~20 repos — do as a tracked sweep or flag per-repo.
4. Rewire `publish-on-tag.yml` (and `release.yml`) to build + publish `pkg/ui` as `@hanzo/ui@8`, and `pkgs/ui-shadcn` as `@hanzo/ui-shadcn`.
5. `npm deprecate '@hanzo/ui@<8' 'moved to @hanzo/ui-shadcn; @hanzo/ui@8+ is the @hanzo/gui-based unified lib'`.
6. Tag `v8.0.0` → CI publishes `@hanzo/ui@8.0.0`. Verify `npm view @hanzo/ui@8.0.0`.
**Gated on the user's direct go-ahead** (irreversible / globally-visible / ecosystem-wide): steps 26 — the `pkgs/ui` rename, the ~20-repo consumer sweep, the CI rewire, `npm deprecate`, and the `v8.0.0` tag push that triggers publish. These were not executed autonomously.
---
## Step 3 — console re-point (STAGED)
**Gate (per the brief):** cloud `/v1/framework/modules` live **AND** console CMS/ERP/Help native.
- ✅ Backend: `/v1/framework/modules[/:module[/install]]` is **implemented + wired** (`cloud/clients/framework/framework.go:71-73`, HIP-0106 order 129, bound in `subsystems.go:130`, real tests).
- ⏳ Console: `CmsModule.tsx`, `ErpModule.tsx`, `HelpModule.tsx`, `components/doctype/` are **untracked/in-flight** on `feat/console-native-cms`.
→ Gate is **split**, so the re-point is **staged, not applied.** I deliberately did **not** touch `console2`'s working tree (it holds the lanes' uncommitted work — editing it would collide and risk loss, the opposite of the goal).
**Ready-to-apply re-point (mechanical, once the lanes land + merge):**
1. `console2` deps: keep `@hanzo/gui`, `@hanzo/data`; add `@hanzo/ui` (`^6.0.0`). (`@hanzo/data` may stay as a direct dep or be dropped in favor of `@hanzo/ui/data` — both resolve to the same source.)
2. Re-point imports (delete the now-duplicated in-console copies — extract, don't copy):
- `~/components/ui/{DataTable,PageHeader,Field,Charts,Donut,StatusTag,EmptyState,Metric,ComboBox,combobox/filter,PrimaryButton,HanzoMark,ProductIcon,ProviderLogo,SlideOver,SelectMenu,Toast,Reorder,FadeIn,ThemeToggle,color}`**`@hanzo/ui`** (or `@hanzo/ui/product`). Two spot-renames: Metric's `Sparkline``MetricSparkline`, standalone `Donut``DonutRing`.
- `@hanzo/data` (in `doctype/*`, `base-data/*`, `products/*Module`) → **`@hanzo/ui/data`** (identical surface).
- `~/components/{DetailPane,ChunkGuard}`**`@hanzo/ui`**.
- `app/globals.css` motion block → `import '@hanzo/ui/styles/motion.css'` (keep base resets local).
- Move the 5 app-coupled components (§G) into the lib only after applying their inject-props contract; until then they stay local.
3. Verify **identical render**: `tsc --noEmit` + `vitest` + `next build` green, then headless-Playwright the live pages pixel-same (the polish is byte-identical, so parity is expected).
**Report:** `@hanzo/ui` is the ONE unified library — product layer + record layer (`@hanzo/data`) + charts + calm tokens + motion, all on `@hanzo/gui`, presentational, cross-platform, clean-room, GREEN. Console re-point is **ready to apply once the CMS/ERP/Help lanes land**; it was not merged to avoid colliding with that in-flight work.
## Follow-ups (semver-minor, with visual e2e)
- Collapse the preserved Sparkline/Donut variants to one each (`MetricSparkline``Sparkline`, `DonutRing``Donut`) once call-sites are proven identical.
- Lift §G's five components after applying their prop-injection contracts.
- Consider publishing the pure `framework`/`base-data` mappers as a small `@hanzo/base-data` adapter (not UI).
+1
View File
@@ -32,6 +32,7 @@ ui/
checkout/ Checkout flow
shop/ Shop components
agent-ui/ AI agent UI components
gui/ GUI component packages (@hanzogui/*)
tokens/ Design tokens
skills/
shadcn/ AI skill definitions for shadcn CLI
-6
View File
@@ -1,6 +0,0 @@
ui
Copyright (c) 2023 Hanzo AI, Inc.
This product includes software from shadcn/ui (https://github.com/shadcn-ui/ui), licensed under MIT:
Copyright (c) 2023 shadcn
-2
View File
@@ -1,5 +1,3 @@
<p align="center"><img src=".github/hero.svg" alt="ui" width="880"></p>
# @hanzo/ui
Accessible and customizable components for React, Vue, Svelte, and React Native. **Built on shadcn/ui with multi-framework support, 3D components, AI components, and advanced features.**
+2 -2
View File
@@ -42,8 +42,8 @@ describe("@hanzo/ui namespace imports - Type Resolution", () => {
* import { GridPattern } from '@hanzo/ui/pattern/grid'
* ```
*
* The package exports are properly configured in pkgs/ui/package.json.
* Build artifacts exist in pkgs/ui/dist/{code,3d,pattern}/.
* The package exports are properly configured in pkg/ui/package.json.
* Build artifacts exist in pkg/ui/dist/{code,3d,pattern}/.
*
* Vitest runtime resolution fails due to internal cross-package imports
* (e.g., CodeBlock imports from @hanzo/ui/lib/utils), which require
+1 -9
View File
@@ -62,15 +62,7 @@ export function CommandMenu({ ...props }: DialogProps) {
const { recentSearches, addRecentSearch, clearRecentSearches } =
useRecentSearches()
// SSR renders without `window`, so the first client (hydration) render MUST
// also produce "Ctrl" — computing the platform-specific glyph during render
// makes the hydrated text ("⌘" on macOS) diverge from the server text
// ("Ctrl") → React #418 (hydration text mismatch). Start from the SSR-stable
// value and upgrade to the platform glyph after mount (client-only effect).
const [modKey, setModKey] = React.useState("Ctrl")
React.useEffect(() => {
if (isMacOS()) setModKey("⌘")
}, [])
const modKey = React.useMemo(() => (isMacOS() ? "⌘" : "Ctrl"), [])
React.useEffect(() => {
const down = (e: KeyboardEvent) => {
@@ -0,0 +1,71 @@
---
title: Stock Market
description: Display real-time stock market overview with indices and major stocks.
component: true
---
<ComponentPreview
name="market-overview"
description="Stock market overview widget"
/>
## Installation
<Tabs defaultValue="cli">
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx @hanzo/ui@latest add market-overview
```
</TabsContent>
<TabsContent value="manual">
<Steps>
<Step>Install the following dependencies:</Step>
```bash
npm install @hanzo/ui
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource name="market-overview" />
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</Tabs>
## Usage
```tsx
import { MarketOverview } from "@hanzo/ui/finance"
export default function Demo() {
return <MarketOverview colorTheme="dark" showFloatingTooltip />
}
```
## Props
| Prop | Type | Default | Description |
| ------------------- | ----------------- | ---------------------------------------- | ---------------------- |
| colorTheme | "light" \| "dark" | "dark" | Color theme |
| width | string \| number | "100%" | Widget width |
| height | string \| number | 400 | Widget height |
| showFloatingTooltip | boolean | false | Show tooltip on hover |
| locale | string | "en" | Language locale |
| isTransparent | boolean | false | Transparent background |
| tabs | string[] | ["indices", "futures", "bonds", "forex"] | Visible tabs |
+3 -3
View File
@@ -30,13 +30,13 @@
"@dnd-kit/modifiers": "^9.0.0",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@faker-js/faker": "^10.4.0",
"@faker-js/faker": "^10.3.0",
"@hanzo/docs-core": "16.5.3",
"@hanzo/docs-docgen": "3.0.7",
"@hanzo/docs-mdx": "14.3.0",
"@hanzo/docs-ui": "16.5.3",
"@hanzo/logo": "^1.0.5",
"@hanzo/ui": "workspace:@hanzo/ui-shadcn@^",
"@hanzo/ui": "workspace:^",
"@hookform/resolvers": "5.2.2",
"@monaco-editor/react": "^4.7.0",
"@radix-ui/react-accessible-icon": "^1.1.8",
@@ -156,7 +156,7 @@
"postcss-selector-parser": "^7.1.1",
"prettier": "^3.8.1",
"prettier-plugin-tailwindcss": "^0.7.2",
"puppeteer": "^25.1.0",
"puppeteer": "^24.40.0",
"rehype-pretty-code": "^0.14.3",
"rimraf": "^6.1.3",
"sharp": "^0.34.5",
+1 -1
View File
@@ -1,4 +1,4 @@
import { docs } from "@/.source/server"
import { docs } from "@/.source"
import { loader } from "fumadocs-core/source"
export const source = loader({
+7 -7
View File
@@ -29,7 +29,7 @@
"@dnd-kit/modifiers": "^9.0.0",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@faker-js/faker": "^10.4.0",
"@faker-js/faker": "^10.1.0",
"@hookform/resolvers": "^3.10.0",
"@hugeicons/core-free-icons": "^1.2.1",
"@hugeicons/react": "^1.1.1",
@@ -50,10 +50,10 @@
"embla-carousel-autoplay": "8.5.2",
"embla-carousel-react": "8.5.2",
"front-matter": "^4.0.2",
"fumadocs-core": "16.10.3",
"fumadocs-docgen": "3.0.10",
"fumadocs-mdx": "15.0.12",
"fumadocs-ui": "16.10.3",
"fumadocs-core": "16.0.5",
"fumadocs-docgen": "2.0.0",
"fumadocs-mdx": "13.0.2",
"fumadocs-ui": "16.0.5",
"input-otp": "^1.4.2",
"jotai": "^2.15.0",
"little-date": "^1.0.0",
@@ -103,8 +103,8 @@
"tailwindcss": "^4",
"tw-animate-css": "^1.4.0",
"typescript": "^5",
"unist-builder": "4.0.0",
"unist-util-visit": "^5.1.0"
"unist-builder": "3.0.0",
"unist-util-visit": "^4.1.2"
},
"prettier": {
"endOfLine": "lf",
-78
View File
@@ -1,78 +0,0 @@
'use client'
/**
* The composable sign-in surface, end to end.
*
* This file is the CONFIGURATION layer — zero auth code. It picks a method set
* (`brand.providers`) and hands it to `<SignIn>`. The PRESENTATION layer
* (`@hanzo/ui` `<SignIn>` / `<SocialButton>` / `<PasswordForm>`) renders it,
* brand-themed by CSS tokens. The MECHANISM layer (`@hanzo/iam`) runs the one
* Authorization-Code + PKCE flow — `provider` is the only knob.
*
* Adoption: every app collapses its hand-rolled `iam-auth.ts` + bespoke login
* page to exactly this — `import { SignIn } from '@hanzo/ui/auth'` +
* `import { configureIam, startLogin, getIam } from '@hanzo/iam'`.
*/
import * as React from 'react'
import { SignIn } from '../src/auth'
// ── App brand config (the ONLY app-level knob) ──────────────────────────────
//
// Social/web3 are LIVE: one shared org-level OAuth provider per network in IAM
// (admin/provider-google, admin/provider-github), reused by every app via a
// `canSignIn` toggle. Apps NEVER register per-app Google/GitHub clients — the
// button just delegates with `provider`.
const brand = {
serverUrl: 'https://hanzo.id',
clientId: 'hanzo-app',
providers: ['password', 'google', 'github', 'web3'] as const,
}
export function SignInDemo() {
// The mechanism comes from `@hanzo/iam`. Configure once; pass the SDK's
// `startLogin` (provider knob) and `loginWithPassword` (embedded credential)
// into the presentation. Lazy-imported so this demo file stays render-only.
const [iam, setIam] = React.useState<null | {
startLogin: (o: { provider?: string }) => Promise<void>
loginWithPassword: (email: string, password: string) => Promise<string>
}>(null)
React.useEffect(() => {
let alive = true
void import('@hanzo/iam').then((sdk) => {
sdk.configureIam({ issuer: brand.serverUrl, clientId: brand.clientId })
const engine = sdk.getIam()
if (alive) {
setIam({
startLogin: (o) => sdk.startLogin(o),
loginWithPassword: (email, password) => engine.loginWithPassword(email, password),
})
}
})
return () => {
alive = false
}
}, [])
return (
<div className="mx-auto flex min-h-[480px] w-full max-w-sm items-center justify-center">
<SignIn
title="Sign in"
providers={[...brand.providers]}
config={{ serverUrl: brand.serverUrl, clientId: brand.clientId }}
// Social/web3: delegate to the SDK's startLogin (adds &provider=…).
onLogin={iam ? (opts) => iam.startLogin({ provider: opts.provider }) : undefined}
// Password: the SDK's embedded credential login → PKCE-bound code.
onPasswordSubmit={
iam
? async ({ email, password }) => {
const callbackUrl = await iam.loginWithPassword(email, password)
window.location.href = callbackUrl
}
: undefined
}
/>
</div>
)
}
+547
View File
@@ -0,0 +1,547 @@
# Hanzo UI - UX Enhancement Plan
**Date**: 2025-11-13
**Created By**: UI/UX Design Review via Playwright Testing
**Status**: Ready for Implementation
## Executive Summary
After comprehensive UI/UX review using Playwright automated testing and visual inspection, we've identified **12 high-impact improvements** that will elevate the Hanzo UI component library to world-class standards. This plan prioritizes user experience, accessibility, and modern design patterns.
### Key Metrics from Review
-**8/13 tests passed** - Good foundation
- ⚠️ **Page load time**: 14.7s (Target: <3s)
- ⚠️ **First Contentful Paint**: 8.4s (Target: <1.5s)
-**Theme switcher**: Working perfectly
- ⚠️ **Mobile navigation**: Missing hamburger menu
-**Accessibility**: Good alt text coverage (100%)
- ⚠️ **Skip links**: Missing (critical for a11y)
---
## Priority 1: Critical UX Issues (Immediate)
### 1. Mobile Navigation Enhancement
**Issue**: No hamburger menu on mobile viewports
**Impact**: ❌ Critical - Mobile users cannot navigate
**Solution**:
- Add responsive hamburger menu for viewports <768px
- Smooth slide-in animation from right
- Overlay with backdrop blur
- Touch-optimized buttons (min 44x44px)
**Implementation**:
```tsx
// app/components/mobile-nav.tsx
"use client"
import { useState } from "react"
import { Menu, X } from "lucide-react"
import { Sheet, SheetContent, SheetTrigger } from "@/registry/default/ui/sheet"
import { Button } from "@/registry/default/ui/button"
export function MobileNav() {
const [open, setOpen] = useState(false)
return (
<Sheet open={open} onOpenChange={setOpen}>
<SheetTrigger asChild className="md:hidden">
<Button variant="ghost" size="icon" aria-label="Open menu">
<Menu className="h-5 w-5" />
</Button>
</SheetTrigger>
<SheetContent side="right" className="w-[300px] sm:w-[400px]">
{/* Navigation items */}
</SheetContent>
</Sheet>
)
}
```
**Files to modify**:
- `app/components/site-header.tsx` - Add mobile nav
- `app/components/mobile-nav.tsx` - New file
---
### 2. Performance Optimization
**Issue**: 14.7s page load, 8.4s first contentful paint
**Impact**: ❌ Critical - Users abandon slow sites
**Target**: <3s total load, <1.5s FCP
**Solutions**:
1. **Image Optimization**
- Convert all images to WebP/AVIF
- Add lazy loading with blur placeholders
- Implement next/image for automatic optimization
2. **Code Splitting**
- Dynamic imports for heavy components
- Route-based code splitting
- Lazy load component preview iframes
3. **Loading States**
- Skeleton screens for component gallery
- Progressive loading for blocks page
- Suspense boundaries for async content
**Implementation**:
```tsx
// app/components/skeleton-card.tsx
export function SkeletonCard() {
return (
<div className="space-y-3 animate-pulse">
<div className="h-48 bg-muted rounded-lg" />
<div className="h-4 bg-muted rounded w-3/4" />
<div className="h-3 bg-muted rounded w-1/2" />
</div>
)
}
// Usage in blocks page
<Suspense fallback={<SkeletonCard />}>
<BlockCard />
</Suspense>
```
---
### 3. Accessibility - Skip Links
**Issue**: Missing skip navigation links
**Impact**: ❌ High - Screen reader users stuck in nav
**WCAG Requirement**: Level A compliance
**Implementation**:
```tsx
// app/components/skip-links.tsx
export function SkipLinks() {
return (
<a
href="#main-content"
className="sr-only focus:not-sr-only focus:fixed focus:top-4 focus:left-4 focus:z-50 focus:px-4 focus:py-2 focus:bg-primary focus:text-primary-foreground focus:rounded-md focus:outline-none focus:ring-2 focus:ring-ring"
>
Skip to main content
</a>
)
}
```
Add to `app/layout.tsx` before header.
---
## Priority 2: High-Impact Enhancements
### 4. Hero Section Redesign
**Current Issues**:
- CTAs not immediately visible (hidden button)
- Visual hierarchy could be stronger
- Missing animated elements to draw attention
**Improvements**:
1. **Enhanced Visual Hierarchy**
```tsx
<section className="relative overflow-hidden">
{/* Animated gradient background */}
<div className="absolute inset-0 -z-10">
<div className="absolute inset-0 bg-gradient-to-br from-primary/10 via-transparent to-accent/10 animate-gradient" />
<div className="absolute inset-0 bg-grid-white/[0.02]" />
</div>
{/* Hero content */}
<div className="container py-24 md:py-32 space-y-8">
{/* Badge with animation */}
<div className="flex justify-center">
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-muted text-sm font-medium border animate-fade-in-up">
<span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75" />
<span className="relative inline-flex rounded-full h-2 w-2 bg-primary" />
</span>
New: 149+ components, Page Builder, and more
</div>
</div>
{/* Main heading with gradient */}
<h1 className="text-center text-5xl md:text-7xl font-bold tracking-tight">
<span className="bg-clip-text text-transparent bg-gradient-to-r from-foreground to-foreground/70">
Hanzo UI Component Library
</span>
</h1>
{/* Subtitle */}
<p className="text-center text-xl md:text-2xl text-muted-foreground max-w-3xl mx-auto">
Beautifully designed components built by Hanzo AI. Accessible.
Customizable. Open Source. Built with React and Tailwind CSS.
</p>
{/* CTAs with clear hierarchy */}
<div className="flex flex-col sm:flex-row gap-4 justify-center items-center">
<Button size="lg" className="gap-2 text-lg h-12 px-8">
Get Started
<ArrowRight className="h-5 w-5" />
</Button>
<Button variant="outline" size="lg" className="text-lg h-12 px-8">
View Components
</Button>
</div>
{/* Trust indicators */}
<div className="flex justify-center gap-8 text-sm text-muted-foreground">
<div className="flex items-center gap-2">
<CheckCircle2 className="h-4 w-4 text-primary" />
Open Source
</div>
<div className="flex items-center gap-2">
<CheckCircle2 className="h-4 w-4 text-primary" />
TypeScript
</div>
<div className="flex items-center gap-2">
<CheckCircle2 className="h-4 w-4 text-primary" />
Accessible
</div>
</div>
</div>
</section>
```
2. **Add Component Preview Carousel**
- Showcase 3-4 popular components
- Auto-rotate with smooth transitions
- Interactive - click to navigate to component
---
### 5. Enhanced Search Experience
**Current State**: Basic search in sidebar
**Target**: Instant, fuzzy search with keyboard shortcuts
**Features**:
1. **Command Palette** (⌘K)
```tsx
// Global keyboard shortcut
<CommandDialog>
<CommandInput placeholder="Search components..." />
<CommandList>
<CommandGroup heading="Components">
{/* Fuzzy search results */}
</CommandGroup>
<CommandGroup heading="Blocks">
{/* Block results */}
</CommandGroup>
</CommandList>
</CommandDialog>
```
2. **Search Features**:
- Fuzzy matching (button → "btn" matches)
- Category filters
- Recent searches
- Keyboard navigation (↑↓ to navigate, Enter to select)
- Visual preview on hover
---
### 6. Component Gallery Enhancements
**Current Issues**:
- Cards lack visual interest
- No quick preview
- Missing category badges
**Improvements**:
```tsx
<Card className="group relative overflow-hidden transition-all hover:shadow-lg hover:-translate-y-1">
{/* Hover effect gradient */}
<div className="absolute inset-0 bg-gradient-to-br from-primary/0 via-primary/5 to-accent/10 opacity-0 group-hover:opacity-100 transition-opacity" />
{/* Preview */}
<div className="aspect-video bg-muted/50 relative overflow-hidden">
<ComponentPreview />
{/* Quick action overlay */}
<div className="absolute inset-0 bg-background/80 backdrop-blur-sm opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center gap-2">
<Button size="sm" variant="secondary">
<Eye className="h-4 w-4 mr-2" />
Preview
</Button>
<Button size="sm" variant="secondary">
<Copy className="h-4 w-4 mr-2" />
Copy Code
</Button>
</div>
</div>
{/* Card content */}
<CardHeader>
<div className="flex items-center justify-between">
<CardTitle>Button</CardTitle>
<Badge variant="secondary">New</Badge>
</div>
<CardDescription>Displays a button or a component that looks like a button.</CardDescription>
</CardHeader>
{/* Stats */}
<CardFooter className="text-xs text-muted-foreground">
<div className="flex gap-4">
<span>12 variants</span>
<span>•</span>
<span>Updated 2d ago</span>
</div>
</CardFooter>
</Card>
```
---
### 7. Builder Interface Improvements
**Current Issues**:
- Drag affordances not obvious
- No undo/redo
- Limited viewport preview
**Enhancements**:
1. **Clear Drag Indicators**
```tsx
<div className="relative group cursor-move">
{/* Drag handle */}
<div className="absolute left-0 top-1/2 -translate-y-1/2 -translate-x-full pr-2 opacity-0 group-hover:opacity-100 transition-opacity">
<GripVertical className="h-4 w-4 text-muted-foreground" />
</div>
{/* Drop zones */}
<div className="absolute inset-x-0 -top-1 h-2 bg-primary/20 opacity-0 data-[droppable=true]:opacity-100" />
</div>
```
2. **History Management**
```tsx
<div className="flex items-center gap-1 border rounded-md p-1">
<Button
size="icon"
variant="ghost"
disabled={!canUndo}
onClick={undo}
title="Undo (⌘Z)"
>
<Undo className="h-4 w-4" />
</Button>
<Button
size="icon"
variant="ghost"
disabled={!canRedo}
onClick={redo}
title="Redo (⌘⇧Z)"
>
<Redo className="h-4 w-4" />
</Button>
</div>
```
3. **Enhanced Viewport Switcher**
```tsx
<ToggleGroup type="single" value={viewport}>
<ToggleGroupItem value="mobile" aria-label="Mobile view">
<Smartphone className="h-4 w-4" />
<span className="ml-2 hidden sm:inline">Mobile</span>
<span className="ml-1 text-xs text-muted-foreground hidden lg:inline">(375px)</span>
</ToggleGroupItem>
<ToggleGroupItem value="tablet" aria-label="Tablet view">
<Tablet className="h-4 w-4" />
<span className="ml-2 hidden sm:inline">Tablet</span>
<span className="ml-1 text-xs text-muted-foreground hidden lg:inline">(768px)</span>
</ToggleGroupItem>
<ToggleGroupItem value="desktop" aria-label="Desktop view">
<Monitor className="h-4 w-4" />
<span className="ml-2 hidden sm:inline">Desktop</span>
<span className="ml-1 text-xs text-muted-foreground hidden lg:inline">(1440px)</span>
</ToggleGroupItem>
</ToggleGroup>
```
---
## Priority 3: Polish & Delight
### 8. Micro-Interactions
Add subtle animations to enhance feel:
```css
/* tailwind.config.ts */
{
animation: {
'fade-in-up': 'fade-in-up 0.6s ease-out',
'fade-in': 'fade-in 0.4s ease-out',
'scale-in': 'scale-in 0.3s ease-out',
'gradient': 'gradient 8s ease infinite',
},
keyframes: {
'fade-in-up': {
'0%': { opacity: '0', transform: 'translateY(20px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
},
'fade-in': {
'0%': { opacity: '0' },
'100%': { opacity: '1' },
},
'scale-in': {
'0%': { opacity: '0', transform: 'scale(0.95)' },
'100%': { opacity: '1', transform: 'scale(1)' },
},
'gradient': {
'0%, 100%': { backgroundPosition: '0% 50%' },
'50%': { backgroundPosition: '100% 50%' },
},
},
}
```
### 9. Toast Notifications
Replace alert() with beautiful toasts:
```tsx
import { toast } from 'sonner'
// Success
toast.success('Component copied to clipboard!')
// Error
toast.error('Failed to load preview', {
description: 'Please check your connection and try again.',
action: {
label: 'Retry',
onClick: () => retry(),
},
})
```
### 10. Enhanced Dark Mode
**Current**: Works well
**Enhancement**: Add smooth transitions
```tsx
// app/components/theme-provider.tsx
<div className="transition-colors duration-300">
{children}
</div>
```
### 11. Empty States
Add delightful empty states:
```tsx
<div className="flex flex-col items-center justify-center py-12 text-center">
<div className="rounded-full bg-muted p-4 mb-4">
<Search className="h-8 w-8 text-muted-foreground" />
</div>
<h3 className="text-lg font-semibold mb-2">No components found</h3>
<p className="text-muted-foreground mb-4 max-w-sm">
Try adjusting your search or filters to find what you're looking for.
</p>
<Button variant="outline" onClick={clearFilters}>
Clear filters
</Button>
</div>
```
### 12. Keyboard Shortcuts Panel
Add discoverable shortcuts:
```tsx
<kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100">
<span className="text-xs">⌘</span>K
</kbd>
```
Shortcuts panel (? key):
- `⌘K` - Open search
- `/` - Focus search
- `⌘B` - Toggle sidebar
- `⌘D` - Toggle dark mode
- `?` - Show shortcuts
---
## Implementation Roadmap
### Week 1: Critical Fixes
- [ ] Mobile navigation hamburger menu
- [ ] Skip links for accessibility
- [ ] Performance audit & initial optimizations
### Week 2: Hero & Search
- [ ] Hero section redesign
- [ ] Command palette search
- [ ] Component preview carousel
### Week 3: Gallery & Builder
- [ ] Component card enhancements
- [ ] Builder drag indicators
- [ ] Undo/redo functionality
### Week 4: Polish
- [ ] Micro-interactions
- [ ] Toast notifications
- [ ] Empty states
- [ ] Keyboard shortcuts panel
---
## Success Metrics
### Performance
- ⬇️ Page load: 14.7s → **<3s**
- ⬇️ FCP: 8.4s → **<1.5s**
- ⬆️ Lighthouse score: ? → **>95**
### Accessibility
- ⬆️ WCAG compliance: A → **AAA**
- ✅ All interactive elements keyboard accessible
- ✅ Screen reader tested
### User Engagement
- ⬆️ Time on site: +30%
- ⬆️ Component copies: +50%
- ⬇️ Bounce rate: -20%
---
## Testing Plan
1. **Automated Testing**
- Playwright tests for all new features
- Visual regression testing
- Performance benchmarks
2. **Manual Testing**
- Cross-browser (Chrome, Firefox, Safari, Edge)
- Mobile devices (iOS, Android)
- Screen readers (NVDA, JAWS, VoiceOver)
3. **User Testing**
- 5-user think-aloud sessions
- A/B test hero variants
- Heatmap analysis
---
## Resources Required
- **Design**: 20 hours (hero redesign, component cards)
- **Development**: 60 hours (implementation)
- **Testing**: 15 hours (QA, accessibility)
- **Total**: ~95 hours (~2.5 weeks for 1 developer)
---
## Conclusion
These enhancements will transform Hanzo UI from a good component library to an **exceptional** one. Focusing on performance, accessibility, and delightful interactions will set it apart from competitors like shadcn/ui and create a world-class developer experience.
**Next Steps**:
1. Review and approve plan
2. Prioritize features
3. Begin Week 1 critical fixes
4. Iterate based on user feedback
---
*Document generated from automated UI/UX review*
*Last updated: 2025-11-13*
+44 -43
View File
@@ -11,7 +11,8 @@
"workspaces": [
"app",
"apps/*",
"pkgs/*"
"packages/*",
"pkg/*"
],
"scripts": {
"build": "turbo run build",
@@ -50,10 +51,10 @@
"format:write": "turbo run format:write",
"format:check": "turbo run format:check",
"sync:templates": "./scripts/sync-templates.sh \"templates/*\"",
"check": "bash scripts/check-no-brand-pkg.sh && turbo lint typecheck format:check",
"check": "turbo lint typecheck format:check",
"release": "changeset version",
"pub:beta": "cd pkgs/hanzo && pnpm pub:beta",
"pub:release": "cd pkgs/hanzo && pnpm pub:release",
"pub:beta": "cd packages/hanzo && pnpm pub:beta",
"pub:release": "cd packages/hanzo && pnpm pub:release",
"test:dev": "turbo run test --filter=!hanzo-ui --force",
"test": "start-server-and-test v4:dev http://localhost:4000 test:dev",
"validate:registries": "pnpm --filter=v4 validate:registries",
@@ -70,67 +71,67 @@
},
"packageManager": "pnpm@9.0.6",
"dependencies": {
"@babel/core": "^7.29.7",
"@changesets/changelog-github": "^0.7.0",
"@changesets/cli": "^2.31.0",
"@commitlint/cli": "^21.0.2",
"@commitlint/config-conventional": "^21.0.2",
"@babel/core": "^7.29.0",
"@changesets/changelog-github": "^0.6.0",
"@changesets/cli": "^2.30.0",
"@commitlint/cli": "^20.5.0",
"@commitlint/config-conventional": "^20.5.0",
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@manypkg/cli": "^0.25.1",
"@tanstack/react-table": "^8.21.3",
"@typescript-eslint/parser": "^8.60.1",
"autoprefixer": "^10.5.0",
"chrono-node": "^2.9.1",
"eslint": "^10.4.1",
"eslint-config-next": "16.2.7",
"@typescript-eslint/parser": "^8.57.1",
"autoprefixer": "^10.4.27",
"chrono-node": "^2.9.0",
"eslint": "^10.1.0",
"eslint-config-next": "16.2.1",
"eslint-config-prettier": "^10.1.8",
"eslint-config-turbo": "^2.9.16",
"eslint-config-turbo": "^2.8.20",
"eslint-plugin-react": "^7.37.5",
"little-date": "^1.2.1",
"motion": "^12.40.0",
"postcss": "^8.5.15",
"puppeteer": "^25.1.0",
"recharts": "^3.8.1",
"motion": "^12.38.0",
"postcss": "^8.5.8",
"puppeteer": "^24.40.0",
"recharts": "^3.8.0",
"tailwindcss-animate": "^1.0.7",
"tsx": "^4.22.4",
"tsx": "^4.21.0",
"vite-tsconfig-paths": "^6.1.1"
},
"devDependencies": {
"@ianvs/prettier-plugin-sort-imports": "^4.7.1",
"@playwright/test": "^1.60.0",
"@tailwindcss/oxide": "^4.3.0",
"@playwright/test": "^1.58.2",
"@tailwindcss/oxide": "^4.2.2",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.1",
"@types/hast": "^3.0.4",
"@types/node": "^25.9.1",
"@types/react": "19.2.16",
"@types/node": "^25.5.0",
"@types/react": "19.2.14",
"@types/react-dom": "19.2.3",
"@vitejs/plugin-react": "^6.0.2",
"@vitest/coverage-v8": "4.1.8",
"@vitest/ui": "^4.1.8",
"@vitejs/plugin-react": "^6.0.1",
"@vitest/coverage-v8": "4.1.0",
"@vitest/ui": "^4.1.0",
"chalk": "^5.6.2",
"concurrently": "^10.0.3",
"concurrently": "^9.2.1",
"cross-env": "^10.1.0",
"eslint-plugin-tailwindcss": "3.18.3",
"happy-dom": "^20.9.0",
"eslint-plugin-tailwindcss": "3.18.2",
"happy-dom": "^20.8.4",
"jest-axe": "^10.0.0",
"jsdom": "^29.1.1",
"lucide-react": "^1.17.0",
"playwright": "^1.60.0",
"prettier": "^3.8.3",
"jsdom": "^29.0.1",
"lucide-react": "^0.577.0",
"playwright": "^1.58.2",
"prettier": "^3.8.1",
"pretty-quick": "^4.2.2",
"react": "19.2.7",
"react-dom": "19.2.7",
"start-server-and-test": "^3.0.6",
"tailwindcss": "4.3.0",
"react": "19.2.4",
"react-dom": "19.2.4",
"start-server-and-test": "^2.1.5",
"tailwindcss": "4.2.2",
"tsup": "^8.5.1",
"turbo": "^2.9.16",
"typescript": "^6.0.3",
"vite": "^8.0.16",
"vitest": "^4.1.8",
"turbo": "^2.8.20",
"typescript": "^5.9.3",
"vite": "^8.0.1",
"vitest": "^4.1.0",
"vitest-axe": "^0.1.0"
},
"pnpm": {
@@ -170,6 +171,6 @@
]
},
"optionalDependencies": {
"react-resizable-panels": "^4.11.2"
"react-resizable-panels": "^3.0.6"
}
}
@@ -2,6 +2,9 @@
"name": "shadcn",
"version": "4.1.0",
"description": "Add components to your apps.",
"publishConfig": {
"access": "public"
},
"license": "MIT",
"author": {
"name": "shadcn",
@@ -80,7 +83,7 @@
"@babel/parser": "^7.28.0",
"@babel/plugin-transform-typescript": "^7.28.0",
"@babel/preset-typescript": "^7.27.1",
"@dotenvx/dotenvx": "^1.73.1",
"@dotenvx/dotenvx": "^1.48.4",
"@modelcontextprotocol/sdk": "^1.26.0",
"@types/validate-npm-package-name": "^4.0.2",
"browserslist": "^4.26.2",
@@ -121,6 +124,5 @@
"tsup": "^8.5.0",
"type-fest": "^4.41.0",
"typescript": "^5.9.2"
},
"private": true
}
}

Some files were not shown because too many files have changed in this diff Show More