cursedbelt 3.0.2 → 4.0.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 (250) hide show
  1. package/dist/react/components/ListToolbar.d.ts +94 -0
  2. package/dist/react/components/ListToolbar.d.ts.map +1 -0
  3. package/dist/react/components/ListToolbar.js +66 -0
  4. package/dist/react/components/ListToolbar.js.map +1 -0
  5. package/dist/react/file-tree/FileTree.d.ts +282 -3
  6. package/dist/react/file-tree/FileTree.d.ts.map +1 -1
  7. package/dist/react/file-tree/FileTree.js +799 -131
  8. package/dist/react/file-tree/FileTree.js.map +1 -1
  9. package/dist/react/file-tree/fileTree.css +151 -0
  10. package/dist/react/file-tree/fileTreeSelection.d.ts +187 -0
  11. package/dist/react/file-tree/fileTreeSelection.d.ts.map +1 -0
  12. package/dist/react/file-tree/fileTreeSelection.js +264 -0
  13. package/dist/react/file-tree/fileTreeSelection.js.map +1 -0
  14. package/dist/react/file-tree/index.d.ts +1 -0
  15. package/dist/react/file-tree/index.d.ts.map +1 -1
  16. package/dist/react/file-tree/index.js +8 -0
  17. package/dist/react/file-tree/index.js.map +1 -1
  18. package/dist/react/index.d.ts +1 -0
  19. package/dist/react/index.d.ts.map +1 -1
  20. package/dist/react/index.js +1 -0
  21. package/dist/react/index.js.map +1 -1
  22. package/dist/react/lib/form.d.ts +3 -0
  23. package/dist/react/lib/form.d.ts.map +1 -1
  24. package/dist/react/lib/form.js +43 -5
  25. package/dist/react/lib/form.js.map +1 -1
  26. package/dist/react/media/DenseGalleryShell.d.ts +19 -3
  27. package/dist/react/media/DenseGalleryShell.d.ts.map +1 -1
  28. package/dist/react/media/DenseGalleryShell.js +55 -15
  29. package/dist/react/media/DenseGalleryShell.js.map +1 -1
  30. package/dist/react/media/FocusViewer.d.ts.map +1 -1
  31. package/dist/react/media/FocusViewer.js +14 -14
  32. package/dist/react/media/FocusViewer.js.map +1 -1
  33. package/dist/react/media/FrameGrabber.d.ts +23 -0
  34. package/dist/react/media/FrameGrabber.d.ts.map +1 -1
  35. package/dist/react/media/FrameGrabber.js +67 -1
  36. package/dist/react/media/FrameGrabber.js.map +1 -1
  37. package/dist/react/media/MediaResize.d.ts +51 -19
  38. package/dist/react/media/MediaResize.d.ts.map +1 -1
  39. package/dist/react/media/MediaResize.js +20 -13
  40. package/dist/react/media/MediaResize.js.map +1 -1
  41. package/dist/react/media/VideoChapterEditor.d.ts +67 -0
  42. package/dist/react/media/VideoChapterEditor.d.ts.map +1 -0
  43. package/dist/react/media/VideoChapterEditor.js +148 -0
  44. package/dist/react/media/VideoChapterEditor.js.map +1 -0
  45. package/dist/react/media/VideoPlayer.d.ts +46 -4
  46. package/dist/react/media/VideoPlayer.d.ts.map +1 -1
  47. package/dist/react/media/VideoPlayer.js +124 -11
  48. package/dist/react/media/VideoPlayer.js.map +1 -1
  49. package/dist/react/media/VideoTurner.d.ts +15 -2
  50. package/dist/react/media/VideoTurner.d.ts.map +1 -1
  51. package/dist/react/media/VideoTurner.js +29 -2
  52. package/dist/react/media/VideoTurner.js.map +1 -1
  53. package/dist/react/media/denseGallery.css +104 -46
  54. package/dist/react/media/hlsSource.d.ts +57 -0
  55. package/dist/react/media/hlsSource.d.ts.map +1 -1
  56. package/dist/react/media/hlsSource.js +177 -1
  57. package/dist/react/media/hlsSource.js.map +1 -1
  58. package/dist/react/media/index.d.ts +2 -0
  59. package/dist/react/media/index.d.ts.map +1 -1
  60. package/dist/react/media/index.js +6 -0
  61. package/dist/react/media/index.js.map +1 -1
  62. package/dist/react/media/mediaResize.css +127 -54
  63. package/dist/react/media/pictureEditor.css +52 -6
  64. package/dist/react/media/videoChapterEditor.css +203 -0
  65. package/dist/react/media/videoChapters.d.ts +117 -0
  66. package/dist/react/media/videoChapters.d.ts.map +1 -0
  67. package/dist/react/media/videoChapters.js +95 -0
  68. package/dist/react/media/videoChapters.js.map +1 -0
  69. package/dist/react/media-gallery/GalleryTable.d.ts +52 -1
  70. package/dist/react/media-gallery/GalleryTable.d.ts.map +1 -1
  71. package/dist/react/media-gallery/GalleryTable.js +40 -9
  72. package/dist/react/media-gallery/GalleryTable.js.map +1 -1
  73. package/dist/react/media-gallery/MediaGallery.d.ts +107 -4
  74. package/dist/react/media-gallery/MediaGallery.d.ts.map +1 -1
  75. package/dist/react/media-gallery/MediaGallery.js +484 -104
  76. package/dist/react/media-gallery/MediaGallery.js.map +1 -1
  77. package/dist/react/media-gallery/MediaMetaEditor.d.ts +48 -0
  78. package/dist/react/media-gallery/MediaMetaEditor.d.ts.map +1 -0
  79. package/dist/react/media-gallery/MediaMetaEditor.js +66 -0
  80. package/dist/react/media-gallery/MediaMetaEditor.js.map +1 -0
  81. package/dist/react/media-gallery/index.d.ts +2 -0
  82. package/dist/react/media-gallery/index.d.ts.map +1 -1
  83. package/dist/react/media-gallery/index.js +5 -0
  84. package/dist/react/media-gallery/index.js.map +1 -1
  85. package/dist/react/media-gallery/mediaGallery.css +180 -4
  86. package/dist/react/media-gallery/mediaMeta.d.ts +62 -0
  87. package/dist/react/media-gallery/mediaMeta.d.ts.map +1 -0
  88. package/dist/react/media-gallery/mediaMeta.js +56 -0
  89. package/dist/react/media-gallery/mediaMeta.js.map +1 -0
  90. package/dist/react/media-gallery/playbackPreferences.d.ts +77 -0
  91. package/dist/react/media-gallery/playbackPreferences.d.ts.map +1 -1
  92. package/dist/react/media-gallery/playbackPreferences.js +42 -0
  93. package/dist/react/media-gallery/playbackPreferences.js.map +1 -1
  94. package/dist/react/media-gallery/types.d.ts +34 -0
  95. package/dist/react/media-gallery/types.d.ts.map +1 -1
  96. package/dist/scripts/guardrailsEnforce.d.ts +29 -0
  97. package/dist/scripts/guardrailsEnforce.d.ts.map +1 -0
  98. package/dist/styles-areas/activity-bar.css +30 -0
  99. package/dist/styles-areas/analytics.css +672 -0
  100. package/dist/styles-areas/auth.css +154 -0
  101. package/dist/styles-areas/calendar.css +416 -0
  102. package/dist/styles-areas/chart-table.css +41 -0
  103. package/dist/styles-areas/charts.css +89 -0
  104. package/dist/styles-areas/chat.css +364 -0
  105. package/dist/styles-areas/clipboard.css +26 -0
  106. package/dist/styles-areas/code-editor.css +130 -0
  107. package/dist/styles-areas/companion-link.css +70 -0
  108. package/dist/styles-areas/core.css +2503 -0
  109. package/dist/styles-areas/dashboard-grid.css +84 -0
  110. package/dist/styles-areas/data-table.css +657 -0
  111. package/dist/styles-areas/deep-link.css +26 -0
  112. package/dist/styles-areas/diff-viewer.css +30 -0
  113. package/dist/styles-areas/disk-usage.css +262 -0
  114. package/dist/styles-areas/emoji.css +154 -0
  115. package/dist/styles-areas/fields.css +582 -0
  116. package/dist/styles-areas/file-tree.css +33 -0
  117. package/dist/styles-areas/filter-rail.css +235 -0
  118. package/dist/styles-areas/folder-tree.css +219 -0
  119. package/dist/styles-areas/keep-awake.css +26 -0
  120. package/dist/styles-areas/layout-engine.css +239 -0
  121. package/dist/styles-areas/markdown.css +87 -0
  122. package/dist/styles-areas/master-detail.css +239 -0
  123. package/dist/styles-areas/master-lock.css +26 -0
  124. package/dist/styles-areas/media-gallery.css +351 -0
  125. package/dist/styles-areas/media.css +658 -0
  126. package/dist/styles-areas/nav.css +488 -0
  127. package/dist/styles-areas/notifications.css +245 -0
  128. package/dist/styles-areas/overlays.css +133 -0
  129. package/dist/styles-areas/palette.css +140 -0
  130. package/dist/styles-areas/pdf-viewer.css +47 -0
  131. package/dist/styles-areas/problem-detail.css +97 -0
  132. package/dist/styles-areas/rich-text.css +167 -0
  133. package/dist/styles-areas/sharing.css +153 -0
  134. package/dist/styles-areas/spreadsheet.css +37 -0
  135. package/dist/styles-areas/stats.css +281 -0
  136. package/dist/styles-areas/test-report.css +133 -0
  137. package/dist/styles-areas/virtual.css +30 -0
  138. package/dist/styles-areas/wizard.css +381 -0
  139. package/dist/styles-areas/workbench.css +543 -0
  140. package/dist/styles-areas/workbook-viewer.css +44 -0
  141. package/dist/styles-static.css +34 -23
  142. package/dist/styles.css +34 -23
  143. package/package.json +111 -31
  144. package/scripts/checkDistExports.ts +67 -0
  145. package/scripts/cssRules.ts +125 -0
  146. package/scripts/fixtureAppCss.ts +344 -0
  147. package/scripts/generateAreaStyles.ts +253 -0
  148. package/scripts/guardrailsEnforce.spec.ts +62 -0
  149. package/scripts/guardrailsEnforce.ts +67 -3
  150. package/scripts/styleAreas.ts +585 -0
  151. package/scripts/verify.ts +5 -0
  152. package/src/barrelsReachNoOptionalPeer.spec.ts +117 -9
  153. package/src/docsMatchTheSplit.spec.ts +98 -0
  154. package/src/fixtureAppCss.spec.ts +177 -0
  155. package/src/namedSubpathsResolve.spec.ts +35 -0
  156. package/src/publishShape.spec.ts +67 -0
  157. package/src/react/components/ListToolbar.spec.tsx +172 -0
  158. package/src/react/components/ListToolbar.tsx +151 -0
  159. package/src/react/file-tree/FileTree.spec.tsx +1009 -0
  160. package/src/react/file-tree/FileTree.tsx +1459 -309
  161. package/src/react/file-tree/fileTree.css +151 -0
  162. package/src/react/file-tree/fileTreeSelection.spec.ts +327 -0
  163. package/src/react/file-tree/fileTreeSelection.ts +321 -0
  164. package/src/react/file-tree/index.ts +21 -0
  165. package/src/react/index.ts +1 -0
  166. package/src/react/lib/form.ts +51 -8
  167. package/src/react/media/DenseGalleryShell.tsx +108 -36
  168. package/src/react/media/FocusViewer.tsx +15 -8
  169. package/src/react/media/FrameGrabber.spec.tsx +175 -0
  170. package/src/react/media/FrameGrabber.tsx +67 -0
  171. package/src/react/media/MediaResize.spec.tsx +84 -14
  172. package/src/react/media/MediaResize.tsx +51 -19
  173. package/src/react/media/VideoChapterEditor.tsx +428 -0
  174. package/src/react/media/VideoPlayer.spec.tsx +111 -1
  175. package/src/react/media/VideoPlayer.tsx +158 -11
  176. package/src/react/media/VideoTurner.spec.tsx +67 -0
  177. package/src/react/media/VideoTurner.tsx +70 -15
  178. package/src/react/media/denseGallery.css +104 -46
  179. package/src/react/media/hlsSource.recovery.spec.ts +213 -0
  180. package/src/react/media/hlsSource.spec.ts +8 -0
  181. package/src/react/media/hlsSource.ts +189 -1
  182. package/src/react/media/index.ts +14 -0
  183. package/src/react/media/mediaResize.css +127 -54
  184. package/src/react/media/pictureEditor.css +52 -6
  185. package/src/react/media/videoChapterEditor.css +203 -0
  186. package/src/react/media/videoChapters.spec.ts +176 -0
  187. package/src/react/media/videoChapters.ts +181 -0
  188. package/src/react/media-gallery/GalleryTable.tsx +93 -3
  189. package/src/react/media-gallery/MediaGallery.spec.tsx +1156 -10
  190. package/src/react/media-gallery/MediaGallery.tsx +813 -95
  191. package/src/react/media-gallery/MediaMetaEditor.tsx +237 -0
  192. package/src/react/media-gallery/galleryTable.spec.ts +41 -1
  193. package/src/react/media-gallery/index.ts +7 -0
  194. package/src/react/media-gallery/mediaGallery.css +180 -4
  195. package/src/react/media-gallery/mediaMeta.spec.ts +95 -0
  196. package/src/react/media-gallery/mediaMeta.ts +101 -0
  197. package/src/react/media-gallery/playbackPreferences.spec.ts +172 -0
  198. package/src/react/media-gallery/playbackPreferences.ts +100 -0
  199. package/src/react/media-gallery/types.ts +34 -0
  200. package/src/shippedFilesAreTracked.spec.ts +69 -0
  201. package/src/styles-areas/activity-bar.css +30 -0
  202. package/src/styles-areas/analytics.css +672 -0
  203. package/src/styles-areas/auth.css +154 -0
  204. package/src/styles-areas/calendar.css +416 -0
  205. package/src/styles-areas/chart-table.css +41 -0
  206. package/src/styles-areas/charts.css +89 -0
  207. package/src/styles-areas/chat.css +364 -0
  208. package/src/styles-areas/clipboard.css +26 -0
  209. package/src/styles-areas/code-editor.css +130 -0
  210. package/src/styles-areas/companion-link.css +70 -0
  211. package/src/styles-areas/core.css +2503 -0
  212. package/src/styles-areas/dashboard-grid.css +84 -0
  213. package/src/styles-areas/data-table.css +657 -0
  214. package/src/styles-areas/deep-link.css +26 -0
  215. package/src/styles-areas/diff-viewer.css +30 -0
  216. package/src/styles-areas/disk-usage.css +262 -0
  217. package/src/styles-areas/emoji.css +154 -0
  218. package/src/styles-areas/fields.css +582 -0
  219. package/src/styles-areas/file-tree.css +33 -0
  220. package/src/styles-areas/filter-rail.css +235 -0
  221. package/src/styles-areas/folder-tree.css +219 -0
  222. package/src/styles-areas/keep-awake.css +26 -0
  223. package/src/styles-areas/layout-engine.css +239 -0
  224. package/src/styles-areas/markdown.css +87 -0
  225. package/src/styles-areas/master-detail.css +239 -0
  226. package/src/styles-areas/master-lock.css +26 -0
  227. package/src/styles-areas/media-gallery.css +351 -0
  228. package/src/styles-areas/media.css +658 -0
  229. package/src/styles-areas/nav.css +488 -0
  230. package/src/styles-areas/notifications.css +245 -0
  231. package/src/styles-areas/overlays.css +133 -0
  232. package/src/styles-areas/palette.css +140 -0
  233. package/src/styles-areas/pdf-viewer.css +47 -0
  234. package/src/styles-areas/problem-detail.css +97 -0
  235. package/src/styles-areas/rich-text.css +167 -0
  236. package/src/styles-areas/sharing.css +153 -0
  237. package/src/styles-areas/spreadsheet.css +37 -0
  238. package/src/styles-areas/stats.css +281 -0
  239. package/src/styles-areas/test-report.css +133 -0
  240. package/src/styles-areas/virtual.css +30 -0
  241. package/src/styles-areas/wizard.css +381 -0
  242. package/src/styles-areas/workbench.css +543 -0
  243. package/src/styles-areas/workbook-viewer.css +44 -0
  244. package/src/styles-static.css +34 -23
  245. package/src/styles.css +34 -23
  246. package/src/stylesAreas.spec.ts +247 -0
  247. package/src/stylesUtilitiesMatches.spec.ts +6 -77
  248. package/src/testFilesRunInParallel.spec.ts +79 -0
  249. package/src/typecheckCachesAreSeparate.spec.ts +128 -0
  250. package/src/verifyGraph.spec.ts +6 -0
@@ -21,13 +21,38 @@
21
21
  * So the gesture is a hook and the affordances are components, and a third player gets both
22
22
  * by calling them rather than by copying eighty lines that drift.
23
23
  *
24
+ * ── 🔴 Both affordances live in a RAIL, below the picture ─────────────────────────────
25
+ * Owner, `ideas/collections-09-14.md`: *"Fix the drag to resize area to no longer overlap
26
+ * part of the horizontal play timeline area that shows what part of the video is playing. It
27
+ * should only be draggable when my mouse pointer is at the bottom right corner of the video
28
+ * player, just like mac windows for other apps work."*
29
+ *
30
+ * So every consumer renders exactly this, directly after the box that holds the picture:
31
+ *
32
+ * <div className='cbmr-rail'>
33
+ * <MediaResizeBar {...handle} label='…' />
34
+ * <MediaResizeCorner {...handle} label='…' />
35
+ * </div>
36
+ *
37
+ * and `MediaResize.spec.tsx` fails if a player stops doing so. The rail is a strip of chrome
38
+ * OUTSIDE the frame — a Mac window's grab zone is the window's own edge, not a patch of its
39
+ * content — which is what makes "nothing of it overlaps the control bar" a property of the
40
+ * layout rather than a gutter that has to be tuned against whatever the player draws. The
41
+ * geometry is proved in `e2e/resize-grip-rail.spec.ts`, in a real browser, at two viewports;
42
+ * happy-dom computes no layout, so nothing under `bun test` can see it.
43
+ *
24
44
  * ── What each affordance is for ───────────────────────────────────────────────────────
25
- * · {@link MediaResizeCorner} — the literal ask. Bottom-right of the picture, on top of it,
26
- * the same overlay convention the gallery's ⟨ ⟩ step arrows already use inside the same
27
- * clipped frame. Visible at rest, because that is the whole point of this pass.
28
- * · {@link MediaResizeBar} — a full-width edge under the frame. Kept because a corner is a
29
- * small target on a phone and because a letterboxed picture's corner is black on a
30
- * portrait clip; the bar is always exactly where the bottom edge is.
45
+ * · {@link MediaResizeCorner} — the literal ask. The rail's bottom-right corner, 64px of
46
+ * reach, visible at rest, because that is the whole point of this pass.
47
+ * · {@link MediaResizeBar} — the rail's full-width edge. 🔴 **Coarse pointers only, and that
48
+ * is this pass's second decision.** *"It should only be draggable when my mouse pointer is
49
+ * at the bottom right corner"* is a verdict on the bar too: on a desktop there is now one
50
+ * drag surface and it is the corner, exactly like a window. The one argument that was ever
51
+ * made for keeping the bar beside the corner is about a THUMB — a corner is a small target
52
+ * on a phone, and on a portrait clip the picture's corner is empty letterboxing while the
53
+ * bottom edge is always where the picture ends — so it survives under `(pointer: coarse)`
54
+ * and nowhere else. It is still rendered by both players at every size; `mediaResize.css`
55
+ * decides where it is shown, because the input device is a media query and not a prop.
31
56
  *
32
57
  * Both drive the same {@link useMediaResize} state, so a viewer may render either or both
33
58
  * and they can never disagree about how tall it is.
@@ -81,24 +106,31 @@ export interface MediaResizeAffordanceProps extends MediaResizeHandleProps {
81
106
  style?: CSSProperties;
82
107
  }
83
108
  /**
84
- * The corner grip — *"dragging the corner"*, drawn ON the picture at its bottom-right.
109
+ * The corner grip — *"dragging the corner"*, at the bottom-right of the rail under the
110
+ * picture.
85
111
  *
86
- * 🔴 An overlay INSIDE the clipped frame, deliberately, and the earlier note in
87
- * `DenseGalleryShell` arguing a handle there would be "painted over by a full-bleed video"
88
- * is superseded by the frame's own ⟨ ⟩ step arrows, which are exactly this: absolutely
89
- * positioned children of the same box, over arbitrary media, that have always been
90
- * clickable. Being on the picture is what makes it a CORNER rather than a bar that happens
91
- * to sit near one.
112
+ * 🔴 OUTSIDE the clipped frame since 2026-09-16, and the reason is in `mediaResize.css`'s
113
+ * header: keeping an overlay in that corner clear of a control bar means shortening the
114
+ * control bar, which costs the timeline the width it was complained about for and works only
115
+ * on a player this package styles. *"just like mac windows for other apps work"* — a window's
116
+ * grab zone is its outside corner, not a patch of its content, and the rail is that corner.
92
117
  */
93
118
  export declare function MediaResizeCorner({ label, className, style, ...handle }: MediaResizeAffordanceProps): import("react").JSX.Element;
94
119
  /**
95
- * The bottom edge — a full-width bar under the frame.
120
+ * The bottom edge — the rail's full-width bar.
121
+ *
122
+ * 🔴 **Shown on coarse pointers only** (`mediaResize.css`), which is the decision this
123
+ * component's existence turns on and is argued in this file's header: on a desktop the owner
124
+ * asked for one drag surface, in the corner, and the bar's own stated reason — a corner is a
125
+ * small target for a thumb, and a letterboxed picture's corner is empty black on a portrait
126
+ * clip while the bottom edge is always where the picture ends — is entirely about touch. It
127
+ * is rendered unconditionally so the two players cannot disagree about the markup; where it
128
+ * is SHOWN is a media query, because the input device is not something a prop can know.
96
129
  *
97
- * Kept alongside the corner because the corner is a small target on a phone, and because a
98
- * letterboxed picture's corner is empty black on a portrait clip and off the edge of the
99
- * picture on a wide one; the bottom edge is the one part of the stage whose position does
100
- * not move with the file. `DESIGN.md` §5 wants a 44px target: the bar is 10px of ink with
101
- * the rest as invisible padding, so it reads as a hairline and is hit like a button.
130
+ * `DESIGN.md` §5 wants a 44px target: the bar is 4px of ink with the rest as invisible
131
+ * padding, so it reads as a hairline and is hit like a button. That padding stays INSIDE the
132
+ * rail — it used to be pulled back over the picture and the transport with `margin-block:
133
+ * -11px`, which is one of the overlaps the 2026-09-14 report is about.
102
134
  */
103
135
  export declare function MediaResizeBar({ label, className, style, ...handle }: MediaResizeAffordanceProps): import("react").JSX.Element;
104
136
  //# sourceMappingURL=MediaResize.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MediaResize.d.ts","sourceRoot":"","sources":["../../../src/react/media/MediaResize.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,IAAI,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAG9E,OAAO,mBAAmB,CAAC;AAU3B,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,0EAA0E;IAC1E,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,yFAAyF;IACzF,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,MAAM,EAAE,sBAAsB,CAAC;CAChC;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IAC/D,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IAC7D,aAAa,EAAE,MAAM,IAAI,CAAC;CAC3B;AAMD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,EAC7B,UAAU,EACV,WAAW,EACX,OAAO,GACR,EAAE,qBAAqB,GAAG,gBAAgB,CAgG1C;AAyBD,MAAM,WAAW,0BAA2B,SAAQ,sBAAsB;IACxE,uFAAuF;IACvF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,KAAuB,EACvB,SAAS,EACT,KAAK,EACL,GAAG,MAAM,EACV,EAAE,0BAA0B,+BAe5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,EAC7B,KAAuB,EACvB,SAAS,EACT,KAAK,EACL,GAAG,MAAM,EACV,EAAE,0BAA0B,+BAY5B"}
1
+ {"version":3,"file":"MediaResize.d.ts","sourceRoot":"","sources":["../../../src/react/media/MediaResize.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,IAAI,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAG9E,OAAO,mBAAmB,CAAC;AAU3B,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,0EAA0E;IAC1E,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,yFAAyF;IACzF,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,MAAM,EAAE,sBAAsB,CAAC;CAChC;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IAC/D,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IAC7D,aAAa,EAAE,MAAM,IAAI,CAAC;CAC3B;AAMD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,EAC7B,UAAU,EACV,WAAW,EACX,OAAO,GACR,EAAE,qBAAqB,GAAG,gBAAgB,CAgG1C;AAyBD,MAAM,WAAW,0BAA2B,SAAQ,sBAAsB;IACxE,uFAAuF;IACvF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,KAAuB,EACvB,SAAS,EACT,KAAK,EACL,GAAG,MAAM,EACV,EAAE,0BAA0B,+BAe5B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,EAC7B,KAAuB,EACvB,SAAS,EACT,KAAK,EACL,GAAG,MAAM,EACV,EAAE,0BAA0B,+BAY5B"}
@@ -116,26 +116,33 @@ function sliderAria(props, label) {
116
116
  }
117
117
  const TIP = 'Drag to resize the viewer · ↑↓ to nudge · double-click to fit automatically';
118
118
  /**
119
- * The corner grip — *"dragging the corner"*, drawn ON the picture at its bottom-right.
119
+ * The corner grip — *"dragging the corner"*, at the bottom-right of the rail under the
120
+ * picture.
120
121
  *
121
- * 🔴 An overlay INSIDE the clipped frame, deliberately, and the earlier note in
122
- * `DenseGalleryShell` arguing a handle there would be "painted over by a full-bleed video"
123
- * is superseded by the frame's own ⟨ ⟩ step arrows, which are exactly this: absolutely
124
- * positioned children of the same box, over arbitrary media, that have always been
125
- * clickable. Being on the picture is what makes it a CORNER rather than a bar that happens
126
- * to sit near one.
122
+ * 🔴 OUTSIDE the clipped frame since 2026-09-16, and the reason is in `mediaResize.css`'s
123
+ * header: keeping an overlay in that corner clear of a control bar means shortening the
124
+ * control bar, which costs the timeline the width it was complained about for and works only
125
+ * on a player this package styles. *"just like mac windows for other apps work"* — a window's
126
+ * grab zone is its outside corner, not a patch of its content, and the rail is that corner.
127
127
  */
128
128
  export function MediaResizeCorner({ label = 'Viewer height', className, style, ...handle }) {
129
129
  return (_jsx(Tooltip, { content: TIP, children: _jsx("div", { ...sliderAria(handle, label), className: `cbmr-corner${className ? ` ${className}` : ''}`, style: style, children: _jsxs("svg", { "aria-hidden": 'true', viewBox: '0 0 12 12', className: 'cbmr-corner-glyph', children: [_jsx("title", { children: "Resize" }), _jsx("path", { d: 'M11 3 L3 11 M11 7 L7 11' })] }) }) }));
130
130
  }
131
131
  /**
132
- * The bottom edge — a full-width bar under the frame.
132
+ * The bottom edge — the rail's full-width bar.
133
133
  *
134
- * Kept alongside the corner because the corner is a small target on a phone, and because a
135
- * letterboxed picture's corner is empty black on a portrait clip and off the edge of the
136
- * picture on a wide one; the bottom edge is the one part of the stage whose position does
137
- * not move with the file. `DESIGN.md` §5 wants a 44px target: the bar is 10px of ink with
138
- * the rest as invisible padding, so it reads as a hairline and is hit like a button.
134
+ * 🔴 **Shown on coarse pointers only** (`mediaResize.css`), which is the decision this
135
+ * component's existence turns on and is argued in this file's header: on a desktop the owner
136
+ * asked for one drag surface, in the corner, and the bar's own stated reason — a corner is a
137
+ * small target for a thumb, and a letterboxed picture's corner is empty black on a portrait
138
+ * clip while the bottom edge is always where the picture ends — is entirely about touch. It
139
+ * is rendered unconditionally so the two players cannot disagree about the markup; where it
140
+ * is SHOWN is a media query, because the input device is not something a prop can know.
141
+ *
142
+ * `DESIGN.md` §5 wants a 44px target: the bar is 4px of ink with the rest as invisible
143
+ * padding, so it reads as a hairline and is hit like a button. That padding stays INSIDE the
144
+ * rail — it used to be pulled back over the picture and the transport with `margin-block:
145
+ * -11px`, which is one of the overlaps the 2026-09-14 report is about.
139
146
  */
140
147
  export function MediaResizeBar({ label = 'Viewer height', className, style, ...handle }) {
141
148
  return (_jsx(Tooltip, { content: TIP, children: _jsx("div", { ...sliderAria(handle, label), className: `cbmr-bar${className ? ` ${className}` : ''}`, style: style, children: _jsx("span", { className: 'cbmr-bar-grip', "aria-hidden": 'true' }) }) }));
@@ -1 +1 @@
1
- {"version":3,"file":"MediaResize.js","sourceRoot":"","sources":["../../../src/react/media/MediaResize.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MediaResize.js","sourceRoot":"","sources":["../../../src/react/media/MediaResize.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ import './videoChapterEditor.css';
2
+ import React from 'react';
3
+ import { type VideoChapter } from './videoChapters';
4
+ /**
5
+ * Put markers on a video at points in time and NAME them — the dialog.
6
+ *
7
+ * ── The owner's ask, 2026-09-15, which is the whole scope ──────────────────────────────
8
+ * *"allow putting markers on videos at points in time and giving them a title for the section
9
+ * for knowing what that part of the video is about, like youtube chapters."*
10
+ *
11
+ * So this dialog never touches a byte and never queues anything. It produces a
12
+ * `VideoChapter[]`, hands it to `onSubmit`, and closes — everything about what makes a list
13
+ * valid is `videoChapters.ts`, shared with the player that draws the dividers, so the strip in
14
+ * here and the scrub bar out there cannot disagree about where a section starts.
15
+ *
16
+ * 🔴 The sibling of `VideoCutEditor`, and deliberately NOT part of it. The two gestures look
17
+ * identical on a timeline — click a point, do something to it — and have nothing else in
18
+ * common. A cut is a REQUEST that costs a full re-encode and comes back as a second file
19
+ * minutes or hours later; a chapter is metadata that applies the moment it is saved and is
20
+ * free to be wrong. One dialog holding both would mean naming a section and queueing an ffmpeg
21
+ * job through the same Send button.
22
+ *
23
+ * ── Why the name comes BEFORE the mark ────────────────────────────────────────────────
24
+ * The field is filled first and `◆ Mark here` is disabled until it holds something. The other
25
+ * order — mark now, name later — is how every list of "Chapter 3" ends up in a video nobody
26
+ * can navigate: the marker exists, it is already useful enough to leave alone, and the name is
27
+ * the part that gets skipped. Requiring it up front costs one keystroke's worth of order and
28
+ * makes an unnamed chapter unreachable rather than merely discouraged.
29
+ *
30
+ * ── Keeping it out of the way when it is not in use ───────────────────────────────────
31
+ * One `InfoHint` for the whole model, the fleet's standard ⓘ — a 16px glyph at rest that
32
+ * opens on hover, focus or tap. A line of instructions under the player is permanent rent paid
33
+ * by every visit after the first.
34
+ */
35
+ export interface VideoChapterEditorProps {
36
+ /** The clip, as a URL a `<video>` can play. */
37
+ src: string;
38
+ /** Shown until the first frame decodes — a black box reads as a broken player. */
39
+ posterUrl?: string;
40
+ name?: string;
41
+ /**
42
+ * The clip's length, when the app already knows it. The element's own metadata still wins
43
+ * once it loads: a duration the catalog rounded to the second would put the last chapter's
44
+ * section a fraction out, and could refuse a mark near the end that is perfectly legal.
45
+ */
46
+ durationSeconds?: number | null;
47
+ /** The sections this video already has. Edited in place; nothing is saved until Save. */
48
+ chapters?: readonly VideoChapter[];
49
+ open?: boolean;
50
+ onClose: () => void;
51
+ /**
52
+ * Save the sections. Resolving CLOSES the dialog; rejecting leaves it open with the list
53
+ * intact, because the alternative is losing several minutes of careful naming to one failed
54
+ * request.
55
+ *
56
+ * An EMPTY list is a legitimate answer — it means "this video has no sections" and is how
57
+ * every chapter gets removed. Unlike a cut list, there is nothing expensive on the other
58
+ * side of it to refuse.
59
+ */
60
+ onSubmit: (chapters: VideoChapter[]) => void | Promise<void>;
61
+ /** Wording for the confirm button — apps store this differently. */
62
+ submitLabel?: string;
63
+ /** Shown under the list: anything the app wants to say about where these are kept. */
64
+ note?: React.ReactNode;
65
+ }
66
+ export declare function VideoChapterEditor({ src, posterUrl, name, durationSeconds, chapters: initialChapters, open, onClose, onSubmit, submitLabel, note, }: VideoChapterEditorProps): React.JSX.Element;
67
+ //# sourceMappingURL=VideoChapterEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VideoChapterEditor.d.ts","sourceRoot":"","sources":["../../../src/react/media/VideoChapterEditor.tsx"],"names":[],"mappings":"AAAA,OAAO,0BAA0B,CAAC;AAClC,OAAO,KAAK,MAAM,OAAO,CAAC;AAQ1B,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,WAAW,uBAAuB;IACtC,+CAA+C;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,kFAAkF;IAClF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,yFAAyF;IACzF,QAAQ,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IACnC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB;;;;;;;;OAQG;IACH,QAAQ,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sFAAsF;IACtF,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACxB;AAED,wBAAgB,kBAAkB,CAAC,EACjC,GAAG,EACH,SAAS,EACT,IAAI,EACJ,eAAe,EACf,QAAQ,EAAE,eAAe,EACzB,IAAW,EACX,OAAO,EACP,QAAQ,EACR,WAA6B,EAC7B,IAAI,GACL,EAAE,uBAAuB,qBAiVzB"}
@@ -0,0 +1,148 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import './videoChapterEditor.css';
3
+ import React from 'react';
4
+ import { Bookmark, Trash2 } from 'lucide-react';
5
+ import { cutTimecode } from 'cursedbelt-core/media/video-cuts';
6
+ import { ActionBar } from '../components/ActionBar';
7
+ import { Button } from '../components/Button';
8
+ import { InfoHint } from '../components/InfoHint';
9
+ import { Input } from '../components/Input';
10
+ import { Modal } from '../components/Modal';
11
+ import { chapterProblem, chapterSpans, normalizeChapters, } from './videoChapters';
12
+ export function VideoChapterEditor({ src, posterUrl, name, durationSeconds, chapters: initialChapters, open = true, onClose, onSubmit, submitLabel = 'Save sections', note, }) {
13
+ const videoRef = React.useRef(null);
14
+ const [duration, setDuration] = React.useState(durationSeconds && Number.isFinite(durationSeconds) ? durationSeconds : 0);
15
+ const [playhead, setPlayhead] = React.useState(0);
16
+ /*
17
+ * 🔴 Seeded from the prop SORTED but not normalized, and this is the bug that shape avoids:
18
+ * `normalizeChapters` needs a duration, the duration is frequently unknown at mount (the
19
+ * element has not read its metadata yet), and with `duration === 0` it returns an empty
20
+ * list. Normalizing here would therefore wipe every existing chapter of every video whose
21
+ * length the app did not already know — and since this is initial state, they would never
22
+ * come back. Normalization happens where a duration is real: on the strip, and on save.
23
+ */
24
+ const [chapters, setChapters] = React.useState(() => [...(initialChapters ?? [])].sort((a, b) => a.startSeconds - b.startSeconds));
25
+ const [draftTitle, setDraftTitle] = React.useState('');
26
+ const [submitting, setSubmitting] = React.useState(false);
27
+ const [error, setError] = React.useState(null);
28
+ const spans = React.useMemo(() => chapterSpans(chapters, duration), [chapters, duration]);
29
+ /** What Save would send. Also what `isDirty` compares, so the two can never disagree. */
30
+ const saved = React.useMemo(() => normalizeChapters(chapters, duration), [chapters, duration]);
31
+ const baseline = React.useMemo(() => JSON.stringify(normalizeChapters(initialChapters ?? [], duration)), [initialChapters, duration]);
32
+ const isDirty = JSON.stringify(saved) !== baseline;
33
+ /**
34
+ * A row whose name has been cleared. It is REPORTED rather than dropped: `normalizeChapters`
35
+ * would quietly discard it on save, so somebody who emptied a field to retype it and then
36
+ * pressed Save would be told the save succeeded and lose the marker.
37
+ */
38
+ const unnamed = chapters.filter((chapter) => chapter.title.trim().length === 0).length;
39
+ const pct = React.useCallback((seconds) => (duration > 0 ? Math.min(100, Math.max(0, (seconds / duration) * 100)) : 0), [duration]);
40
+ const seek = React.useCallback((seconds) => {
41
+ const video = videoRef.current;
42
+ if (!video || !Number.isFinite(seconds))
43
+ return;
44
+ video.currentTime = Math.max(0, seconds);
45
+ setPlayhead(Math.max(0, seconds));
46
+ }, []);
47
+ /** ◆ — name the section that starts at the playhead. */
48
+ const markHere = React.useCallback(() => {
49
+ const draft = { startSeconds: playhead, title: draftTitle };
50
+ const problem = chapterProblem(draft, chapters, duration);
51
+ if (problem) {
52
+ setError(problem);
53
+ return;
54
+ }
55
+ setError(null);
56
+ setChapters((current) => [...current, { startSeconds: playhead, title: draftTitle.trim() }].sort((a, b) => a.startSeconds - b.startSeconds));
57
+ setDraftTitle('');
58
+ }, [playhead, draftTitle, chapters, duration]);
59
+ /** Rename in place. Keyed by the START, which is unique and does not move when a name does. */
60
+ const rename = React.useCallback((startSeconds, title) => {
61
+ setError(null);
62
+ setChapters((current) => current.map((chapter) => chapter.startSeconds === startSeconds ? { ...chapter, title } : chapter));
63
+ }, []);
64
+ const remove = React.useCallback((startSeconds) => {
65
+ setError(null);
66
+ setChapters((current) => current.filter((chapter) => chapter.startSeconds !== startSeconds));
67
+ }, []);
68
+ /*
69
+ * `Space` plays, and nothing else is bound — deliberately.
70
+ *
71
+ * 🔴 There is no key for "mark here". This dialog's primary control is a TEXT FIELD, which
72
+ * owns the keyboard the whole time somebody is using it: any letter bound on the container
73
+ * is a letter that either cannot be typed or fires twice depending on where focus happens to
74
+ * be. Enter in the field marks, which is the one shortcut that needs no arbitration.
75
+ *
76
+ * Bound on the DIALOG, not the window: the gallery has its own ⇧←/⇧→ and Space handling, and
77
+ * a global listener would keep firing after this closed. `Modal` traps focus, so the dialog
78
+ * really does have the keystrokes while it is open.
79
+ */
80
+ const onKeyDown = (event) => {
81
+ const target = event.target;
82
+ if (target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA'))
83
+ return;
84
+ if (event.key !== ' ')
85
+ return;
86
+ event.preventDefault();
87
+ const video = videoRef.current;
88
+ if (!video)
89
+ return;
90
+ if (video.paused)
91
+ void video.play().catch(() => undefined);
92
+ else
93
+ video.pause();
94
+ };
95
+ const submit = async () => {
96
+ if (unnamed > 0) {
97
+ setError(unnamed === 1
98
+ ? 'One section has no name. Name it, or remove it.'
99
+ : `${unnamed} sections have no name. Name them, or remove them.`);
100
+ return;
101
+ }
102
+ setSubmitting(true);
103
+ setError(null);
104
+ try {
105
+ await onSubmit(saved);
106
+ onClose();
107
+ }
108
+ catch (err) {
109
+ // 🔴 Left open, with the list intact. A failed request must not cost somebody the
110
+ // several minutes of scrubbing and naming that produced it.
111
+ setError(err instanceof Error ? err.message : 'That could not be saved. Nothing was changed.');
112
+ }
113
+ finally {
114
+ setSubmitting(false);
115
+ }
116
+ };
117
+ /** Why `◆ Mark here` is unavailable, as the sentence its tooltip shows. */
118
+ const markProblem = chapterProblem({ startSeconds: playhead, title: draftTitle }, chapters, duration);
119
+ const leadPct = spans.length > 0 ? pct(spans[0]?.startSeconds ?? 0) : 0;
120
+ return (_jsx(Modal, { open: open, onClose: onClose, title: name ? `Sections of ${name}` : 'Video sections', subtitle: 'Mark a point, name the part that starts there \u2014 the player shows them on the scrub bar.', size: 'lg',
121
+ // 🔴 The discard guard. This body holds text fields, so a backdrop click without it
122
+ // throws away every name typed since the dialog opened, with no prompt.
123
+ isDirty: isDirty, ...(error ? { problem: error } : {}), footer: _jsx(ActionBar, { primary: _jsxs(_Fragment, { children: [_jsx(Button, { variant: 'secondary', onClick: onClose, tooltip: 'Close without saving anything', children: "Cancel" }), _jsx(Button, { onClick: () => void submit(), disabled: submitting || unnamed > 0, tooltip: unnamed > 0
124
+ ? 'Every section needs a name before this can be saved'
125
+ : 'Save these sections — nothing about the video itself is changed', children: submitting ? 'Saving…' : submitLabel })] }) }), children: _jsxs("fieldset", { className: 'cbch', onKeyDown: onKeyDown, "aria-label": 'Name the sections of this video. Type a name, then mark the point it starts at. Space plays and pauses.', children: [_jsx("video", { ref: videoRef, className: 'cbch-video', src: src, poster: posterUrl, controls: true, playsInline: true, preload: 'metadata', onLoadedMetadata: (event) => {
126
+ const seen = event.currentTarget.duration;
127
+ // The element's own metadata wins over anything the catalog rounded.
128
+ if (Number.isFinite(seen) && seen > 0)
129
+ setDuration(seen);
130
+ }, onTimeUpdate: (event) => setPlayhead(event.currentTarget.currentTime), onSeeked: (event) => setPlayhead(event.currentTarget.currentTime) }), _jsxs("div", { className: 'cbch-add', children: [_jsx("div", { className: 'cbch-add-field', children: _jsx(Input, { value: draftTitle, onChange: (event) => {
131
+ setDraftTitle(event.currentTarget.value);
132
+ setError(null);
133
+ }, onEnter: markHere, "aria-label": 'What this part of the video is about', placeholder: 'What is this part about?' }) }), _jsx(Button, { size: 'sm', variant: 'secondary', onClick: markHere, disabled: markProblem !== null, leftIcon: _jsx(Bookmark, { "aria-hidden": 'true', size: 14 }), tooltip: markProblem ?? `Start a section called "${draftTitle.trim()}" here`, children: "Mark here" }), _jsx("span", { className: 'cbch-playhead', children: cutTimecode(playhead) }), _jsxs(InfoHint, { title: 'Naming the parts of a video', align: 'right', children: [_jsxs("p", { children: ["Play or scrub to where a part begins, type what it is about, and press", ' ', _jsx("strong", { children: "Mark here" }), " (or ", _jsx("kbd", { children: "Enter" }), " in the box)."] }), _jsxs("p", { children: ["Each section runs until the next one starts. Click a section's time to jump there, edit a name in place, and ", _jsx("kbd", { children: "Space" }), " plays and pauses."] }), _jsx("p", { children: "Nothing here changes your video \u2014 these are names the player shows on the scrub bar and in its chapters menu." })] })] }), _jsxs("ul", { className: 'cbch-strip', "aria-label": spans.length === 0
134
+ ? 'No sections yet — the whole clip is one unnamed part'
135
+ : `${spans.length} section${spans.length === 1 ? '' : 's'}`, children: [leadPct > 0 ? (_jsx("li", { className: 'cbch-lead', style: { width: `${leadPct}%` }, "aria-label": 'The opening, which has no section yet' })) : null, spans.map((span) => (_jsx("li", { className: 'cbch-span-item', style: { width: `${pct(span.endSeconds) - pct(span.startSeconds)}%` }, children: _jsx("button", {
136
+ // guardrails-ignore no-raw-action-button: a section of the timeline, sized to
137
+ // its own duration — a `Button` carries padding and a min-width, which is
138
+ // exactly wrong for a control whose WIDTH is the information.
139
+ type: 'button', className: 'cbch-span', "aria-label": `Jump to "${span.title}" at ${cutTimecode(span.startSeconds)}`, onClick: () => seek(span.startSeconds), children: _jsx("span", { className: 'cbch-span-label', children: span.title }) }) }, span.key))), _jsx("span", { className: 'cbch-strip-head', style: { left: `${pct(playhead)}%` } })] }), _jsx("p", { className: 'cbch-summary', children: duration > 0
140
+ ? spans.length === 0
141
+ ? `${cutTimecode(duration)} of video, in one unnamed part`
142
+ : `${spans.length} section${spans.length === 1 ? '' : 's'} across ${cutTimecode(duration)}`
143
+ : 'Reading the clip…' }), chapters.length === 0 ? (_jsx("p", { className: 'cbch-empty', children: "No sections yet. Scrub to where a part begins, name it, and mark it." })) : (_jsx("ul", { className: 'cbch-list', children: chapters.map((chapter) => (_jsxs("li", { className: 'cbch-row', children: [_jsxs("button", {
144
+ // guardrails-ignore no-raw-action-button: a plain-CSS row inside a lazily
145
+ // imported, deliberately Tailwind-free editor — see `videoCutEditor.css`.
146
+ type: 'button', className: 'cbch-row-goto', "aria-label": `Jump to ${cutTimecode(chapter.startSeconds)}`, onClick: () => seek(chapter.startSeconds), children: [_jsx(Bookmark, { "aria-hidden": 'true', size: 12 }), " ", cutTimecode(chapter.startSeconds)] }), _jsx("div", { className: 'cbch-row-title', children: _jsx(Input, { size: 'sm', value: chapter.title, onChange: (event) => rename(chapter.startSeconds, event.currentTarget.value), "aria-label": `Name of the section at ${cutTimecode(chapter.startSeconds)}`, "aria-invalid": chapter.title.trim().length === 0, placeholder: 'Name this section' }) }), _jsx(Button, { size: 'sm', variant: 'ghost', tooltip: 'Remove this section \u2014 the video keeps playing straight through', "aria-label": `Remove the section at ${cutTimecode(chapter.startSeconds)}`, onClick: () => remove(chapter.startSeconds), children: _jsx(Trash2, { "aria-hidden": 'true', size: 14 }) })] }, chapter.startSeconds.toFixed(3)))) })), note ? _jsx("div", { className: 'cbch-note', children: note }) : null] }) }));
147
+ }
148
+ //# sourceMappingURL=VideoChapterEditor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VideoChapterEditor.js","sourceRoot":"","sources":["../../../src/react/media/VideoChapterEditor.tsx"],"names":[],"mappings":"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"}
@@ -5,6 +5,8 @@ import { type MediaPlayerInstance, type MediaProviderAdapter } from '@vidstack/r
5
5
  import { type DefaultVideoLayoutSlots } from '@vidstack/react/player/layouts/default';
6
6
  import { type RefObject } from 'react';
7
7
  import type { PlayableVideo } from 'cursedbelt-core/media';
8
+ import { type SessionVolume } from '../media-gallery/playbackPreferences';
9
+ import { type ChapteredVideo } from './videoChapters';
8
10
  /**
9
11
  * The reusable video player primitive. Consumes a {@link PlayableVideo} (URLs already
10
12
  * resolved by a `cursedbelt-server/storage` source) and renders Vidstack's default layout —
@@ -19,16 +21,36 @@ import type { PlayableVideo } from 'cursedbelt-core/media';
19
21
  * `<video>` element safe here — no canvas workaround. Scrub-preview thumbnails come from the
20
22
  * source's WebVTT track (`vttUrl`); while derivatives are still being built, a thin progress
21
23
  * bar rides the bottom edge of the surface (the original bytes stay playable behind it).
24
+ *
25
+ * Named sections (`chapters`) become a real `kind='chapters'` text track, which is what turns
26
+ * Vidstack's default layout from a bare bar into a YouTube-shaped one — dividers on the time
27
+ * slider, the current section's name above it, and a chapters menu. See {@link ChaptersTrack}.
22
28
  */
23
29
  export interface VideoPlayerProps {
24
- video: PlayableVideo;
30
+ /**
31
+ * The clip, with every URL already resolved — and its named sections, when the app carries
32
+ * any. {@link ChapteredVideo} is `PlayableVideo` plus `chapters`, so every existing source
33
+ * still satisfies this unchanged.
34
+ */
35
+ video: ChapteredVideo;
25
36
  /**
26
37
  * Start playing on mount. **Defaults to `true`** — see {@link usePrefersReducedMotion} and
27
38
  * the block on {@link AUTOPLAY_DEFAULT}.
28
39
  */
29
40
  autoPlay?: boolean;
30
- /** Start silent. **Defaults to `true` whenever autoplay is in effect** (see below). */
41
+ /**
42
+ * Start silent. **Defaults to `true` whenever autoplay is in effect** (see below) — unless
43
+ * the person has already set a volume on this surface THIS SESSION, which wins over both.
44
+ */
31
45
  muted?: boolean;
46
+ /**
47
+ * Where this surface's session volume is kept. Defaults to {@link PLAYER_VOLUME_KEY}.
48
+ *
49
+ * 🔴 Pass a different key for a player that is a DIFFERENT surface — the gallery stage
50
+ * passes `STAGE_VOLUME_KEY` — for the reason `media/stageResize.ts` keys the remembered
51
+ * height: one shared key makes two viewers on one page fight over a single number.
52
+ */
53
+ volumeKey?: string;
32
54
  className?: string;
33
55
  /**
34
56
  * Intrinsic aspect ratio (a CSS `aspect-ratio` value, e.g. `'16/9'` or `'4/3'`). Gives the
@@ -233,21 +255,41 @@ export declare const AUTOPLAY_DEFAULT = true;
233
255
  * preference", which is the behavior everything had before this existed.
234
256
  */
235
257
  /**
236
- * The autoplay decision, as a pure function so it can be asserted without a browser.
258
+ * The autoplay decision — and, since 2026-09-16, how loud the clip opens.
237
259
  *
238
260
  * 🔴 It is extracted rather than inlined because nothing below a real browser can see the
239
261
  * difference: `autoPlay` and `muted` are two props on one JSX element, and swapping them,
240
262
  * dropping the reduced-motion term, or letting `muted` default independently all typecheck
241
263
  * and render identically under happy-dom. The same reasoning `posterFraming.ts` and
242
264
  * `mediaGalleryModel.ts` already apply to their own decisions.
265
+ *
266
+ * ── 🔴 Where `session` sits in the precedence, and why ──────────────────────────────────
267
+ * Owner, `ideas/collections-09-14.md`: *"Keep the media player volume where I set it after
268
+ * changing it during a session except if I refresh or first log in then continue starting it
269
+ * at mute. Then if I unmute it, keep that value as I change to other videos."*
270
+ *
271
+ * · an explicit `muted` prop still wins — an app that says "silent" means silent
272
+ * · then what he set THIS SESSION ({@link readSessionVolume}, `null` until he touches it)
273
+ * · then the old rule: muted follows autoPlay, because an unmuted autoplay is refused
274
+ *
275
+ * A `null` session is therefore byte-for-byte the behavior every consumer had before this
276
+ * existed, which is what makes "a refresh starts at mute" true rather than merely intended:
277
+ * a fresh tab has no session entry, so a fresh tab takes the third line.
278
+ *
279
+ * `volume` is returned separately from `muted` on purpose — see {@link SessionVolume}. A mute
280
+ * stored as `volume: 0` would make the control bar's unmute button return to silence, and
281
+ * *"if I unmute it, keep that value"* is the sentence that forbids it.
243
282
  */
244
283
  export declare function resolveAutoplay(opts: {
245
284
  autoPlay?: boolean;
246
285
  muted?: boolean;
247
286
  reducedMotion: boolean;
287
+ /** What he set this session on this surface, or `null`/absent for "he has not". */
288
+ session?: SessionVolume | null;
248
289
  }): {
249
290
  autoPlay: boolean;
250
291
  muted: boolean;
292
+ volume: number;
251
293
  };
252
294
  /**
253
295
  * 🔴 Make the picture follow the scrub bar WHILE it is dragged, not only on release.
@@ -325,7 +367,7 @@ export declare function useLiveScrub(hostRef: RefObject<HTMLElement | null>, pla
325
367
  */
326
368
  export declare function preferBundledHls(provider: MediaProviderAdapter | null): void;
327
369
  export declare function usePrefersReducedMotion(): boolean;
328
- export declare function VideoPlayer({ video, autoPlay, muted, className, aspectRatio, onEnded, loop, liveScrub, smallLayoutWhen, onStep, canStep, fullscreenOnDoubleClick, }: VideoPlayerProps): import("react").JSX.Element;
370
+ export declare function VideoPlayer({ video, autoPlay, muted, volumeKey, className, aspectRatio, onEnded, loop, liveScrub, smallLayoutWhen, onStep, canStep, fullscreenOnDoubleClick, }: VideoPlayerProps): import("react").JSX.Element;
329
371
  /**
330
372
  * The processing state for a video surface: a thin progress bar pinned across the bottom edge
331
373
  * while derivatives build (indeterminate shimmer until real progress arrives), or a compact
@@ -1 +1 @@
1
- {"version":3,"file":"VideoPlayer.d.ts","sourceRoot":"","sources":["../../../src/react/media/VideoPlayer.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"VideoPlayer.d.ts","sourceRoot":"","sources":["../../../src/react/media/VideoPlayer.tsx"],"names":[],"mappings":"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"}