@bysages/react 0.3.1 → 0.4.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 (272) hide show
  1. package/dist/{ai-response-BfKTmtCt.mjs → ai-response-B4DX7nmJ.mjs} +3 -1
  2. package/dist/chevron-a2nIZKN4.mjs +6 -0
  3. package/dist/components/accordion/index.d.mts +22 -4
  4. package/dist/components/accordion/index.mjs +31 -1
  5. package/dist/components/affix/index.d.mts +4 -1
  6. package/dist/components/affix/index.mjs +5 -3
  7. package/dist/components/ai/index.d.mts +1 -1
  8. package/dist/components/ai/index.mjs +5 -3
  9. package/dist/components/ai-action/index.d.mts +4 -1
  10. package/dist/components/ai-action/index.mjs +3 -1
  11. package/dist/components/ai-attachments/index.d.mts +10 -4
  12. package/dist/components/ai-attachments/index.mjs +16 -44
  13. package/dist/components/ai-message/index.d.mts +4 -1
  14. package/dist/components/ai-message/index.mjs +3 -1
  15. package/dist/components/ai-prompt-input/index.d.mts +5 -2
  16. package/dist/components/ai-prompt-input/index.mjs +10 -14
  17. package/dist/components/ai-reasoning/index.d.mts +4 -1
  18. package/dist/components/ai-reasoning/index.mjs +4 -2
  19. package/dist/components/ai-response/index.d.mts +4 -1
  20. package/dist/components/ai-response/index.mjs +1 -1
  21. package/dist/components/ai-source/index.d.mts +8 -2
  22. package/dist/components/ai-source/index.mjs +5 -2
  23. package/dist/components/ai-suggestion/index.d.mts +4 -1
  24. package/dist/components/ai-suggestion/index.mjs +3 -1
  25. package/dist/components/ai-tool/index.d.mts +4 -1
  26. package/dist/components/ai-tool/index.mjs +4 -2
  27. package/dist/components/alert/index.d.mts +2 -0
  28. package/dist/components/alert/index.mjs +11 -18
  29. package/dist/components/angle-slider/index.d.mts +19 -2
  30. package/dist/components/angle-slider/index.mjs +31 -8
  31. package/dist/components/aspect-ratio/index.d.mts +4 -1
  32. package/dist/components/aspect-ratio/index.mjs +3 -1
  33. package/dist/components/autocomplete/index.d.mts +3 -1
  34. package/dist/components/autocomplete/index.mjs +6 -1
  35. package/dist/components/avatar/index.d.mts +2 -2
  36. package/dist/components/avatar/index.mjs +9 -2
  37. package/dist/components/avatar-group/index.d.mts +4 -1
  38. package/dist/components/avatar-group/index.mjs +3 -1
  39. package/dist/components/back-top/index.d.mts +7 -1
  40. package/dist/components/back-top/index.mjs +12 -17
  41. package/dist/components/badge/index.d.mts +4 -1
  42. package/dist/components/badge/index.mjs +3 -1
  43. package/dist/components/banner/index.mjs +2 -11
  44. package/dist/components/block-ui/index.d.mts +4 -1
  45. package/dist/components/block-ui/index.mjs +3 -1
  46. package/dist/components/button/index.d.mts +4 -1
  47. package/dist/components/button/index.mjs +3 -1
  48. package/dist/components/calendar/index.d.mts +3 -1
  49. package/dist/components/calendar/index.mjs +9 -10
  50. package/dist/components/carousel/index.d.mts +21 -1
  51. package/dist/components/carousel/index.mjs +43 -2
  52. package/dist/components/cascade-select/index.d.mts +6 -1
  53. package/dist/components/cascade-select/index.mjs +12 -35
  54. package/dist/components/checkbox/index.d.mts +20 -2
  55. package/dist/components/checkbox/index.mjs +28 -8
  56. package/dist/components/checkbox-group/index.d.mts +8 -6
  57. package/dist/components/checkbox-group/index.mjs +44 -48
  58. package/dist/components/chip/index.d.mts +4 -1
  59. package/dist/components/chip/index.mjs +3 -1
  60. package/dist/components/client-only/index.d.mts +7 -2
  61. package/dist/components/client-only/index.mjs +5 -1
  62. package/dist/components/clipboard/index.d.mts +17 -4
  63. package/dist/components/clipboard/index.mjs +33 -5
  64. package/dist/components/collapsible/index.d.mts +16 -4
  65. package/dist/components/collapsible/index.mjs +25 -1
  66. package/dist/components/color-picker/index.d.mts +20 -4
  67. package/dist/components/color-picker/index.mjs +56 -14
  68. package/dist/components/combobox/index.d.mts +27 -1
  69. package/dist/components/combobox/index.mjs +62 -5
  70. package/dist/components/command/index.d.mts +4 -1
  71. package/dist/components/command/index.mjs +7 -1
  72. package/dist/components/comment/index.d.mts +4 -1
  73. package/dist/components/comment/index.mjs +3 -1
  74. package/dist/components/config-provider/index.d.mts +4 -1
  75. package/dist/components/config-provider/index.mjs +3 -1
  76. package/dist/components/container/index.d.mts +4 -1
  77. package/dist/components/container/index.mjs +3 -1
  78. package/dist/components/data-view/index.d.mts +4 -1
  79. package/dist/components/data-view/index.mjs +3 -1
  80. package/dist/components/date-input/index.d.mts +19 -4
  81. package/dist/components/date-input/index.mjs +33 -9
  82. package/dist/components/date-picker/index.d.mts +21 -4
  83. package/dist/components/date-picker/index.mjs +58 -11
  84. package/dist/components/deferred-content/index.d.mts +4 -1
  85. package/dist/components/deferred-content/index.mjs +3 -1
  86. package/dist/components/descriptions/index.d.mts +10 -2
  87. package/dist/components/descriptions/index.mjs +13 -8
  88. package/dist/components/dialog/index.d.mts +18 -5
  89. package/dist/components/dialog/index.mjs +43 -1
  90. package/dist/components/download-trigger/index.d.mts +7 -2
  91. package/dist/components/download-trigger/index.mjs +5 -1
  92. package/dist/components/drawer/index.d.mts +18 -6
  93. package/dist/components/drawer/index.mjs +40 -1
  94. package/dist/components/dynamic-input/index.d.mts +4 -1
  95. package/dist/components/dynamic-input/index.mjs +10 -18
  96. package/dist/components/editable/index.d.mts +28 -7
  97. package/dist/components/editable/index.mjs +43 -4
  98. package/dist/components/ellipsis/index.d.mts +4 -1
  99. package/dist/components/ellipsis/index.mjs +3 -1
  100. package/dist/components/field/index.d.mts +30 -5
  101. package/dist/components/field/index.mjs +36 -3
  102. package/dist/components/fieldset/index.d.mts +19 -4
  103. package/dist/components/fieldset/index.mjs +28 -3
  104. package/dist/components/file-upload/index.d.mts +29 -9
  105. package/dist/components/file-upload/index.mjs +46 -10
  106. package/dist/components/floating-panel/index.d.mts +18 -6
  107. package/dist/components/floating-panel/index.mjs +55 -1
  108. package/dist/components/focus-trap/index.d.mts +7 -2
  109. package/dist/components/focus-trap/index.mjs +5 -1
  110. package/dist/components/form/index.d.mts +1 -1
  111. package/dist/components/form/index.mjs +5 -2
  112. package/dist/components/frame/index.d.mts +4 -8
  113. package/dist/components/frame/index.mjs +13 -1
  114. package/dist/components/grid/index.d.mts +4 -1
  115. package/dist/components/grid/index.mjs +3 -1
  116. package/dist/components/highlight/index.d.mts +3 -5
  117. package/dist/components/highlight/index.mjs +6 -1
  118. package/dist/components/hover-card/index.d.mts +20 -4
  119. package/dist/components/hover-card/index.mjs +32 -1
  120. package/dist/components/icon/index.d.mts +10 -8
  121. package/dist/components/icon/index.mjs +5 -3
  122. package/dist/components/image/index.d.mts +5 -2
  123. package/dist/components/image/index.mjs +14 -29
  124. package/dist/components/image-cropper/index.d.mts +13 -2
  125. package/dist/components/image-cropper/index.mjs +34 -2
  126. package/dist/components/image-viewer/index.d.mts +2 -24
  127. package/dist/components/image-viewer/index.mjs +3 -113
  128. package/dist/components/input/index.d.mts +3 -1
  129. package/dist/components/input/index.mjs +1 -1
  130. package/dist/components/json-tree-view/index.d.mts +17 -1
  131. package/dist/components/json-tree-view/index.mjs +26 -5
  132. package/dist/components/kbd/index.d.mts +4 -1
  133. package/dist/components/kbd/index.mjs +3 -1
  134. package/dist/components/layout/index.d.mts +25 -7
  135. package/dist/components/layout/index.mjs +157 -63
  136. package/dist/components/link/index.d.mts +4 -1
  137. package/dist/components/link/index.mjs +3 -1
  138. package/dist/components/listbox/index.d.mts +22 -1
  139. package/dist/components/listbox/index.mjs +36 -4
  140. package/dist/components/marquee/index.d.mts +18 -1
  141. package/dist/components/marquee/index.mjs +34 -2
  142. package/dist/components/masonry/index.d.mts +4 -1
  143. package/dist/components/masonry/index.mjs +3 -1
  144. package/dist/components/media-player/index.d.mts +2 -0
  145. package/dist/components/media-player/index.mjs +2 -0
  146. package/dist/components/mentions/index.d.mts +1 -1
  147. package/dist/components/mentions/index.mjs +1 -1
  148. package/dist/components/menu/index.d.mts +29 -11
  149. package/dist/components/menu/index.mjs +34 -12
  150. package/dist/components/menubar/index.d.mts +3 -1
  151. package/dist/components/menubar/index.mjs +6 -1
  152. package/dist/components/navigation-menu/index.d.mts +25 -1
  153. package/dist/components/navigation-menu/index.mjs +36 -1
  154. package/dist/components/number-input/index.d.mts +28 -6
  155. package/dist/components/number-input/index.mjs +33 -8
  156. package/dist/components/order-list/index.d.mts +4 -1
  157. package/dist/components/order-list/index.mjs +26 -24
  158. package/dist/components/pagination/index.d.mts +23 -3
  159. package/dist/components/pagination/index.mjs +57 -12
  160. package/dist/components/password-input/index.d.mts +24 -6
  161. package/dist/components/password-input/index.mjs +31 -8
  162. package/dist/components/pin-input/index.d.mts +23 -5
  163. package/dist/components/pin-input/index.mjs +29 -7
  164. package/dist/components/popconfirm/index.d.mts +9 -5
  165. package/dist/components/popconfirm/index.mjs +23 -18
  166. package/dist/components/popover/index.d.mts +2 -8
  167. package/dist/components/popover/index.mjs +44 -4
  168. package/dist/components/presence/index.d.mts +10 -2
  169. package/dist/components/presence/index.mjs +6 -1
  170. package/dist/components/progress/index.d.mts +18 -3
  171. package/dist/components/progress/index.mjs +34 -9
  172. package/dist/components/progress-group/index.d.mts +4 -1
  173. package/dist/components/progress-group/index.mjs +4 -2
  174. package/dist/components/qr-code/index.d.mts +14 -1
  175. package/dist/components/qr-code/index.mjs +26 -2
  176. package/dist/components/radio-group/index.d.mts +27 -2
  177. package/dist/components/radio-group/index.mjs +32 -8
  178. package/dist/components/rating-group/index.d.mts +20 -3
  179. package/dist/components/rating-group/index.mjs +26 -8
  180. package/dist/components/result/index.d.mts +1 -1
  181. package/dist/components/result/index.mjs +2 -2
  182. package/dist/components/scroll-area/index.d.mts +14 -1
  183. package/dist/components/scroll-area/index.mjs +32 -2
  184. package/dist/components/segment-group/index.d.mts +28 -2
  185. package/dist/components/segment-group/index.mjs +34 -7
  186. package/dist/components/select/index.d.mts +2 -2
  187. package/dist/components/select/index.mjs +1 -1
  188. package/dist/components/separator/index.d.mts +4 -1
  189. package/dist/components/separator/index.mjs +3 -1
  190. package/dist/components/signature-pad/index.d.mts +25 -5
  191. package/dist/components/signature-pad/index.mjs +37 -3
  192. package/dist/components/skeleton/index.d.mts +4 -1
  193. package/dist/components/skeleton/index.mjs +3 -1
  194. package/dist/components/slider/index.d.mts +21 -2
  195. package/dist/components/slider/index.mjs +31 -8
  196. package/dist/components/spinner/index.d.mts +4 -1
  197. package/dist/components/spinner/index.mjs +3 -1
  198. package/dist/components/split-button/index.d.mts +3 -1
  199. package/dist/components/split-button/index.mjs +12 -17
  200. package/dist/components/splitter/index.d.mts +17 -4
  201. package/dist/components/splitter/index.mjs +35 -1
  202. package/dist/components/spotlight/index.d.mts +4 -1
  203. package/dist/components/spotlight/index.mjs +3 -1
  204. package/dist/components/stack/index.d.mts +4 -1
  205. package/dist/components/stack/index.mjs +6 -4
  206. package/dist/components/steps/index.d.mts +26 -6
  207. package/dist/components/steps/index.mjs +26 -11
  208. package/dist/components/swap/index.d.mts +11 -5
  209. package/dist/components/swap/index.mjs +30 -3
  210. package/dist/components/switch/index.d.mts +20 -2
  211. package/dist/components/switch/index.mjs +27 -8
  212. package/dist/components/table/index.d.mts +4 -1
  213. package/dist/components/table/index.mjs +26 -56
  214. package/dist/components/tabs/index.d.mts +24 -2
  215. package/dist/components/tabs/index.mjs +25 -9
  216. package/dist/components/tags-input/index.d.mts +33 -8
  217. package/dist/components/tags-input/index.mjs +41 -9
  218. package/dist/components/terminal/index.d.mts +4 -1
  219. package/dist/components/terminal/index.mjs +3 -1
  220. package/dist/components/textarea/index.d.mts +4 -1
  221. package/dist/components/textarea/index.mjs +3 -1
  222. package/dist/components/timer/index.d.mts +18 -1
  223. package/dist/components/timer/index.mjs +51 -2
  224. package/dist/components/toast/index.d.mts +3 -6
  225. package/dist/components/toast/index.mjs +22 -2
  226. package/dist/components/toc/index.d.mts +19 -5
  227. package/dist/components/toc/index.mjs +31 -5
  228. package/dist/components/toggle/index.d.mts +11 -4
  229. package/dist/components/toggle/index.mjs +21 -1
  230. package/dist/components/toggle-group/index.d.mts +26 -2
  231. package/dist/components/toggle-group/index.mjs +31 -6
  232. package/dist/components/toolbar/index.d.mts +4 -1
  233. package/dist/components/toolbar/index.mjs +3 -1
  234. package/dist/components/tooltip/index.d.mts +17 -4
  235. package/dist/components/tooltip/index.mjs +28 -1
  236. package/dist/components/tour/index.d.mts +18 -9
  237. package/dist/components/tour/index.mjs +44 -2
  238. package/dist/components/transfer/index.d.mts +3 -1
  239. package/dist/components/transfer/index.mjs +14 -26
  240. package/dist/components/tree-select/index.d.mts +3 -1
  241. package/dist/components/tree-select/index.mjs +11 -22
  242. package/dist/components/tree-view/index.d.mts +22 -2
  243. package/dist/components/tree-view/index.mjs +50 -8
  244. package/dist/components/typography/index.d.mts +4 -0
  245. package/dist/components/typography/index.mjs +1 -0
  246. package/dist/components/user/index.d.mts +4 -1
  247. package/dist/components/user/index.mjs +3 -1
  248. package/dist/components/virtual-list/index.d.mts +4 -1
  249. package/dist/components/virtual-list/index.mjs +10 -12
  250. package/dist/components/watermark/index.d.mts +4 -1
  251. package/dist/components/watermark/index.mjs +4 -2
  252. package/dist/family-DE_GQeeM.mjs +9 -0
  253. package/dist/icon-BALgGtNK.mjs +18 -0
  254. package/dist/id-C37UYLwJ.mjs +13 -0
  255. package/dist/image-viewer-Cf6thHax.mjs +141 -0
  256. package/dist/{index-Uefyw7Im.d.mts → index-Bbg4heDO.d.mts} +12 -7
  257. package/dist/index-BcRdWGY-.d.mts +115 -0
  258. package/dist/{index-Iy8m0Qev.d.mts → index-D_iKc2Uw.d.mts} +31 -2
  259. package/dist/{index-Dn5mHf1g.d.mts → index-DdNKngUQ.d.mts} +56 -17
  260. package/dist/index-Dj8S4eyJ.d.mts +41 -0
  261. package/dist/index-Eu-Bttta.d.mts +24 -0
  262. package/dist/{index-uPyYiWaL.d.mts → index-PsgGWW3m.d.mts} +8 -2
  263. package/dist/index.d.mts +36 -35
  264. package/dist/index.mjs +11 -10
  265. package/dist/{input-2oezH-dY.mjs → input-C21Zzuy6.mjs} +3 -1
  266. package/dist/media-player-gQrnxU52.mjs +554 -0
  267. package/dist/{mentions-DMIBCBOd.mjs → mentions-BuWibdci.mjs} +74 -42
  268. package/dist/select-ozUFq0zd.mjs +121 -0
  269. package/package.json +3 -3
  270. package/dist/chevron-BeHvt46K.mjs +0 -17
  271. package/dist/glyph-VI989p8H.mjs +0 -14
  272. package/dist/select-eAHutw56.mjs +0 -70
@@ -0,0 +1,554 @@
1
+ import { t as iconNode } from "./icon-BALgGtNK.mjs";
2
+ import { t as Select } from "./select-ozUFq0zd.mjs";
3
+ import { injectComponentStyle } from "@bysages/core";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
6
+ //#region src/components/media-player/context.ts
7
+ const MediaPlayerProvider = createContext(null);
8
+ function useMediaPlayer() {
9
+ const context = useContext(MediaPlayerProvider);
10
+ if (!context) throw new Error("Media player parts must be used inside Audio.Root or Video.Root");
11
+ return context;
12
+ }
13
+ //#endregion
14
+ //#region src/components/media-player/use-media-controls.ts
15
+ /** The shared HTMLMediaElement state: one source of truth for both the
16
+ * audio and video faces, so their controls never drift apart. */
17
+ function useMediaControls(media) {
18
+ const [currentTime, setCurrentTime] = useState(0);
19
+ const [duration, setDuration] = useState(0);
20
+ const [playing, setPlaying] = useState(false);
21
+ const [muted, setMuted] = useState(false);
22
+ const [volume, setVolumeState] = useState(1);
23
+ const [playbackRate, setPlaybackRateState] = useState(1);
24
+ const [selectedTextTrack, setSelectedTextTrack] = useState(-1);
25
+ const [error, setError] = useState(false);
26
+ const readMedia = useCallback((element) => {
27
+ setCurrentTime(element.currentTime || 0);
28
+ setDuration(Number.isFinite(element.duration) ? element.duration : 0);
29
+ setPlaying(!element.paused && !element.ended);
30
+ setMuted(element.muted);
31
+ setVolumeState(element.volume);
32
+ setPlaybackRateState(element.playbackRate);
33
+ setError(false);
34
+ }, []);
35
+ const readTextTracks = useCallback((element) => {
36
+ setSelectedTextTrack(Array.from(element.textTracks).findIndex((track) => track.mode === "showing"));
37
+ }, []);
38
+ const clamp = useCallback((value, min, max) => {
39
+ return Math.min(Math.max(value, min), max);
40
+ }, []);
41
+ const seek = useCallback((time) => {
42
+ const element = media.current;
43
+ if (!element) return;
44
+ const limit = Number.isFinite(element.duration) ? element.duration : Number.MAX_SAFE_INTEGER;
45
+ element.currentTime = clamp(time, 0, limit);
46
+ }, [clamp, media]);
47
+ const setVolume = useCallback((value) => {
48
+ const element = media.current;
49
+ if (!element) return;
50
+ element.volume = clamp(value, 0, 1);
51
+ }, [clamp, media]);
52
+ const setPlaybackRate = useCallback((value) => {
53
+ const element = media.current;
54
+ if (!element) return;
55
+ element.playbackRate = value;
56
+ }, [media]);
57
+ const toggleMuted = useCallback(() => {
58
+ const element = media.current;
59
+ if (!element) return;
60
+ element.muted = !element.muted;
61
+ }, [media]);
62
+ const toggle = useCallback(async () => {
63
+ const element = media.current;
64
+ if (!element) return;
65
+ if (element.paused) await element.play();
66
+ else element.pause();
67
+ }, [media]);
68
+ const selectTextTrack = useCallback((index) => {
69
+ const element = media.current;
70
+ if (!element) return;
71
+ Array.from(element.textTracks).forEach((track, trackIndex) => {
72
+ track.mode = trackIndex === index ? "showing" : "disabled";
73
+ });
74
+ setSelectedTextTrack(index);
75
+ }, [media]);
76
+ const togglePictureInPicture = useCallback(async () => {
77
+ const element = media.current;
78
+ if (!element?.requestPictureInPicture) return;
79
+ if (document.pictureInPictureElement) await document.exitPictureInPicture();
80
+ else await element.requestPictureInPicture();
81
+ }, [media]);
82
+ const toggleFullscreen = useCallback(async (root) => {
83
+ if (document.fullscreenElement) await document.exitFullscreen();
84
+ else await root.requestFullscreen();
85
+ }, []);
86
+ useEffect(() => {
87
+ const element = media.current;
88
+ if (!element) return;
89
+ const updateFromEvent = (event) => {
90
+ readMedia(element);
91
+ setError(event.type === "error");
92
+ if (event.type === "error") readTextTracks(element);
93
+ };
94
+ const syncTracks = () => {
95
+ readTextTracks(element);
96
+ window.setTimeout(() => readTextTracks(element), 0);
97
+ };
98
+ const events = [
99
+ "loadedmetadata",
100
+ "durationchange",
101
+ "timeupdate",
102
+ "progress",
103
+ "play",
104
+ "pause",
105
+ "ended",
106
+ "waiting",
107
+ "playing",
108
+ "seeking",
109
+ "seeked",
110
+ "volumechange",
111
+ "ratechange",
112
+ "error"
113
+ ];
114
+ for (const event of events) element.addEventListener(event, updateFromEvent);
115
+ element.addEventListener("loadedmetadata", syncTracks);
116
+ element.addEventListener("loadstart", syncTracks);
117
+ readMedia(element);
118
+ readTextTracks(element);
119
+ return () => {
120
+ for (const event of events) element.removeEventListener(event, updateFromEvent);
121
+ element.removeEventListener("loadedmetadata", syncTracks);
122
+ element.removeEventListener("loadstart", syncTracks);
123
+ element.pause();
124
+ };
125
+ }, [
126
+ media,
127
+ readMedia,
128
+ readTextTracks
129
+ ]);
130
+ return {
131
+ currentTime,
132
+ duration,
133
+ error,
134
+ muted,
135
+ playing,
136
+ playbackRate,
137
+ selectedTextTrack,
138
+ seek,
139
+ selectTextTrack,
140
+ setPlaybackRate,
141
+ setVolume,
142
+ toggle,
143
+ toggleFullscreen,
144
+ toggleMuted,
145
+ togglePictureInPicture,
146
+ volume
147
+ };
148
+ }
149
+ /** A compact clock for player chrome: hours only when the media asks
150
+ * for them, stable digits so the time never jitters the controls. */
151
+ function formatMediaTime(seconds) {
152
+ if (!Number.isFinite(seconds) || seconds < 0) return "0:00";
153
+ const whole = Math.floor(seconds);
154
+ const hours = Math.floor(whole / 3600);
155
+ const minutes = Math.floor(whole % 3600 / 60);
156
+ const secs = String(whole % 3600 % 60).padStart(2, "0");
157
+ return hours > 0 ? `${hours}:${String(minutes).padStart(2, "0")}:${secs}` : `${minutes}:${secs}`;
158
+ }
159
+ //#endregion
160
+ //#region src/components/media-player/parts.tsx
161
+ function part(name) {
162
+ function MediaPart(props) {
163
+ return /* @__PURE__ */ jsx("div", {
164
+ ...props,
165
+ "data-scope": "media-player",
166
+ "data-part": name.toLowerCase(),
167
+ children: props.children
168
+ });
169
+ }
170
+ return MediaPart;
171
+ }
172
+ /** The native media element, framed by the shared shell's state machine. */
173
+ function Media(props) {
174
+ const context = useMediaPlayer();
175
+ const Element = context.kind === "video" ? "video" : "audio";
176
+ const nativeProps = {
177
+ ...props,
178
+ src: context.sources.length > 0 ? void 0 : context.src,
179
+ "data-scope": "media-player",
180
+ "data-part": "media",
181
+ autoPlay: void 0,
182
+ loop: void 0,
183
+ muted: void 0,
184
+ preload: void 0,
185
+ poster: void 0,
186
+ playsInline: void 0,
187
+ ref: (value) => {
188
+ context.media.current = value;
189
+ },
190
+ "aria-label": context.label,
191
+ onPlay: (event) => context.emit("play", event),
192
+ onPause: (event) => context.emit("pause", event),
193
+ onEnded: (event) => context.emit("ended", event),
194
+ onTimeUpdate: (event) => context.emit("timeupdate", event),
195
+ onVolumeChange: (event) => context.emit("volumechange", event),
196
+ onRateChange: (event) => context.emit("ratechange", event),
197
+ onError: (event) => context.emit("error", event)
198
+ };
199
+ if (context.kind === "video") {
200
+ nativeProps.poster = context.poster;
201
+ nativeProps.playsInline = context.playsInline;
202
+ }
203
+ nativeProps.autoPlay = context.autoplay;
204
+ nativeProps.loop = context.loop;
205
+ nativeProps.muted = context.muted;
206
+ nativeProps.preload = context.preload;
207
+ return /* @__PURE__ */ jsxs(Element, {
208
+ ...nativeProps,
209
+ children: [context.sources.map((source) => /* @__PURE__ */ jsx("source", {
210
+ src: source.src,
211
+ type: source.type
212
+ }, source.src)), context.tracks.map((track) => /* @__PURE__ */ jsx("track", {
213
+ src: track.src,
214
+ kind: track.kind ?? "subtitles",
215
+ label: track.label,
216
+ srcLang: track.srcLang,
217
+ default: track.default
218
+ }, track.src))]
219
+ });
220
+ }
221
+ /** Play and pause share one seal-cut control: the state changes the mark,
222
+ * never the control's place in the hand. */
223
+ function PlayButton({ label, ...props }) {
224
+ const context = useMediaPlayer();
225
+ const text = label ?? (context.controls.playing ? "Pause" : "Play");
226
+ return /* @__PURE__ */ jsx("button", {
227
+ ...props,
228
+ type: "button",
229
+ "data-scope": "media-player",
230
+ "data-part": "play-button",
231
+ "aria-label": text,
232
+ "aria-pressed": context.controls.playing,
233
+ title: text,
234
+ disabled: context.disabled,
235
+ onClick: () => void context.controls.toggle(),
236
+ children: iconNode(context.controls.playing ? "pause" : "play", {
237
+ width: "16",
238
+ height: "16"
239
+ })
240
+ });
241
+ }
242
+ /** The elapsed and total time bracket the timeline. */
243
+ function Time(props) {
244
+ const context = useMediaPlayer();
245
+ return /* @__PURE__ */ jsxs("span", {
246
+ ...props,
247
+ "data-scope": "media-player",
248
+ "data-part": "time",
249
+ children: [
250
+ formatMediaTime(context.controls.currentTime),
251
+ " / ",
252
+ formatMediaTime(context.controls.duration)
253
+ ]
254
+ });
255
+ }
256
+ /** Seeking writes straight to currentTime; buffered ranges can later
257
+ * ride the same part as a second ink wash. */
258
+ function Timeline({ label = "Seek", ...props }) {
259
+ const context = useMediaPlayer();
260
+ const progress = context.controls.duration > 0 ? Math.min(context.controls.currentTime / context.controls.duration * 100, 100) : 0;
261
+ return /* @__PURE__ */ jsx("input", {
262
+ ...props,
263
+ type: "range",
264
+ "data-scope": "media-player",
265
+ "data-part": "timeline",
266
+ min: 0,
267
+ max: context.controls.duration || 0,
268
+ step: .1,
269
+ value: context.controls.currentTime,
270
+ disabled: context.disabled || context.controls.duration <= 0,
271
+ "aria-label": label,
272
+ "aria-valuetext": formatMediaTime(context.controls.currentTime),
273
+ style: {
274
+ ...props.style,
275
+ "--bs-media-progress": `${progress}%`
276
+ },
277
+ onInput: (event) => context.controls.seek(Number(event.currentTarget.value))
278
+ });
279
+ }
280
+ /** Muting stays at the left of the volume well, the way a hand expects. */
281
+ function MuteButton({ label, ...props }) {
282
+ const context = useMediaPlayer();
283
+ const muted = context.controls.muted || context.controls.volume === 0;
284
+ const text = label ?? (muted ? "Unmute" : "Mute");
285
+ return /* @__PURE__ */ jsx("button", {
286
+ ...props,
287
+ type: "button",
288
+ "data-scope": "media-player",
289
+ "data-part": "mute-button",
290
+ "aria-label": text,
291
+ "aria-pressed": muted,
292
+ title: text,
293
+ disabled: context.disabled,
294
+ onClick: () => context.controls.toggleMuted(),
295
+ children: iconNode(muted ? "volume-x" : "volume-2", {
296
+ width: "16",
297
+ height: "16"
298
+ })
299
+ });
300
+ }
301
+ function Volume({ label = "Volume", ...props }) {
302
+ const context = useMediaPlayer();
303
+ const volume = context.controls.muted ? 0 : context.controls.volume;
304
+ return /* @__PURE__ */ jsx("input", {
305
+ ...props,
306
+ type: "range",
307
+ "data-scope": "media-player",
308
+ "data-part": "volume",
309
+ min: 0,
310
+ max: 1,
311
+ step: .01,
312
+ value: volume,
313
+ disabled: context.disabled,
314
+ "aria-label": label,
315
+ "aria-valuetext": `${Math.round(volume * 100)}%`,
316
+ style: {
317
+ ...props.style,
318
+ "--bs-media-progress": `${volume * 100}%`
319
+ },
320
+ onInput: (event) => context.controls.setVolume(Number(event.currentTarget.value))
321
+ });
322
+ }
323
+ /** Playback rate is a real choice, not hidden behind native menus. */
324
+ function Rate({ label = "Playback speed", ...props }) {
325
+ const context = useMediaPlayer();
326
+ return /* @__PURE__ */ jsx("div", {
327
+ ...props,
328
+ "data-scope": "media-player",
329
+ "data-part": "rate",
330
+ children: /* @__PURE__ */ jsx(Select, {
331
+ clearable: false,
332
+ disabled: context.disabled,
333
+ options: context.playbackRates.map((rate) => ({
334
+ label: `${rate}×`,
335
+ value: String(rate)
336
+ })),
337
+ placeholder: label,
338
+ size: "sm",
339
+ value: String(context.controls.playbackRate),
340
+ onValueChange: (value) => context.controls.setPlaybackRate(Number(value))
341
+ })
342
+ });
343
+ }
344
+ /** Text tracks use the browser's native model; the control chooses a
345
+ * track index, while rendering stays with the media element. */
346
+ function Captions({ label = "Captions", ...props }) {
347
+ const context = useMediaPlayer();
348
+ if (context.tracks.length === 0) return null;
349
+ return /* @__PURE__ */ jsx("div", {
350
+ ...props,
351
+ "data-scope": "media-player",
352
+ "data-part": "captions",
353
+ children: /* @__PURE__ */ jsx(Select, {
354
+ clearable: false,
355
+ disabled: context.disabled,
356
+ options: [{
357
+ label: "Off",
358
+ value: "-1"
359
+ }, ...context.tracks.map((track, index) => ({
360
+ label: track.label ?? `Track ${index + 1}`,
361
+ value: String(index)
362
+ }))],
363
+ placeholder: label,
364
+ size: "sm",
365
+ value: String(context.controls.selectedTextTrack),
366
+ onValueChange: (value) => context.controls.selectTextTrack(Number(value))
367
+ })
368
+ });
369
+ }
370
+ /** Picture-in-picture is video-only and capability-detected. */
371
+ function PipButton({ label = "Toggle picture in picture", ...props }) {
372
+ const context = useMediaPlayer();
373
+ if (context.kind !== "video") return null;
374
+ return /* @__PURE__ */ jsx("button", {
375
+ ...props,
376
+ type: "button",
377
+ "data-scope": "media-player",
378
+ "data-part": "pip-button",
379
+ "aria-label": label,
380
+ title: label,
381
+ disabled: context.disabled,
382
+ onClick: () => void context.controls.togglePictureInPicture(),
383
+ children: iconNode("picture-in-picture", {
384
+ width: "16",
385
+ height: "16"
386
+ })
387
+ });
388
+ }
389
+ /** Fullscreen takes the whole vessel, not just the moving picture. */
390
+ function FullscreenButton({ label = "Toggle fullscreen", ...props }) {
391
+ const context = useMediaPlayer();
392
+ return /* @__PURE__ */ jsx("button", {
393
+ ...props,
394
+ type: "button",
395
+ "data-scope": "media-player",
396
+ "data-part": "fullscreen-button",
397
+ "aria-label": label,
398
+ title: label,
399
+ disabled: context.disabled,
400
+ onClick: () => {
401
+ const root = context.root.current;
402
+ if (root) context.controls.toggleFullscreen(root);
403
+ },
404
+ children: iconNode("maximize-2", {
405
+ width: "16",
406
+ height: "16"
407
+ })
408
+ });
409
+ }
410
+ const Stage = part("Stage");
411
+ const Controls = part("Controls");
412
+ //#endregion
413
+ //#region src/components/media-player/shell.tsx
414
+ /** The headless shell: it owns the media reference and the shared state
415
+ * machine, while the public parts remain free to compose in any order. */
416
+ function MediaPlayerShell(props) {
417
+ injectComponentStyle("media-player");
418
+ const media = useRef(null);
419
+ const root = useRef(null);
420
+ const controls = useMediaControls(media);
421
+ const { kind, children, label = "Media player", src, sources = [], tracks = [], autoplay = false, loop = false, muted = false, preload = "metadata", volume = 1, playbackRate = 1, playbackRates = [
422
+ .5,
423
+ .75,
424
+ 1,
425
+ 1.25,
426
+ 1.5,
427
+ 2
428
+ ], disabled = false, poster, playsInline = true, onPlay, onPause, onEnded, onTimeupdate, onVolumechange, onRatechange, onError, ...rest } = props;
429
+ useEffect(() => {
430
+ const element = media.current;
431
+ if (!element) return;
432
+ element.volume = volume;
433
+ element.playbackRate = playbackRate;
434
+ }, [playbackRate, volume]);
435
+ return /* @__PURE__ */ jsx(MediaPlayerProvider, {
436
+ value: {
437
+ autoplay,
438
+ controls,
439
+ disabled,
440
+ emit: (event, source) => {
441
+ if (event === "play") onPlay?.(source);
442
+ if (event === "pause") onPause?.(source);
443
+ if (event === "ended") onEnded?.(source);
444
+ if (event === "timeupdate") onTimeupdate?.(source);
445
+ if (event === "volumechange") onVolumechange?.(source);
446
+ if (event === "ratechange") onRatechange?.(source);
447
+ if (event === "error") onError?.(source);
448
+ },
449
+ kind,
450
+ label,
451
+ loop,
452
+ media,
453
+ muted,
454
+ playbackRates,
455
+ playsInline,
456
+ poster,
457
+ preload,
458
+ root,
459
+ sources,
460
+ src,
461
+ tracks
462
+ },
463
+ children: /* @__PURE__ */ jsx("div", {
464
+ ...rest,
465
+ ref: root,
466
+ "data-scope": "media-player",
467
+ "data-part": "root",
468
+ "data-kind": kind,
469
+ "data-playing": controls.playing,
470
+ "data-muted": controls.muted,
471
+ "data-error": controls.error ? true : void 0,
472
+ children
473
+ })
474
+ });
475
+ }
476
+ //#endregion
477
+ //#region src/components/media-player/index.tsx
478
+ function createRoot(kind) {
479
+ function MediaRoot(props) {
480
+ return /* @__PURE__ */ jsx(MediaPlayerShell, {
481
+ kind,
482
+ ...props
483
+ });
484
+ }
485
+ return MediaRoot;
486
+ }
487
+ function facade(Root, extra) {
488
+ function MediaPlayerFacade(props) {
489
+ return /* @__PURE__ */ jsx(Root, {
490
+ ...props,
491
+ children: extra
492
+ });
493
+ }
494
+ return MediaPlayerFacade;
495
+ }
496
+ const AudioRoot = createRoot("audio");
497
+ const VideoRoot = createRoot("video");
498
+ /** The complete audio player: source controls compose into one compact
499
+ * rail, while custom arrangement stays on Audio.Root. */
500
+ const AudioFacade = facade(AudioRoot, [/* @__PURE__ */ jsx(Stage, { children: /* @__PURE__ */ jsx(Media, {}) }, "stage"), /* @__PURE__ */ jsxs(Controls, { children: [
501
+ /* @__PURE__ */ jsx(PlayButton, {}),
502
+ /* @__PURE__ */ jsx(Timeline, {}),
503
+ /* @__PURE__ */ jsx(Time, {}),
504
+ /* @__PURE__ */ jsx(MuteButton, {}),
505
+ /* @__PURE__ */ jsx(Volume, {}),
506
+ /* @__PURE__ */ jsx(Rate, {})
507
+ ] }, "controls")]);
508
+ /** The complete video player: source, caption, PiP and fullscreen
509
+ * controls compose under the stage, while Video.Root stays open. */
510
+ const VideoFacade = facade(VideoRoot, [/* @__PURE__ */ jsx(Stage, { children: /* @__PURE__ */ jsx(Media, {}) }, "stage"), /* @__PURE__ */ jsxs(Controls, { children: [
511
+ /* @__PURE__ */ jsx(PlayButton, {}),
512
+ /* @__PURE__ */ jsx(Timeline, {}),
513
+ /* @__PURE__ */ jsx(Time, {}),
514
+ /* @__PURE__ */ jsx(MuteButton, {}),
515
+ /* @__PURE__ */ jsx(Volume, {}),
516
+ /* @__PURE__ */ jsx(Rate, {}),
517
+ /* @__PURE__ */ jsx(Captions, {}),
518
+ /* @__PURE__ */ jsx(PipButton, {}),
519
+ /* @__PURE__ */ jsx(FullscreenButton, {})
520
+ ] }, "controls")]);
521
+ /** Audio and video share one instrument: the same state, the same keys,
522
+ * and the same control rhythm, while each face keeps its native element's
523
+ * own semantics. The parts — Root, Stage, Media, Controls, PlayButton,
524
+ * Timeline, Time, MuteButton, Volume, Rate, Captions, PipButton,
525
+ * FullscreenButton. */
526
+ const Audio = Object.assign(AudioFacade, {
527
+ Root: AudioRoot,
528
+ Stage,
529
+ Media,
530
+ Controls,
531
+ PlayButton,
532
+ Timeline,
533
+ Time,
534
+ MuteButton,
535
+ Volume,
536
+ Rate
537
+ });
538
+ const Video = Object.assign(VideoFacade, {
539
+ Root: VideoRoot,
540
+ Stage,
541
+ Media,
542
+ Controls,
543
+ PlayButton,
544
+ Timeline,
545
+ Time,
546
+ MuteButton,
547
+ Volume,
548
+ Rate,
549
+ Captions,
550
+ PipButton,
551
+ FullscreenButton
552
+ });
553
+ //#endregion
554
+ export { Video as n, formatMediaTime as r, Audio as t };