@hanzo/ui 8.0.7 → 8.0.8

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 (214) hide show
  1. package/dist/ThemeToggleNext-7727UR5W.js +4 -0
  2. package/dist/ThemeToggleNext-7727UR5W.js.map +1 -0
  3. package/dist/ThemeToggleNext-ICB5KL5J.cjs +19 -0
  4. package/dist/ThemeToggleNext-ICB5KL5J.cjs.map +1 -0
  5. package/dist/billing.cjs +15 -0
  6. package/dist/billing.cjs.map +1 -0
  7. package/{types → dist}/billing.d.ts +0 -1
  8. package/dist/billing.js +4 -0
  9. package/dist/billing.js.map +1 -0
  10. package/dist/canvas.cjs +15 -0
  11. package/dist/canvas.cjs.map +1 -0
  12. package/dist/canvas.d.ts +1 -0
  13. package/dist/canvas.js +4 -0
  14. package/dist/canvas.js.map +1 -0
  15. package/{types → dist}/cd/layout.d.ts +0 -1
  16. package/{types → dist}/cd/status.d.ts +0 -1
  17. package/{types → dist}/cd/time.d.ts +0 -1
  18. package/{types → dist}/cd/types.d.ts +0 -1
  19. package/dist/chunk-42CU5GSF.js +98 -0
  20. package/dist/chunk-42CU5GSF.js.map +1 -0
  21. package/dist/chunk-GDGVXU7W.js +1999 -0
  22. package/dist/chunk-GDGVXU7W.js.map +1 -0
  23. package/dist/chunk-HSPMQQVJ.cjs +2066 -0
  24. package/dist/chunk-HSPMQQVJ.cjs.map +1 -0
  25. package/dist/chunk-YBXVUV7P.cjs +103 -0
  26. package/dist/chunk-YBXVUV7P.cjs.map +1 -0
  27. package/dist/dashboard.cjs +15 -0
  28. package/dist/dashboard.cjs.map +1 -0
  29. package/dist/dashboard.d.ts +1 -0
  30. package/dist/dashboard.js +4 -0
  31. package/dist/dashboard.js.map +1 -0
  32. package/dist/data.cjs +15 -0
  33. package/dist/data.cjs.map +1 -0
  34. package/dist/data.d.ts +1 -0
  35. package/dist/data.js +4 -0
  36. package/dist/data.js.map +1 -0
  37. package/dist/gitops.cjs +15 -0
  38. package/dist/gitops.cjs.map +1 -0
  39. package/dist/gitops.d.ts +1 -0
  40. package/dist/gitops.js +4 -0
  41. package/dist/gitops.js.map +1 -0
  42. package/dist/index.cjs +291 -0
  43. package/dist/index.cjs.map +1 -0
  44. package/{types → dist}/index.d.ts +0 -1
  45. package/dist/index.js +6 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/network.cjs +15 -0
  48. package/dist/network.cjs.map +1 -0
  49. package/{types → dist}/network.d.ts +0 -1
  50. package/dist/network.js +4 -0
  51. package/dist/network.js.map +1 -0
  52. package/dist/primitives/bases/data/index.cjs +15 -0
  53. package/dist/primitives/bases/data/index.cjs.map +1 -0
  54. package/dist/primitives/bases/data/index.d.ts +1 -0
  55. package/dist/primitives/bases/data/index.js +4 -0
  56. package/dist/primitives/bases/data/index.js.map +1 -0
  57. package/{types → dist}/product/AppHeader.d.ts +0 -1
  58. package/{types → dist}/product/BrandMark.d.ts +0 -1
  59. package/{types → dist}/product/Charts.d.ts +0 -1
  60. package/{types → dist}/product/ComboBox.d.ts +0 -1
  61. package/{types → dist}/product/DataTable.d.ts +0 -1
  62. package/{types → dist}/product/Donut.d.ts +0 -1
  63. package/{types → dist}/product/EmptyState.d.ts +0 -1
  64. package/{types → dist}/product/FadeIn.d.ts +0 -1
  65. package/{types → dist}/product/Field.d.ts +0 -1
  66. package/{types → dist}/product/HanzoMark.d.ts +0 -1
  67. package/{types → dist}/product/Metric.d.ts +0 -1
  68. package/{types → dist}/product/OrgSwitcher.d.ts +0 -1
  69. package/{types → dist}/product/PageHeader.d.ts +0 -1
  70. package/{types → dist}/product/PrimaryButton.d.ts +0 -1
  71. package/{types → dist}/product/ProductIcon.d.ts +0 -1
  72. package/{types → dist}/product/ProviderLogo.d.ts +0 -1
  73. package/{types → dist}/product/Reorder.d.ts +0 -1
  74. package/{types → dist}/product/SelectMenu.d.ts +6 -8
  75. package/{types → dist}/product/SlideOver.d.ts +0 -1
  76. package/{types → dist}/product/StatusTag.d.ts +0 -1
  77. package/{types → dist}/product/ThemeToggle.d.ts +0 -1
  78. package/{types → dist}/product/ThemeToggleNext.d.ts +0 -1
  79. package/{types → dist}/product/Toast.d.ts +0 -1
  80. package/{types → dist}/product/color.d.ts +0 -1
  81. package/{types → dist}/product/combobox/filter.d.ts +0 -1
  82. package/dist/product/index.cjs +278 -0
  83. package/dist/product/index.cjs.map +1 -0
  84. package/{types → dist}/product/index.d.ts +0 -1
  85. package/dist/product/index.js +5 -0
  86. package/dist/product/index.js.map +1 -0
  87. package/{types → dist}/product/menu/ContextMenu.d.ts +3 -6
  88. package/dist/product/menu/DropdownMenu.d.ts +29 -0
  89. package/dist/product/menu/FloatingMenu.d.ts +36 -0
  90. package/{types → dist}/product/menu/index.d.ts +1 -1
  91. package/{types → dist}/product/menu/items.d.ts +0 -1
  92. package/{types → dist}/product/menu/portal-theme.d.ts +0 -1
  93. package/{types → dist}/product/menu/roving.d.ts +0 -1
  94. package/{types → dist}/product/scope.d.ts +0 -1
  95. package/{types → dist}/product/surfaces.data.d.ts +0 -1
  96. package/dist/usage.cjs +15 -0
  97. package/dist/usage.cjs.map +1 -0
  98. package/dist/usage.d.ts +1 -0
  99. package/dist/usage.js +4 -0
  100. package/dist/usage.js.map +1 -0
  101. package/dist/wallet.cjs +15 -0
  102. package/dist/wallet.cjs.map +1 -0
  103. package/{types → dist}/wallet.d.ts +0 -1
  104. package/dist/wallet.js +4 -0
  105. package/dist/wallet.js.map +1 -0
  106. package/package.json +54 -32
  107. package/src/billing.ts +0 -9
  108. package/src/canvas.ts +0 -11
  109. package/src/cd/layout.ts +0 -184
  110. package/src/cd/status.ts +0 -158
  111. package/src/cd/time.ts +0 -52
  112. package/src/cd/types.ts +0 -318
  113. package/src/dashboard.ts +0 -8
  114. package/src/data.ts +0 -12
  115. package/src/gitops.ts +0 -5
  116. package/src/gui-env.d.ts +0 -27
  117. package/src/index.ts +0 -22
  118. package/src/network.ts +0 -11
  119. package/src/primitives/bases/data/index.ts +0 -13
  120. package/src/product/AppHeader.tsx +0 -183
  121. package/src/product/BrandMark.tsx +0 -27
  122. package/src/product/Charts.tsx +0 -471
  123. package/src/product/ComboBox.tsx +0 -127
  124. package/src/product/DataTable.tsx +0 -99
  125. package/src/product/Donut.tsx +0 -83
  126. package/src/product/EmptyState.tsx +0 -129
  127. package/src/product/FadeIn.tsx +0 -38
  128. package/src/product/Field.tsx +0 -160
  129. package/src/product/HanzoMark.tsx +0 -31
  130. package/src/product/Metric.tsx +0 -253
  131. package/src/product/OrgSwitcher.tsx +0 -332
  132. package/src/product/PageHeader.tsx +0 -31
  133. package/src/product/PrimaryButton.tsx +0 -17
  134. package/src/product/ProductIcon.tsx +0 -61
  135. package/src/product/ProviderLogo.tsx +0 -137
  136. package/src/product/Reorder.test.ts +0 -41
  137. package/src/product/Reorder.tsx +0 -110
  138. package/src/product/SelectMenu.tsx +0 -80
  139. package/src/product/SlideOver.tsx +0 -197
  140. package/src/product/StatusTag.tsx +0 -49
  141. package/src/product/ThemeToggle.tsx +0 -135
  142. package/src/product/ThemeToggleNext.tsx +0 -27
  143. package/src/product/Toast.tsx +0 -166
  144. package/src/product/color.ts +0 -17
  145. package/src/product/combobox/filter.test.ts +0 -51
  146. package/src/product/combobox/filter.ts +0 -39
  147. package/src/product/index.ts +0 -76
  148. package/src/product/menu/ContextMenu.tsx +0 -114
  149. package/src/product/menu/DropdownMenu.tsx +0 -76
  150. package/src/product/menu/index.ts +0 -15
  151. package/src/product/menu/items.tsx +0 -230
  152. package/src/product/menu/portal-theme.tsx +0 -33
  153. package/src/product/menu/roving.ts +0 -34
  154. package/src/product/scope.test.ts +0 -92
  155. package/src/product/scope.ts +0 -123
  156. package/src/product/surfaces.data.ts +0 -42
  157. package/src/usage.ts +0 -8
  158. package/src/wallet.ts +0 -11
  159. package/types/billing.d.ts.map +0 -1
  160. package/types/canvas.d.ts +0 -2
  161. package/types/canvas.d.ts.map +0 -1
  162. package/types/cd/layout.d.ts.map +0 -1
  163. package/types/cd/status.d.ts.map +0 -1
  164. package/types/cd/time.d.ts.map +0 -1
  165. package/types/cd/types.d.ts.map +0 -1
  166. package/types/dashboard.d.ts +0 -2
  167. package/types/dashboard.d.ts.map +0 -1
  168. package/types/data.d.ts +0 -2
  169. package/types/data.d.ts.map +0 -1
  170. package/types/gitops.d.ts +0 -2
  171. package/types/gitops.d.ts.map +0 -1
  172. package/types/index.d.ts.map +0 -1
  173. package/types/network.d.ts.map +0 -1
  174. package/types/primitives/bases/data/index.d.ts +0 -2
  175. package/types/primitives/bases/data/index.d.ts.map +0 -1
  176. package/types/product/AppHeader.d.ts.map +0 -1
  177. package/types/product/BrandMark.d.ts.map +0 -1
  178. package/types/product/Charts.d.ts.map +0 -1
  179. package/types/product/ComboBox.d.ts.map +0 -1
  180. package/types/product/DataTable.d.ts.map +0 -1
  181. package/types/product/Donut.d.ts.map +0 -1
  182. package/types/product/EmptyState.d.ts.map +0 -1
  183. package/types/product/FadeIn.d.ts.map +0 -1
  184. package/types/product/Field.d.ts.map +0 -1
  185. package/types/product/HanzoMark.d.ts.map +0 -1
  186. package/types/product/Metric.d.ts.map +0 -1
  187. package/types/product/OrgSwitcher.d.ts.map +0 -1
  188. package/types/product/PageHeader.d.ts.map +0 -1
  189. package/types/product/PrimaryButton.d.ts.map +0 -1
  190. package/types/product/ProductIcon.d.ts.map +0 -1
  191. package/types/product/ProviderLogo.d.ts.map +0 -1
  192. package/types/product/Reorder.d.ts.map +0 -1
  193. package/types/product/SelectMenu.d.ts.map +0 -1
  194. package/types/product/SlideOver.d.ts.map +0 -1
  195. package/types/product/StatusTag.d.ts.map +0 -1
  196. package/types/product/ThemeToggle.d.ts.map +0 -1
  197. package/types/product/ThemeToggleNext.d.ts.map +0 -1
  198. package/types/product/Toast.d.ts.map +0 -1
  199. package/types/product/color.d.ts.map +0 -1
  200. package/types/product/combobox/filter.d.ts.map +0 -1
  201. package/types/product/index.d.ts.map +0 -1
  202. package/types/product/menu/ContextMenu.d.ts.map +0 -1
  203. package/types/product/menu/DropdownMenu.d.ts +0 -34
  204. package/types/product/menu/DropdownMenu.d.ts.map +0 -1
  205. package/types/product/menu/index.d.ts.map +0 -1
  206. package/types/product/menu/items.d.ts.map +0 -1
  207. package/types/product/menu/portal-theme.d.ts.map +0 -1
  208. package/types/product/menu/roving.d.ts.map +0 -1
  209. package/types/product/scope.d.ts.map +0 -1
  210. package/types/product/surfaces.data.d.ts.map +0 -1
  211. package/types/usage.d.ts +0 -2
  212. package/types/usage.d.ts.map +0 -1
  213. package/types/wallet.d.ts.map +0 -1
  214. /package/{src → dist}/styles/hanzo-motion.css +0 -0
package/package.json CHANGED
@@ -1,69 +1,90 @@
1
1
  {
2
2
  "name": "@hanzo/ui",
3
- "version": "8.0.7",
3
+ "version": "8.0.8",
4
4
  "type": "module",
5
5
  "description": "Hanzo UI \u2014 the one cross-platform component library on @hanzo/gui. The product/app layer (charts, metrics, page headers, status tags, rich empty states, combobox, slide-over, toasts, drag-reorder, labeled field rows, provider/product marks) + the metadata-driven record layer (@hanzo/data: RecordsView, DataTable, board, typed field editors) + the calm dark-first tokens and motion. Presentational, host-agnostic (data/effects injected), clean-room. Web + native (iOS) + desktop.",
6
6
  "exports": {
7
7
  ".": {
8
- "types": "./types/index.d.ts",
9
- "default": "./src/index.ts"
8
+ "types": "./dist/index.d.ts",
9
+ "import": "./dist/index.js",
10
+ "require": "./dist/index.cjs",
11
+ "default": "./dist/index.js"
10
12
  },
11
13
  "./product": {
12
- "types": "./types/product/index.d.ts",
13
- "default": "./src/product/index.ts"
14
+ "types": "./dist/product/index.d.ts",
15
+ "import": "./dist/product/index.js",
16
+ "require": "./dist/product/index.cjs",
17
+ "default": "./dist/product/index.js"
14
18
  },
15
19
  "./data": {
16
- "types": "./types/data.d.ts",
17
- "default": "./src/data.ts"
20
+ "types": "./dist/data.d.ts",
21
+ "import": "./dist/data.js",
22
+ "require": "./dist/data.cjs",
23
+ "default": "./dist/data.js"
18
24
  },
19
25
  "./primitives/bases/data": {
20
- "types": "./types/primitives/bases/data/index.d.ts",
21
- "default": "./src/primitives/bases/data/index.ts"
26
+ "types": "./dist/primitives/bases/data/index.d.ts",
27
+ "import": "./dist/primitives/bases/data/index.js",
28
+ "require": "./dist/primitives/bases/data/index.cjs",
29
+ "default": "./dist/primitives/bases/data/index.js"
22
30
  },
23
31
  "./gitops": {
24
- "types": "./types/gitops.d.ts",
25
- "default": "./src/gitops.ts"
32
+ "types": "./dist/gitops.d.ts",
33
+ "import": "./dist/gitops.js",
34
+ "require": "./dist/gitops.cjs",
35
+ "default": "./dist/gitops.js"
26
36
  },
27
37
  "./canvas": {
28
- "types": "./types/canvas.d.ts",
29
- "default": "./src/canvas.ts"
38
+ "types": "./dist/canvas.d.ts",
39
+ "import": "./dist/canvas.js",
40
+ "require": "./dist/canvas.cjs",
41
+ "default": "./dist/canvas.js"
30
42
  },
31
43
  "./wallet": {
32
- "types": "./types/wallet.d.ts",
33
- "default": "./src/wallet.ts"
44
+ "types": "./dist/wallet.d.ts",
45
+ "import": "./dist/wallet.js",
46
+ "require": "./dist/wallet.cjs",
47
+ "default": "./dist/wallet.js"
34
48
  },
35
49
  "./network": {
36
- "types": "./types/network.d.ts",
37
- "default": "./src/network.ts"
50
+ "types": "./dist/network.d.ts",
51
+ "import": "./dist/network.js",
52
+ "require": "./dist/network.cjs",
53
+ "default": "./dist/network.js"
38
54
  },
39
55
  "./billing": {
40
- "types": "./types/billing.d.ts",
41
- "default": "./src/billing.ts"
56
+ "types": "./dist/billing.d.ts",
57
+ "import": "./dist/billing.js",
58
+ "require": "./dist/billing.cjs",
59
+ "default": "./dist/billing.js"
42
60
  },
43
61
  "./dashboard": {
44
- "types": "./types/dashboard.d.ts",
45
- "default": "./src/dashboard.ts"
62
+ "types": "./dist/dashboard.d.ts",
63
+ "import": "./dist/dashboard.js",
64
+ "require": "./dist/dashboard.cjs",
65
+ "default": "./dist/dashboard.js"
46
66
  },
47
67
  "./usage": {
48
- "types": "./types/usage.d.ts",
49
- "default": "./src/usage.ts"
68
+ "types": "./dist/usage.d.ts",
69
+ "import": "./dist/usage.js",
70
+ "require": "./dist/usage.cjs",
71
+ "default": "./dist/usage.js"
50
72
  },
51
- "./styles/motion.css": "./src/styles/hanzo-motion.css",
73
+ "./styles/motion.css": "./dist/styles/hanzo-motion.css",
52
74
  "./package.json": "./package.json"
53
75
  },
54
- "main": "./src/index.ts",
55
- "module": "./src/index.ts",
56
- "types": "./types/index.d.ts",
76
+ "main": "./dist/index.cjs",
77
+ "module": "./dist/index.js",
78
+ "types": "./dist/index.d.ts",
57
79
  "sideEffects": [
58
80
  "**/*.css"
59
81
  ],
60
82
  "files": [
61
- "src",
62
- "types"
83
+ "dist"
63
84
  ],
64
85
  "scripts": {
65
- "build": "tsc -p tsconfig.build.json",
66
- "clean": "rm -rf types",
86
+ "build": "tsup && tsc -p tsconfig.build.json && mkdir -p dist/styles && cp src/styles/hanzo-motion.css dist/styles/hanzo-motion.css && node scripts/add-use-client.mjs",
87
+ "clean": "rm -rf dist types",
67
88
  "prepack": "pnpm run build",
68
89
  "tc": "tsc --noEmit",
69
90
  "typecheck": "tsc --noEmit",
@@ -120,7 +141,8 @@
120
141
  "react-dom": "^19.0.0",
121
142
  "typescript": "^5.7.2",
122
143
  "vitest": "^4.1.8",
123
- "react-native-web": "^0.21.2"
144
+ "react-native-web": "^0.21.2",
145
+ "tsup": "^8.5.1"
124
146
  },
125
147
  "publishConfig": {
126
148
  "access": "public"
package/src/billing.ts DELETED
@@ -1,9 +0,0 @@
1
- // @hanzo/ui/billing — the shared billing surface, re-exported from its home
2
- // module @hanzo/ui-shadcn/billing. `CreditModal` presents trial + prepaid credit
3
- // buckets with an injected top-up handler (no payment logic in the component).
4
- // Thin subpath so every console shows the same credit UI:
5
- //
6
- // import { CreditModal } from '@hanzo/ui/billing'
7
- //
8
- // Optional peer — only pulled when the subpath is used.
9
- export * from '@hanzo/ui-shadcn/billing'
package/src/canvas.ts DELETED
@@ -1,11 +0,0 @@
1
- // @hanzo/ui/canvas — the PaaS project canvas, re-exported from its home package
2
- // @hanzo/canvas (a Railway-grade pannable/zoomable board of service nodes with
3
- // live status, metric sparklines, deploy timelines, an environment switcher and
4
- // a service detail drawer). Kept as a thin subpath so a console can
5
- //
6
- // import { ProjectCanvas, ServiceNode, ServiceStatusBadge, DeployTimeline,
7
- // EnvSwitcher, ServiceDetailDrawer } from '@hanzo/ui/canvas'
8
- //
9
- // while the code lives once in @hanzo/canvas. Optional peer — only pulled when
10
- // the subpath is used.
11
- export * from '@hanzo/canvas'
package/src/cd/layout.ts DELETED
@@ -1,184 +0,0 @@
1
- /**
2
- * Deterministic layered graph layout — pure, no React, no DOM, unit-tested. This
3
- * is the dependency-free equivalent of the GitOps engine UI's dagre `rankdir:LR`
4
- * pass: resources flow left→right by ownership depth, each tier a clean column.
5
- *
6
- * Three folds:
7
- * 1. columns — longest-path layering (Kahn topological order). A root (no
8
- * incoming edge) sits in column 0; every other node one column right of its
9
- * deepest parent. Cycles degrade gracefully (a child keeps its best column),
10
- * so a malformed graph can never wedge the layout.
11
- * 2. order — within a column, nodes are ordered by the barycentre of their
12
- * parents' rows (then name), so children cluster under their owner and edge
13
- * crossings stay low — dagre's crossing-reduction, cheaply.
14
- * 3. place — nodes stack top-to-bottom at their own height (pods are taller
15
- * than controllers) with a fixed gap, and each column is vertically centred
16
- * on a shared axis so tiers read as balanced columns.
17
- *
18
- * The same graph always yields byte-identical positions.
19
- */
20
-
21
- export interface LayoutNode {
22
- id: string
23
- /** Rendered height in px (pods are taller than controllers). */
24
- h: number
25
- }
26
-
27
- export interface LayoutEdge {
28
- source: string
29
- target: string
30
- }
31
-
32
- export interface LayoutOptions {
33
- /** Uniform node width in px (x is placed on a fixed column pitch). */
34
- nodeWidth?: number
35
- /** Horizontal gap between a column's right edge and the next column. */
36
- columnGap?: number
37
- /** Vertical gap between stacked nodes in a column. */
38
- rowGap?: number
39
- }
40
-
41
- export interface PositionedNode {
42
- id: string
43
- /** Top-left corner, px. */
44
- x: number
45
- y: number
46
- w: number
47
- h: number
48
- col: number
49
- }
50
-
51
- export interface GraphLayout {
52
- nodes: PositionedNode[]
53
- /** Content bounds — the transformed layer's intrinsic size. */
54
- width: number
55
- height: number
56
- }
57
-
58
- const DEFAULTS = { nodeWidth: 260, columnGap: 68, rowGap: 22 } as const
59
-
60
- /**
61
- * Assign each node a column via longest-path layering over the edges. Processes
62
- * nodes in Kahn topological order; an edge into an unknown/cyclic parent is
63
- * skipped so a cycle never wedges the pass.
64
- */
65
- function assignColumns(ids: string[], edges: LayoutEdge[]): Map<string, number> {
66
- const present = new Set(ids)
67
- const outgoing = new Map<string, string[]>()
68
- const indeg = new Map<string, number>()
69
- for (const id of ids) {
70
- outgoing.set(id, [])
71
- indeg.set(id, 0)
72
- }
73
- for (const e of edges) {
74
- if (!present.has(e.source) || !present.has(e.target) || e.source === e.target) continue
75
- outgoing.get(e.source)!.push(e.target)
76
- indeg.set(e.target, (indeg.get(e.target) ?? 0) + 1)
77
- }
78
-
79
- const column = new Map<string, number>()
80
- for (const id of ids) column.set(id, 0)
81
-
82
- const remaining = new Map(indeg)
83
- const queue = ids.filter((id) => (remaining.get(id) ?? 0) === 0).sort()
84
- const seen = new Set<string>()
85
- while (queue.length) {
86
- const u = queue.shift()!
87
- if (seen.has(u)) continue
88
- seen.add(u)
89
- const cu = column.get(u) ?? 0
90
- for (const v of outgoing.get(u) ?? []) {
91
- if (cu + 1 > (column.get(v) ?? 0)) column.set(v, cu + 1)
92
- const left = (remaining.get(v) ?? 0) - 1
93
- remaining.set(v, left)
94
- if (left <= 0 && !seen.has(v)) queue.push(v)
95
- }
96
- queue.sort()
97
- }
98
- return column
99
- }
100
-
101
- /**
102
- * Lay a resource graph out into centred LR columns. Returns one positioned node
103
- * per input node (input order preserved in the result array) plus content bounds.
104
- */
105
- export function layoutTree(
106
- nodes: LayoutNode[],
107
- edges: LayoutEdge[],
108
- opts: LayoutOptions = {}
109
- ): GraphLayout {
110
- const nodeWidth = opts.nodeWidth ?? DEFAULTS.nodeWidth
111
- const columnGap = opts.columnGap ?? DEFAULTS.columnGap
112
- const rowGap = opts.rowGap ?? DEFAULTS.rowGap
113
-
114
- const ids = nodes.map((n) => n.id)
115
- const heightOf = new Map(nodes.map((n) => [n.id, n.h]))
116
- const column = assignColumns(ids, edges)
117
-
118
- // Parents per node (for the barycentre ordering).
119
- const parents = new Map<string, string[]>()
120
- for (const id of ids) parents.set(id, [])
121
- const present = new Set(ids)
122
- for (const e of edges) {
123
- if (!present.has(e.source) || !present.has(e.target) || e.source === e.target) continue
124
- parents.get(e.target)!.push(e.source)
125
- }
126
-
127
- // Group ids by column, preserving input order as the stable tie-break.
128
- const inputOrder = new Map(ids.map((id, i) => [id, i]))
129
- const byColumn = new Map<number, string[]>()
130
- for (const id of ids) {
131
- const c = column.get(id) ?? 0
132
- const list = byColumn.get(c)
133
- if (list) list.push(id)
134
- else byColumn.set(c, [id])
135
- }
136
-
137
- // Order each column left→right by the barycentre of parents' rows in the
138
- // previous column, so children sit under their owner.
139
- const rowOrder = new Map<string, number>()
140
- const sortedColumns = Array.from(byColumn.keys()).sort((a, b) => a - b)
141
- for (const c of sortedColumns) {
142
- const list = byColumn.get(c)!
143
- list.sort((a, b) => {
144
- const key = (id: string): number => {
145
- const ps = parents.get(id) ?? []
146
- const rows = ps.map((p) => rowOrder.get(p)).filter((r): r is number => r != null)
147
- return rows.length ? rows.reduce((s, r) => s + r, 0) / rows.length : Number.POSITIVE_INFINITY
148
- }
149
- const ka = key(a)
150
- const kb = key(b)
151
- if (ka !== kb) return ka - kb
152
- return (inputOrder.get(a) ?? 0) - (inputOrder.get(b) ?? 0)
153
- })
154
- list.forEach((id, i) => rowOrder.set(id, i))
155
- }
156
-
157
- // Column heights → the shared vertical axis (tallest column centred).
158
- const columnHeight = new Map<number, number>()
159
- for (const [c, list] of byColumn) {
160
- const total = list.reduce((s, id) => s + (heightOf.get(id) ?? 0), 0) + Math.max(0, list.length - 1) * rowGap
161
- columnHeight.set(c, total)
162
- }
163
- const axis = Math.max(0, ...Array.from(columnHeight.values())) / 2
164
-
165
- const pos = new Map<string, { x: number; y: number }>()
166
- for (const c of sortedColumns) {
167
- const list = byColumn.get(c)!
168
- const x = c * (nodeWidth + columnGap)
169
- let y = axis - (columnHeight.get(c) ?? 0) / 2
170
- for (const id of list) {
171
- pos.set(id, { x, y })
172
- y += (heightOf.get(id) ?? 0) + rowGap
173
- }
174
- }
175
-
176
- const positioned: PositionedNode[] = nodes.map((n) => {
177
- const p = pos.get(n.id) ?? { x: 0, y: 0 }
178
- return { id: n.id, x: p.x, y: p.y, w: nodeWidth, h: n.h, col: column.get(n.id) ?? 0 }
179
- })
180
-
181
- const width = positioned.reduce((m, n) => Math.max(m, n.x + n.w), 0)
182
- const height = positioned.reduce((m, n) => Math.max(m, n.y + n.h), 0)
183
- return { nodes: positioned, width, height }
184
- }
package/src/cd/status.ts DELETED
@@ -1,158 +0,0 @@
1
- /**
2
- * CD status → colour, tone, label, priority — the ONE semantic mapping, pure and
3
- * unit-tested. Everything visual reads from here so a health/sync verdict looks
4
- * identical in a pill, a tree node's accent, a mini-bar, and the minimap.
5
- *
6
- * The hues keep the GitOps meaning (green = healthy/synced, amber = out-of-sync /
7
- * missing, red = degraded, blue = progressing, purple = suspended, grey =
8
- * unknown) but are re-tuned for a dark-first surface so they stay legible on
9
- * near-black without the washed-out look of the light-theme originals.
10
- */
11
- import type { HealthStatus, OperationPhase, PodPhase, SyncStatus } from './types'
12
-
13
- /** A coarse tone bucket, shared with the rest of @hanzo/ui's tag vocabulary. */
14
- export type StatusTone = 'green' | 'yellow' | 'red' | 'blue' | 'purple' | 'neutral'
15
-
16
- /** The concrete swatch a status renders in: dot/text hue + a soft chip fill. */
17
- export interface StatusColor {
18
- /** The saturated hue — the dot, the accent bar, the pill text. */
19
- hue: string
20
- tone: StatusTone
21
- }
22
-
23
- // Dark-tuned semantic hues. Bright enough to read as the pill's own text on a
24
- // near-black surface; the soft chip fill is derived from these at low alpha.
25
- const HUES: Record<StatusTone, string> = {
26
- green: '#22c55e',
27
- yellow: '#f5b544',
28
- red: '#f4636e',
29
- blue: '#38a0f5',
30
- purple: '#a684f5',
31
- neutral: '#8b96a5',
32
- }
33
-
34
- const HEALTH_TONE: Record<HealthStatus, StatusTone> = {
35
- Healthy: 'green',
36
- Progressing: 'blue',
37
- Degraded: 'red',
38
- Suspended: 'purple',
39
- Missing: 'yellow',
40
- Unknown: 'neutral',
41
- }
42
-
43
- const SYNC_TONE: Record<SyncStatus, StatusTone> = {
44
- Synced: 'green',
45
- OutOfSync: 'yellow',
46
- Unknown: 'neutral',
47
- }
48
-
49
- const OPERATION_TONE: Record<OperationPhase, StatusTone> = {
50
- Succeeded: 'green',
51
- Running: 'blue',
52
- Pending: 'blue',
53
- Terminating: 'red',
54
- Failed: 'red',
55
- Error: 'red',
56
- }
57
-
58
- const POD_TONE: Record<PodPhase, StatusTone> = {
59
- Running: 'green',
60
- Succeeded: 'green',
61
- Pending: 'blue',
62
- Failed: 'red',
63
- Unknown: 'neutral',
64
- }
65
-
66
- /**
67
- * Worst-first ordering (lower = worse), so a rollup surfaces the most broken
68
- * verdict and a sort puts problems on top — matching the GitOps engine's own
69
- * health precedence.
70
- */
71
- export const HEALTH_PRIORITY: Record<HealthStatus, number> = {
72
- Missing: 0,
73
- Degraded: 1,
74
- Unknown: 2,
75
- Progressing: 3,
76
- Suspended: 4,
77
- Healthy: 5,
78
- }
79
-
80
- export const SYNC_PRIORITY: Record<SyncStatus, number> = {
81
- OutOfSync: 0,
82
- Unknown: 1,
83
- Synced: 2,
84
- }
85
-
86
- const HEALTH_SET = new Set<string>(Object.keys(HEALTH_TONE))
87
- const SYNC_SET = new Set<string>(Object.keys(SYNC_TONE))
88
-
89
- /** Coerce a free-form backend string into a known health code (fails to Unknown). */
90
- export function normalizeHealth(s?: string): HealthStatus {
91
- return s && HEALTH_SET.has(s) ? (s as HealthStatus) : 'Unknown'
92
- }
93
-
94
- /** Coerce a free-form backend string into a known sync code (fails to Unknown). */
95
- export function normalizeSync(s?: string): SyncStatus {
96
- return s && SYNC_SET.has(s) ? (s as SyncStatus) : 'Unknown'
97
- }
98
-
99
- export function healthColor(status: HealthStatus): StatusColor {
100
- const tone = HEALTH_TONE[status] ?? 'neutral'
101
- return { hue: HUES[tone], tone }
102
- }
103
-
104
- export function syncColor(status: SyncStatus): StatusColor {
105
- const tone = SYNC_TONE[status] ?? 'neutral'
106
- return { hue: HUES[tone], tone }
107
- }
108
-
109
- export function operationColor(phase: OperationPhase): StatusColor {
110
- const tone = OPERATION_TONE[phase] ?? 'neutral'
111
- return { hue: HUES[tone], tone }
112
- }
113
-
114
- export function podColor(phase: PodPhase): StatusColor {
115
- const tone = POD_TONE[phase] ?? 'neutral'
116
- return { hue: HUES[tone], tone }
117
- }
118
-
119
- /** The saturated hue for a tone (for callers that already have a tone). */
120
- export function toneHue(tone: StatusTone): string {
121
- return HUES[tone]
122
- }
123
-
124
- /**
125
- * Roll a set of resource healths up to the single verdict that best describes
126
- * the whole — the worst one present. Empty ⇒ `Unknown` (honest, never `Healthy`).
127
- */
128
- export function worstHealth(statuses: HealthStatus[]): HealthStatus {
129
- if (statuses.length === 0) return 'Unknown'
130
- return statuses.reduce((worst, s) =>
131
- HEALTH_PRIORITY[s] < HEALTH_PRIORITY[worst] ? s : worst
132
- )
133
- }
134
-
135
- /** Roll a set of sync verdicts up to one — OutOfSync wins, then Unknown. */
136
- export function worstSync(statuses: SyncStatus[]): SyncStatus {
137
- if (statuses.length === 0) return 'Unknown'
138
- return statuses.reduce((worst, s) =>
139
- SYNC_PRIORITY[s] < SYNC_PRIORITY[worst] ? s : worst
140
- )
141
- }
142
-
143
- /**
144
- * Parse a `#rgb`/`#rrggbb` hue into an `rgba()` at the given alpha — for the
145
- * soft chip fills and translucent accents. Non-hex input passes through (so a
146
- * caller may hand a hue that's already `rgba(...)`).
147
- */
148
- export function withAlpha(hex: string, alpha: number): string {
149
- const m = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.exec(hex)
150
- if (!m) return hex
151
- let h = m[1]
152
- if (h.length === 3) h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2]
153
- const r = parseInt(h.slice(0, 2), 16)
154
- const g = parseInt(h.slice(2, 4), 16)
155
- const b = parseInt(h.slice(4, 6), 16)
156
- const a = Math.max(0, Math.min(1, alpha))
157
- return `rgba(${r}, ${g}, ${b}, ${a})`
158
- }
package/src/cd/time.ts DELETED
@@ -1,52 +0,0 @@
1
- /**
2
- * Compact relative time — pure and deterministic given `now`. Future or invalid
3
- * timestamps degrade honestly (`—` / `now`), never a fabricated duration. Shared
4
- * by the tile's last-synced, the drawer's created/age, and the history rows.
5
- */
6
- export function relativeTime(
7
- epochMs: number | undefined | null,
8
- now: number = Date.now()
9
- ): string {
10
- if (epochMs == null || !Number.isFinite(epochMs) || epochMs <= 0) return '—'
11
- const diff = now - epochMs
12
- if (diff < 0) return 'now'
13
- const s = Math.floor(diff / 1000)
14
- if (s < 5) return 'now'
15
- if (s < 60) return `${s}s ago`
16
- const m = Math.floor(s / 60)
17
- if (m < 60) return `${m}m ago`
18
- const h = Math.floor(m / 60)
19
- if (h < 24) return `${h}h ago`
20
- const d = Math.floor(h / 24)
21
- if (d < 7) return `${d}d ago`
22
- const w = Math.floor(d / 7)
23
- if (w < 5) return `${w}w ago`
24
- const mo = Math.floor(d / 30)
25
- if (mo < 12) return `${mo}mo ago`
26
- const y = Math.floor(d / 365)
27
- return `${y}y ago`
28
- }
29
-
30
- /**
31
- * Parse an ISO-8601 (or any `Date`-parseable) timestamp to epoch **ms**, or
32
- * `undefined` when absent/unparseable — so the contract's string timestamps
33
- * (`createdAt`, event times) flow into `relativeTime` without throwing.
34
- */
35
- export function toEpochMs(v: string | number | undefined | null): number | undefined {
36
- if (v == null) return undefined
37
- if (typeof v === 'number') {
38
- if (!Number.isFinite(v) || v <= 0) return undefined
39
- // Hanzo `/v1` rows may report epoch seconds; scale sub-2001 values to ms.
40
- return v < 1e12 ? Math.round(v * 1000) : Math.round(v)
41
- }
42
- const t = Date.parse(v)
43
- return Number.isFinite(t) && t > 0 ? t : undefined
44
- }
45
-
46
- /** Relative time for a string/number timestamp (parses, then formats). */
47
- export function relativeTimeOf(
48
- v: string | number | undefined | null,
49
- now: number = Date.now()
50
- ): string {
51
- return relativeTime(toEpochMs(v), now)
52
- }