@vuer-ai/vuer-uikit 0.0.96 → 0.0.98

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 (341) hide show
  1. package/README.md +106 -7
  2. package/cli/dial-cli.js +49 -7
  3. package/dist/SyncScroll/SyncScroll.cjs +10 -10
  4. package/dist/SyncScroll/SyncScroll.mjs +3 -3
  5. package/dist/SyncScroll/index.cjs +10 -10
  6. package/dist/SyncScroll/index.mjs +3 -3
  7. package/dist/chunk-3HEZVWRW.mjs +62 -0
  8. package/dist/chunk-4KWGGESI.cjs +494 -0
  9. package/dist/{chunk-CCMKL2OA.cjs → chunk-7GWDO25E.cjs} +2 -2
  10. package/dist/chunk-A5LCX2UQ.cjs +208 -0
  11. package/dist/chunk-BEJIZ56L.mjs +300 -0
  12. package/dist/chunk-C7VGRU3O.mjs +283 -0
  13. package/dist/{chunk-LONOMMFA.cjs → chunk-LJMNHTTG.cjs} +21 -21
  14. package/dist/chunk-O66RESRR.cjs +285 -0
  15. package/dist/{chunk-RINTUFYQ.cjs → chunk-RMK6W774.cjs} +24 -19
  16. package/dist/{chunk-BFQ2WL5U.mjs → chunk-TTYSYGVE.mjs} +2 -2
  17. package/dist/chunk-VA3PEYFM.mjs +489 -0
  18. package/dist/chunk-VBBJSIY7.cjs +308 -0
  19. package/dist/{chunk-AIINOWEH.mjs → chunk-W4JCKCW7.mjs} +5 -5
  20. package/dist/chunk-WWGF6TBZ.mjs +206 -0
  21. package/dist/chunk-ZGN4UEJR.cjs +679 -0
  22. package/dist/chunk-ZQLRMOUW.mjs +661 -0
  23. package/dist/dial/DialPanel.cjs +24 -24
  24. package/dist/dial/DialPanel.mjs +23 -23
  25. package/dist/dial/DialProvider.cjs +3 -3
  26. package/dist/dial/DialProvider.d.cts +1 -0
  27. package/dist/dial/DialProvider.d.ts +1 -0
  28. package/dist/dial/DialProvider.example.cjs +72 -0
  29. package/dist/dial/DialProvider.example.d.cts +7 -0
  30. package/dist/dial/DialProvider.example.d.ts +7 -0
  31. package/dist/dial/DialProvider.example.mjs +68 -0
  32. package/dist/dial/DialProvider.mjs +1 -1
  33. package/dist/dial/index.cjs +42 -42
  34. package/dist/dial/index.mjs +23 -23
  35. package/dist/dial/wrapped-inputs/ControlledInputs.cjs +27 -27
  36. package/dist/dial/wrapped-inputs/ControlledInputs.mjs +23 -23
  37. package/dist/dial/wrapped-inputs/DialInputs.cjs +34 -34
  38. package/dist/dial/wrapped-inputs/DialInputs.mjs +23 -23
  39. package/dist/dial/wrapped-inputs/DialVectorInput.cjs +24 -24
  40. package/dist/dial/wrapped-inputs/DialVectorInput.mjs +23 -23
  41. package/dist/dial/wrapped-inputs/index.cjs +39 -39
  42. package/dist/dial/wrapped-inputs/index.mjs +23 -23
  43. package/dist/highlight-cursor/cursor-provider.cjs +3 -3
  44. package/dist/highlight-cursor/cursor-provider.mjs +2 -2
  45. package/dist/highlight-cursor/enhanced-components.cjs +10 -10
  46. package/dist/highlight-cursor/enhanced-components.mjs +5 -5
  47. package/dist/highlight-cursor/index.cjs +16 -16
  48. package/dist/highlight-cursor/index.mjs +6 -6
  49. package/dist/hooks/index.cjs +5 -5
  50. package/dist/hooks/index.mjs +1 -1
  51. package/dist/index.cjs +190 -190
  52. package/dist/index.mjs +23 -23
  53. package/dist/ui/UIKitBadge.cjs +6 -6
  54. package/dist/ui/UIKitBadge.mjs +2 -2
  55. package/dist/ui/avatar.cjs +1 -1
  56. package/dist/ui/avatar.mjs +1 -1
  57. package/dist/ui/badge.cjs +1 -1
  58. package/dist/ui/badge.d.cts +1 -1
  59. package/dist/ui/badge.d.ts +1 -1
  60. package/dist/ui/badge.mjs +1 -1
  61. package/dist/ui/button.cjs +1 -1
  62. package/dist/ui/button.mjs +1 -1
  63. package/dist/ui/card.cjs +1 -1
  64. package/dist/ui/card.mjs +1 -1
  65. package/dist/ui/checkbox.cjs +1 -1
  66. package/dist/ui/checkbox.mjs +1 -1
  67. package/dist/ui/collapsible.cjs +1 -1
  68. package/dist/ui/collapsible.mjs +1 -1
  69. package/dist/ui/drawer.cjs +1 -1
  70. package/dist/ui/drawer.mjs +1 -1
  71. package/dist/ui/dropdown.cjs +1 -1
  72. package/dist/ui/dropdown.mjs +1 -1
  73. package/dist/ui/index.cjs +107 -107
  74. package/dist/ui/index.mjs +17 -17
  75. package/dist/ui/inputs/color-input.cjs +1 -1
  76. package/dist/ui/inputs/color-input.mjs +1 -1
  77. package/dist/ui/inputs/index.cjs +11 -11
  78. package/dist/ui/inputs/index.mjs +3 -3
  79. package/dist/ui/inputs/input-numbers.cjs +1 -1
  80. package/dist/ui/inputs/input-numbers.mjs +1 -1
  81. package/dist/ui/inputs/input.cjs +1 -1
  82. package/dist/ui/inputs/input.d.cts +1 -1
  83. package/dist/ui/inputs/input.d.ts +1 -1
  84. package/dist/ui/inputs/input.mjs +1 -1
  85. package/dist/ui/inputs/number-inputs/CmInput.cjs +1 -1
  86. package/dist/ui/inputs/number-inputs/CmInput.mjs +1 -1
  87. package/dist/ui/inputs/number-inputs/DegInput.cjs +1 -1
  88. package/dist/ui/inputs/number-inputs/DegInput.mjs +1 -1
  89. package/dist/ui/inputs/number-inputs/EulerDegInput.cjs +1 -1
  90. package/dist/ui/inputs/number-inputs/EulerDegInput.mjs +1 -1
  91. package/dist/ui/inputs/number-inputs/EulerInput.cjs +1 -1
  92. package/dist/ui/inputs/number-inputs/EulerInput.mjs +1 -1
  93. package/dist/ui/inputs/number-inputs/EulerRadInput.cjs +1 -1
  94. package/dist/ui/inputs/number-inputs/EulerRadInput.mjs +1 -1
  95. package/dist/ui/inputs/number-inputs/InchInput.cjs +1 -1
  96. package/dist/ui/inputs/number-inputs/InchInput.mjs +1 -1
  97. package/dist/ui/inputs/number-inputs/IntInput.cjs +1 -1
  98. package/dist/ui/inputs/number-inputs/IntInput.mjs +1 -1
  99. package/dist/ui/inputs/number-inputs/KVectorInput.cjs +1 -1
  100. package/dist/ui/inputs/number-inputs/KVectorInput.mjs +1 -1
  101. package/dist/ui/inputs/number-inputs/QuaternionInput.cjs +1 -1
  102. package/dist/ui/inputs/number-inputs/QuaternionInput.mjs +1 -1
  103. package/dist/ui/inputs/number-inputs/RadInput.cjs +1 -1
  104. package/dist/ui/inputs/number-inputs/RadInput.mjs +1 -1
  105. package/dist/ui/inputs/number-inputs/TimeInput.cjs +1 -1
  106. package/dist/ui/inputs/number-inputs/TimeInput.mjs +1 -1
  107. package/dist/ui/inputs/number-inputs/Vec3Input.cjs +1 -1
  108. package/dist/ui/inputs/number-inputs/Vec3Input.mjs +1 -1
  109. package/dist/ui/inputs/number-inputs/VectorInput.cjs +1 -1
  110. package/dist/ui/inputs/number-inputs/VectorInput.mjs +1 -1
  111. package/dist/ui/inputs/number-inputs/index.cjs +11 -11
  112. package/dist/ui/inputs/number-inputs/index.mjs +3 -3
  113. package/dist/ui/inputs/presets-input.cjs +1 -1
  114. package/dist/ui/inputs/presets-input.mjs +1 -1
  115. package/dist/ui/label.cjs +1 -1
  116. package/dist/ui/label.mjs +1 -1
  117. package/dist/ui/layout.cjs +1 -1
  118. package/dist/ui/layout.mjs +1 -1
  119. package/dist/ui/layouts/dock-layout/DockLayoutView.cjs +1 -1
  120. package/dist/ui/layouts/dock-layout/DockLayoutView.mjs +1 -1
  121. package/dist/ui/layouts/dock-layout/LayoutSlots.cjs +1 -1
  122. package/dist/ui/layouts/dock-layout/LayoutSlots.mjs +1 -1
  123. package/dist/ui/layouts/dock-layout/index.cjs +1 -1
  124. package/dist/ui/layouts/dock-layout/index.mjs +1 -1
  125. package/dist/ui/layouts/index.cjs +2 -2
  126. package/dist/ui/layouts/index.mjs +2 -2
  127. package/dist/ui/layouts/liquid-layout/LayoutSlots.cjs +1 -1
  128. package/dist/ui/layouts/liquid-layout/LayoutSlots.mjs +1 -1
  129. package/dist/ui/layouts/liquid-layout/LiquidLayoutView.cjs +1 -1
  130. package/dist/ui/layouts/liquid-layout/LiquidLayoutView.mjs +1 -1
  131. package/dist/ui/layouts/liquid-layout/index.cjs +1 -1
  132. package/dist/ui/layouts/liquid-layout/index.mjs +1 -1
  133. package/dist/ui/modal.cjs +1 -1
  134. package/dist/ui/modal.mjs +1 -1
  135. package/dist/ui/navigation.cjs +1 -1
  136. package/dist/ui/navigation.mjs +1 -1
  137. package/dist/ui/pagination.cjs +1 -1
  138. package/dist/ui/pagination.mjs +1 -1
  139. package/dist/ui/panel.cjs +1 -1
  140. package/dist/ui/panel.mjs +1 -1
  141. package/dist/ui/popover.cjs +1 -1
  142. package/dist/ui/popover.mjs +1 -1
  143. package/dist/ui/radio-group.cjs +1 -1
  144. package/dist/ui/radio-group.mjs +1 -1
  145. package/dist/ui/resizable.cjs +1 -1
  146. package/dist/ui/resizable.mjs +1 -1
  147. package/dist/ui/select.cjs +1 -1
  148. package/dist/ui/select.d.cts +1 -1
  149. package/dist/ui/select.d.ts +1 -1
  150. package/dist/ui/select.mjs +1 -1
  151. package/dist/ui/separator.cjs +1 -1
  152. package/dist/ui/separator.mjs +1 -1
  153. package/dist/ui/sheet.cjs +1 -1
  154. package/dist/ui/sheet.mjs +1 -1
  155. package/dist/ui/sidebar.cjs +26 -26
  156. package/dist/ui/sidebar.mjs +2 -2
  157. package/dist/ui/simple-tree-view.cjs +1 -1
  158. package/dist/ui/simple-tree-view.mjs +1 -1
  159. package/dist/ui/skeleton.cjs +1 -1
  160. package/dist/ui/skeleton.mjs +1 -1
  161. package/dist/ui/slider.cjs +1 -1
  162. package/dist/ui/slider.mjs +1 -1
  163. package/dist/ui/switch.cjs +1 -1
  164. package/dist/ui/switch.mjs +1 -1
  165. package/dist/ui/table.cjs +1 -1
  166. package/dist/ui/table.mjs +1 -1
  167. package/dist/ui/tabs.cjs +1 -1
  168. package/dist/ui/tabs.mjs +1 -1
  169. package/dist/ui/textarea.cjs +1 -1
  170. package/dist/ui/textarea.d.cts +1 -1
  171. package/dist/ui/textarea.d.ts +1 -1
  172. package/dist/ui/textarea.mjs +1 -1
  173. package/dist/ui/theme/ThemeToggles.cjs +1 -1
  174. package/dist/ui/theme/ThemeToggles.mjs +1 -1
  175. package/dist/ui/theme/index.cjs +1 -1
  176. package/dist/ui/theme/index.mjs +1 -1
  177. package/dist/ui/toggle-buttons.cjs +1 -1
  178. package/dist/ui/toggle-buttons.mjs +1 -1
  179. package/dist/ui/toggle-group.cjs +1 -1
  180. package/dist/ui/toggle-group.mjs +1 -1
  181. package/dist/ui/toggle.cjs +1 -1
  182. package/dist/ui/toggle.mjs +1 -1
  183. package/dist/ui/toolbar.cjs +1 -1
  184. package/dist/ui/toolbar.mjs +1 -1
  185. package/dist/ui/tooltip.cjs +1 -1
  186. package/dist/ui/tooltip.mjs +1 -1
  187. package/dist/ui/tree-view/TreeSearchBar.cjs +1 -1
  188. package/dist/ui/tree-view/TreeSearchBar.mjs +1 -1
  189. package/dist/ui/tree-view/TreeView.cjs +1 -1
  190. package/dist/ui/tree-view/TreeView.mjs +1 -1
  191. package/dist/ui/tree-view/index.cjs +6 -6
  192. package/dist/ui/tree-view/index.mjs +2 -2
  193. package/dist/ui/tree-view-legacy.cjs +9 -9
  194. package/dist/ui/tree-view-legacy.mjs +5 -5
  195. package/dist/ui/waterfall/CursorOverlay.cjs +1 -1
  196. package/dist/ui/waterfall/CursorOverlay.mjs +1 -1
  197. package/dist/ui/waterfall/TimelineEvent.cjs +1 -1
  198. package/dist/ui/waterfall/TimelineEvent.mjs +1 -1
  199. package/dist/ui/waterfall/TimelineProcessBar.cjs +1 -1
  200. package/dist/ui/waterfall/TimelineProcessBar.mjs +1 -1
  201. package/dist/ui/waterfall/Wedges.cjs +1 -1
  202. package/dist/ui/waterfall/Wedges.mjs +1 -1
  203. package/dist/ui/waterfall/index.cjs +8 -8
  204. package/dist/ui/waterfall/index.mjs +7 -7
  205. package/package.json +28 -2
  206. package/src/SyncScroll/README.md +283 -0
  207. package/src/SyncScroll/SyncScroll.tsx +361 -0
  208. package/src/SyncScroll/index.ts +22 -0
  209. package/src/SyncScroll/useSyncScroll.tsx +226 -0
  210. package/src/cli/dial-cli.ts +1133 -0
  211. package/src/dial/DialPanel.tsx +208 -0
  212. package/src/dial/DialProvider.example.tsx +80 -0
  213. package/src/dial/DialProvider.tsx +138 -0
  214. package/src/dial/index.ts +26 -0
  215. package/src/dial/wrapped-inputs/ControlledInputs.tsx +176 -0
  216. package/src/dial/wrapped-inputs/DialInputs.tsx +401 -0
  217. package/src/dial/wrapped-inputs/DialVectorInput.tsx +125 -0
  218. package/src/dial/wrapped-inputs/index.ts +25 -0
  219. package/src/highlight-cursor/cursor-context.tsx +23 -0
  220. package/src/highlight-cursor/cursor-provider.tsx +264 -0
  221. package/src/highlight-cursor/enhanced-components.tsx +16 -0
  222. package/src/highlight-cursor/index.ts +21 -0
  223. package/src/highlight-cursor/tabs-cursor-context.tsx +121 -0
  224. package/src/highlight-cursor/types.ts +40 -0
  225. package/src/highlight-cursor/with-cursor.tsx +144 -0
  226. package/src/hooks/clientOnly.tsx +54 -0
  227. package/src/hooks/cn.ts +33 -0
  228. package/src/hooks/index.ts +9 -0
  229. package/src/hooks/useDocument.tsx +18 -0
  230. package/src/hooks/useDragSelect.ts +116 -0
  231. package/src/hooks/useIsMobile.ts +35 -0
  232. package/src/hooks/useLocalStorage.ts +122 -0
  233. package/src/hooks/useLocation.tsx +95 -0
  234. package/src/hooks/useQueryParams.tsx +31 -0
  235. package/src/hooks/useWindow.tsx +18 -0
  236. package/src/index.css +5 -0
  237. package/src/index.ts +5 -0
  238. package/src/styles/.editorconfig +0 -0
  239. package/src/styles/theme.css +152 -0
  240. package/src/styles/toast.css +67 -0
  241. package/src/styles/variables.css +229 -0
  242. package/src/ui/UIKitBadge.tsx +171 -0
  243. package/src/ui/avatar.tsx +221 -0
  244. package/src/ui/badge.tsx +74 -0
  245. package/src/ui/button.tsx +143 -0
  246. package/src/ui/card.tsx +146 -0
  247. package/src/ui/checkbox.tsx +78 -0
  248. package/src/ui/collapsible.tsx +43 -0
  249. package/src/ui/drag-selectable/DragSelectProvider.tsx +178 -0
  250. package/src/ui/drag-selectable/createSelectable.tsx +43 -0
  251. package/src/ui/drag-selectable/index.ts +2 -0
  252. package/src/ui/drawer.tsx +137 -0
  253. package/src/ui/dropdown.tsx +707 -0
  254. package/src/ui/icons/MouseCursorIcons.tsx +39 -0
  255. package/src/ui/icons/cursor.tsx +38 -0
  256. package/src/ui/icons/index.ts +2 -0
  257. package/src/ui/index.ts +45 -0
  258. package/src/ui/inputs/color-input.tsx +61 -0
  259. package/src/ui/inputs/index.tsx +5 -0
  260. package/src/ui/inputs/input-numbers.tsx +394 -0
  261. package/src/ui/inputs/input.tsx +155 -0
  262. package/src/ui/inputs/number-inputs/CmInput.tsx +26 -0
  263. package/src/ui/inputs/number-inputs/DegInput.tsx +26 -0
  264. package/src/ui/inputs/number-inputs/EulerDegInput.tsx +14 -0
  265. package/src/ui/inputs/number-inputs/EulerInput.tsx +30 -0
  266. package/src/ui/inputs/number-inputs/EulerRadInput.tsx +14 -0
  267. package/src/ui/inputs/number-inputs/InchInput.tsx +26 -0
  268. package/src/ui/inputs/number-inputs/IntInput.tsx +46 -0
  269. package/src/ui/inputs/number-inputs/KVectorInput.tsx +20 -0
  270. package/src/ui/inputs/number-inputs/QuaternionInput.tsx +27 -0
  271. package/src/ui/inputs/number-inputs/RadInput.tsx +26 -0
  272. package/src/ui/inputs/number-inputs/TimeInput.tsx +26 -0
  273. package/src/ui/inputs/number-inputs/Vec3Input.tsx +26 -0
  274. package/src/ui/inputs/number-inputs/VectorInput.tsx +38 -0
  275. package/src/ui/inputs/number-inputs/index.ts +38 -0
  276. package/src/ui/inputs/presets-input.tsx +59 -0
  277. package/src/ui/label.tsx +35 -0
  278. package/src/ui/layout.tsx +43 -0
  279. package/src/ui/layouts/dock-layout/DockLayoutView.tsx +128 -0
  280. package/src/ui/layouts/dock-layout/LayoutSlots.tsx +85 -0
  281. package/src/ui/layouts/dock-layout/index.tsx +2 -0
  282. package/src/ui/layouts/index.ts +2 -0
  283. package/src/ui/layouts/liquid-layout/LayoutSlots.tsx +82 -0
  284. package/src/ui/layouts/liquid-layout/LiquidLayoutView.tsx +76 -0
  285. package/src/ui/layouts/liquid-layout/index.ts +1 -0
  286. package/src/ui/modal.tsx +211 -0
  287. package/src/ui/navigation.tsx +86 -0
  288. package/src/ui/pagination.tsx +129 -0
  289. package/src/ui/panel.tsx +146 -0
  290. package/src/ui/popover.tsx +112 -0
  291. package/src/ui/radio-group.tsx +63 -0
  292. package/src/ui/resizable.tsx +52 -0
  293. package/src/ui/select.tsx +365 -0
  294. package/src/ui/separator.tsx +26 -0
  295. package/src/ui/sheet.tsx +257 -0
  296. package/src/ui/sidebar.tsx +695 -0
  297. package/src/ui/simple-tree-view.tsx +604 -0
  298. package/src/ui/skeleton.tsx +15 -0
  299. package/src/ui/slider.tsx +204 -0
  300. package/src/ui/switch.tsx +45 -0
  301. package/src/ui/table.tsx +99 -0
  302. package/src/ui/tabs.tsx +192 -0
  303. package/src/ui/textarea.tsx +55 -0
  304. package/src/ui/theme/ThemeProvider.tsx +319 -0
  305. package/src/ui/theme/ThemeToggles.tsx +84 -0
  306. package/src/ui/theme/index.ts +21 -0
  307. package/src/ui/theme/themeScript.tsx +179 -0
  308. package/src/ui/theme/types.ts +61 -0
  309. package/src/ui/toast.tsx +30 -0
  310. package/src/ui/toggle-buttons.tsx +290 -0
  311. package/src/ui/toggle-group.tsx +236 -0
  312. package/src/ui/toggle.tsx +94 -0
  313. package/src/ui/toolbar.tsx +54 -0
  314. package/src/ui/tooltip.tsx +171 -0
  315. package/src/ui/tree-view/TreeSearchBar.tsx +88 -0
  316. package/src/ui/tree-view/TreeView.tsx +232 -0
  317. package/src/ui/tree-view/hooks.tsx +289 -0
  318. package/src/ui/tree-view/index.ts +4 -0
  319. package/src/ui/tree-view/types.ts +23 -0
  320. package/src/ui/tree-view-legacy.tsx +644 -0
  321. package/src/ui/version-badge.tsx +0 -0
  322. package/src/ui/waterfall/CursorOverlay.tsx +96 -0
  323. package/src/ui/waterfall/NavigationControls.tsx +42 -0
  324. package/src/ui/waterfall/Tick.tsx +51 -0
  325. package/src/ui/waterfall/TimeRuleEventDot.tsx +19 -0
  326. package/src/ui/waterfall/TimelineEvent.tsx +60 -0
  327. package/src/ui/waterfall/TimelineProcessBar.tsx +207 -0
  328. package/src/ui/waterfall/Wedges.tsx +67 -0
  329. package/src/ui/waterfall/WheelZoomContext.tsx +128 -0
  330. package/src/ui/waterfall/hooks/useTimelineState.tsx +134 -0
  331. package/src/ui/waterfall/hooks/useViewport.tsx +293 -0
  332. package/src/ui/waterfall/index.tsx +326 -0
  333. package/src/ui/waterfall/types.ts +20 -0
  334. package/src/ui/waterfall/utils.ts +91 -0
  335. package/dist/chunk-W2YAQV5N.mjs +0 -57
  336. package/dist/{chunk-QLCEHV4Q.mjs → chunk-2OZK5DY5.mjs} +2 -2
  337. package/dist/{chunk-Z35DNFRZ.cjs → chunk-7IS37C3P.cjs} +2 -2
  338. package/dist/{chunk-4AOAH77D.mjs → chunk-A2PCEL5S.mjs} +2 -2
  339. package/dist/{chunk-K4VD5PPY.mjs → chunk-BIUDC66P.mjs} +1 -1
  340. package/dist/{chunk-RKJR6RZU.cjs → chunk-OYNLQTHW.cjs} +1 -1
  341. package/dist/{chunk-VE3XLQLO.cjs → chunk-QUFZWF4E.cjs} +2 -2
@@ -0,0 +1,96 @@
1
+ import { Magnet } from "lucide-react";
2
+ import React, { HTMLProps } from "react";
3
+
4
+ import { cn } from "../../hooks";
5
+
6
+ export interface TimelineCursorProps extends HTMLProps<HTMLDivElement> {
7
+ /** Position as percentage (0-100) */
8
+ left?: number;
9
+ /** Label text to display */
10
+ label?: string;
11
+ /** Cursor color */
12
+ color?: string;
13
+ /** Whether to show the readout tooltip */
14
+ showReadout?: boolean;
15
+ /** Whether to show magnet icon (only when showReadout is true) */
16
+ showMagnet?: boolean;
17
+ /** Readout variant - 'active' for interactive cursors, 'static' for fixed markers */
18
+ variant?: "active" | "static";
19
+ /** Additional CSS classes */
20
+ className?: string;
21
+ /** Z-index override */
22
+ zIndex?: number;
23
+ }
24
+
25
+ /**
26
+ * Simple timeline cursor component.
27
+ *
28
+ * @example
29
+ * // Simple cursor line
30
+ * <CursorOverlay left={50} color="blue" />
31
+ *
32
+ * // Cursor with readout
33
+ * <CursorOverlay left={50} label="2.5s" showReadout />
34
+ */
35
+ export function CursorOverlay({
36
+ left = 0,
37
+ label,
38
+ color,
39
+ showReadout = false,
40
+ showMagnet = false,
41
+ variant = "active",
42
+ zIndex = 20,
43
+ }: TimelineCursorProps) {
44
+ const leftValue = `${left}%`;
45
+
46
+ // Default colors based on variant
47
+ const lineColor = color || (variant === "active" ? "rgb(239 68 68)" : "rgb(148 163 184)");
48
+
49
+ return (
50
+ <>
51
+ {/* Cursor Line */}
52
+ <div
53
+ className="pointer-events-none absolute top-0 z-75 h-full w-px"
54
+ style={{
55
+ left: leftValue,
56
+ backgroundColor: lineColor,
57
+ zIndex,
58
+ }}
59
+ />
60
+
61
+ {/* Readout Tooltip */}
62
+ {showReadout && (
63
+ <div
64
+ className={cn(
65
+ "absolute top-1",
66
+ "flex items-center justify-center",
67
+ variant === "active" ? "pointer-events-none" : "pointer-events-auto",
68
+ "px-2 py-0.5",
69
+ "text-uk-sm z-80",
70
+ "border-line-primary/50",
71
+ variant === "active" && [
72
+ "bg-bg-primary rounded-uk-sm border",
73
+ "shadow-[0_4px_16px_0_var(--color-shadow-secondary)]",
74
+ ],
75
+ variant === "static" && [
76
+ "bg-bg-secondary backdrop-blur-sm",
77
+ "rounded-uk-sm",
78
+ "text-text-secondary",
79
+ ],
80
+ )}
81
+ style={{
82
+ left: leftValue,
83
+ transform: "translateX(-50%)",
84
+ minWidth: "11ch",
85
+ zIndex,
86
+ }}
87
+ >
88
+ {showMagnet && (
89
+ <Magnet className="text-text-secondary mr-1.5 size-3 transition-opacity" />
90
+ )}
91
+ <span className="font-mono tabular-nums">{label}</span>
92
+ </div>
93
+ )}
94
+ </>
95
+ );
96
+ }
@@ -0,0 +1,42 @@
1
+ import { ChevronLeft, ChevronRight } from "lucide-react";
2
+ import React from "react";
3
+
4
+ import { formatDuration } from "./utils";
5
+
6
+ // Component props interface
7
+ export interface NavigationControlsProps {
8
+ viewDuration: number;
9
+ handlePan: (direction: "left" | "right") => void;
10
+ handleZoomDragStart: (e: React.MouseEvent) => void;
11
+ }
12
+
13
+ export function NavigationControls({
14
+ viewDuration,
15
+ handlePan,
16
+ handleZoomDragStart,
17
+ }: NavigationControlsProps) {
18
+ return (
19
+ <div className="sticky left-1/2 z-20 w-max">
20
+ <div className="bg-bg-primary/75 flex items-center gap-2 rounded-full p-1 text-sm shadow-[0_4px_16px_0_var(--color-shadow-secondary)] backdrop-blur-[2px]">
21
+ <button
22
+ onClick={() => handlePan("left")}
23
+ className="hover:bg-bg-secondary rounded-full p-1"
24
+ >
25
+ <ChevronLeft className="size-4" />
26
+ </button>
27
+ <span
28
+ className="text-uk-sm hover:bg-bg-secondary/50 w-24 cursor-col-resize rounded px-1 py-0.5 text-center font-mono transition-colors select-none"
29
+ onMouseDown={handleZoomDragStart}
30
+ >
31
+ {formatDuration(viewDuration)}
32
+ </span>
33
+ <button
34
+ onClick={() => handlePan("right")}
35
+ className="hover:bg-bg-secondary rounded-full p-1"
36
+ >
37
+ <ChevronRight className="size-4" />
38
+ </button>
39
+ </div>
40
+ </div>
41
+ );
42
+ }
@@ -0,0 +1,51 @@
1
+ import React from "react";
2
+
3
+ export interface TimelineTickProps {
4
+ /** Time value for this tick */
5
+ time: number;
6
+ /** Label to display */
7
+ label: string;
8
+ /** Function to convert time to percentage */
9
+ timeToPercent: (time: number) => number;
10
+ /** Z-index for layering */
11
+ zIndex?: number;
12
+ }
13
+
14
+ /**
15
+ * Timeline tick mark with label.
16
+ * Shows time divisions on the timeline ruler.
17
+ */
18
+ export function Tick({ time, label, timeToPercent, zIndex = 10 }: TimelineTickProps) {
19
+ const naturalCenterPercent = timeToPercent(time);
20
+
21
+ if (naturalCenterPercent < -20 || naturalCenterPercent > 120) {
22
+ return null;
23
+ }
24
+
25
+ // Keep label visible even when tick is near edges
26
+ const labelHalfWidthPercent = 3;
27
+ const clampedCenterPercent = Math.min(
28
+ 100 - labelHalfWidthPercent,
29
+ Math.max(labelHalfWidthPercent, naturalCenterPercent),
30
+ );
31
+
32
+ return (
33
+ <>
34
+ {/* Tick line */}
35
+ <div
36
+ className="bg-line-primary absolute top-0 h-full w-px"
37
+ style={{ left: `${naturalCenterPercent}%` }}
38
+ />
39
+ {/* Label */}
40
+ <div
41
+ className="bg-bg-primary text-text-secondary rounded-uk-xs text-uk-sm pointer-events-none absolute top-1/2 -translate-x-1/2 -translate-y-1/2 px-1 backdrop-blur-sm"
42
+ style={{
43
+ left: `${clampedCenterPercent}%`,
44
+ zIndex,
45
+ }}
46
+ >
47
+ {label}
48
+ </div>
49
+ </>
50
+ );
51
+ }
@@ -0,0 +1,19 @@
1
+ export interface TimeRuleEventDotProps {
2
+ /** Position as percentage (0-100) */
3
+ percent: number;
4
+ }
5
+
6
+ /**
7
+ * Small dot indicator for key events on the timeline ruler.
8
+ * Shows where significant events occur for visual reference and snapping.
9
+ */
10
+ export function TimeRuleEventDot({ percent }: TimeRuleEventDotProps) {
11
+ if (percent < 0 || percent > 100) return null;
12
+
13
+ return (
14
+ <div
15
+ className="bg-bg-tertiary absolute top-1/2 z-0 h-1 w-1 -translate-y-1/2 rounded-full"
16
+ style={{ left: `${percent}%` }}
17
+ />
18
+ );
19
+ }
@@ -0,0 +1,60 @@
1
+ import React from "react";
2
+
3
+ import { LogItemWithMeta } from "./types";
4
+ import { colorClasses } from "./utils";
5
+ import { cn } from "../../hooks";
6
+
7
+ export interface TimelineEventProps {
8
+ item: LogItemWithMeta;
9
+ isHovered: boolean;
10
+ onMouseEnter: () => void;
11
+ onMouseLeave: () => void;
12
+ onClick?: (time: number) => void;
13
+ timeToPercent: (time: number) => number;
14
+ index?: number;
15
+ }
16
+
17
+ /**
18
+ * Timeline event component for instant events.
19
+ * Renders events that occur at a specific point in time (no duration).
20
+ * Displays as a diamond shape on the timeline.
21
+ */
22
+ export function TimelineEvent({
23
+ item,
24
+ isHovered,
25
+ onMouseEnter,
26
+ onMouseLeave,
27
+ onClick,
28
+ timeToPercent,
29
+ }: TimelineEventProps) {
30
+ // Only render if item has a time property (instant event)
31
+ if (item?.time === undefined || item?.time === null) return null;
32
+
33
+ return (
34
+ <div
35
+ className={cn("relative h-[32px]", isHovered && "bg-bg-secondary")}
36
+ onMouseEnter={onMouseEnter}
37
+ onMouseLeave={onMouseLeave}
38
+ >
39
+ {/* Diamond shape for instant event */}
40
+ <div
41
+ className={cn(
42
+ "absolute top-1/2 -translate-x-1/2 -translate-y-1/2",
43
+ "border-bg-primary h-3 w-3 rotate-45 border-2",
44
+ item.color && colorClasses[item.color],
45
+ onClick && "cursor-pointer transition-transform hover:scale-110",
46
+ )}
47
+ style={{
48
+ left: `${timeToPercent(item.time)}%`,
49
+ }}
50
+ onClick={(e) => {
51
+ if (onClick && item.time !== undefined) {
52
+ e.stopPropagation();
53
+ onClick(item.time);
54
+ }
55
+ }}
56
+ title={item.label}
57
+ />
58
+ </div>
59
+ );
60
+ }
@@ -0,0 +1,207 @@
1
+ import React from "react";
2
+
3
+ import { LogItemWithMeta } from "./types";
4
+ import { borderColorClasses, colorClasses, formatDuration } from "./utils";
5
+ import { cn } from "../../hooks";
6
+
7
+ export interface TimelineEventBarProps {
8
+ item: LogItemWithMeta;
9
+ isHovered: boolean;
10
+ onMouseEnter: () => void;
11
+ onMouseLeave: () => void;
12
+ onClick?: (time: number) => void;
13
+ viewStart: number;
14
+ viewWindow: number;
15
+ timeToPercent: (time: number) => number;
16
+ index?: number;
17
+ }
18
+
19
+ /**
20
+ * Individual timeline event bar component.
21
+ * Renders a single event with its launch wait line and execution bar.
22
+ */
23
+ export function TimelineProcessBar({
24
+ item,
25
+ isHovered,
26
+ onMouseEnter,
27
+ onMouseLeave,
28
+ onClick,
29
+ viewStart,
30
+ viewWindow,
31
+ timeToPercent,
32
+ }: TimelineEventBarProps) {
33
+ const viewEnd = viewStart + viewWindow;
34
+ const isHaltedStep = item.isHaltedStep;
35
+ const barStart = item.startTime;
36
+ const barEnd =
37
+ item.startTime !== undefined && item.duration !== undefined
38
+ ? item.startTime + item.duration
39
+ : undefined;
40
+
41
+ return (
42
+ <div
43
+ className={cn("relative h-[32px] w-full", isHovered && "bg-bg-secondary")}
44
+ onMouseEnter={onMouseEnter}
45
+ onMouseLeave={onMouseLeave}
46
+ >
47
+ {/* Launch Wait Line */}
48
+ {item.createTime !== undefined &&
49
+ item.startTime !== undefined &&
50
+ item.createTime < item.startTime &&
51
+ item.color && (
52
+ <div
53
+ className="absolute top-1/2 h-2 -translate-y-1/2"
54
+ style={{
55
+ left: `${timeToPercent(item.createTime)}%`,
56
+ width: `${((item.startTime - item.createTime) / viewWindow) * 100}%`,
57
+ }}
58
+ >
59
+ <div
60
+ className={cn(
61
+ "absolute top-1/2 left-0 h-2 w-px -translate-y-1/2",
62
+ colorClasses[item.color],
63
+ )}
64
+ />
65
+ <div
66
+ className={cn(
67
+ "absolute top-1/2 w-full -translate-y-1/2 border-t",
68
+ borderColorClasses[item.color],
69
+ )}
70
+ />
71
+ <div
72
+ className={cn(
73
+ "absolute top-1/2 right-0 h-2 w-px -translate-y-1/2",
74
+ colorClasses[item.color],
75
+ )}
76
+ />
77
+ </div>
78
+ )}
79
+
80
+ {/* Execution Bar */}
81
+ {item.startTime !== undefined && item.duration !== undefined && !isHaltedStep && (
82
+ <div
83
+ className={cn(
84
+ "rounded-uk-xs absolute top-1/2 flex h-5 -translate-y-1/2 items-center justify-center overflow-hidden",
85
+ item.color && colorClasses[item.color],
86
+ item.hasStripes &&
87
+ "bg-[repeating-linear-gradient(-45deg,transparent,transparent_4px,rgba(0,0,0,0.1)_4px,rgba(0,0,0,0.1)_8px)]",
88
+ onClick && "cursor-pointer",
89
+ )}
90
+ style={{
91
+ left: `${timeToPercent(item.startTime)}%`,
92
+ width: `${(item.duration / viewWindow) * 100}%`,
93
+ }}
94
+ onClick={(e) => {
95
+ if (onClick && item.startTime !== undefined) {
96
+ e.stopPropagation();
97
+ // Calculate click position within the bar
98
+ const rect = e.currentTarget.getBoundingClientRect();
99
+ const clickX = e.clientX - rect.left;
100
+ const clickPercent = clickX / rect.width;
101
+ const clickTime = item.startTime + item.duration! * clickPercent;
102
+ onClick(clickTime);
103
+ }
104
+ }}
105
+ />
106
+ )}
107
+
108
+ {/* Visible Label for Execution Bar */}
109
+ {item.startTime !== undefined &&
110
+ item.duration !== undefined &&
111
+ !isHaltedStep &&
112
+ (() => {
113
+ const visibleStart = Math.max(barStart!, viewStart);
114
+ const visibleEnd = Math.min(barEnd!, viewEnd);
115
+
116
+ if (visibleEnd <= visibleStart) return null;
117
+
118
+ const visibleDuration = visibleEnd - visibleStart;
119
+ const visibleWidthPercent = (visibleDuration / viewWindow) * 100;
120
+
121
+ if (visibleWidthPercent < 4) return null;
122
+
123
+ return (
124
+ <div
125
+ className="pointer-events-none absolute top-1/2 flex h-5 -translate-y-1/2 items-center justify-center"
126
+ style={{
127
+ left: `${timeToPercent(visibleStart)}%`,
128
+ width: `${visibleWidthPercent}%`,
129
+ }}
130
+ >
131
+ <span
132
+ className={cn(
133
+ "text-uk-sm font-medium whitespace-nowrap",
134
+ item.color === "gray-light" || item.color === "gray-medium"
135
+ ? "text-slate-600 dark:text-slate-300"
136
+ : "text-text-withbg",
137
+ )}
138
+ >
139
+ {formatDuration(item.duration)}
140
+ </span>
141
+ </div>
142
+ );
143
+ })()}
144
+
145
+ {/* Start Circle */}
146
+ {item.startTime !== undefined &&
147
+ item.duration !== undefined &&
148
+ !isHaltedStep &&
149
+ item.color && (
150
+ <div
151
+ className={cn(
152
+ "bg-bg-primary absolute top-1/2 z-10 size-2 -translate-x-1/2 -translate-y-1/2 rounded-full border-2",
153
+ borderColorClasses[item.color],
154
+ )}
155
+ style={{
156
+ left: `${timeToPercent(item.startTime)}%`,
157
+ }}
158
+ />
159
+ )}
160
+
161
+ {/* Special Halted Step Visualization */}
162
+ {isHaltedStep && item.startTime !== undefined && item.duration !== undefined && (
163
+ <div
164
+ className="absolute top-1/2 flex h-full -translate-y-1/2 items-center"
165
+ style={{
166
+ left: `${timeToPercent(item.startTime)}%`,
167
+ width: `${(item.duration / viewWindow) * 100}%`,
168
+ }}
169
+ >
170
+ <div className="relative flex h-full w-full items-center justify-center">
171
+ <div className="bg-line-secondary absolute top-1/2 left-0 h-2 w-px -translate-y-1/2" />
172
+ <div className="bg-line-secondary w-full border-t border-dashed" />
173
+ <div className="bg-line-secondary absolute top-1/2 right-0 h-2 w-px -translate-y-1/2" />
174
+ </div>
175
+ </div>
176
+ )}
177
+
178
+ {/* Halted Step Label */}
179
+ {isHaltedStep &&
180
+ item.startTime !== undefined &&
181
+ item.duration !== undefined &&
182
+ (() => {
183
+ const visibleStart = Math.max(barStart!, viewStart);
184
+ const visibleEnd = Math.min(barEnd!, viewEnd);
185
+
186
+ if (visibleEnd <= visibleStart) return null;
187
+
188
+ const visibleDuration = visibleEnd - visibleStart;
189
+ const visibleWidthPercent = (visibleDuration / viewWindow) * 100;
190
+
191
+ if (visibleWidthPercent < 8) return null;
192
+
193
+ return (
194
+ <div
195
+ className="pointer-events-none absolute top-1/2 flex -translate-y-1/2 items-center justify-center"
196
+ style={{
197
+ left: `${timeToPercent(visibleStart)}%`,
198
+ width: `${visibleWidthPercent}%`,
199
+ }}
200
+ >
201
+ <span className="text-text-secondary text-xs italic">Halted</span>
202
+ </div>
203
+ );
204
+ })()}
205
+ </div>
206
+ );
207
+ }
@@ -0,0 +1,67 @@
1
+ import React from "react";
2
+
3
+ import { LogItemWithMeta } from "./types";
4
+ import { cn } from "../../hooks";
5
+
6
+ interface LeftWedgeProps {
7
+ item: LogItemWithMeta;
8
+ classes: Record<string, string>;
9
+ viewStart: number;
10
+ index: number;
11
+ }
12
+
13
+ interface RightWedgeProps {
14
+ item: LogItemWithMeta;
15
+ classes: Record<string, string>;
16
+ viewEnd: number;
17
+ index: number;
18
+ }
19
+
20
+ export function LeftWedge({ item, classes, viewStart }: LeftWedgeProps) {
21
+ const barEnd =
22
+ item.startTime !== undefined && item.duration !== undefined
23
+ ? item.startTime + item.duration
24
+ : undefined;
25
+ const isOffscreenLeft =
26
+ (barEnd !== undefined && barEnd < viewStart) ||
27
+ (item.time !== undefined && item.time < viewStart);
28
+
29
+ return (
30
+ <div
31
+ key={`left-wedge=${item.id}`}
32
+ className={cn("relative flex h-[32px] w-0 flex-row justify-items-center")}
33
+ >
34
+ {isOffscreenLeft && item.color ? (
35
+ <div
36
+ className={cn(
37
+ "my-auto border-y-[6px] border-r-[5px] border-y-transparent",
38
+ classes[item.color],
39
+ )}
40
+ />
41
+ ) : null}
42
+ </div>
43
+ );
44
+ }
45
+
46
+ export function RightWedge({ item, classes, viewEnd }: RightWedgeProps) {
47
+ const barStart = item.startTime;
48
+ const isOffscreenRight =
49
+ (barStart !== undefined && barStart > viewEnd) ||
50
+ (item.time !== undefined && item.time > viewEnd);
51
+
52
+ return (
53
+ <div
54
+ key={`right-wedge=${item.id}`}
55
+ className={cn("relative flex h-[32px] w-0 flex-row justify-items-center")}
56
+ >
57
+ {isOffscreenRight && item.color ? (
58
+ <div
59
+ className={cn(
60
+ "my-auto border-y-[6px] border-l-[5px] border-y-transparent",
61
+ classes[item.color],
62
+ )}
63
+ />
64
+ ) : null}
65
+ </div>
66
+ );
67
+ }
@@ -0,0 +1,128 @@
1
+ import React, { useCallback, useEffect, useRef, type HTMLProps, RefObject } from "react";
2
+
3
+ export interface WheelZoomContextProps extends HTMLProps<HTMLDivElement> {
4
+ /** Current view start position */
5
+ viewStart: number;
6
+ /** Current view duration/viewWindow */
7
+ viewDuration: number;
8
+ /** Callback when view start changes */
9
+ onViewStartChange: (newStart: number) => void;
10
+ /** Callback when view duration/viewWindow changes */
11
+ onWindowChange: (newDuration: number) => void;
12
+ /** Minimum zoom viewWindow duration in seconds (default: 0.01) */
13
+ minWindow?: number;
14
+ /** Maximum zoom viewWindow duration in seconds (default: Infinity) */
15
+ maxWindow?: number;
16
+ /** Zoom factor for mouse wheel zoom (default: 1.1) */
17
+ zoomFactor?: number;
18
+ /** Enable wheel handling for pan and zoom (default: true) */
19
+ enabled?: boolean;
20
+ /** Children elements to wrap with wheel zoom functionality */
21
+ children: React.ReactNode;
22
+ /** Additional CSS classes for the wrapper */
23
+ className?: string;
24
+ }
25
+
26
+ /**
27
+ * Wrapper component that provides wheel zoom and pan functionality to its children.
28
+ * Uses both React synthetic events and native events for proper scroll prevention.
29
+ *
30
+ * - Normal wheel: Pan horizontally and vertically
31
+ * - Shift/Alt + wheel: Zoom in/out while maintaining cursor position
32
+ *
33
+ * @example
34
+ * ```tsx
35
+ * <WheelZoomContext
36
+ * viewStart={viewStart}
37
+ * viewWindow={viewWindow}
38
+ * onViewStartChange={setViewStart}
39
+ * onWindowChange={setViewDuration}
40
+ * minWindow={0.01}
41
+ * maxWindow={100}
42
+ * >
43
+ * <TimelineContent />
44
+ * </WheelZoomContext>
45
+ * ```
46
+ */
47
+ export function WheelZoomContext({
48
+ ref,
49
+ className,
50
+ viewStart,
51
+ viewDuration,
52
+ onViewStartChange,
53
+ onWindowChange,
54
+ minWindow = 0.01,
55
+ maxWindow = Infinity,
56
+ zoomFactor = 1.1,
57
+ enabled = true,
58
+ children,
59
+ }: WheelZoomContextProps) {
60
+ const localRef = useRef<HTMLDivElement>(null);
61
+ const containerRef = (ref as RefObject<HTMLDivElement>) || localRef;
62
+
63
+ // Native event listener to prevent default scrolling
64
+ useEffect(() => {
65
+ const container = containerRef.current;
66
+ if (!container || !enabled) return;
67
+
68
+ const preventScroll = (e: WheelEvent) => {
69
+ e.preventDefault();
70
+ };
71
+
72
+ // Add passive: false to ensure preventDefault works
73
+ container.addEventListener("wheel", preventScroll, { passive: false });
74
+
75
+ return () => {
76
+ container.removeEventListener("wheel", preventScroll);
77
+ };
78
+ }, [enabled]);
79
+
80
+ const handleWheel = useCallback(
81
+ (e: React.WheelEvent<HTMLDivElement>) => {
82
+ if (!enabled) return;
83
+
84
+ const container = containerRef.current;
85
+ if (!container) return;
86
+
87
+ if (e.shiftKey || e.altKey) {
88
+ // Zoom: maintain cursor position
89
+ const rect = container.getBoundingClientRect();
90
+ const cursorX = e.clientX - rect.left;
91
+ const cursorRatio = cursorX / container.offsetWidth;
92
+ const timeAtCursor = viewStart + cursorRatio * viewDuration;
93
+
94
+ // Calculate new duration
95
+ const scaleFactor = e.deltaY < 0 ? 1 / zoomFactor : zoomFactor;
96
+ const newDuration = Math.max(minWindow, Math.min(maxWindow, viewDuration * scaleFactor));
97
+
98
+ if (newDuration === viewDuration) return;
99
+
100
+ // Adjust view start to keep cursor position stable
101
+ const newViewStart = timeAtCursor - cursorRatio * newDuration;
102
+
103
+ onWindowChange(newDuration);
104
+ onViewStartChange(newViewStart);
105
+ } else {
106
+ // Pan: convert wheel delta to time offset
107
+ const panAmount = ((e.deltaX + e.deltaY) / container.offsetWidth) * viewDuration;
108
+ onViewStartChange(viewStart + panAmount);
109
+ }
110
+ },
111
+ [
112
+ enabled,
113
+ viewStart,
114
+ viewDuration,
115
+ onViewStartChange,
116
+ onWindowChange,
117
+ minWindow,
118
+ maxWindow,
119
+ zoomFactor,
120
+ ],
121
+ );
122
+
123
+ return (
124
+ <div ref={containerRef} className={className} onWheel={handleWheel}>
125
+ {children}
126
+ </div>
127
+ );
128
+ }