@hanzo/ui 8.0.8 → 8.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/LICENSE.md +21 -0
  2. package/dist/backends/gui/index.d.ts +2 -0
  3. package/dist/backends/shadcn/aspect-ratio.d.ts +4 -0
  4. package/dist/backends/shadcn/avatar.d.ts +6 -0
  5. package/dist/backends/shadcn/badge.d.ts +9 -0
  6. package/dist/backends/shadcn/button.d.ts +19 -0
  7. package/dist/backends/shadcn/card.d.ts +9 -0
  8. package/dist/backends/shadcn/checkbox.d.ts +9 -0
  9. package/dist/backends/shadcn/collapsible.d.ts +5 -0
  10. package/dist/backends/shadcn/command.d.ts +80 -0
  11. package/dist/backends/shadcn/dialog.d.ts +15 -0
  12. package/dist/backends/shadcn/dropdown-menu.d.ts +34 -0
  13. package/dist/backends/shadcn/index.d.ts +23 -0
  14. package/dist/backends/shadcn/input.d.ts +11 -0
  15. package/dist/backends/shadcn/label.d.ts +4 -0
  16. package/dist/backends/shadcn/popover.d.ts +7 -0
  17. package/dist/backends/shadcn/progress.d.ts +4 -0
  18. package/dist/backends/shadcn/scroll-area.d.ts +5 -0
  19. package/dist/backends/shadcn/select.d.ts +13 -0
  20. package/dist/backends/shadcn/separator.d.ts +4 -0
  21. package/dist/backends/shadcn/slider.d.ts +4 -0
  22. package/dist/backends/shadcn/switch.d.ts +4 -0
  23. package/dist/backends/shadcn/tabs.d.ts +7 -0
  24. package/dist/backends/shadcn/textarea.d.ts +4 -0
  25. package/dist/backends/shadcn/toaster.d.ts +10 -0
  26. package/dist/backends/shadcn/tooltip.d.ts +7 -0
  27. package/dist/backends/shadcn/utils.d.ts +8 -0
  28. package/dist/components.d.ts +1 -0
  29. package/dist/core/cn.d.ts +11 -0
  30. package/dist/core/fonts.d.ts +26 -0
  31. package/dist/core/index.d.ts +3 -0
  32. package/dist/core/tokens.d.ts +16 -0
  33. package/dist/index.cjs +1138 -283
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.ts +2 -2
  36. package/dist/index.js +1017 -3
  37. package/dist/index.js.map +1 -1
  38. package/dist/models/ModelSelector.d.ts +23 -0
  39. package/dist/models/catalog.d.ts +53 -0
  40. package/dist/models/index.d.ts +5 -0
  41. package/dist/models/types.d.ts +39 -0
  42. package/dist/oss/blueprint.d.ts +37 -0
  43. package/dist/oss/catalog.d.ts +67 -0
  44. package/dist/oss.cjs +190 -0
  45. package/dist/oss.cjs.map +1 -0
  46. package/dist/oss.d.ts +2 -0
  47. package/dist/oss.js +180 -0
  48. package/dist/oss.js.map +1 -0
  49. package/dist/primitives/AspectRatio.d.ts +1 -0
  50. package/dist/primitives/Avatar.d.ts +1 -0
  51. package/dist/primitives/AvatarFallback.d.ts +1 -0
  52. package/dist/primitives/AvatarImage.d.ts +1 -0
  53. package/dist/primitives/Badge.d.ts +1 -0
  54. package/dist/primitives/Button.d.ts +1 -0
  55. package/dist/primitives/Card.d.ts +1 -0
  56. package/dist/primitives/CardAction.d.ts +1 -0
  57. package/dist/primitives/CardContent.d.ts +1 -0
  58. package/dist/primitives/CardDescription.d.ts +1 -0
  59. package/dist/primitives/CardFooter.d.ts +1 -0
  60. package/dist/primitives/CardHeader.d.ts +1 -0
  61. package/dist/primitives/CardTitle.d.ts +1 -0
  62. package/dist/primitives/Checkbox.d.ts +1 -0
  63. package/dist/primitives/Collapsible.d.ts +1 -0
  64. package/dist/primitives/CollapsibleContent.d.ts +1 -0
  65. package/dist/primitives/CollapsibleTrigger.d.ts +1 -0
  66. package/dist/primitives/Command.d.ts +1 -0
  67. package/dist/primitives/CommandDialog.d.ts +1 -0
  68. package/dist/primitives/CommandEmpty.d.ts +1 -0
  69. package/dist/primitives/CommandGroup.d.ts +1 -0
  70. package/dist/primitives/CommandInput.d.ts +1 -0
  71. package/dist/primitives/CommandItem.d.ts +1 -0
  72. package/dist/primitives/CommandList.d.ts +1 -0
  73. package/dist/primitives/CommandSeparator.d.ts +1 -0
  74. package/dist/primitives/CommandShortcut.d.ts +1 -0
  75. package/dist/primitives/Dialog.d.ts +1 -0
  76. package/dist/primitives/DialogClose.d.ts +1 -0
  77. package/dist/primitives/DialogContent.d.ts +1 -0
  78. package/dist/primitives/DialogDescription.d.ts +1 -0
  79. package/dist/primitives/DialogFooter.d.ts +1 -0
  80. package/dist/primitives/DialogHeader.d.ts +1 -0
  81. package/dist/primitives/DialogOverlay.d.ts +1 -0
  82. package/dist/primitives/DialogPortal.d.ts +1 -0
  83. package/dist/primitives/DialogTitle.d.ts +1 -0
  84. package/dist/primitives/DialogTrigger.d.ts +1 -0
  85. package/dist/primitives/DropdownMenu.d.ts +1 -0
  86. package/dist/primitives/DropdownMenuCheckboxItem.d.ts +1 -0
  87. package/dist/primitives/DropdownMenuContent.d.ts +1 -0
  88. package/dist/primitives/DropdownMenuGroup.d.ts +1 -0
  89. package/dist/primitives/DropdownMenuItem.d.ts +1 -0
  90. package/dist/primitives/DropdownMenuLabel.d.ts +1 -0
  91. package/dist/primitives/DropdownMenuPortal.d.ts +1 -0
  92. package/dist/primitives/DropdownMenuRadioGroup.d.ts +1 -0
  93. package/dist/primitives/DropdownMenuRadioItem.d.ts +1 -0
  94. package/dist/primitives/DropdownMenuSeparator.d.ts +1 -0
  95. package/dist/primitives/DropdownMenuShortcut.d.ts +1 -0
  96. package/dist/primitives/DropdownMenuSub.d.ts +1 -0
  97. package/dist/primitives/DropdownMenuSubContent.d.ts +1 -0
  98. package/dist/primitives/DropdownMenuSubTrigger.d.ts +1 -0
  99. package/dist/primitives/DropdownMenuTrigger.d.ts +1 -0
  100. package/dist/primitives/Input.d.ts +1 -0
  101. package/dist/primitives/Label.d.ts +1 -0
  102. package/dist/primitives/Popover.d.ts +1 -0
  103. package/dist/primitives/PopoverAnchor.d.ts +1 -0
  104. package/dist/primitives/PopoverContent.d.ts +1 -0
  105. package/dist/primitives/PopoverTrigger.d.ts +1 -0
  106. package/dist/primitives/Progress.d.ts +1 -0
  107. package/dist/primitives/ScrollArea.d.ts +1 -0
  108. package/dist/primitives/ScrollBar.d.ts +1 -0
  109. package/dist/primitives/Select.d.ts +1 -0
  110. package/dist/primitives/SelectContent.d.ts +1 -0
  111. package/dist/primitives/SelectGroup.d.ts +1 -0
  112. package/dist/primitives/SelectItem.d.ts +1 -0
  113. package/dist/primitives/SelectLabel.d.ts +1 -0
  114. package/dist/primitives/SelectScrollDownButton.d.ts +1 -0
  115. package/dist/primitives/SelectScrollUpButton.d.ts +1 -0
  116. package/dist/primitives/SelectSeparator.d.ts +1 -0
  117. package/dist/primitives/SelectTrigger.d.ts +1 -0
  118. package/dist/primitives/SelectValue.d.ts +1 -0
  119. package/dist/primitives/Separator.d.ts +1 -0
  120. package/dist/primitives/Slider.d.ts +1 -0
  121. package/dist/primitives/Switch.d.ts +1 -0
  122. package/dist/primitives/Tabs.d.ts +1 -0
  123. package/dist/primitives/TabsContent.d.ts +1 -0
  124. package/dist/primitives/TabsList.d.ts +1 -0
  125. package/dist/primitives/TabsTrigger.d.ts +1 -0
  126. package/dist/primitives/Textarea.d.ts +1 -0
  127. package/dist/primitives/Toaster.d.ts +1 -0
  128. package/dist/primitives/Tooltip.d.ts +1 -0
  129. package/dist/primitives/TooltipContent.d.ts +1 -0
  130. package/dist/primitives/TooltipProvider.d.ts +1 -0
  131. package/dist/primitives/TooltipTrigger.d.ts +1 -0
  132. package/dist/primitives/badgeVariants.d.ts +1 -0
  133. package/dist/primitives/buttonVariants.d.ts +1 -0
  134. package/dist/primitives/index.d.ts +1 -0
  135. package/dist/primitives/toast.d.ts +1 -0
  136. package/dist/product/AnimatedLogo.d.ts +47 -0
  137. package/dist/product/BackendState.d.ts +42 -0
  138. package/dist/product/Charts.d.ts +4 -0
  139. package/dist/product/CommerceResource.d.ts +32 -0
  140. package/dist/product/ConfirmDelete.d.ts +8 -0
  141. package/dist/product/DataTable.d.ts +30 -2
  142. package/dist/product/Field.d.ts +7 -2
  143. package/dist/product/Filters.d.ts +29 -0
  144. package/dist/product/OrgMark.d.ts +21 -0
  145. package/dist/product/OrgSwitcher.d.ts +8 -1
  146. package/dist/product/PrimaryButton.d.ts +5 -0
  147. package/dist/product/SiteFooter.d.ts +28 -0
  148. package/dist/product/SiteNav.d.ts +60 -0
  149. package/dist/product/accent.d.ts +33 -0
  150. package/dist/product/animatedLogo.logic.d.ts +52 -0
  151. package/dist/product/brand.d.ts +45 -0
  152. package/dist/product/host.d.ts +21 -0
  153. package/dist/product/index.cjs +3205 -257
  154. package/dist/product/index.cjs.map +1 -1
  155. package/dist/product/index.d.ts +12 -0
  156. package/dist/product/index.js +3103 -1
  157. package/dist/product/index.js.map +1 -1
  158. package/dist/product/social/CampaignCard.d.ts +13 -0
  159. package/dist/product/social/ChannelBadge.d.ts +12 -0
  160. package/dist/product/social/PostAgenda.d.ts +5 -0
  161. package/dist/product/social/PostCard.d.ts +15 -0
  162. package/dist/product/social/PostComposer.d.ts +24 -0
  163. package/dist/product/social/ProviderReadinessList.d.ts +10 -0
  164. package/dist/product/social/SocialSummaryBar.d.ts +9 -0
  165. package/dist/product/social/ViewToggle.d.ts +5 -0
  166. package/dist/product/social/format.d.ts +16 -0
  167. package/dist/product/social/index.d.ts +9 -0
  168. package/dist/product/surfaces.data.d.ts +1 -0
  169. package/dist/styles/hanzo-motion.css +52 -0
  170. package/dist/telemetry.cjs +15 -0
  171. package/dist/telemetry.cjs.map +1 -0
  172. package/dist/telemetry.d.ts +1 -0
  173. package/dist/telemetry.js +4 -0
  174. package/dist/telemetry.js.map +1 -0
  175. package/package.json +106 -19
  176. package/dist/chunk-GDGVXU7W.js +0 -1999
  177. package/dist/chunk-GDGVXU7W.js.map +0 -1
  178. package/dist/chunk-HSPMQQVJ.cjs +0 -2066
  179. package/dist/chunk-HSPMQQVJ.cjs.map +0 -1
@@ -0,0 +1,47 @@
1
+ /**
2
+ * AnimatedLogo — the ONE animated brand logo across every Hanzo surface.
3
+ *
4
+ * On mount the full wordmark shows ("Hanzo {surface}", e.g. "Hanzo Cloud"), then
5
+ * collapses INTO just the brand mark; hover or keyboard-focus expands it back to
6
+ * the full name. This is the shared brand-identity primitive — the behavior that
7
+ * ships on hanzo.ai and cloud.hanzo.ai, made one component, white-label aware.
8
+ *
9
+ * <AnimatedLogo surface="Cloud" /> // Hanzo Cloud → H
10
+ * <AnimatedLogo surface="Studio" /> // Hanzo Studio → H
11
+ * <AnimatedLogo surface="Cloud" brand={LUX} /> // Lux Cloud → Lux mark
12
+ *
13
+ * Presentational + host-agnostic (plain React + inline SVG, no @hanzo/gui, no
14
+ * framer): drops into any surface — the Tamagui console, the Next marketing site,
15
+ * a desktop shell. Theme-aware (the mark is `currentColor`), and accessible: the
16
+ * accessible name is always the full "Hanzo {surface}" regardless of the visual
17
+ * collapse, and `prefers-reduced-motion` yields a static mark with no animation.
18
+ */
19
+ import React from 'react';
20
+ import { type BrandIdentity } from './brand';
21
+ export interface AnimatedLogoProps {
22
+ /** Surface word after the brand ("AI", "Cloud", "Studio", "Chat", "App", "Console", "Team"). */
23
+ surface?: string;
24
+ /** Brand identity — mark + name + home. Defaults to Hanzo. */
25
+ brand?: BrandIdentity;
26
+ /** Mark size in px (square). Default 22. */
27
+ size?: number;
28
+ /** Gap in px between the mark and the wordmark when expanded. Default 8. */
29
+ gap?: number;
30
+ /** Hold in ms before the wordmark auto-collapses on mount. 0 disables the intro
31
+ * (starts collapsed). Default 1500. */
32
+ introMs?: number;
33
+ /** Collapse/expand duration in ms. Default 360 (echoes the mark's fold-in). */
34
+ durationMs?: number;
35
+ /** Easing curve. Default the Hanzo house expo-out. */
36
+ easing?: string;
37
+ /** Link target. Defaults to the brand's home. */
38
+ href?: string;
39
+ onClick?: React.MouseEventHandler;
40
+ /** Root element/component (e.g. a router `Link`). Default `'a'`. */
41
+ component?: React.ElementType;
42
+ className?: string;
43
+ style?: React.CSSProperties;
44
+ /** Override the accessible name (default is the full "Hanzo {surface}"). */
45
+ 'aria-label'?: string;
46
+ }
47
+ export declare function AnimatedLogo({ surface, brand, size, gap, introMs, durationMs, easing, href, onClick, component, className, style, 'aria-label': ariaLabel, }: AnimatedLogoProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Honest backend states for `/v1`-backed modules — ONE place that maps a thrown
3
+ * HTTP error to a truthful explanation.
4
+ *
5
+ * A 503 means the runtime/keys aren't wired on this deployment yet, a 404/405
6
+ * means the route isn't mounted here, 401/403 means the session can't read it,
7
+ * 402 means the org has no funded balance. Nothing is fabricated — on failure the
8
+ * caller shows this card instead of placeholder rows/charts.
9
+ *
10
+ * Classification is duck-typed on `status`, so any client's error class works
11
+ * (console's `ApiError`, commerce's `CommerceError`, …) without this layer
12
+ * depending on one. Effects come from `useHost()`.
13
+ */
14
+ import type { ReactNode } from 'react';
15
+ export type BackendStateKind = 'not-initialized' | 'unavailable' | 'not-implemented' | 'access' | 'signin' | 'billing' | 'error';
16
+ export type BackendState = {
17
+ kind: BackendStateKind;
18
+ message: string;
19
+ };
20
+ /**
21
+ * Classify a thrown `/v1` error into an honest kind + raw message.
22
+ *
23
+ * 401 and 403 are DISTINCT for a signed-in user: 401 = the session is expired /
24
+ * not recognized (re-auth fixes it → `signin`), 403 = the account IS signed in
25
+ * but this surface isn't authorized/enabled for its org (`access`). A signed-in
26
+ * user is NEVER told to "sign in" for a 403 — that would be a false instruction.
27
+ */
28
+ export declare function classifyBackend(e: unknown): BackendState;
29
+ /**
30
+ * Classify a READ (GET/list) failure. Identical to `classifyBackend` EXCEPT a 402
31
+ * is NOT a wall: listing/reading a resource is never credit-gated, so a 402 on a
32
+ * read means "nothing is provisioned yet" — the caller shows its honest EMPTY
33
+ * state (e.g. "No buckets yet · Create one"), never an "add credits" paywall
34
+ * (that belongs only on a paid WRITE). Returns `null` for a 402 → treat as empty.
35
+ */
36
+ export declare function classifyRead(e: unknown): BackendState | null;
37
+ /** A truthful state card for a `/v1` load failure, with an optional retry + hint. */
38
+ export declare function BackendStateCard({ state, onRetry, hint, }: {
39
+ state: BackendState;
40
+ onRetry?: () => void;
41
+ hint?: ReactNode;
42
+ }): import("react/jsx-runtime").JSX.Element;
@@ -34,6 +34,10 @@ export type Slice = {
34
34
  color?: string;
35
35
  hint?: string;
36
36
  };
37
+ export declare function useContainerWidth(): {
38
+ ref: import("react").RefObject<HTMLDivElement | null>;
39
+ w: number;
40
+ };
37
41
  export declare function Sparkline({ values, width, height, color, }: {
38
42
  values: number[];
39
43
  width?: number;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * CommerceResource — the ONE list surface every Commerce store page renders (Products,
3
+ * Orders, Customers, Inventory, Promotions). It owns the fetch → honest loading / empty
4
+ * / error lifecycle (identical to the Subscriptions/Functions modules) so each page is
5
+ * just a title + a `load()` + its columns; there is one way to render a store list.
6
+ *
7
+ * `load` is held in a ref so a page can pass an inline `() => CommerceApi.products()`
8
+ * without re-triggering the mount effect — the list fetches once and on explicit
9
+ * Refresh. Every row is real (the caller's org-scoped `/v1` fetch); an empty store
10
+ * shows the honest empty copy, never a placeholder row. Both the console's Store
11
+ * category and the standalone Commerce admin render THIS.
12
+ */
13
+ import { type ReactNode } from 'react';
14
+ import { type Column } from './DataTable';
15
+ /** A commerce list page — the rows on this page plus the total the backend reports. */
16
+ export type CommerceList<T> = {
17
+ rows: T[];
18
+ count: number;
19
+ };
20
+ export declare function CommerceResource<T>({ title, subtitle, load, columns, rowKey, empty, hint, actions, }: {
21
+ title: string;
22
+ subtitle: string;
23
+ /** Real per-org fetch (via the `/commerce` proxy). Identity may change per render. */
24
+ load: () => Promise<CommerceList<T>>;
25
+ columns: Column<T>[];
26
+ rowKey: (row: T) => string;
27
+ empty: string;
28
+ /** BackendStateCard hint — the real endpoint, e.g. `GET /v1/product`. */
29
+ hint: string;
30
+ /** Optional extra header actions (given the reload fn), left of Refresh. */
31
+ actions?: (reload: () => void) => ReactNode;
32
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,8 @@
1
+ export declare function ConfirmDelete({ message, confirmLabel, run, onDone, }: {
2
+ /** The full consequence, stated plainly ("Delete X and all N of its records?"). */
3
+ message: string;
4
+ confirmLabel: string;
5
+ run: () => Promise<void>;
6
+ /** Called on success AND on cancel — the caller closes the drawer and reloads. */
7
+ onDone: () => void;
8
+ }): import("react/jsx-runtime").JSX.Element;
@@ -3,7 +3,16 @@
3
3
  *
4
4
  * Rows are typed `<T>`; columns declare a key, header, and optional cell
5
5
  * renderer. Built on Hanzo GUI Stacks (shorthand style props per the v5 config)
6
- * so it adapts across platforms. Loading and empty states are first-class.
6
+ * so it adapts across platforms. Loading and empty states are first-class:
7
+ * loading paints SKELETON ROWS in the real column layout (an honest "loading",
8
+ * never a spinner void); numeric columns opt into right-aligned Geist Mono
9
+ * tabular figures so amounts/counts/IDs read as precise, column-aligned data.
10
+ *
11
+ * SORTING is opt-in and caller-owned: a column marks itself `sortable`, the caller
12
+ * passes the current `sort` + an `onSortChange`, and the table only reports the
13
+ * clicked key (it never reorders `rows` itself — the caller's own pure comparator
14
+ * stays the one source of order). Omit all three and the table behaves exactly as
15
+ * before, so every existing consumer is unchanged.
7
16
  */
8
17
  import type { ReactNode } from 'react';
9
18
  export type Column<T> = {
@@ -13,12 +22,31 @@ export type Column<T> = {
13
22
  render?: (row: T) => ReactNode;
14
23
  /** Fixed width (px) for the column; otherwise flexes. */
15
24
  width?: number;
25
+ /** Horizontal alignment — `right` for numeric/amount columns. */
26
+ align?: 'left' | 'right';
27
+ /** Typeset the default cell + header as Geist Mono tabular (counts, amounts, IDs). */
28
+ mono?: boolean;
29
+ /** Clickable header that reports `onSortChange(key)` (needs both table props). */
30
+ sortable?: boolean;
31
+ };
32
+ /** The active sort — which column key, which direction. */
33
+ export type SortState = {
34
+ key: string;
35
+ dir: 'asc' | 'desc';
16
36
  };
17
- export declare function DataTable<T>({ columns, rows, loading, empty, rowKey, onRowPress, }: {
37
+ export declare function DataTable<T>({ columns, rows, loading, empty, rowKey, onRowPress, isRowExpanded, renderExpanded, sort, onSortChange, }: {
18
38
  columns: Column<T>[];
19
39
  rows: T[];
20
40
  loading?: boolean;
21
41
  empty?: string;
22
42
  rowKey: (row: T) => string;
23
43
  onRowPress?: (row: T) => void;
44
+ /** When set + true for a row, its `renderExpanded` panel is shown below it. */
45
+ isRowExpanded?: (row: T) => boolean;
46
+ /** Full-width detail panel rendered under an expanded row (master-detail accordion). */
47
+ renderExpanded?: (row: T) => ReactNode;
48
+ /** The active sort, for the header caret + `aria-sort`. */
49
+ sort?: SortState;
50
+ /** Called with the clicked column key; the caller owns the reordering. */
51
+ onSortChange?: (key: string) => void;
24
52
  }): import("react/jsx-runtime").JSX.Element;
@@ -6,7 +6,11 @@
6
6
  * use the v5 shorthand set (p/px/items/justify/...).
7
7
  */
8
8
  import type { ReactNode } from 'react';
9
- /** Labeled row: fixed label column + flexing control. */
9
+ /**
10
+ * Labeled row. STACKED on phones (label full-width above a full-width control) so a
11
+ * form inside a SlideOver stays usable and never clips its labels; a fixed 180px
12
+ * label column + flexing control at $md+ (the two-column desktop/tablet layout).
13
+ */
10
14
  export declare function FieldRow({ label, children }: {
11
15
  label: string;
12
16
  children: ReactNode;
@@ -29,11 +33,12 @@ export declare function FieldSwitch({ checked, onChange, disabled, }: {
29
33
  onChange: (v: boolean) => void;
30
34
  disabled?: boolean;
31
35
  }): import("react/jsx-runtime").JSX.Element;
32
- export declare function FieldSelect({ value, options, onChange, disabled, }: {
36
+ export declare function FieldSelect({ value, options, onChange, disabled, placeholder, }: {
33
37
  value: string;
34
38
  options: string[];
35
39
  onChange: (v: string) => void;
36
40
  disabled?: boolean;
41
+ placeholder?: string;
37
42
  }): import("react/jsx-runtime").JSX.Element;
38
43
  export declare function FieldSlider({ value, min, max, step, onChange, disabled, }: {
39
44
  value: number;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * List-filter atoms — the ONE segmented pill control and the ONE search box every
3
+ * table surface filters with.
4
+ *
5
+ * These were first written for the Inference endpoints dashboard; promoted here so a
6
+ * sibling product (Infrastructure, …) never reaches into `inference/` for shell chrome
7
+ * — the same separation-of-concerns move `ui/Metric.tsx` made out of `gpus/`.
8
+ * `inference/parts.tsx` re-exports them, so there is exactly one definition.
9
+ */
10
+ import type { ComponentProps } from 'react';
11
+ import { Button } from '@hanzo/gui';
12
+ /** One pill in a segmented control. */
13
+ export type Option<T extends string> = {
14
+ label: string;
15
+ value: T;
16
+ };
17
+ /** A compact segmented pill control — the ONE way filters/ranges/toggles render. */
18
+ export declare function Segmented<T extends string>({ options, value, onChange, size, }: {
19
+ options: Option<T>[];
20
+ value: T;
21
+ onChange: (v: T) => void;
22
+ size?: ComponentProps<typeof Button>['size'];
23
+ }): import("react/jsx-runtime").JSX.Element;
24
+ /** A search input with a leading magnifier. */
25
+ export declare function SearchInput({ value, onChange, placeholder }: {
26
+ value: string;
27
+ onChange: (v: string) => void;
28
+ placeholder?: string;
29
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,21 @@
1
+ import type { Org } from './scope';
2
+ /**
3
+ * The monogram for a name: the first letter of each of the first two words,
4
+ * uppercased — the SAME rule @hanzo/iam's account widget applies to a person, so
5
+ * a workspace and a user wear one treatment. Words break on whitespace and on the
6
+ * separators an org id carries (`.`, `_`, `-`, `/`), so `acme-labs` reads AL
7
+ * while a single word reads its one initial.
8
+ */
9
+ export declare function monogram(name: string): string;
10
+ export type OrgMarkProps = {
11
+ /** The org to mark — its `logo` wins, else the monogram of its display name. */
12
+ org: Org;
13
+ /** Edge of the square tile / height of the logo. Default 22. */
14
+ size?: number;
15
+ /**
16
+ * Widest a LOGO may run, for a wordmark that is not square. Omit to keep the
17
+ * logo square like the monogram (a switcher row, an avatar slot).
18
+ */
19
+ maxW?: number;
20
+ };
21
+ export declare function OrgMark({ org, size, maxW }: OrgMarkProps): import("react/jsx-runtime").JSX.Element;
@@ -10,9 +10,16 @@ export type OrgSwitcherProps = {
10
10
  orgs?: (page: number, query: string) => Promise<Org[]>;
11
11
  /** Rows per page the loader returns. Default 20. */
12
12
  pageSize?: number;
13
+ /**
14
+ * The org the surface is scoped to, already resolved (display name + logo).
15
+ * Omit and the trigger synthesizes it from the scope id alone — enough to name
16
+ * the org, but it cannot know a logo. Pass it wherever the host already
17
+ * resolves the org, so the switcher and the chrome's org mark agree.
18
+ */
19
+ current?: Org;
13
20
  /** Create-org hook → the created org's id; omit to hide the affordance. */
14
21
  create?: (name: string) => Promise<string>;
15
22
  /** Show the "All organizations" de-scope row (`scope.leaveOrg`). */
16
23
  picker?: boolean;
17
24
  };
18
- export declare function OrgSwitcher({ scope, orgs, pageSize, create, picker }: OrgSwitcherProps): import("react/jsx-runtime").JSX.Element;
25
+ export declare function OrgSwitcher({ scope, orgs, pageSize, current: given, create, picker }: OrgSwitcherProps): import("react/jsx-runtime").JSX.Element;
@@ -6,6 +6,11 @@
6
6
  * hue accent. Use it for the single primary action in a view (sign in, save,
7
7
  * get started). Secondary and destructive actions use the default neutral
8
8
  * `Button`.
9
+ *
10
+ * When an org enables a custom brand color, this — the console's one primary
11
+ * action — recolors to the org accent (inline bg + the color prop the label/icon
12
+ * inherit), reading the live accent from `useAccent()`; with no custom theme it
13
+ * stays the default white. A caller's own `style`/`color` still win (spread last).
9
14
  */
10
15
  import type { ComponentProps } from 'react';
11
16
  import { Button } from '@hanzo/gui';
@@ -0,0 +1,28 @@
1
+ /**
2
+ * SiteFooter — the ONE footer, rendering `@hanzo/products`' `FOOTER`.
3
+ *
4
+ * 57 hand-written footers existed across the stack, differing in link set, column
5
+ * count, type scale and legal line, so the bottom of every Hanzo page quietly
6
+ * disagreed about what the company offers. The content question is already
7
+ * settled in `@hanzo/products` (columns built from `FAMILY` and `DESTINATIONS`,
8
+ * so a footer link and its menu twin cannot diverge); this is only the renderer.
9
+ *
10
+ * Deliberately not a mirror of the launcher: a footer is an index, not a menu, so
11
+ * every entry is a plain link and no product copy is repeated here.
12
+ */
13
+ import type { ReactNode } from 'react';
14
+ import type { Footer } from '@hanzo/products';
15
+ import type { LinkRender } from './SiteNav';
16
+ export type SiteFooterProps = {
17
+ /** The footer model — `FOOTER` from @hanzo/products. */
18
+ footer: Footer;
19
+ /** Brand slot above the columns — usually `<BrandMark/>`. */
20
+ brand?: ReactNode;
21
+ /** One line under the brand: what this company is. */
22
+ tagline?: string;
23
+ /** Social / status / app-store row, rendered opposite the copyright. */
24
+ meta?: ReactNode;
25
+ /** Host link primitive. */
26
+ link?: LinkRender;
27
+ };
28
+ export declare function SiteFooter({ footer, brand, tagline, meta, link }: SiteFooterProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * SiteNav — the ONE header every Hanzo property renders.
3
+ *
4
+ * `@hanzo/products` already decides WHAT the navigation is: `HEADERS[site]` gives
5
+ * a property's local nav and its call-to-action, and `MEET_HANZO_MENU` gives the
6
+ * ecosystem launcher (the six-product grid, the utility row, the install row).
7
+ * Nothing about that content lives here. This module is only the renderer — the
8
+ * missing half — so a property supplies a `SiteId` and gets the same header as
9
+ * every other property, and the six hand-written `DesktopNav`/`MobileMenu` copies
10
+ * that used to drift have nothing left to disagree about.
11
+ *
12
+ * It sits at the same 52px, border and background as `AppHeader`, so the
13
+ * signed-out marketing bar and the signed-in shell bar read as one object.
14
+ *
15
+ * Three deliberate choices, each fixing something the old menus got wrong:
16
+ *
17
+ * • The panel is FULL-BLEED. The old ones anchored a floating card to whichever
18
+ * word opened it, so a wide panel hung off-centre and the bar's alignment
19
+ * stopped meaning anything. Anchoring to the bar lets columns line up with the
20
+ * header and with each other.
21
+ * • Hover switches menus but never opens one. A bar where a passing cursor
22
+ * throws a full-width panel is hostile; the first open must be intentional.
23
+ * • ONE action. `SiteHeader.action` is a single call-to-action, so a property
24
+ * cannot render two competing sign-in buttons the way cloud.hanzo.ai did.
25
+ *
26
+ * Host-agnostic like the rest of this layer: `link` injects the host's navigation
27
+ * primitive and `icon` resolves a product/link id to a glyph, so nothing here
28
+ * imports a framework or an icon set.
29
+ */
30
+ import { type ReactNode } from 'react';
31
+ import type { MeetHanzoMenu, SiteHeader } from '@hanzo/products';
32
+ /** Render a destination. Hosts pass next/link etc.; the default is a plain anchor. */
33
+ export type LinkRender = (props: {
34
+ href: string;
35
+ children: ReactNode;
36
+ onNavigate?: () => void;
37
+ }) => ReactNode;
38
+ export type SiteNavProps = {
39
+ /** The property's header model — `HEADERS[site]` from @hanzo/products. */
40
+ header: SiteHeader;
41
+ /** The ecosystem launcher — `MEET_HANZO_MENU`. Omit to hide the launcher. */
42
+ menu?: MeetHanzoMenu;
43
+ /** Brand slot — usually `<BrandMark/>`; pressing it goes home. */
44
+ brand?: ReactNode;
45
+ /**
46
+ * Right-hand cluster BEFORE the action: an identity menu when signed in, or a
47
+ * sign-in link when signed out. The action itself comes from `header`, so this
48
+ * slot must not repeat it.
49
+ */
50
+ actions?: ReactNode;
51
+ /** Host link primitive. */
52
+ link?: LinkRender;
53
+ /** Resolve a product/link `id` to a glyph. Entries render fine without it. */
54
+ icon?: (id: string) => ReactNode;
55
+ /** Marks the active local-nav item by its `Link.id`. */
56
+ active?: string;
57
+ /** Launcher label. */
58
+ meetLabel?: string;
59
+ };
60
+ export declare function SiteNav({ header, menu, brand, actions, link, icon, active, meetLabel }: SiteNavProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,33 @@
1
+ /** An org's persisted theme block (mirrors IAM `themeData`; only the fields we apply). */
2
+ export type OrgThemeData = {
3
+ colorPrimary?: string;
4
+ isEnabled?: boolean;
5
+ };
6
+ /** The live accent — a resolved hex + a readable text color for content on it, or null. */
7
+ export type Accent = {
8
+ accent: string | null;
9
+ contrast: string;
10
+ };
11
+ /** True for a 3- or 6-digit CSS hex color (`#RGB` / `#RRGGBB`). */
12
+ export declare function isHexColor(v: string | undefined | null): boolean;
13
+ /**
14
+ * The accent hex to apply for an org, or `null` when no custom accent should be used —
15
+ * i.e. the theme is disabled, missing, or the color is not a valid hex. PURE.
16
+ */
17
+ export declare function resolveAccent(theme: OrgThemeData | null | undefined): string | null;
18
+ /**
19
+ * A readable text color (`#000000` / `#ffffff`) for content placed ON the accent,
20
+ * chosen by the accent's relative luminance (WCAG-style). PURE. Falls back to white
21
+ * for a non-hex input (never throws).
22
+ */
23
+ export declare function contrastText(hex: string): '#000000' | '#ffffff';
24
+ /** Resolve a theme block to the `Accent` value it should apply (accent+contrast or null). PURE. */
25
+ export declare function accentFor(theme: OrgThemeData | null | undefined): Accent;
26
+ /**
27
+ * Set the live accent from an org theme block. Called on load (from the fetched org) AND
28
+ * immediately on save — the SINGLE mechanism, so the accent survives reload and updates
29
+ * without one. A no-op when the resolved accent is unchanged (keeps the snapshot stable).
30
+ */
31
+ export declare function setOrgAccent(theme: OrgThemeData | null | undefined): void;
32
+ /** The live accent (subscribes to the store). Returns the default until an org theme is applied. */
33
+ export declare function useAccent(): Accent;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Pure logic for `AnimatedLogo` — the wordmark ⇄ mark collapse. No React, no DOM,
3
+ * no @hanzo/gui: just the state → style math, unit-tested in a plain Node env
4
+ * (the house convention — view components are proven by build + visual e2e).
5
+ */
6
+ /**
7
+ * The Hanzo house motion curve (expo-out) — the ONE easing used across the app
8
+ * shell (sidebar collapse, fade-up) and the animated mark's fold-in. Reused here
9
+ * so the wordmark collapse feels of a piece with every other Hanzo surface.
10
+ */
11
+ export declare const HOUSE_EASE = "cubic-bezier(0.16, 1, 0.3, 1)";
12
+ /** Default collapse/expand duration (ms) — echoes the mark's ~0.4s fold-in. */
13
+ export declare const DEFAULT_DURATION_MS = 360;
14
+ /** Default hold before the wordmark auto-collapses to the mark on mount (ms). */
15
+ export declare const DEFAULT_INTRO_MS = 1500;
16
+ /** Default gap (px) between the mark and the wordmark when expanded. */
17
+ export declare const DEFAULT_GAP = 8;
18
+ /** The full accessible/visible name: brand word + optional surface word. */
19
+ export declare function wordmarkText(name: string, surface?: string): string;
20
+ /**
21
+ * Is the wordmark shown? Expanded whenever the user is pointing at or keyboard-
22
+ * focused on the logo, OR during the on-mount intro (full name shows, then tucks
23
+ * into the mark). Hover/focus always win, so the name is reachable after intro.
24
+ */
25
+ export declare function isExpanded(s: {
26
+ hovered: boolean;
27
+ focused: boolean;
28
+ introShowing: boolean;
29
+ }): boolean;
30
+ export interface WordmarkStyleInput {
31
+ expanded: boolean;
32
+ /** Measured natural width (px); undefined before first measure (SSR/first paint). */
33
+ naturalWidth?: number;
34
+ gap: number;
35
+ durationMs: number;
36
+ easing: string;
37
+ /** prefers-reduced-motion: no transition (instant), so there is no motion. */
38
+ reduce: boolean;
39
+ }
40
+ export interface WordmarkStyle {
41
+ width: number | string;
42
+ opacity: number;
43
+ marginLeft: number;
44
+ transition: string;
45
+ }
46
+ /**
47
+ * The inline style for the clipping wordmark wrapper. Collapsed = width 0 /
48
+ * opacity 0 / no gap (the name tucks fully into the mark); expanded = the measured
49
+ * natural width (or `auto` until measured). Under reduced motion the transition is
50
+ * dropped entirely — the state still resolves, just without animating.
51
+ */
52
+ export declare function wordmarkStyle(i: WordmarkStyleInput): WordmarkStyle;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Brand identities for the animated logo — the white-label source of truth.
3
+ *
4
+ * ONE component (`AnimatedLogo`) renders any brand: pass a `BrandIdentity` and it
5
+ * shows THAT brand's mark + name (never a hardcoded Hanzo asset). The mark
6
+ * geometry is byte-identical to the console's host-driven brand registry
7
+ * (`console/src/lib/branding/brands.ts`) so a lux/zoo/pars surface renders the
8
+ * exact same glyph the chrome already uses — one mark, everywhere.
9
+ *
10
+ * `content` is inner SVG markup (a build-time-trusted constant, never user
11
+ * input). Marks use `currentColor` so they inherit the surrounding text color and
12
+ * adapt to the dark/light theme with no per-theme asset — except Zoo, whose mark
13
+ * is intentionally full-color (`fullColor`).
14
+ */
15
+ export interface BrandIdentity {
16
+ /** Stable id — also the IAM org slug (hanzo/lux/zoo/pars). */
17
+ id: string;
18
+ /** Brand word shown before the surface (e.g. "Hanzo" → "Hanzo Cloud"). */
19
+ name: string;
20
+ /** viewBox for the inline mark SVG. */
21
+ viewBox: string;
22
+ /** Inner SVG markup for the mark (multi-path, build-time-trusted constant). */
23
+ content: string;
24
+ /** The mark carries its own fills (Zoo) — do NOT force `currentColor`. */
25
+ fullColor?: boolean;
26
+ /** Brand home, used as the logo link's default href. */
27
+ href?: string;
28
+ }
29
+ /**
30
+ * The canonical Hanzo block-"H" — 5 paths, no opacity facets, `currentColor`.
31
+ * Byte-identical to the mark shipped in the chrome (HanzoMark + brand registry),
32
+ * so the default render matches the existing product surfaces exactly.
33
+ */
34
+ export declare const HANZO_MARK_CONTENT: string;
35
+ export declare const HANZO: BrandIdentity;
36
+ /** Lux — downward triangle (the explorer/console registry mark, currentColor). */
37
+ export declare const LUX: BrandIdentity;
38
+ /** Zoo — interlocking circles (intentional full-color fills, not currentColor). */
39
+ export declare const ZOO: BrandIdentity;
40
+ /** Pars — Persian 8-pointed star (the explorer/console registry mark). */
41
+ export declare const PARS: BrandIdentity;
42
+ /** All shipped brands, keyed by id — the white-label registry. */
43
+ export declare const BRANDS: Record<string, BrandIdentity>;
44
+ /** Resolve a brand by id, falling back to Hanzo (the canonical default). */
45
+ export declare function resolveBrand(id?: string): BrandIdentity;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The host seam — the ONE place an app injects its effects into this layer.
3
+ *
4
+ * The product layer is presentational and host-agnostic: it never imports a
5
+ * router or an auth module. An honest state card still has to OFFER "Sign in
6
+ * again" (401) or "Add credits" (402), so the app provides those two effects
7
+ * once at its root and every card below renders the right affordance. Without a
8
+ * provider the affordance is simply not offered — nothing is faked.
9
+ */
10
+ import { type ReactNode } from 'react';
11
+ export type HostActions = {
12
+ /** Re-authenticate and return to this exact page (401). */
13
+ signIn?: () => void;
14
+ /** Navigate to the org's top-up surface (402). */
15
+ addCredits?: () => void;
16
+ };
17
+ export declare const HostProvider: ({ actions, children }: {
18
+ actions: HostActions;
19
+ children: ReactNode;
20
+ }) => import("react/jsx-runtime").JSX.Element;
21
+ export declare const useHost: () => HostActions;