cursedbelt 1.0.0 → 2.5.0

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 (537) hide show
  1. package/dist/client/index.js +1 -1
  2. package/dist/core/category/index.d.ts.map +1 -1
  3. package/dist/core/category/index.js +2 -1
  4. package/dist/core/category/index.js.map +1 -1
  5. package/dist/core/category/types.js +1 -1
  6. package/dist/core/category/types.js.map +1 -1
  7. package/dist/core/file-tree/fileTreeModel.d.ts +49 -0
  8. package/dist/core/file-tree/fileTreeModel.d.ts.map +1 -1
  9. package/dist/core/file-tree/fileTreeModel.js +84 -0
  10. package/dist/core/file-tree/fileTreeModel.js.map +1 -1
  11. package/dist/core/layout/index.js +1 -1
  12. package/dist/core/layout/index.js.map +1 -1
  13. package/dist/core/media/index.js +1 -1
  14. package/dist/core/media/index.js.map +1 -1
  15. package/dist/core/media/types.js +1 -1
  16. package/dist/core/media/types.js.map +1 -1
  17. package/dist/core/media/uploadLimits.js +1 -1
  18. package/dist/core/media/uploadLimits.js.map +1 -1
  19. package/dist/core/sharing/model.d.ts +1 -1
  20. package/dist/ctgr/index.js +1 -1
  21. package/dist/index.js +1 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/react/activity-bar/ActivityBar.d.ts +17 -0
  24. package/dist/react/activity-bar/ActivityBar.d.ts.map +1 -1
  25. package/dist/react/activity-bar/ActivityBar.js.map +1 -1
  26. package/dist/react/analytics/index.d.ts +1 -1
  27. package/dist/react/analytics/index.js +1 -1
  28. package/dist/react/chat/MessageComposer.d.ts.map +1 -1
  29. package/dist/react/chat/MessageComposer.js +5 -4
  30. package/dist/react/chat/MessageComposer.js.map +1 -1
  31. package/dist/react/components/Button.d.ts.map +1 -1
  32. package/dist/react/components/Button.js +3 -2
  33. package/dist/react/components/Button.js.map +1 -1
  34. package/dist/react/components/Checkbox.d.ts +19 -3
  35. package/dist/react/components/Checkbox.d.ts.map +1 -1
  36. package/dist/react/components/Checkbox.js +29 -12
  37. package/dist/react/components/Checkbox.js.map +1 -1
  38. package/dist/react/components/CodeArea.d.ts.map +1 -1
  39. package/dist/react/components/CodeArea.js +2 -1
  40. package/dist/react/components/CodeArea.js.map +1 -1
  41. package/dist/react/components/Collapsible.d.ts.map +1 -1
  42. package/dist/react/components/Collapsible.js +2 -1
  43. package/dist/react/components/Collapsible.js.map +1 -1
  44. package/dist/react/components/ComboboxField.d.ts.map +1 -1
  45. package/dist/react/components/ComboboxField.js +3 -2
  46. package/dist/react/components/ComboboxField.js.map +1 -1
  47. package/dist/react/components/CopyButton.d.ts.map +1 -1
  48. package/dist/react/components/CopyButton.js +2 -1
  49. package/dist/react/components/CopyButton.js.map +1 -1
  50. package/dist/react/components/DataTable/ColumnChecklist.d.ts.map +1 -1
  51. package/dist/react/components/DataTable/ColumnChecklist.js +2 -1
  52. package/dist/react/components/DataTable/ColumnChecklist.js.map +1 -1
  53. package/dist/react/components/DataTable/Pagination.d.ts.map +1 -1
  54. package/dist/react/components/DataTable/Pagination.js +2 -1
  55. package/dist/react/components/DataTable/Pagination.js.map +1 -1
  56. package/dist/react/components/DataTable/SortHeader.d.ts.map +1 -1
  57. package/dist/react/components/DataTable/SortHeader.js +2 -1
  58. package/dist/react/components/DataTable/SortHeader.js.map +1 -1
  59. package/dist/react/components/DataTable/TableFilterBuilder.d.ts +61 -0
  60. package/dist/react/components/DataTable/TableFilterBuilder.d.ts.map +1 -0
  61. package/dist/react/components/DataTable/{FilterBuilder.js → TableFilterBuilder.js} +26 -3
  62. package/dist/react/components/DataTable/TableFilterBuilder.js.map +1 -0
  63. package/dist/react/components/DataTable/Toolbar.d.ts +1 -1
  64. package/dist/react/components/DataTable/Toolbar.js +3 -3
  65. package/dist/react/components/DataTable/Toolbar.js.map +1 -1
  66. package/dist/react/components/DataTable/cells/LinkCell.d.ts.map +1 -1
  67. package/dist/react/components/DataTable/cells/LinkCell.js +2 -1
  68. package/dist/react/components/DataTable/cells/LinkCell.js.map +1 -1
  69. package/dist/react/components/DataTable/index.d.ts +1 -1
  70. package/dist/react/components/DataTable/index.d.ts.map +1 -1
  71. package/dist/react/components/DataTable/index.js +4 -1
  72. package/dist/react/components/DataTable/index.js.map +1 -1
  73. package/dist/react/components/DragHandle.d.ts.map +1 -1
  74. package/dist/react/components/DragHandle.js +2 -1
  75. package/dist/react/components/DragHandle.js.map +1 -1
  76. package/dist/react/components/EmojiField.d.ts.map +1 -1
  77. package/dist/react/components/EmojiField.js +2 -1
  78. package/dist/react/components/EmojiField.js.map +1 -1
  79. package/dist/react/components/EventTimeline.d.ts +3 -2
  80. package/dist/react/components/EventTimeline.d.ts.map +1 -1
  81. package/dist/react/components/EventTimeline.js +3 -2
  82. package/dist/react/components/EventTimeline.js.map +1 -1
  83. package/dist/react/components/IconButton.d.ts +1 -1
  84. package/dist/react/components/IconButton.js +1 -1
  85. package/dist/react/components/InfoHint.d.ts.map +1 -1
  86. package/dist/react/components/InfoHint.js +5 -4
  87. package/dist/react/components/InfoHint.js.map +1 -1
  88. package/dist/react/components/InheritBadge.js +1 -1
  89. package/dist/react/components/InheritBadge.js.map +1 -1
  90. package/dist/react/components/InlineEditableText.d.ts.map +1 -1
  91. package/dist/react/components/InlineEditableText.js +2 -1
  92. package/dist/react/components/InlineEditableText.js.map +1 -1
  93. package/dist/react/components/MeterList.d.ts.map +1 -1
  94. package/dist/react/components/MeterList.js +2 -1
  95. package/dist/react/components/MeterList.js.map +1 -1
  96. package/dist/react/components/PathText.d.ts +2 -2
  97. package/dist/react/components/PathText.d.ts.map +1 -1
  98. package/dist/react/components/PathText.js +2 -1
  99. package/dist/react/components/PathText.js.map +1 -1
  100. package/dist/react/components/RatingField.d.ts.map +1 -1
  101. package/dist/react/components/RatingField.js +2 -1
  102. package/dist/react/components/RatingField.js.map +1 -1
  103. package/dist/react/components/SecretInput.js +3 -2
  104. package/dist/react/components/SecretInput.js.map +1 -1
  105. package/dist/react/components/SegmentedControl.d.ts.map +1 -1
  106. package/dist/react/components/SegmentedControl.js +2 -1
  107. package/dist/react/components/SegmentedControl.js.map +1 -1
  108. package/dist/react/components/StarRating.d.ts.map +1 -1
  109. package/dist/react/components/StarRating.js +9 -5
  110. package/dist/react/components/StarRating.js.map +1 -1
  111. package/dist/react/components/StatStrip.d.ts.map +1 -1
  112. package/dist/react/components/StatStrip.js +2 -1
  113. package/dist/react/components/StatStrip.js.map +1 -1
  114. package/dist/react/components/StatTile.d.ts.map +1 -1
  115. package/dist/react/components/StatTile.js +3 -2
  116. package/dist/react/components/StatTile.js.map +1 -1
  117. package/dist/react/components/Tabs.d.ts.map +1 -1
  118. package/dist/react/components/Tabs.js +2 -1
  119. package/dist/react/components/Tabs.js.map +1 -1
  120. package/dist/react/components/TruncatedText.d.ts +2 -1
  121. package/dist/react/components/TruncatedText.d.ts.map +1 -1
  122. package/dist/react/components/TruncatedText.js +2 -1
  123. package/dist/react/components/TruncatedText.js.map +1 -1
  124. package/dist/react/components/calendar/MonthGrid.d.ts.map +1 -1
  125. package/dist/react/components/calendar/MonthGrid.js +2 -1
  126. package/dist/react/components/calendar/MonthGrid.js.map +1 -1
  127. package/dist/react/components/calendar/WeekView.d.ts.map +1 -1
  128. package/dist/react/components/calendar/WeekView.js +2 -1
  129. package/dist/react/components/calendar/WeekView.js.map +1 -1
  130. package/dist/react/components/revealOnHover.d.ts.map +1 -1
  131. package/dist/react/components/revealOnHover.js +2 -1
  132. package/dist/react/components/revealOnHover.js.map +1 -1
  133. package/dist/react/file-tree/FileTree.d.ts +50 -1
  134. package/dist/react/file-tree/FileTree.d.ts.map +1 -1
  135. package/dist/react/file-tree/FileTree.js +234 -6
  136. package/dist/react/file-tree/FileTree.js.map +1 -1
  137. package/dist/react/file-tree/fileTree.css +52 -0
  138. package/dist/react/filter-rail/FilterRail.d.ts.map +1 -1
  139. package/dist/react/filter-rail/FilterRail.js +5 -4
  140. package/dist/react/filter-rail/FilterRail.js.map +1 -1
  141. package/dist/react/folder-tree/FolderTreeRail.d.ts.map +1 -1
  142. package/dist/react/folder-tree/FolderTreeRail.js +2 -1
  143. package/dist/react/folder-tree/FolderTreeRail.js.map +1 -1
  144. package/dist/react/index.d.ts +5 -1
  145. package/dist/react/index.d.ts.map +1 -1
  146. package/dist/react/index.js +5 -1
  147. package/dist/react/index.js.map +1 -1
  148. package/dist/react/layoutEngine/index.js +1 -1
  149. package/dist/react/layoutEngine/index.js.map +1 -1
  150. package/dist/react/lib/field.d.ts.map +1 -1
  151. package/dist/react/lib/field.js +3 -2
  152. package/dist/react/lib/field.js.map +1 -1
  153. package/dist/react/lib/floatingStyles.d.ts.map +1 -1
  154. package/dist/react/lib/floatingStyles.js +2 -1
  155. package/dist/react/lib/floatingStyles.js.map +1 -1
  156. package/dist/react/lib/tapTarget.d.ts +96 -0
  157. package/dist/react/lib/tapTarget.d.ts.map +1 -0
  158. package/dist/react/lib/tapTarget.js +96 -0
  159. package/dist/react/lib/tapTarget.js.map +1 -0
  160. package/dist/react/media/VideoTrimmer.d.ts +1 -1
  161. package/dist/react/media/VideoTrimmer.js +1 -1
  162. package/dist/react/media/denseGallery.css +3 -3
  163. package/dist/react/media/ffmpegWasm.js +2 -2
  164. package/dist/react/media/ffmpegWasm.js.map +1 -1
  165. package/dist/react/media/videoPlayer.css +42 -0
  166. package/dist/react/namespace/NamespaceTargetCapsule.d.ts +2 -2
  167. package/dist/react/namespace/NamespaceTargetCapsule.d.ts.map +1 -1
  168. package/dist/react/nav/BreadcrumbTrail.d.ts.map +1 -1
  169. package/dist/react/nav/BreadcrumbTrail.js +4 -3
  170. package/dist/react/nav/BreadcrumbTrail.js.map +1 -1
  171. package/dist/react/nav/HubTileGrid.d.ts.map +1 -1
  172. package/dist/react/nav/HubTileGrid.js +2 -1
  173. package/dist/react/nav/HubTileGrid.js.map +1 -1
  174. package/dist/react/nav/SideNav.d.ts.map +1 -1
  175. package/dist/react/nav/SideNav.js +4 -3
  176. package/dist/react/nav/SideNav.js.map +1 -1
  177. package/dist/react/nav/SideNavCustomize.d.ts.map +1 -1
  178. package/dist/react/nav/SideNavCustomize.js +2 -1
  179. package/dist/react/nav/SideNavCustomize.js.map +1 -1
  180. package/dist/react/palette/CommandPalette.d.ts.map +1 -1
  181. package/dist/react/palette/CommandPalette.js +3 -2
  182. package/dist/react/palette/CommandPalette.js.map +1 -1
  183. package/dist/server/drivers/pooledControlStores.pg.test.js +1 -0
  184. package/dist/server/drivers/pooledControlStores.pg.test.js.map +1 -1
  185. package/dist/server/drivers/pooledIdentityStore.pg.test.js +1 -0
  186. package/dist/server/drivers/pooledIdentityStore.pg.test.js.map +1 -1
  187. package/dist/server/drivers/retentionPolicy.pg.test.js +1 -0
  188. package/dist/server/drivers/retentionPolicy.pg.test.js.map +1 -1
  189. package/dist/server/guard/argon2Binding.d.ts +1 -1
  190. package/dist/server/guard/argon2Binding.js +1 -1
  191. package/dist/server/incidents/store.d.ts +3 -3
  192. package/dist/server/index.js +1 -1
  193. package/dist/server/index.js.map +1 -1
  194. package/dist/server/master-lock/masterLock.d.ts +1 -1
  195. package/dist/server/media-bun/index.js +1 -1
  196. package/dist/server/media-bun/index.js.map +1 -1
  197. package/dist/server/paths/appDataHome.d.ts +20 -0
  198. package/dist/server/paths/appDataHome.d.ts.map +1 -0
  199. package/dist/server/paths/appDataHome.js +69 -0
  200. package/dist/server/paths/appDataHome.js.map +1 -0
  201. package/dist/server/retention/archive.d.ts +3 -4
  202. package/dist/server/retention/archive.d.ts.map +1 -1
  203. package/dist/server/retention/archive.js +20 -15
  204. package/dist/server/retention/archive.js.map +1 -1
  205. package/dist/server/retention/index.d.ts +1 -1
  206. package/dist/server/retention/index.js +1 -1
  207. package/dist/server/retention/policy.d.ts +2 -2
  208. package/dist/server/retention/policy.d.ts.map +1 -1
  209. package/dist/server/retention/policy.js +1 -1
  210. package/dist/server/retention/store.d.ts.map +1 -1
  211. package/dist/server/retention/store.js +27 -20
  212. package/dist/server/retention/store.js.map +1 -1
  213. package/dist/server/runtime/localHost.d.ts +10 -5
  214. package/dist/server/runtime/localHost.d.ts.map +1 -1
  215. package/dist/server/runtime/localHost.js +12 -8
  216. package/dist/server/runtime/localHost.js.map +1 -1
  217. package/dist/server/runtime/meterRollup.pg.test.js +1 -0
  218. package/dist/server/runtime/meterRollup.pg.test.js.map +1 -1
  219. package/dist/server/runtime/recipe.d.ts +4 -4
  220. package/dist/server/runtime/retentionJob.pg.test.js +1 -0
  221. package/dist/server/runtime/retentionJob.pg.test.js.map +1 -1
  222. package/dist/server/search/pgSearchProvider.pg.test.js +1 -0
  223. package/dist/server/search/pgSearchProvider.pg.test.js.map +1 -1
  224. package/dist/shared/errors.d.ts +1 -1
  225. package/dist/shared/errors.js +1 -1
  226. package/dist/styles-static.css +413 -0
  227. package/dist/styles-utilities.css +5074 -0
  228. package/dist/styles.css +49 -0
  229. package/package.json +30 -168
  230. package/scripts/generateStaticStyles.ts +122 -0
  231. package/scripts/generateUtilityStyles.ts +215 -0
  232. package/scripts/publicSurface.ts +455 -0
  233. package/scripts/testTmpRoot.ts +34 -5
  234. package/src/client/index.ts +1 -1
  235. package/src/core/category/index.ts +2 -1
  236. package/src/core/category/types.ts +1 -1
  237. package/src/core/file-tree/fileTreeModel.spec.ts +134 -0
  238. package/src/core/file-tree/fileTreeModel.ts +104 -0
  239. package/src/core/layout/index.ts +1 -1
  240. package/src/core/media/index.ts +1 -1
  241. package/src/core/media/types.ts +1 -1
  242. package/src/core/media/uploadLimits.ts +1 -1
  243. package/src/core/sharing/model.ts +1 -1
  244. package/src/ctgr/index.ts +1 -1
  245. package/src/declaredDepsAreImported.spec.ts +87 -0
  246. package/src/demoFixture.spec.ts +133 -0
  247. package/src/index.ts +1 -1
  248. package/src/lockfileIsTracked.spec.ts +50 -0
  249. package/src/namedSubpathsResolve.spec.ts +119 -0
  250. package/src/publicSurface.spec.ts +72 -0
  251. package/src/react/activity-bar/ActivityBar.tsx +17 -0
  252. package/src/react/analytics/index.ts +1 -1
  253. package/src/react/chat/MessageComposer.tsx +5 -4
  254. package/src/react/components/Button.tsx +3 -2
  255. package/src/react/components/Checkbox.spec.tsx +51 -0
  256. package/src/react/components/Checkbox.tsx +68 -26
  257. package/src/react/components/CodeArea.tsx +2 -1
  258. package/src/react/components/CodeChip.spec.tsx +2 -2
  259. package/src/react/components/Collapsible.tsx +2 -1
  260. package/src/react/components/ComboboxField.tsx +3 -2
  261. package/src/react/components/CopyButton.tsx +2 -1
  262. package/src/react/components/CopyableText.spec.tsx +1 -1
  263. package/src/react/components/DataTable/ColumnChecklist.tsx +2 -1
  264. package/src/react/components/DataTable/Pagination.tsx +2 -1
  265. package/src/react/components/DataTable/SortHeader.tsx +2 -1
  266. package/src/react/components/DataTable/{FilterBuilder.tsx → TableFilterBuilder.tsx} +33 -5
  267. package/src/react/components/DataTable/Toolbar.tsx +3 -3
  268. package/src/react/components/DataTable/cells/LinkCell.tsx +2 -1
  269. package/src/react/components/DataTable/index.ts +8 -1
  270. package/src/react/components/DragHandle.tsx +2 -1
  271. package/src/react/components/EmojiField.tsx +2 -1
  272. package/src/react/components/EventTimeline.tsx +3 -2
  273. package/src/react/components/FileLocation.spec.tsx +1 -1
  274. package/src/react/components/IconButton.tsx +1 -1
  275. package/src/react/components/InfoHint.tsx +5 -4
  276. package/src/react/components/InheritBadge.tsx +1 -1
  277. package/src/react/components/InlineEditableText.tsx +2 -1
  278. package/src/react/components/MeterList.tsx +2 -1
  279. package/src/react/components/PathText.tsx +4 -3
  280. package/src/react/components/RatingField.tsx +2 -1
  281. package/src/react/components/SecretInput.tsx +3 -3
  282. package/src/react/components/SegmentedControl.tsx +2 -2
  283. package/src/react/components/StarRating.spec.tsx +2 -2
  284. package/src/react/components/StarRating.tsx +9 -5
  285. package/src/react/components/StatStrip.tsx +2 -1
  286. package/src/react/components/StatTile.tsx +3 -3
  287. package/src/react/components/Tabs.spec.tsx +3 -2
  288. package/src/react/components/Tabs.tsx +2 -1
  289. package/src/react/components/TruncatedText.tsx +2 -1
  290. package/src/react/components/calendar/MonthGrid.spec.tsx +2 -1
  291. package/src/react/components/calendar/MonthGrid.tsx +2 -1
  292. package/src/react/components/calendar/WeekView.tsx +2 -1
  293. package/src/react/components/revealOnHover.ts +3 -2
  294. package/src/react/file-tree/FileTree.spec.tsx +248 -0
  295. package/src/react/file-tree/FileTree.tsx +304 -4
  296. package/src/react/file-tree/fileTree.css +52 -0
  297. package/src/react/file-tree/fileTreeGeometry.fixture.json +151 -0
  298. package/src/react/file-tree/fileTreeGeometry.spec.ts +33 -52
  299. package/src/react/filter-rail/FilterRail.spec.tsx +2 -1
  300. package/src/react/filter-rail/FilterRail.tsx +5 -4
  301. package/src/react/folder-tree/FolderTreeRail.tsx +2 -1
  302. package/src/react/index.ts +13 -3
  303. package/src/react/layoutEngine/index.ts +1 -1
  304. package/src/react/layoutEngine/types.ts +1 -1
  305. package/src/react/lib/field.ts +4 -2
  306. package/src/react/lib/floatingStyles.spec.ts +2 -1
  307. package/src/react/lib/floatingStyles.ts +3 -1
  308. package/src/react/lib/tapTarget.ts +100 -0
  309. package/src/react/media/MaskPainter.tsx +2 -2
  310. package/src/react/media/VideoTrimmer.tsx +1 -1
  311. package/src/react/media/denseGallery.css +3 -3
  312. package/src/react/media/ffmpegWasm.ts +2 -2
  313. package/src/react/media/videoPlayer.css +42 -0
  314. package/src/react/namespace/NamespaceTargetCapsule.tsx +2 -2
  315. package/src/react/nav/BreadcrumbTrail.tsx +4 -3
  316. package/src/react/nav/HubTileGrid.tsx +2 -1
  317. package/src/react/nav/SideNav.tsx +4 -3
  318. package/src/react/nav/SideNavCustomize.tsx +2 -1
  319. package/src/react/palette/CommandPalette.tsx +3 -2
  320. package/src/server/ctgr.ts +1 -1
  321. package/src/server/drivers/pooledControlStores.pg.test.ts +1 -0
  322. package/src/server/drivers/pooledIdentityStore.pg.test.ts +1 -0
  323. package/src/server/drivers/retentionPolicy.pg.test.ts +1 -0
  324. package/src/server/guard/argon2Binding.ts +1 -1
  325. package/src/server/incidents/store.ts +3 -3
  326. package/src/server/index.ts +1 -1
  327. package/src/server/master-lock/masterLock.spec.ts +18 -2
  328. package/src/server/master-lock/masterLock.ts +1 -1
  329. package/src/server/media-bun/image.spec.ts +1 -0
  330. package/src/server/media-bun/index.ts +1 -1
  331. package/src/server/media-bun/video.spec.ts +1 -0
  332. package/src/server/paths/appDataHome.spec.ts +87 -0
  333. package/src/server/paths/appDataHome.ts +84 -0
  334. package/src/server/retention/archive.spec.ts +26 -4
  335. package/src/server/retention/archive.ts +20 -15
  336. package/src/server/retention/index.ts +1 -1
  337. package/src/server/retention/policy.ts +2 -2
  338. package/src/server/retention/store.spec.ts +38 -10
  339. package/src/server/retention/store.ts +26 -19
  340. package/src/server/runtime/localHost.spec.ts +22 -3
  341. package/src/server/runtime/localHost.ts +12 -9
  342. package/src/server/runtime/meterRollup.pg.test.ts +1 -0
  343. package/src/server/runtime/recipe.ts +4 -4
  344. package/src/server/runtime/retentionJob.pg.test.ts +1 -0
  345. package/src/server/search/pgSearchProvider.pg.test.ts +1 -0
  346. package/src/server/storage/binaryServerProcessing.integration.spec.ts +6 -2
  347. package/src/server/storage/chunked.integration.spec.ts +5 -2
  348. package/src/server/storage/fileUploadClient-chunked.integration.spec.ts +5 -2
  349. package/src/server/storage/files/adapter.photo.display.spec.ts +1 -0
  350. package/src/server/storage/imageThumbnail.spec.ts +1 -0
  351. package/src/server/storage/transcode.integration.spec.ts +5 -2
  352. package/src/server/storage/videoProcessor.posterOnly.spec.ts +1 -0
  353. package/src/shared/errors.ts +1 -1
  354. package/src/skippedTestsAreAnswered.spec.ts +215 -0
  355. package/src/styles-static.css +413 -0
  356. package/src/styles-utilities.css +5074 -0
  357. package/src/styles.css +49 -0
  358. package/src/stylesStaticMatches.spec.ts +134 -0
  359. package/src/stylesUtilitiesMatches.spec.ts +314 -0
  360. package/src/tapTargetStylesheet.spec.ts +150 -0
  361. package/src/testTmpRoot.spec.ts +102 -0
  362. package/dist/core/duplicates/index.d.ts +0 -116
  363. package/dist/core/duplicates/index.d.ts.map +0 -1
  364. package/dist/core/duplicates/index.js +0 -178
  365. package/dist/core/duplicates/index.js.map +0 -1
  366. package/dist/core/namespace/helpers.d.ts +0 -14
  367. package/dist/core/namespace/helpers.d.ts.map +0 -1
  368. package/dist/core/namespace/helpers.js +0 -29
  369. package/dist/core/namespace/helpers.js.map +0 -1
  370. package/dist/core/namespace/index.d.ts +0 -4
  371. package/dist/core/namespace/index.d.ts.map +0 -1
  372. package/dist/core/namespace/index.js +0 -6
  373. package/dist/core/namespace/index.js.map +0 -1
  374. package/dist/core/namespace/memoryStore.d.ts +0 -19
  375. package/dist/core/namespace/memoryStore.d.ts.map +0 -1
  376. package/dist/core/namespace/memoryStore.js +0 -70
  377. package/dist/core/namespace/memoryStore.js.map +0 -1
  378. package/dist/core/namespace/types.d.ts +0 -44
  379. package/dist/core/namespace/types.d.ts.map +0 -1
  380. package/dist/core/namespace/types.js +0 -8
  381. package/dist/core/namespace/types.js.map +0 -1
  382. package/dist/game/core/DisposeRegistry.d.ts +0 -42
  383. package/dist/game/core/DisposeRegistry.d.ts.map +0 -1
  384. package/dist/game/core/DisposeRegistry.js +0 -67
  385. package/dist/game/core/DisposeRegistry.js.map +0 -1
  386. package/dist/game/core/drawBudget.d.ts +0 -26
  387. package/dist/game/core/drawBudget.d.ts.map +0 -1
  388. package/dist/game/core/drawBudget.js +0 -55
  389. package/dist/game/core/drawBudget.js.map +0 -1
  390. package/dist/game/core/fixedTimestep.d.ts +0 -38
  391. package/dist/game/core/fixedTimestep.d.ts.map +0 -1
  392. package/dist/game/core/fixedTimestep.js +0 -47
  393. package/dist/game/core/fixedTimestep.js.map +0 -1
  394. package/dist/game/core/index.d.ts +0 -9
  395. package/dist/game/core/index.d.ts.map +0 -1
  396. package/dist/game/core/index.js +0 -8
  397. package/dist/game/core/index.js.map +0 -1
  398. package/dist/game/core/inputCollector.d.ts +0 -82
  399. package/dist/game/core/inputCollector.d.ts.map +0 -1
  400. package/dist/game/core/inputCollector.js +0 -176
  401. package/dist/game/core/inputCollector.js.map +0 -1
  402. package/dist/game/core/resizeCanvas.d.ts +0 -19
  403. package/dist/game/core/resizeCanvas.d.ts.map +0 -1
  404. package/dist/game/core/resizeCanvas.js +0 -29
  405. package/dist/game/core/resizeCanvas.js.map +0 -1
  406. package/dist/game/react/index.d.ts +0 -3
  407. package/dist/game/react/index.d.ts.map +0 -1
  408. package/dist/game/react/index.js +0 -5
  409. package/dist/game/react/index.js.map +0 -1
  410. package/dist/game/react/useGameEngine.d.ts +0 -64
  411. package/dist/game/react/useGameEngine.d.ts.map +0 -1
  412. package/dist/game/react/useGameEngine.js +0 -78
  413. package/dist/game/react/useGameEngine.js.map +0 -1
  414. package/dist/react/canvas/CanvasNavHUD.d.ts +0 -64
  415. package/dist/react/canvas/CanvasNavHUD.d.ts.map +0 -1
  416. package/dist/react/canvas/CanvasNavHUD.js +0 -58
  417. package/dist/react/canvas/CanvasNavHUD.js.map +0 -1
  418. package/dist/react/canvas/fitLabel.d.ts +0 -53
  419. package/dist/react/canvas/fitLabel.d.ts.map +0 -1
  420. package/dist/react/canvas/fitLabel.js +0 -104
  421. package/dist/react/canvas/fitLabel.js.map +0 -1
  422. package/dist/react/canvas/index.d.ts +0 -4
  423. package/dist/react/canvas/index.d.ts.map +0 -1
  424. package/dist/react/canvas/index.js +0 -4
  425. package/dist/react/canvas/index.js.map +0 -1
  426. package/dist/react/canvas/lod.d.ts +0 -40
  427. package/dist/react/canvas/lod.d.ts.map +0 -1
  428. package/dist/react/canvas/lod.js +0 -37
  429. package/dist/react/canvas/lod.js.map +0 -1
  430. package/dist/react/components/DataTable/FilterBuilder.d.ts +0 -38
  431. package/dist/react/components/DataTable/FilterBuilder.d.ts.map +0 -1
  432. package/dist/react/components/DataTable/FilterBuilder.js.map +0 -1
  433. package/dist/react/seo/HeadProvider.d.ts +0 -14
  434. package/dist/react/seo/HeadProvider.d.ts.map +0 -1
  435. package/dist/react/seo/HeadProvider.js +0 -44
  436. package/dist/react/seo/HeadProvider.js.map +0 -1
  437. package/dist/react/seo/applyHeadToDocument.d.ts +0 -3
  438. package/dist/react/seo/applyHeadToDocument.d.ts.map +0 -1
  439. package/dist/react/seo/applyHeadToDocument.js +0 -66
  440. package/dist/react/seo/applyHeadToDocument.js.map +0 -1
  441. package/dist/react/seo/index.d.ts +0 -3
  442. package/dist/react/seo/index.d.ts.map +0 -1
  443. package/dist/react/seo/index.js +0 -7
  444. package/dist/react/seo/index.js.map +0 -1
  445. package/dist/react/timeline/ClipView.d.ts +0 -29
  446. package/dist/react/timeline/ClipView.d.ts.map +0 -1
  447. package/dist/react/timeline/ClipView.js +0 -53
  448. package/dist/react/timeline/ClipView.js.map +0 -1
  449. package/dist/react/timeline/Playhead.d.ts +0 -16
  450. package/dist/react/timeline/Playhead.d.ts.map +0 -1
  451. package/dist/react/timeline/Playhead.js +0 -26
  452. package/dist/react/timeline/Playhead.js.map +0 -1
  453. package/dist/react/timeline/TimeRuler.d.ts +0 -21
  454. package/dist/react/timeline/TimeRuler.d.ts.map +0 -1
  455. package/dist/react/timeline/TimeRuler.js +0 -31
  456. package/dist/react/timeline/TimeRuler.js.map +0 -1
  457. package/dist/react/timeline/TimelineSurface.d.ts +0 -29
  458. package/dist/react/timeline/TimelineSurface.d.ts.map +0 -1
  459. package/dist/react/timeline/TimelineSurface.js +0 -56
  460. package/dist/react/timeline/TimelineSurface.js.map +0 -1
  461. package/dist/react/timeline/TrackLane.d.ts +0 -31
  462. package/dist/react/timeline/TrackLane.d.ts.map +0 -1
  463. package/dist/react/timeline/TrackLane.js +0 -32
  464. package/dist/react/timeline/TrackLane.js.map +0 -1
  465. package/dist/react/timeline/index.d.ts +0 -6
  466. package/dist/react/timeline/index.d.ts.map +0 -1
  467. package/dist/react/timeline/index.js +0 -12
  468. package/dist/react/timeline/index.js.map +0 -1
  469. package/dist/server/private-media/index.d.ts +0 -7
  470. package/dist/server/private-media/index.d.ts.map +0 -1
  471. package/dist/server/private-media/index.js +0 -13
  472. package/dist/server/private-media/index.js.map +0 -1
  473. package/dist/server/seo/index.d.ts +0 -3
  474. package/dist/server/seo/index.d.ts.map +0 -1
  475. package/dist/server/seo/index.js +0 -6
  476. package/dist/server/seo/index.js.map +0 -1
  477. package/dist/server/seo/mountSeoRoutes.d.ts +0 -9
  478. package/dist/server/seo/mountSeoRoutes.d.ts.map +0 -1
  479. package/dist/server/seo/mountSeoRoutes.js +0 -19
  480. package/dist/server/seo/mountSeoRoutes.js.map +0 -1
  481. package/dist/server/seo/serveHeadInjectedIndex.d.ts +0 -9
  482. package/dist/server/seo/serveHeadInjectedIndex.d.ts.map +0 -1
  483. package/dist/server/seo/serveHeadInjectedIndex.js +0 -20
  484. package/dist/server/seo/serveHeadInjectedIndex.js.map +0 -1
  485. package/dist/upload.d.ts +0 -148
  486. package/dist/upload.d.ts.map +0 -1
  487. package/dist/upload.js +0 -159
  488. package/dist/upload.js.map +0 -1
  489. package/dist/verify/runtime/index.d.ts +0 -16
  490. package/dist/verify/runtime/index.d.ts.map +0 -1
  491. package/dist/verify/runtime/index.js +0 -16
  492. package/dist/verify/runtime/index.js.map +0 -1
  493. package/scripts/demoCheck.ts +0 -42
  494. package/src/core/duplicates/index.spec.ts +0 -116
  495. package/src/core/duplicates/index.ts +0 -203
  496. package/src/core/namespace/helpers.ts +0 -31
  497. package/src/core/namespace/index.ts +0 -12
  498. package/src/core/namespace/memoryStore.ts +0 -77
  499. package/src/core/namespace/namespace.spec.ts +0 -117
  500. package/src/core/namespace/types.ts +0 -53
  501. package/src/game/core/DisposeRegistry.spec.ts +0 -53
  502. package/src/game/core/DisposeRegistry.ts +0 -70
  503. package/src/game/core/drawBudget.spec.ts +0 -51
  504. package/src/game/core/drawBudget.ts +0 -75
  505. package/src/game/core/fixedTimestep.spec.ts +0 -91
  506. package/src/game/core/fixedTimestep.ts +0 -79
  507. package/src/game/core/index.ts +0 -16
  508. package/src/game/core/inputCollector.spec.ts +0 -29
  509. package/src/game/core/inputCollector.ts +0 -245
  510. package/src/game/core/resizeCanvas.ts +0 -31
  511. package/src/game/react/index.ts +0 -10
  512. package/src/game/react/useGameEngine.ts +0 -125
  513. package/src/react/canvas/CanvasNavHUD.spec.tsx +0 -62
  514. package/src/react/canvas/CanvasNavHUD.tsx +0 -210
  515. package/src/react/canvas/fitLabel.spec.ts +0 -82
  516. package/src/react/canvas/fitLabel.ts +0 -150
  517. package/src/react/canvas/index.ts +0 -15
  518. package/src/react/canvas/lod.ts +0 -53
  519. package/src/react/seo/HeadProvider.tsx +0 -67
  520. package/src/react/seo/applyHeadToDocument.ts +0 -73
  521. package/src/react/seo/index.ts +0 -12
  522. package/src/react/seo/seo.spec.tsx +0 -101
  523. package/src/react/timeline/ClipView.tsx +0 -146
  524. package/src/react/timeline/Playhead.tsx +0 -63
  525. package/src/react/timeline/TimeRuler.tsx +0 -85
  526. package/src/react/timeline/TimelineSurface.tsx +0 -157
  527. package/src/react/timeline/TrackLane.tsx +0 -87
  528. package/src/react/timeline/index.ts +0 -12
  529. package/src/react/timeline/timeline.spec.tsx +0 -175
  530. package/src/server/private-media/index.ts +0 -45
  531. package/src/server/seo/index.ts +0 -8
  532. package/src/server/seo/mountSeoRoutes.ts +0 -37
  533. package/src/server/seo/seo.spec.ts +0 -128
  534. package/src/server/seo/serveHeadInjectedIndex.ts +0 -36
  535. package/src/upload.spec.ts +0 -300
  536. package/src/upload.ts +0 -288
  537. package/src/verify/runtime/index.ts +0 -64
@@ -1,53 +0,0 @@
1
- /**
2
- * Adaptive level of detail for an infinite canvas.
3
- *
4
- * `DESIGN.md` §7: *"Large-scale interactive graphs … must not render full textual
5
- * strings when zoomed out past 50%. Dynamically scale down information density:
6
- * collapse names or details entirely, displaying only clean geometric glyph nodes
7
- * or color-coded markers until zoomed in or hovered over."*
8
- *
9
- * `UX_STANDARDS.md` §3.1–§3.2 states the same thing as a principle — *"zooming out
10
- * changes the DESIGN, not the scale"* — and nothing in the fleet implemented it, so
11
- * every canvas shrinks its text into illegible grey fur instead. This is the shared
12
- * decision, kept as a pure function because the interesting part is the THRESHOLDS
13
- * and those must be identical in the tree, the atlas and the orch lanes.
14
- */
15
-
16
- /**
17
- * `full` — name plus its secondary line, portraits, badges.
18
- * `compact` — the name only, at the node's own size.
19
- * `glyph` — no text at all: a geometric marker, coloured by category. Labels
20
- * come back on hover/focus, which is what keeps this navigable.
21
- */
22
- export type CanvasLod = 'full' | 'compact' | 'glyph';
23
-
24
- export interface LodThresholds {
25
- /** At or above this zoom, everything is drawn. Default 0.75. */
26
- full?: number;
27
- /** At or above this zoom, the name survives. Default 0.5 — DESIGN.md §7's line. */
28
- compact?: number;
29
- }
30
-
31
- /** The level of detail a canvas should draw at `zoom` (1 = 100%). */
32
- export function lodForZoom(zoom: number, thresholds: LodThresholds = {}): CanvasLod {
33
- const full = thresholds.full ?? 0.75;
34
- const compact = thresholds.compact ?? 0.5;
35
- if (!Number.isFinite(zoom)) return 'full';
36
- if (zoom >= full) return 'full';
37
- if (zoom >= compact) return 'compact';
38
- return 'glyph';
39
- }
40
-
41
- /** Whether a node at this level of detail should render any text at all. */
42
- export const lodShowsText = (lod: CanvasLod): boolean => lod !== 'glyph';
43
-
44
- /** Whether a node at this level of detail should render its secondary line. */
45
- export const lodShowsDetail = (lod: CanvasLod): boolean => lod === 'full';
46
-
47
- /**
48
- * A hovered or focused node always renders its label, whatever the zoom — that is
49
- * the "until zoomed in OR HOVERED over" half of the clause, and it is the thing
50
- * that keeps a glyph field usable rather than merely pretty.
51
- */
52
- export const lodForNode = (zoom: number, active: boolean, thresholds?: LodThresholds): CanvasLod =>
53
- active ? 'full' : lodForZoom(zoom, thresholds);
@@ -1,67 +0,0 @@
1
- import type { HeadModel } from 'cwip/seo';
2
- import { createContext, type ReactNode, useContext, useEffect, useMemo } from 'react';
3
- import { applyHeadToDocument } from './applyHeadToDocument';
4
-
5
- export interface HeadProviderConfig {
6
- // Applied under every route's model unless the route overrides the same field
7
- // (route wins — see `useHead`).
8
- default?: HeadModel;
9
- siteUrl?: string;
10
- titleTemplate?: string;
11
- }
12
-
13
- const HeadContext = createContext<HeadProviderConfig>({});
14
-
15
- export interface HeadProviderProps extends HeadProviderConfig {
16
- children?: ReactNode;
17
- }
18
-
19
- // Provides the site-wide SEO defaults (base head + siteUrl + title template) that
20
- // every `useHead` call merges under its own model. Mount once near the app root.
21
- // Read the site-wide SEO config supplied by the nearest `HeadProvider` (siteUrl,
22
- // title template, base head). Returns `{}` when no provider is mounted, so a
23
- // consumer can fall back (e.g. to `window.location.origin`) without crashing.
24
- export const useHeadConfig = (): HeadProviderConfig => useContext(HeadContext);
25
-
26
- export const HeadProvider = ({ children, ...config }: HeadProviderProps) => {
27
- const value = useMemo<HeadProviderConfig>(
28
- () => ({
29
- default: config.default,
30
- siteUrl: config.siteUrl,
31
- titleTemplate: config.titleTemplate,
32
- }),
33
- [config.default, config.siteUrl, config.titleTemplate],
34
- );
35
- return <HeadContext.Provider value={value}>{children}</HeadContext.Provider>;
36
- };
37
-
38
- const mergeHead = (
39
- base: HeadModel | undefined,
40
- model: HeadModel,
41
- titleTemplate?: string,
42
- ): HeadModel => ({
43
- titleTemplate,
44
- ...base,
45
- ...model,
46
- });
47
-
48
- // Reconciles `document.head` for the CURRENT route. Merges the provider's default
49
- // head with `model` (model wins field-by-field), then applies it imperatively on
50
- // mount/update. SSR-safe — a no-op when `document` is unavailable.
51
- //
52
- // Multi-caller semantics (last-writer-wins): if more than one component calls
53
- // `useHead` while mounted at once, the effect that (re)runs LAST wins — its model
54
- // fully replaces the previously-applied managed tags, because `applyHeadToDocument`
55
- // removes any managed tag not present in the new render. Design routes so exactly
56
- // one component per active route calls `useHead`; a nested component that also
57
- // calls it will overwrite the route's head on every one of its own re-renders.
58
- export const useHead = (model: HeadModel): void => {
59
- const config = useContext(HeadContext);
60
- const merged = mergeHead(config.default, model, config.titleTemplate);
61
- const serialized = JSON.stringify(merged);
62
-
63
- useEffect(() => {
64
- if (typeof document === 'undefined') return;
65
- applyHeadToDocument(JSON.parse(serialized) as HeadModel);
66
- }, [serialized]);
67
- };
@@ -1,73 +0,0 @@
1
- import { type HeadModel, renderHead, SEO_TAG_MARKER } from 'cwip/seo';
2
-
3
- // Applies a HeadModel to a live document: sets `document.title` and upserts the
4
- // managed <meta>/<link>/<script type="application/ld+json"> tags into <head>. Every
5
- // tag it creates or updates carries SEO_TAG_MARKER so a later call can find and
6
- // replace its own tags without ever touching app-authored markup, and so it can
7
- // remove a managed tag that is no longer present in the new model. Idempotent:
8
- // calling twice with the same model produces the same DOM, never duplicates.
9
- //
10
- // Built directly on cwip's `renderHead` output (a string of tags) so the client
11
- // reconciler and every other delivery mechanism (prerender/edge/server) stay in
12
- // sync on exactly what a HeadModel renders to — this module only does the DOM
13
- // diffing, not the serialization.
14
- export const applyHeadToDocument = (model: HeadModel, doc: Document = document): void => {
15
- const html = renderHead(model, { marker: true });
16
- const template = doc.createElement('template');
17
- template.innerHTML = html;
18
- const nextNodes = Array.from(template.content.childNodes).filter(
19
- (node): node is Element => node.nodeType === 1,
20
- );
21
-
22
- const title = nextNodes.find((node) => node.tagName === 'TITLE');
23
- doc.title = title?.textContent ?? doc.title;
24
-
25
- const previouslyManaged = Array.from(doc.head.querySelectorAll(`[${SEO_TAG_MARKER}]`));
26
- const stillPresent = new Set<Element>();
27
-
28
- for (const node of nextNodes) {
29
- if (node.tagName === 'TITLE') continue; // handled via doc.title above
30
- const match = previouslyManaged.find(
31
- (existing) => !stillPresent.has(existing) && isSameTag(existing, node),
32
- );
33
- if (match) {
34
- copyAttributes(match, node);
35
- match.textContent = node.textContent;
36
- stillPresent.add(match);
37
- } else {
38
- const clone = node.cloneNode(true) as Element;
39
- doc.head.appendChild(clone);
40
- stillPresent.add(clone);
41
- }
42
- }
43
-
44
- for (const existing of previouslyManaged) {
45
- if (!stillPresent.has(existing)) existing.remove();
46
- }
47
- };
48
-
49
- // Two tags are "the same" managed tag if they share a tag name and identifying key
50
- // (meta name/property, link rel+href, or — for scripts/title — just the tag name,
51
- // since a HeadModel carries at most one <title> and callers rarely emit more than
52
- // one ld+json script; multiple ld+json blocks are matched positionally by falling
53
- // through to a fresh append once earlier ones are claimed).
54
- const isSameTag = (a: Element, b: Element): boolean => {
55
- if (a.tagName !== b.tagName) return false;
56
- if (a.tagName === 'META') {
57
- return (
58
- identity(a, 'name') === identity(b, 'name') &&
59
- identity(a, 'property') === identity(b, 'property')
60
- );
61
- }
62
- if (a.tagName === 'LINK') {
63
- return identity(a, 'rel') === identity(b, 'rel') && identity(a, 'href') === identity(b, 'href');
64
- }
65
- return true; // SCRIPT (ld+json) — matched positionally among managed scripts
66
- };
67
-
68
- const identity = (el: Element, attr: string): string => el.getAttribute(attr) ?? '';
69
-
70
- const copyAttributes = (target: Element, source: Element): void => {
71
- for (const attr of Array.from(target.attributes)) target.removeAttribute(attr.name);
72
- for (const attr of Array.from(source.attributes)) target.setAttribute(attr.name, attr.value);
73
- };
@@ -1,12 +0,0 @@
1
- // cursedbelt/react/seo — a tiny, react-helmet-style head manager keyed to cwip's
2
- // `HeadModel`. `HeadProvider` supplies site-wide defaults; a route calls `useHead`
3
- // once to own `document.head` for as long as it's mounted. Dedicated subpath so an
4
- // app that never touches SEO pays nothing for it.
5
- export { applyHeadToDocument } from './applyHeadToDocument';
6
- export {
7
- HeadProvider,
8
- type HeadProviderConfig,
9
- type HeadProviderProps,
10
- useHead,
11
- useHeadConfig,
12
- } from './HeadProvider';
@@ -1,101 +0,0 @@
1
- import { afterEach, describe, expect, test } from 'bun:test';
2
- import { cleanup, render } from '@testing-library/react';
3
- import type { HeadModel } from 'cwip/seo';
4
- import { SEO_TAG_MARKER } from 'cwip/seo';
5
- import { applyHeadToDocument } from './applyHeadToDocument';
6
- import { HeadProvider, useHead } from './HeadProvider';
7
-
8
- afterEach(() => {
9
- cleanup();
10
- document.head.innerHTML = '';
11
- document.title = '';
12
- });
13
-
14
- describe('applyHeadToDocument', () => {
15
- test('sets document.title from a templated title', () => {
16
- applyHeadToDocument({ title: 'Free monads', titleTemplate: '%s | Cursed Alchemy' });
17
- expect(document.title).toBe('Free monads | Cursed Alchemy');
18
- });
19
-
20
- test('upserts meta/link/jsonLd tags, all carrying the marker', () => {
21
- const model: HeadModel = {
22
- description: 'An article about free monads',
23
- canonical: 'https://example.com/articles/free-monads',
24
- openGraph: { title: 'Free monads', type: 'article' },
25
- jsonLd: [{ '@type': 'Article', headline: 'Free monads' }],
26
- };
27
- applyHeadToDocument(model);
28
-
29
- const description = document.head.querySelector('meta[name="description"]');
30
- expect(description?.getAttribute('content')).toBe('An article about free monads');
31
- expect(description?.hasAttribute(SEO_TAG_MARKER)).toBe(true);
32
-
33
- const canonical = document.head.querySelector('link[rel="canonical"]');
34
- expect(canonical?.getAttribute('href')).toBe('https://example.com/articles/free-monads');
35
-
36
- const ogTitle = document.head.querySelector('meta[property="og:title"]');
37
- expect(ogTitle?.getAttribute('content')).toBe('Free monads');
38
-
39
- const script = document.head.querySelector('script[type="application/ld+json"]');
40
- expect(script).not.toBeNull();
41
- expect(JSON.parse(script?.textContent ?? '{}')).toEqual({
42
- '@type': 'Article',
43
- headline: 'Free monads',
44
- });
45
- });
46
-
47
- test('re-applying the same model twice is idempotent (no duplicate tags)', () => {
48
- const model: HeadModel = {
49
- description: 'same description',
50
- canonical: 'https://example.com/a',
51
- };
52
- applyHeadToDocument(model);
53
- applyHeadToDocument(model);
54
- expect(document.head.querySelectorAll('meta[name="description"]').length).toBe(1);
55
- expect(document.head.querySelectorAll('link[rel="canonical"]').length).toBe(1);
56
- });
57
-
58
- test('removes a previously-managed tag that is absent from the new model', () => {
59
- applyHeadToDocument({ description: 'first', canonical: 'https://example.com/a' });
60
- expect(document.head.querySelector('link[rel="canonical"]')).not.toBeNull();
61
-
62
- applyHeadToDocument({ description: 'second' });
63
- expect(document.head.querySelector('meta[name="description"]')?.getAttribute('content')).toBe(
64
- 'second',
65
- );
66
- expect(document.head.querySelector('link[rel="canonical"]')).toBeNull();
67
- });
68
-
69
- test('never touches an app-authored (unmarked) tag', () => {
70
- const appMeta = document.createElement('meta');
71
- appMeta.setAttribute('name', 'viewport');
72
- appMeta.setAttribute('content', 'width=device-width, initial-scale=1');
73
- document.head.appendChild(appMeta);
74
-
75
- applyHeadToDocument({ description: 'managed description' });
76
-
77
- const viewport = document.head.querySelector('meta[name="viewport"]');
78
- expect(viewport).toBe(appMeta);
79
- expect(viewport?.hasAttribute(SEO_TAG_MARKER)).toBe(false);
80
- });
81
- });
82
-
83
- describe('useHead', () => {
84
- const Route = ({ model }: { model: HeadModel }) => {
85
- useHead(model);
86
- return null;
87
- };
88
-
89
- test('applies the merged provider default + route model, route wins on overlap', async () => {
90
- render(
91
- <HeadProvider default={{ description: 'default description', titleTemplate: '%s | Site' }}>
92
- <Route model={{ title: 'Route title', description: 'route description' }} />
93
- </HeadProvider>,
94
- );
95
- // effects flush synchronously under @testing-library/react's act()
96
- expect(document.title).toBe('Route title | Site');
97
- expect(document.head.querySelector('meta[name="description"]')?.getAttribute('content')).toBe(
98
- 'route description',
99
- );
100
- });
101
- });
@@ -1,146 +0,0 @@
1
- import { clipLeftPx, clipWidthPx, pxToSeconds, type TimelineClip } from 'cwip/timeline';
2
- import { Zap } from 'lucide-react';
3
- import type { ReactNode } from 'react';
4
- import { useRef } from 'react';
5
- import { formatTimecode } from '../../core/media';
6
- import { usePointerDrag, type UsePointerDragOptions } from '../hooks/usePointerDrag';
7
- import { cn } from '../lib/cn';
8
-
9
- export type TrimEdge = 'start' | 'end';
10
-
11
- export interface ClipViewProps {
12
- clip: TimelineClip;
13
- zoomScale: number;
14
- selected: boolean;
15
- onSelect: () => void;
16
- /** Live preview during a body drag (raw target start, seconds). */
17
- onMovePreview: (toStartSeconds: number, event: PointerEvent) => void;
18
- onMoveCommit: (toStartSeconds: number, cancelled: boolean) => void;
19
- /** Live preview during an edge drag (raw signed delta, seconds). */
20
- onTrimPreview: (edge: TrimEdge, deltaSeconds: number, event: PointerEvent) => void;
21
- onTrimCommit: (edge: TrimEdge, deltaSeconds: number, cancelled: boolean) => void;
22
- /** Fallback color token when the clip carries none (a theme token name,
23
- * resolved as `var(--<token>)` — e.g. "chart-1"). */
24
- defaultColorToken?: string;
25
- /** Extra content under the label (waveform strip, filmstrip). */
26
- children?: ReactNode;
27
- }
28
-
29
- /**
30
- * One clip block: body drag repositions, edge handles trim, click selects.
31
- * PRESENTATIONAL — it translates pixels to seconds and reports intent; all
32
- * clamping/rippling/snapping is the owner's job (cwip/timeline ops), so the
33
- * block never disagrees with the engine. Colors ride theme tokens via
34
- * `color-mix`, never raw values.
35
- */
36
- export function ClipView({
37
- clip,
38
- zoomScale,
39
- selected,
40
- onSelect,
41
- onMovePreview,
42
- onMoveCommit,
43
- onTrimPreview,
44
- onTrimCommit,
45
- defaultColorToken = 'chart-1',
46
- children,
47
- }: ClipViewProps) {
48
- const token = clip.colorToken ?? defaultColorToken;
49
- const originStart = useRef(0);
50
-
51
- const bodyDrag = usePointerDrag({
52
- onStart: () => {
53
- originStart.current = clip.timelineStart;
54
- onSelect();
55
- },
56
- onMove: ({ dx, event }) =>
57
- onMovePreview(Math.max(0, originStart.current + pxToSeconds(dx, zoomScale)), event),
58
- onEnd: ({ dx, cancelled }) =>
59
- onMoveCommit(Math.max(0, originStart.current + pxToSeconds(dx, zoomScale)), cancelled),
60
- });
61
-
62
- // Both edge handles share one drag recipe, differing only by which edge they trim.
63
- // `usePointerDrag` is a hook, so it's called directly at the top level (never inside a
64
- // helper/closure — Rules of Hooks); `edgeDragOptions` builds the config, not the hook.
65
- const edgeDragOptions = (edge: TrimEdge): UsePointerDragOptions => ({
66
- onStart: () => onSelect(),
67
- onMove: ({ dx, event }) => onTrimPreview(edge, pxToSeconds(dx, zoomScale), event),
68
- onEnd: ({ dx, cancelled }) => onTrimCommit(edge, pxToSeconds(dx, zoomScale), cancelled),
69
- });
70
- const startDrag = usePointerDrag(edgeDragOptions('start'));
71
- const endDrag = usePointerDrag(edgeDragOptions('end'));
72
-
73
- return (
74
- <button
75
- // guardrails-ignore no-raw-action-button: a draggable/trimmable timeline-canvas
76
- // primitive (positioned, pointer-drag-driven, custom color-mix styling via
77
- // `style`) — not a generic action trigger, so it can't route through the
78
- // Button/Tooltip abstraction without breaking the drag/trim contract.
79
- type='button'
80
- {...bodyDrag.handleProps}
81
- onClick={(e) => {
82
- e.stopPropagation(); // the lane behind also listens (deselect/seek)
83
- onSelect();
84
- }}
85
- aria-label={`Clip ${clip.name}`}
86
- aria-pressed={selected}
87
- className={cn(
88
- 'group absolute inset-y-1 z-10 flex flex-col overflow-hidden rounded-md border p-0 text-left',
89
- 'cursor-grab appearance-none active:cursor-grabbing',
90
- selected && 'ring-2 ring-accent-solid ring-offset-1 ring-offset-background',
91
- )}
92
- style={{
93
- ...bodyDrag.handleProps.style,
94
- left: clipLeftPx(clip, zoomScale),
95
- // 2px breathing room so butted clips stay visually distinct at high zoom
96
- width: Math.max(8, clipWidthPx(clip, zoomScale) - 2),
97
- borderColor: `var(--${token})`,
98
- background: `color-mix(in srgb, var(--${token}) 30%, var(--background))`,
99
- }}
100
- >
101
- {/* Media (filmstrip / waveform) fills the whole clip — labels ride ON TOP
102
- as overlays so thumbnails read as pictures, not a sliver under a bar. */}
103
- {children && <div className='pointer-events-none absolute inset-0'>{children}</div>}
104
- <div className='pointer-events-none relative z-1 flex items-center gap-1 px-1.5 pt-0.5'>
105
- <span className='truncate rounded bg-background/70 px-1 text-caption font-medium text-foreground'>
106
- {clip.name}
107
- </span>
108
- {clip.speed !== 1 && (
109
- <span className='inline-flex shrink-0 items-center gap-0.5 rounded bg-background/80 px-1 text-caption text-foreground'>
110
- <Zap aria-hidden className='size-2.5' />
111
- {clip.speed}x
112
- </span>
113
- )}
114
- </div>
115
- <div className='pointer-events-none relative z-1 mt-auto w-fit rounded-tr bg-background/60 px-1.5 text-caption text-muted-foreground'>
116
- {formatTimecode(clip.trackIn)}–{formatTimecode(clip.trackOut)}
117
- </div>
118
-
119
- {/* Trim handles — visible on hover/selection; hit area wider than the visual bar. */}
120
- <div
121
- {...startDrag.handleProps}
122
- className={cn(
123
- 'absolute inset-y-0 -left-1 z-20 flex w-4 cursor-ew-resize items-stretch justify-start',
124
- 'opacity-0 transition-opacity group-hover:opacity-100',
125
- selected && 'opacity-100',
126
- )}
127
- style={startDrag.handleProps.style}
128
- aria-hidden
129
- >
130
- <div className='ml-1 w-1.5 rounded-sm bg-foreground/40' />
131
- </div>
132
- <div
133
- {...endDrag.handleProps}
134
- className={cn(
135
- 'absolute inset-y-0 -right-1 z-20 flex w-4 cursor-ew-resize items-stretch justify-end',
136
- 'opacity-0 transition-opacity group-hover:opacity-100',
137
- selected && 'opacity-100',
138
- )}
139
- style={endDrag.handleProps.style}
140
- aria-hidden
141
- >
142
- <div className='mr-1 w-1.5 rounded-sm bg-foreground/40' />
143
- </div>
144
- </button>
145
- );
146
- }
@@ -1,63 +0,0 @@
1
- import { pxToSeconds, secondsToPx } from 'cwip/timeline';
2
- import { useRef } from 'react';
3
- import { usePointerDrag } from '../hooks/usePointerDrag';
4
-
5
- export interface PlayheadProps {
6
- timeSeconds: number;
7
- zoomScale: number;
8
- /** Drag the head to scrub; omit for a display-only playhead. */
9
- onScrub?: (seconds: number) => void;
10
- onScrubStart?: () => void;
11
- onScrubEnd?: () => void;
12
- }
13
-
14
- /**
15
- * The vertical playhead overlay (line + grab knob). Positioned absolutely in a
16
- * `relative` container spanning the timeline's full scroll width. The knob is
17
- * the drag target; the line itself stays click-through so clips underneath
18
- * remain selectable.
19
- */
20
- export function Playhead({
21
- timeSeconds,
22
- zoomScale,
23
- onScrub,
24
- onScrubStart,
25
- onScrubEnd,
26
- }: PlayheadProps) {
27
- const originSeconds = useRef(0);
28
- const drag = usePointerDrag({
29
- onStart: () => {
30
- originSeconds.current = timeSeconds;
31
- onScrubStart?.();
32
- },
33
- onMove: ({ dx }) => {
34
- onScrub?.(Math.max(0, originSeconds.current + pxToSeconds(dx, zoomScale)));
35
- },
36
- onEnd: () => onScrubEnd?.(),
37
- disabled: !onScrub,
38
- });
39
-
40
- return (
41
- <div
42
- className='pointer-events-none absolute inset-y-0 z-20'
43
- style={{ left: secondsToPx(timeSeconds, zoomScale) }}
44
- >
45
- <div className='absolute inset-y-0 w-px bg-destructive' />
46
- {onScrub && (
47
- <div
48
- {...drag.handleProps}
49
- role='slider'
50
- aria-label='Playhead'
51
- aria-valuemin={0}
52
- aria-valuemax={Number.MAX_SAFE_INTEGER}
53
- aria-valuenow={Math.round(timeSeconds)}
54
- tabIndex={0}
55
- className='pointer-events-auto absolute -top-1 -left-[11px] flex h-6 w-[23px] cursor-ew-resize items-start justify-center'
56
- style={drag.handleProps.style}
57
- >
58
- <div className='h-3 w-3 rounded-full border border-background bg-destructive shadow' />
59
- </div>
60
- )}
61
- </div>
62
- );
63
- }
@@ -1,85 +0,0 @@
1
- import { pxToSeconds, rulerTicks, secondsToPx } from 'cwip/timeline';
2
- import { useRef } from 'react';
3
- import { formatTimecode } from '../../core/media';
4
- import { usePointerDrag } from '../hooks/usePointerDrag';
5
- import { cn } from '../lib/cn';
6
-
7
- export interface TimeRulerProps {
8
- /** Ruler length (seconds) — usually total duration + some tail slack. */
9
- durationSeconds: number;
10
- zoomScale: number;
11
- /** Click/drag anywhere on the ruler seeks (a scrub). */
12
- onScrub: (seconds: number) => void;
13
- /** Fires on pointer-down / pointer-up of a ruler scrub so the owner can
14
- * suppress live playback while the gesture owns the playhead (parity with the
15
- * draggable playhead knob). */
16
- onScrubStart?: () => void;
17
- onScrubEnd?: () => void;
18
- /** Current playhead time — announced as the slider value. */
19
- currentTimeSeconds?: number;
20
- className?: string;
21
- }
22
-
23
- /**
24
- * The clickable time ruler. Tick density self-adjusts with zoom (labels never
25
- * crowd below ~60px apart); pointer down + drag scrubs continuously.
26
- */
27
- export function TimeRuler({
28
- durationSeconds,
29
- zoomScale,
30
- onScrub,
31
- onScrubStart,
32
- onScrubEnd,
33
- currentTimeSeconds = 0,
34
- className,
35
- }: TimeRulerProps) {
36
- const ref = useRef<HTMLDivElement>(null);
37
-
38
- const seekAtClientX = (clientX: number) => {
39
- const rect = ref.current?.getBoundingClientRect();
40
- if (!rect) return;
41
- const seconds = pxToSeconds(clientX - rect.left, zoomScale);
42
- onScrub(Math.min(durationSeconds, Math.max(0, seconds)));
43
- };
44
-
45
- const drag = usePointerDrag({
46
- onStart: (e) => {
47
- onScrubStart?.();
48
- seekAtClientX(e.clientX);
49
- },
50
- onMove: ({ event }) => seekAtClientX(event.clientX),
51
- onEnd: () => onScrubEnd?.(),
52
- });
53
-
54
- const ticks = rulerTicks(durationSeconds, zoomScale);
55
-
56
- return (
57
- <div
58
- ref={ref}
59
- {...drag.handleProps}
60
- className={cn(
61
- 'relative h-7 min-h-7 cursor-ew-resize select-none border-b border-border bg-muted/40',
62
- className,
63
- )}
64
- style={{ ...drag.handleProps.style, width: secondsToPx(durationSeconds, zoomScale) }}
65
- role='slider'
66
- aria-label='Timeline position'
67
- aria-valuemin={0}
68
- aria-valuemax={Math.round(durationSeconds)}
69
- aria-valuenow={Math.min(Math.round(durationSeconds), Math.round(currentTimeSeconds))}
70
- tabIndex={0}
71
- >
72
- {ticks.map((t) => (
73
- <div
74
- key={t}
75
- className='absolute top-0 h-full border-l border-border/70'
76
- style={{ left: secondsToPx(t, zoomScale) }}
77
- >
78
- <span className='pl-1 text-caption leading-7 text-muted-foreground'>
79
- {formatTimecode(t)}
80
- </span>
81
- </div>
82
- ))}
83
- </div>
84
- );
85
- }