ui: export the layout primitives, so an app can actually import from here
Publish Packages / detect-changes (push) Successful in 22s
Publish Packages / publish (${{ fromJson(needs.detect-changes.outputs.packages) }}) (push) Successful in 6m31s
Hanzo CI/CD / cicd (push) Canceled after 7m11s
CI/CD / cicd (push) Canceled after 7m11s

This package's root barrel says it is "the canonical component API apps
import", and it shipped Button, Card and Dialog while omitting the stacks
and the type scale. So no app could obey the rule. Measured in hanzo.app:
216 files import @hanzo/gui DIRECTLY — YStack 199, XStack 185,
SizableText 185, Paragraph 161, H3 66, H1 43, Anchor 41, H2 39, Image 20,
H4 15, plus View/Text/GuiElement — because there was nowhere else to get
them.

An app reaching past its component library is not a style problem. It is
the library failing to be the one door: the app pins its own @hanzo/gui,
can resolve a SECOND copy of the runtime (which is how "Missing theme."
happens), and every primitive it draws then sits outside anything this
package can theme, restyle or fix centrally.

src/backends/gui/layout.ts re-exports them by name — never `export *`,
which this client boundary refuses and which would defeat tree-shaking —
so @hanzo/gui is named in exactly ONE place and is an implementation
detail again. Separator is deliberately not among them: this package
already ships its own, and a duplicate export would shadow it.

Every name verified to resolve against @hanzo/gui@8.1.0 by typechecking
the full import list, not by reading a d.ts — the barrel re-exports
through @hanzogui/* sub-packages, so grepping for a declaration finds
nothing and would have talked me out of a list that is in fact correct.

scripts/gen-primitives.mjs re-run: 114 member entrypoints, so root,
./primitives and ./primitives/* stay three doors into one room.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
This commit is contained in:
zooqueen
2026-08-06 14:20:29 -07:00
co-authored by hanzo-dev
parent 5defea2fb0
commit f7925fc356
23 changed files with 151 additions and 2 deletions
+2 -2
View File
@@ -1,8 +1,8 @@
{
"name": "@hanzo/ui",
"version": "8.0.64",
"version": "8.0.65",
"type": "module",
"description": "Hanzo UI \u2014 the one canonical Hanzo component library, on @hanzo/gui + @hanzo/design. ONE substrate: every component renders through @hanzo/gui primitives, so the same import works on web, native (expo) and desktop (Tauri). Self-contained (theme.css), presentational, host-agnostic, clean-room.",
"description": "Hanzo UI the one canonical Hanzo component library, on @hanzo/gui + @hanzo/design. ONE substrate: every component renders through @hanzo/gui primitives, so the same import works on web, native (expo) and desktop (Tauri). Self-contained (theme.css), presentational, host-agnostic, clean-room.",
"exports": {
".": {
"types": "./dist/index.d.ts",
+9
View File
@@ -89,6 +89,15 @@ export {
type ResizablePanelProps,
type ResizableHandleProps,
} from './resizable'
// The layout primitives. Without these an app cannot obey "import from
// @hanzo/ui" — it has to reach past this package to @hanzo/gui, which is how
// 216 files in hanzo.app ended up doing exactly that. See ./layout.
export {
XStack, YStack, ZStack,
SizableText, Paragraph, Heading, H1, H2, H3, H4, H5, H6, Span, Strong, Em,
Image, Spacer, ScrollView, View, Text,
type GuiElement,
} from './layout'
export { ScrollArea, ScrollBar } from './scroll-area'
export {
Select,
+60
View File
@@ -0,0 +1,60 @@
'use client'
/**
* LAYOUT — the primitives an app lays a screen out with.
*
* These are re-exports of @hanzo/gui, and that is the whole point: this package
* is declared to be "the canonical component API apps import", but it shipped
* Button, Card and Dialog while omitting the stacks and the type scale. So no
* app could actually obey the rule. Measured in hanzo.app: 216 files import
* @hanzo/gui DIRECTLY — YStack (199), XStack (185), SizableText (185),
* Paragraph (161), H3 (66), H1 (43), Anchor (41), H2 (39), Image (20), H4 (15),
* View, Text, GuiElement — because there was nowhere else to get them.
*
* An app reaching past its component library is not a style problem. It is the
* library failing to be the one door: the app then pins its own @hanzo/gui
* version, resolves a second copy of the runtime (which is how "Missing theme."
* happens), and every primitive it draws sits outside anything this package can
* restyle, theme or fix centrally.
*
* So: ONE import source. `@hanzo/gui` is an implementation detail of
* `@hanzo/ui`, named in exactly one place — here.
*
* Named, never `export *`: this is a client boundary and Next refuses a star
* across one ("It's currently unsupported to use `export *` in a client
* boundary"), and a star also defeats tree-shaking, so importing XStack would
* drag the whole gui surface in. Same rule the root barrel already follows.
*/
export {
// Stacks — @hanzogui/stacks
XStack,
YStack,
ZStack,
// Type scale — @hanzogui/text. `SizableText` is the workhorse; the headings
// carry the scale so a screen never hand-picks a font size.
SizableText,
Paragraph,
Heading,
H1,
H2,
H3,
H4,
H5,
H6,
Span,
Strong,
Em,
// Leaves — an image, a rule, a gap, a scroller.
Image,
Spacer,
ScrollView,
// The untyped hosts, for the rare case a component needs a bare box.
View,
Text,
} from '@hanzo/gui'
export type { GuiElement } from '@hanzo/gui'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { Em } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { H1 } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { H2 } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { H3 } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { H4 } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { H5 } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { H6 } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { Heading } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { Image } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { Paragraph } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { ScrollView } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { SizableText } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { Spacer } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { Span } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { Strong } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { Text } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { View } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { XStack } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { YStack } from '../backends/gui/layout'
+4
View File
@@ -0,0 +1,4 @@
// GENERATED by scripts/gen-primitives.mjs — do not edit. Per-member entrypoint
// for hosts that modularize `@hanzo/ui` imports. Source of truth:
// src/backends/gui/index.ts. Re-run: node scripts/gen-primitives.mjs
export { ZStack } from '../backends/gui/layout'