@xiping/react-components 1.0.57 → 1.0.59

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 (75) hide show
  1. package/README.md +92 -6
  2. package/dist/cjs/components/comic-text/ComicText.css +1 -1
  3. package/dist/cjs/components/dock/Duck.css +1 -1
  4. package/dist/cjs/components/gradient-text/index.css +1 -1
  5. package/dist/cjs/components/gradient-text/index.js +1 -1
  6. package/dist/cjs/components/image-compare/ImageCompare.css +1 -1
  7. package/dist/cjs/components/image-viewer/ImageThumbnails.css +1 -1
  8. package/dist/cjs/components/image-viewer/ImageViewer.css +1 -1
  9. package/dist/cjs/components/message/Message.js +1 -1
  10. package/dist/cjs/components/scratch-to-reveal/ScratchToReveal.css +1 -1
  11. package/dist/cjs/components/subtitle-player/LyricsMode.css +1 -1
  12. package/dist/cjs/components/subtitle-player/SubtitlePlayer.js +1 -1
  13. package/dist/cjs/components/txt-reader/TxtReader.js +1 -1
  14. package/dist/cjs/components/typing-animation/index.js +1 -1
  15. package/dist/cjs/components/variable-proximity/index.css +1 -1
  16. package/dist/cjs/components/variable-proximity/index.js +1 -1
  17. package/dist/cjs/components/video-subtitle-player/VideoSubtitlePlayer.css +1 -1
  18. package/dist/cjs/components/video-subtitle-player/VideoSubtitlePlayer.d.ts +3 -3
  19. package/dist/cjs/components/video-subtitle-player/VideoSubtitlePlayer.js +1 -1
  20. package/dist/cjs/components/video-subtitle-player/VideoSubtitlePlayer.mobile.css +1 -0
  21. package/dist/cjs/components/video-subtitle-player/VideoSubtitlePlayer.pc.css +1 -0
  22. package/dist/cjs/components/video-subtitle-player/VideoSubtitlePlayerMobile.d.ts +20 -0
  23. package/dist/cjs/components/video-subtitle-player/VideoSubtitlePlayerMobile.js +1 -0
  24. package/dist/cjs/components/video-subtitle-player/VideoSubtitlePlayerPC.d.ts +23 -0
  25. package/dist/cjs/components/video-subtitle-player/VideoSubtitlePlayerPC.js +1 -0
  26. package/dist/cjs/components/video-subtitle-player/layouts/VideoSubtitlePlayerLayoutMobile.d.ts +8 -0
  27. package/dist/cjs/components/video-subtitle-player/layouts/VideoSubtitlePlayerLayoutMobile.js +1 -0
  28. package/dist/cjs/components/video-subtitle-player/layouts/VideoSubtitlePlayerLayoutPC.d.ts +6 -0
  29. package/dist/cjs/components/video-subtitle-player/layouts/VideoSubtitlePlayerLayoutPC.js +1 -0
  30. package/dist/cjs/components/video-subtitle-player/layouts/index.d.ts +3 -0
  31. package/dist/cjs/components/video-subtitle-player/layouts/types.d.ts +17 -0
  32. package/dist/cjs/components/video-subtitle-player/useXGPlayer.d.ts +10 -0
  33. package/dist/cjs/components/video-subtitle-player/useXGPlayer.js +1 -0
  34. package/dist/cjs/index.js +1 -1
  35. package/dist/cjs/node_modules/.pnpm/xgplayer@3.0.23_core-js@3.47.0/node_modules/xgplayer/dist/index.min.css +1 -1
  36. package/dist/cjs/react-components.css +114 -0
  37. package/dist/cjs/utils/utils.d.ts +1 -0
  38. package/dist/es/components/comic-text/ComicText.css +1 -1
  39. package/dist/es/components/confetti-button/index.js +1 -1
  40. package/dist/es/components/dock/Duck.css +1 -1
  41. package/dist/es/components/gradient-text/index.css +1 -1
  42. package/dist/es/components/gradient-text/index.js +6 -7
  43. package/dist/es/components/image-compare/ImageCompare.css +1 -1
  44. package/dist/es/components/image-viewer/ImageThumbnails.css +1 -1
  45. package/dist/es/components/image-viewer/ImageViewer.css +1 -1
  46. package/dist/es/components/message/Message.js +15 -16
  47. package/dist/es/components/scratch-to-reveal/ScratchToReveal.css +1 -1
  48. package/dist/es/components/subtitle-player/LyricsMode.css +1 -1
  49. package/dist/es/components/subtitle-player/SubtitlePlayer.js +9 -10
  50. package/dist/es/components/txt-reader/TxtReader.js +9 -10
  51. package/dist/es/components/typing-animation/index.js +17 -18
  52. package/dist/es/components/variable-proximity/index.css +1 -1
  53. package/dist/es/components/variable-proximity/index.js +28 -29
  54. package/dist/es/components/video-subtitle-player/VideoSubtitlePlayer.css +1 -1
  55. package/dist/es/components/video-subtitle-player/VideoSubtitlePlayer.d.ts +3 -3
  56. package/dist/es/components/video-subtitle-player/VideoSubtitlePlayer.js +65 -126
  57. package/dist/es/components/video-subtitle-player/VideoSubtitlePlayer.mobile.css +1 -0
  58. package/dist/es/components/video-subtitle-player/VideoSubtitlePlayer.pc.css +1 -0
  59. package/dist/es/components/video-subtitle-player/VideoSubtitlePlayerMobile.d.ts +20 -0
  60. package/dist/es/components/video-subtitle-player/VideoSubtitlePlayerMobile.js +47 -0
  61. package/dist/es/components/video-subtitle-player/VideoSubtitlePlayerPC.d.ts +23 -0
  62. package/dist/es/components/video-subtitle-player/VideoSubtitlePlayerPC.js +75 -0
  63. package/dist/es/components/video-subtitle-player/layouts/VideoSubtitlePlayerLayoutMobile.d.ts +8 -0
  64. package/dist/es/components/video-subtitle-player/layouts/VideoSubtitlePlayerLayoutMobile.js +21 -0
  65. package/dist/es/components/video-subtitle-player/layouts/VideoSubtitlePlayerLayoutPC.d.ts +6 -0
  66. package/dist/es/components/video-subtitle-player/layouts/VideoSubtitlePlayerLayoutPC.js +50 -0
  67. package/dist/es/components/video-subtitle-player/layouts/index.d.ts +3 -0
  68. package/dist/es/components/video-subtitle-player/layouts/types.d.ts +17 -0
  69. package/dist/es/components/video-subtitle-player/useXGPlayer.d.ts +10 -0
  70. package/dist/es/components/video-subtitle-player/useXGPlayer.js +36 -0
  71. package/dist/es/index.js +51 -51
  72. package/dist/es/node_modules/.pnpm/xgplayer@3.0.23_core-js@3.47.0/node_modules/xgplayer/dist/index.min.css +1 -1
  73. package/dist/es/react-components.css +114 -0
  74. package/dist/es/utils/utils.d.ts +1 -0
  75. package/package.json +29 -30
@@ -7,10 +7,10 @@ const R = 16, S = 1.5, A = "normal", O = ({
7
7
  content: a,
8
8
  lineHeight: m = S,
9
9
  fontSize: p = R,
10
- fontWeight: d = A,
11
- className: g = "",
12
- style: f = {},
13
- onProgressChange: x,
10
+ fontWeight: g = A,
11
+ className: d = "",
12
+ style: x = {},
13
+ onProgressChange: f,
14
14
  initialScrollPosition: D,
15
15
  cacheKey: H,
16
16
  showTopProgress: u = !0,
@@ -23,7 +23,7 @@ const R = 16, S = 1.5, A = "normal", O = ({
23
23
  target: n
24
24
  }), i = I(() => (s.get() * 100).toFixed(2).replace(/\.0*$/, "")), F = L`${i}%`;
25
25
  return i.on("change", (_) => {
26
- x?.(Number(_));
26
+ f?.(Number(_));
27
27
  }), /* @__PURE__ */ h(v, { children: [
28
28
  u && /* @__PURE__ */ t(
29
29
  l.div,
@@ -45,12 +45,12 @@ const R = 16, S = 1.5, A = "normal", O = ({
45
45
  "div",
46
46
  {
47
47
  ref: n,
48
- className: r(e["xiping-content"], g),
48
+ className: r(e["xiping-content"], d),
49
49
  style: {
50
50
  fontSize: `${p}px`,
51
51
  lineHeight: m,
52
- fontWeight: d,
53
- ...f
52
+ fontWeight: g,
53
+ ...x
54
54
  },
55
55
  children: a
56
56
  }
@@ -71,6 +71,5 @@ const R = 16, S = 1.5, A = "normal", O = ({
71
71
  ] });
72
72
  };
73
73
  export {
74
- O as TxtReader,
75
- O as default
74
+ O as TxtReader
76
75
  };
@@ -1,22 +1,22 @@
1
1
  "use client";
2
- import { jsx as T } from "react/jsx-runtime";
2
+ import { jsx as d } from "react/jsx-runtime";
3
3
  import { motion as x } from "motion/react";
4
- import { useState as u, useRef as I, useEffect as a } from "react";
4
+ import { useState as u, useRef as I, useEffect as m } from "react";
5
5
  import b from "clsx";
6
6
  import './index.css';/* empty css */
7
7
  function S({
8
8
  children: r,
9
- className: m,
10
- duration: o = 100,
9
+ className: a,
10
+ duration: s = 100,
11
11
  delay: n = 0,
12
12
  as: l = "div",
13
13
  startOnView: i = !1,
14
14
  ...p
15
15
  }) {
16
- const d = x.create(l, {
16
+ const g = x.create(l, {
17
17
  forwardMotionProps: !0
18
- }), [g, v] = u(""), [c, f] = u(!1), s = I(null);
19
- return a(() => {
18
+ }), [v, T] = u(""), [c, f] = u(!1), o = I(null);
19
+ return m(() => {
20
20
  if (!i) {
21
21
  const t = setTimeout(() => {
22
22
  f(!0);
@@ -31,27 +31,26 @@ function S({
31
31
  },
32
32
  { threshold: 0.1 }
33
33
  );
34
- return s.current && e.observe(s.current), () => e.disconnect();
35
- }, [n, i]), a(() => {
34
+ return o.current && e.observe(o.current), () => e.disconnect();
35
+ }, [n, i]), m(() => {
36
36
  if (!c) return;
37
37
  let e = 0;
38
38
  const t = setInterval(() => {
39
- e < r.length ? (v(r.substring(0, e + 1)), e++) : clearInterval(t);
40
- }, o);
39
+ e < r.length ? (T(r.substring(0, e + 1)), e++) : clearInterval(t);
40
+ }, s);
41
41
  return () => {
42
42
  clearInterval(t);
43
43
  };
44
- }, [r, o, c]), /* @__PURE__ */ T(
45
- d,
44
+ }, [r, s, c]), /* @__PURE__ */ d(
45
+ g,
46
46
  {
47
- ref: s,
48
- className: b("xiping-typing-animation", m),
47
+ ref: o,
48
+ className: b("xiping-typing-animation", a),
49
49
  ...p,
50
- children: g
50
+ children: v
51
51
  }
52
52
  );
53
53
  }
54
54
  export {
55
- S as TypingAnimation,
56
- S as default
55
+ S as TypingAnimation
57
56
  };
@@ -1 +1 @@
1
- .xiping-variable-proximity{font-family:Roboto Flex,Noto Sans SC,PingFang SC,Microsoft YaHei,SimHei,sans-serif}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
1
+ .xiping-variable-proximity{font-family:Roboto Flex,Noto Sans SC,PingFang SC,Microsoft YaHei,SimHei,sans-serif}.xiping-variable-proximity__sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
@@ -1,7 +1,7 @@
1
- import { jsxs as G, jsx as k } from "react/jsx-runtime";
2
- import { forwardRef as H, useRef as y, useMemo as N, useEffect as w } from "react";
3
- import { motion as J } from "motion/react";
4
- import K from "clsx";
1
+ import { jsxs as U, jsx as k } from "react/jsx-runtime";
2
+ import { forwardRef as G, useRef as y, useMemo as N, useEffect as w } from "react";
3
+ import { motion as H } from "motion/react";
4
+ import J from "clsx";
5
5
  import './index.css';/* empty css */
6
6
  const l = {
7
7
  robotoFlex: !1,
@@ -16,7 +16,7 @@ function V(n) {
16
16
  return !0;
17
17
  }
18
18
  }
19
- function O() {
19
+ function K() {
20
20
  if (l.loading || l.robotoFlex && l.notoSansSC) return;
21
21
  l.loading = !0;
22
22
  const n = V("Roboto Flex"), r = V("Noto Sans SC");
@@ -62,12 +62,12 @@ function O() {
62
62
  };
63
63
  d(0);
64
64
  }
65
- function Q(n = !0) {
65
+ function O(n = !0) {
66
66
  w(() => {
67
- n && typeof document < "u" && O();
67
+ n && typeof document < "u" && K();
68
68
  }, [n]);
69
69
  }
70
- function W(n) {
70
+ function Q(n) {
71
71
  w(() => {
72
72
  let r;
73
73
  const i = () => {
@@ -76,7 +76,7 @@ function W(n) {
76
76
  return r = requestAnimationFrame(i), () => cancelAnimationFrame(r);
77
77
  }, [n]);
78
78
  }
79
- function Z(n) {
79
+ function W(n) {
80
80
  const r = y({ x: 0, y: 0 });
81
81
  return w(() => {
82
82
  const i = (t, s) => {
@@ -94,7 +94,7 @@ function Z(n) {
94
94
  };
95
95
  }, [n]), r;
96
96
  }
97
- const _ = H(
97
+ const Z = G(
98
98
  (n, r) => {
99
99
  const {
100
100
  label: i,
@@ -106,19 +106,19 @@ const _ = H(
106
106
  className: c = "",
107
107
  onClick: E,
108
108
  style: C,
109
- fontFamily: g,
109
+ fontFamily: h,
110
110
  autoLoadFonts: P = !0,
111
111
  ...A
112
112
  } = n;
113
- Q(P && !g);
114
- const b = y([]), v = y([]), S = Z(t), x = y({
113
+ O(P && !h);
114
+ const b = y([]), v = y([]), S = W(t), x = y({
115
115
  x: null,
116
116
  y: null
117
117
  }), q = N(() => {
118
118
  const e = (o) => new Map(
119
119
  o.split(",").map((p) => p.trim()).map((p) => {
120
- const [h, F] = p.split(" ");
121
- return [h.replace(/['"]/g, ""), parseFloat(F)];
120
+ const [g, F] = p.split(" ");
121
+ return [g.replace(/['"]/g, ""), parseFloat(F)];
122
122
  })
123
123
  ), a = e(f), u = e(d);
124
124
  return Array.from(a.entries()).map(([o, p]) => ({
@@ -137,7 +137,7 @@ const _ = H(
137
137
  return a;
138
138
  }
139
139
  };
140
- W(() => {
140
+ Q(() => {
141
141
  if (!t?.current) return;
142
142
  const { x: e, y: a } = S.current;
143
143
  if (x.current.x === e && x.current.y === a)
@@ -146,7 +146,7 @@ const _ = H(
146
146
  const u = t.current.getBoundingClientRect();
147
147
  b.current.forEach((o, p) => {
148
148
  if (!o) return;
149
- const h = o.getBoundingClientRect(), F = h.left + h.width / 2 - u.left, Y = h.top + h.height / 2 - u.top, L = I(
149
+ const g = o.getBoundingClientRect(), F = g.left + g.width / 2 - u.left, Y = g.top + g.height / 2 - u.top, L = I(
150
150
  S.current.x,
151
151
  S.current.y,
152
152
  F,
@@ -156,9 +156,9 @@ const _ = H(
156
156
  o.style.fontVariationSettings = f;
157
157
  return;
158
158
  }
159
- const z = $(L), M = q.map(({ axis: T, fromValue: R, toValue: D }) => {
160
- const U = R + (D - R) * z;
161
- return `'${T}' ${U}`;
159
+ const z = $(L), M = q.map(({ axis: T, fromValue: R, toValue: _ }) => {
160
+ const D = R + (_ - R) * z;
161
+ return `'${T}' ${D}`;
162
162
  }).join(", ");
163
163
  v.current[p] = M, o.style.fontVariationSettings = M;
164
164
  });
@@ -170,13 +170,13 @@ const _ = H(
170
170
  let B = 0;
171
171
  const X = N(() => {
172
172
  const e = { display: "inline", ...C };
173
- return g && (e.fontFamily = g), e;
174
- }, [g, C]);
175
- return /* @__PURE__ */ G(
173
+ return h && (e.fontFamily = h), e;
174
+ }, [h, C]);
175
+ return /* @__PURE__ */ U(
176
176
  "span",
177
177
  {
178
178
  ref: r,
179
- className: K("xiping-variable-proximity", c),
179
+ className: J("xiping-variable-proximity", c),
180
180
  onClick: E,
181
181
  style: X,
182
182
  ...A,
@@ -184,7 +184,7 @@ const _ = H(
184
184
  j.map((e, a) => {
185
185
  const u = B++;
186
186
  return /* @__PURE__ */ k(
187
- J.span,
187
+ H.span,
188
188
  {
189
189
  ref: (o) => {
190
190
  b.current[u] = o;
@@ -199,14 +199,13 @@ const _ = H(
199
199
  a
200
200
  );
201
201
  }),
202
- /* @__PURE__ */ k("span", { className: "sr-only", children: i })
202
+ /* @__PURE__ */ k("span", { className: "xiping-variable-proximity__sr-only", children: i })
203
203
  ]
204
204
  }
205
205
  );
206
206
  }
207
207
  );
208
- _.displayName = "VariableProximity";
208
+ Z.displayName = "VariableProximity";
209
209
  export {
210
- _ as VariableProximity,
211
- _ as default
210
+ Z as VariableProximity
212
211
  };
@@ -1 +1 @@
1
- .xiping-video-subtitle-player{width:100%;height:100%;background:#1a1a1a;border-radius:8px;overflow:hidden;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.xiping-video-subtitle-player__video-wrapper{width:100%;height:100%;background:#000;overflow:hidden}.xiping-video-subtitle-player__video-container{position:relative;width:100%;height:100%;background:#000;overflow:hidden}.xiping-video-subtitle-player__video{position:absolute;top:0;left:0;width:100%;height:100%;padding:0}.xiping-video-subtitle-player__video-container .xgplayer{width:100%!important;height:100%!important}.xiping-video-subtitle-player__video-container .xgplayer video{-o-object-fit:fill!important;object-fit:fill!important}.xiping-video-subtitle-player__subtitle-container{width:100%;height:100%;padding:20px;overflow-y:auto;background:#0000004d}.xiping-video-subtitle-player__resize-handle--horizontal{position:relative;width:2px;background:#ffffff1a;cursor:col-resize;transition:background .2s ease;flex-shrink:0}.xiping-video-subtitle-player__resize-handle--horizontal:hover{background:#fbbf2480}.xiping-video-subtitle-player__resize-handle--horizontal:active{background:#fbbf24cc}.xiping-video-subtitle-player__resize-handle--horizontal:before{content:"";position:absolute;inset:0 -4px;cursor:col-resize}.xiping-video-subtitle-player__resize-handle--vertical{position:relative;height:2px;background:#ffffff1a;cursor:row-resize;transition:background .2s ease;flex-shrink:0}.xiping-video-subtitle-player__resize-handle--vertical:hover{background:#fbbf2480}.xiping-video-subtitle-player__resize-handle--vertical:active{background:#fbbf24cc}.xiping-video-subtitle-player__resize-handle--vertical:before{content:"";position:absolute;inset:-4px 0;cursor:row-resize}.xiping-video-subtitle-player__right{width:100%;height:100%;border-left:1px solid rgba(255,255,255,.1);background:#00000080;display:flex;flex-direction:column}.xiping-video-subtitle-player__detail{flex:1;padding:24px;overflow-y:auto;color:#fff}.xiping-video-subtitle-player__detail-loading{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:16px;color:#ffffffb3}.xiping-video-subtitle-player__detail-loading-spinner{width:40px;height:40px;border:3px solid rgba(255,255,255,.1);border-top-color:#fbbf24;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.xiping-video-subtitle-player__detail-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:16px;color:#ffffff80;text-align:center}.xiping-video-subtitle-player__detail-empty-icon{font-size:48px;opacity:.5}.xiping-video-subtitle-player__detail-empty-text{font-size:14px;line-height:1.6}.xiping-video-subtitle-player__detail-content{display:flex;flex-direction:column;gap:20px}.xiping-video-subtitle-player__detail-word{font-size:32px;font-weight:700;color:#fbbf24;line-height:1.2;margin-bottom:8px}.xiping-video-subtitle-player__detail-pronunciation{font-size:18px;color:#ffffffb3;font-style:italic;margin-bottom:4px}.xiping-video-subtitle-player__detail-pos{display:inline-block;padding:4px 12px;background:#fbbf2433;color:#fbbf24;border-radius:4px;font-size:12px;font-weight:600;text-transform:uppercase;width:-moz-fit-content;width:fit-content;margin-bottom:8px}.xiping-video-subtitle-player__detail-label{font-size:12px;font-weight:600;color:#ffffff80;text-transform:uppercase;letter-spacing:.05em;margin-bottom:8px}.xiping-video-subtitle-player__detail-text{font-size:16px;line-height:1.6;color:#ffffffe6}.xiping-video-subtitle-player__detail-translation,.xiping-video-subtitle-player__detail-definition{padding-bottom:16px;border-bottom:1px solid rgba(255,255,255,.1)}.xiping-video-subtitle-player__detail-definition{border-bottom:none}.xiping-video-subtitle-player__detail-examples{display:flex;flex-direction:column;gap:16px}.xiping-video-subtitle-player__detail-example{padding:16px;background:#ffffff0d;border-radius:8px;border-left:3px solid #fbbf24}.xiping-video-subtitle-player__detail-example-en{font-size:15px;line-height:1.6;color:#fffffff2;margin-bottom:8px}.xiping-video-subtitle-player__detail-example-zh{font-size:14px;line-height:1.6;color:#ffffffb3;padding-left:12px;border-left:2px solid rgba(255,255,255,.2)}.xiping-video-subtitle-player__subtitle-container::-webkit-scrollbar,.xiping-video-subtitle-player__detail::-webkit-scrollbar{width:8px}.xiping-video-subtitle-player__subtitle-container::-webkit-scrollbar-track,.xiping-video-subtitle-player__detail::-webkit-scrollbar-track{background:#ffffff0d;border-radius:4px}.xiping-video-subtitle-player__subtitle-container::-webkit-scrollbar-thumb,.xiping-video-subtitle-player__detail::-webkit-scrollbar-thumb{background:#fff3;border-radius:4px}.xiping-video-subtitle-player__subtitle-container::-webkit-scrollbar-thumb:hover,.xiping-video-subtitle-player__detail::-webkit-scrollbar-thumb:hover{background:#ffffff4d}@media(max-width:1024px){.xiping-video-subtitle-player{flex-direction:column;min-height:auto}.xiping-video-subtitle-player__right{width:100%;min-width:unset;max-width:unset;border-left:none;border-top:1px solid rgba(255,255,255,.1);max-height:400px}.xiping-video-subtitle-player__subtitle-container{min-height:150px}}@media(max-width:768px){.xiping-video-subtitle-player__detail{padding:16px}.xiping-video-subtitle-player__detail-word{font-size:24px}.xiping-video-subtitle-player__detail-pronunciation{font-size:16px}.xiping-video-subtitle-player__subtitle-container{padding:16px}}
1
+ .xiping-video-subtitle-player{width:100%;height:100%;background:#1a1a1a;border-radius:8px;overflow:hidden;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.xiping-video-subtitle-player__video-wrapper{width:100%;height:100%;background:#000;overflow:hidden}.xiping-video-subtitle-player__video-container{position:relative;width:100%;height:100%;background:#000;overflow:hidden}.xiping-video-subtitle-player__video{position:absolute;top:0;left:0;width:100%;height:100%;padding:0}.xiping-video-subtitle-player__video-container .xgplayer{width:100%!important;height:100%!important}.xiping-video-subtitle-player__video-container .xgplayer video{object-fit:fill!important}.xiping-video-subtitle-player__subtitle-container{width:100%;height:100%;padding:20px;overflow-y:auto;background:#0000004d}.xiping-video-subtitle-player__right{width:100%;height:100%;background:#00000080;display:flex;flex-direction:column}.xiping-video-subtitle-player__detail{flex:1;padding:24px;overflow-y:auto;color:#fff}.xiping-video-subtitle-player__detail-loading{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:16px;color:#ffffffb3}.xiping-video-subtitle-player__detail-loading-spinner{width:40px;height:40px;border:3px solid rgba(255,255,255,.1);border-top-color:#fbbf24;border-radius:50%;animation:xiping-vsp-spin 1s linear infinite}@keyframes xiping-vsp-spin{to{transform:rotate(360deg)}}.xiping-video-subtitle-player__detail-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:16px;color:#ffffff80;text-align:center}.xiping-video-subtitle-player__detail-empty-icon{font-size:48px;opacity:.5}.xiping-video-subtitle-player__detail-empty-text{font-size:14px;line-height:1.6}.xiping-video-subtitle-player__detail-content{display:flex;flex-direction:column;gap:20px}.xiping-video-subtitle-player__detail-word{font-size:32px;font-weight:700;color:#fbbf24;line-height:1.2;margin-bottom:8px}.xiping-video-subtitle-player__detail-pronunciation{font-size:18px;color:#ffffffb3;font-style:italic;margin-bottom:4px}.xiping-video-subtitle-player__detail-pos{display:inline-block;padding:4px 12px;background:#fbbf2433;color:#fbbf24;border-radius:4px;font-size:12px;font-weight:600;text-transform:uppercase;width:fit-content;margin-bottom:8px}.xiping-video-subtitle-player__detail-label{font-size:12px;font-weight:600;color:#ffffff80;text-transform:uppercase;letter-spacing:.05em;margin-bottom:8px}.xiping-video-subtitle-player__detail-text{font-size:16px;line-height:1.6;color:#ffffffe6}.xiping-video-subtitle-player__detail-translation,.xiping-video-subtitle-player__detail-definition{padding-bottom:16px;border-bottom:1px solid rgba(255,255,255,.1)}.xiping-video-subtitle-player__detail-definition{border-bottom:none}.xiping-video-subtitle-player__detail-examples{display:flex;flex-direction:column;gap:16px}.xiping-video-subtitle-player__detail-example{padding:16px;background:#ffffff0d;border-radius:8px;border-left:3px solid #fbbf24}.xiping-video-subtitle-player__detail-example-en{font-size:15px;line-height:1.6;color:#fffffff2;margin-bottom:8px}.xiping-video-subtitle-player__detail-example-zh{font-size:14px;line-height:1.6;color:#ffffffb3;padding-left:12px;border-left:2px solid rgba(255,255,255,.2)}.xiping-video-subtitle-player__subtitle-container::-webkit-scrollbar,.xiping-video-subtitle-player__detail::-webkit-scrollbar{width:8px}.xiping-video-subtitle-player__subtitle-container::-webkit-scrollbar-track,.xiping-video-subtitle-player__detail::-webkit-scrollbar-track{background:#ffffff0d;border-radius:4px}.xiping-video-subtitle-player__subtitle-container::-webkit-scrollbar-thumb,.xiping-video-subtitle-player__detail::-webkit-scrollbar-thumb{background:#fff3;border-radius:4px}.xiping-video-subtitle-player__subtitle-container::-webkit-scrollbar-thumb:hover,.xiping-video-subtitle-player__detail::-webkit-scrollbar-thumb:hover{background:#ffffff4d}
@@ -13,11 +13,11 @@ export interface VideoSubtitlePlayerProps {
13
13
  style?: React.CSSProperties;
14
14
  /** 自定义详情获取函数,用于调用大模型API */
15
15
  onFetchDetail?: (target: HoverTarget | null) => Promise<void>;
16
+ /** 强制使用布局:传入则不再做设备检测,直接使用对应布局 */
17
+ forceLayout?: "mobile" | "pc";
16
18
  }
17
19
  /**
18
- * 视频字幕播放器组件
19
- * 左侧:上部分视频播放器(填充模式),下部分字幕显示
20
- * 右侧:字幕详情(单词/短语的发音、解释等)
20
+ * 视频字幕播放器:根据设备或 forceLayout 选择 PC 或移动端视图,二者完全分离
21
21
  */
22
22
  export declare const VideoSubtitlePlayer: React.FC<VideoSubtitlePlayerProps>;
23
23
  export default VideoSubtitlePlayer;
@@ -1,135 +1,74 @@
1
- import { jsx as e, jsxs as t } from "react/jsx-runtime";
2
- import { useRef as N, useEffect as u, useCallback as R } from "react";
3
- import j from "xgplayer";
4
- import './VideoSubtitlePlayer.css';import '../../node_modules/.pnpm/xgplayer@3.0.23_core-js@3.47.0/node_modules/xgplayer/dist/index.min.css';/* empty css */
5
- import { Group as S, Panel as s, Separator as z } from "react-resizable-panels";
6
- import D from "clsx";
7
- import { SubtitlePlayer as E } from "../subtitle-player/SubtitlePlayer.js";
8
- import { useVideoSubtitleStore as H } from "./useVideoSubtitleStore.js";
9
- /* empty css */
10
- const A = ({
11
- videoUrl: m,
12
- subtitles: o,
13
- poster: v,
14
- className: w = "",
15
- style: P,
16
- onFetchDetail: p
1
+ import { jsx as u } from "react/jsx-runtime";
2
+ import { useRef as v, useEffect as w, useCallback as d } from "react";
3
+ import { isMobile as V, isTablet as g } from "react-device-detect";
4
+ import { useVideoSubtitleStore as k } from "./useVideoSubtitleStore.js";
5
+ import { useXGPlayer as H } from "./useXGPlayer.js";
6
+ import { VideoSubtitlePlayerPC as M } from "./VideoSubtitlePlayerPC.js";
7
+ import { VideoSubtitlePlayerMobile as T } from "./VideoSubtitlePlayerMobile.js";
8
+ import './VideoSubtitlePlayer.css';/* empty css */
9
+ const X = ({
10
+ videoUrl: p,
11
+ subtitles: r,
12
+ poster: b,
13
+ className: l = "",
14
+ style: n,
15
+ onFetchDetail: e,
16
+ forceLayout: m
17
17
  }) => {
18
- const c = N(null), n = N(null), {
19
- currentTime: r,
20
- setCurrentTime: _,
21
- setIsPlaying: d,
22
- setSubtitles: h,
23
- currentDetail: l,
24
- isLoadingDetail: T,
25
- fetchDetail: y
26
- } = H();
27
- u(() => {
28
- h(o);
29
- }, [o, h]), u(() => {
30
- if (!c.current) return;
31
- const a = `xiping-video-subtitle-player-${Date.now()}`;
32
- c.current.id = a;
33
- const i = new j({
34
- id: a,
35
- url: m,
36
- poster: v,
37
- autoplay: !1,
38
- fluid: !1,
39
- width: "100%",
40
- height: "100%",
41
- controls: !0
42
- });
43
- n.current = i;
44
- const x = () => {
45
- const I = i.currentTime || 0;
46
- _(I);
47
- }, f = () => {
48
- d(!0);
49
- }, b = () => {
50
- d(!1);
51
- }, g = () => {
52
- d(!1);
53
- };
54
- return i.on("timeupdate", x), i.on("play", f), i.on("pause", b), i.on("ended", g), () => {
55
- i.off("timeupdate", x), i.off("play", f), i.off("pause", b), i.off("ended", g), i.destroy(), n.current = null;
56
- };
57
- }, [m, v, _, d]), u(() => {
58
- if (n.current) {
59
- const a = n.current;
60
- Math.abs(a.currentTime - r) > 0.5 && (a.currentTime = r);
61
- }
62
- }, [r]);
63
- const C = R(
64
- async (a) => {
65
- p ? await p(a) : await y(a);
18
+ const t = v(null), c = m !== void 0 ? m === "mobile" : V || g, {
19
+ currentTime: a,
20
+ setCurrentTime: C,
21
+ setIsPlaying: y,
22
+ setSubtitles: s,
23
+ currentDetail: P,
24
+ isLoadingDetail: S,
25
+ fetchDetail: i
26
+ } = k();
27
+ w(() => {
28
+ s(r);
29
+ }, [r, s]), H(
30
+ t,
31
+ p,
32
+ b,
33
+ { setCurrentTime: C, setIsPlaying: y },
34
+ a
35
+ );
36
+ const f = d(
37
+ async (o) => {
38
+ e ? await e(o) : await i(o);
39
+ },
40
+ [e, i]
41
+ ), W = d(
42
+ async (o) => {
43
+ e ? await e(o) : await i(o);
66
44
  },
67
- [p, y]
45
+ [e, i]
68
46
  );
69
- return /* @__PURE__ */ e(
70
- "div",
47
+ return c ? /* @__PURE__ */ u(
48
+ T,
49
+ {
50
+ playerRef: t,
51
+ subtitles: r,
52
+ currentTime: a,
53
+ onWordHoverChange: f,
54
+ onWordClick: W,
55
+ className: l,
56
+ style: n
57
+ }
58
+ ) : /* @__PURE__ */ u(
59
+ M,
71
60
  {
72
- className: D("xiping-video-subtitle-player", w),
73
- style: P,
74
- children: /* @__PURE__ */ t(S, { orientation: "horizontal", children: [
75
- /* @__PURE__ */ e(s, { defaultSize: 65, minSize: 40, children: /* @__PURE__ */ t(S, { orientation: "vertical", children: [
76
- /* @__PURE__ */ e(s, { defaultSize: 60, minSize: 30, children: /* @__PURE__ */ e("div", { className: "xiping-video-subtitle-player__video-wrapper", children: /* @__PURE__ */ e("div", { className: "xiping-video-subtitle-player__video-container", children: /* @__PURE__ */ e(
77
- "div",
78
- {
79
- ref: c,
80
- className: "xiping-video-subtitle-player__video"
81
- }
82
- ) }) }) }),
83
- /* @__PURE__ */ e(z, { className: "xiping-video-subtitle-player__resize-handle xiping-video-subtitle-player__resize-handle--vertical" }),
84
- /* @__PURE__ */ e(s, { defaultSize: 40, minSize: 20, children: /* @__PURE__ */ e("div", { className: "xiping-video-subtitle-player__subtitle-container", children: /* @__PURE__ */ e(
85
- E,
86
- {
87
- subtitles: o,
88
- currentTime: r,
89
- mode: "current",
90
- onWordHoverChange: C
91
- }
92
- ) }) })
93
- ] }) }),
94
- /* @__PURE__ */ e(z, { className: "xiping-video-subtitle-player__resize-handle xiping-video-subtitle-player__resize-handle--horizontal" }),
95
- /* @__PURE__ */ e(s, { defaultSize: 35, minSize: 25, maxSize: 50, children: /* @__PURE__ */ e("div", { className: "xiping-video-subtitle-player__right", children: /* @__PURE__ */ e("div", { className: "xiping-video-subtitle-player__detail", children: T ? /* @__PURE__ */ t("div", { className: "xiping-video-subtitle-player__detail-loading", children: [
96
- /* @__PURE__ */ e("div", { className: "xiping-video-subtitle-player__detail-loading-spinner" }),
97
- /* @__PURE__ */ e("span", { children: "加载中..." })
98
- ] }) : l ? /* @__PURE__ */ t("div", { className: "xiping-video-subtitle-player__detail-content", children: [
99
- /* @__PURE__ */ e("div", { className: "xiping-video-subtitle-player__detail-word", children: l.word }),
100
- l.pronunciation && /* @__PURE__ */ e("div", { className: "xiping-video-subtitle-player__detail-pronunciation", children: l.pronunciation }),
101
- l.partOfSpeech && /* @__PURE__ */ e("div", { className: "xiping-video-subtitle-player__detail-pos", children: l.partOfSpeech }),
102
- l.translation && /* @__PURE__ */ t("div", { className: "xiping-video-subtitle-player__detail-translation", children: [
103
- /* @__PURE__ */ e("div", { className: "xiping-video-subtitle-player__detail-label", children: "中文翻译" }),
104
- /* @__PURE__ */ e("div", { className: "xiping-video-subtitle-player__detail-text", children: l.translation })
105
- ] }),
106
- l.definition && /* @__PURE__ */ t("div", { className: "xiping-video-subtitle-player__detail-definition", children: [
107
- /* @__PURE__ */ e("div", { className: "xiping-video-subtitle-player__detail-label", children: "英文解释" }),
108
- /* @__PURE__ */ e("div", { className: "xiping-video-subtitle-player__detail-text", children: l.definition })
109
- ] }),
110
- l.examples && l.examples.length > 0 && /* @__PURE__ */ t("div", { className: "xiping-video-subtitle-player__detail-examples", children: [
111
- /* @__PURE__ */ e("div", { className: "xiping-video-subtitle-player__detail-label", children: "例句" }),
112
- l.examples.map((a, i) => /* @__PURE__ */ t(
113
- "div",
114
- {
115
- className: "xiping-video-subtitle-player__detail-example",
116
- children: [
117
- /* @__PURE__ */ e("div", { className: "xiping-video-subtitle-player__detail-example-en", children: a.sentence }),
118
- /* @__PURE__ */ e("div", { className: "xiping-video-subtitle-player__detail-example-zh", children: a.translation })
119
- ]
120
- },
121
- i
122
- ))
123
- ] })
124
- ] }) : /* @__PURE__ */ t("div", { className: "xiping-video-subtitle-player__detail-empty", children: [
125
- /* @__PURE__ */ e("div", { className: "xiping-video-subtitle-player__detail-empty-icon", children: "📖" }),
126
- /* @__PURE__ */ e("div", { className: "xiping-video-subtitle-player__detail-empty-text", children: "将鼠标悬停在字幕单词上查看详情" })
127
- ] }) }) }) })
128
- ] })
61
+ playerRef: t,
62
+ subtitles: r,
63
+ currentTime: a,
64
+ currentDetail: P,
65
+ isLoadingDetail: S,
66
+ onWordHoverChange: f,
67
+ className: l,
68
+ style: n
129
69
  }
130
70
  );
131
71
  };
132
72
  export {
133
- A as VideoSubtitlePlayer,
134
- A as default
73
+ X as VideoSubtitlePlayer
135
74
  };
@@ -0,0 +1 @@
1
+ .xiping-video-subtitle-player--mobile{display:flex;flex-direction:column;min-height:0;height:100%}.xiping-video-subtitle-player__mobile-video{flex:0 0 auto;width:100%;aspect-ratio:16 / 9;background:#000}.xiping-video-subtitle-player__mobile-video-wrapper{width:100%;height:100%;background:#000;overflow:hidden}.xiping-video-subtitle-player__mobile-video-container{position:relative;width:100%;height:100%;background-color:#a62c2c;overflow:hidden}.xiping-video-subtitle-player__mobile-video-container .xgplayer{width:100%!important;height:100%!important}.xiping-video-subtitle-player__mobile-video-container .xgplayer video{object-fit:fill!important}.xiping-video-subtitle-player__mobile-subtitle{flex:1;min-height:0;padding:12px 16px;overflow-y:auto;background:#0000004d;-webkit-overflow-scrolling:touch}
@@ -0,0 +1 @@
1
+ .xiping-video-subtitle-player--pc .xiping-video-subtitle-player__panel-group,.xiping-video-subtitle-player--pc .xiping-video-subtitle-player__panel-group-inner{width:100%;height:100%}.xiping-video-subtitle-player--pc .xiping-video-subtitle-player__right{border-left:1px solid rgba(255,255,255,.1)}.xiping-video-subtitle-player__resize-handle--horizontal{position:relative;width:2px;background:#ffffff1a;cursor:col-resize;transition:background .2s ease;flex-shrink:0}.xiping-video-subtitle-player__resize-handle--horizontal:hover{background:#fbbf2480}.xiping-video-subtitle-player__resize-handle--horizontal:active{background:#fbbf24cc}.xiping-video-subtitle-player__resize-handle--horizontal:before{content:"";position:absolute;inset:0 -4px;cursor:col-resize}.xiping-video-subtitle-player__resize-handle--vertical{position:relative;height:2px;background:#ffffff1a;cursor:row-resize;transition:background .2s ease;flex-shrink:0}.xiping-video-subtitle-player__resize-handle--vertical:hover{background:#fbbf2480}.xiping-video-subtitle-player__resize-handle--vertical:active{background:#fbbf24cc}.xiping-video-subtitle-player__resize-handle--vertical:before{content:"";position:absolute;inset:-4px 0;cursor:row-resize}
@@ -0,0 +1,20 @@
1
+ import { default as React, RefObject } from 'react';
2
+ import { SubtitleData, HoverTarget, WordClickTarget } from '../subtitle-player/SubtitlePlayer';
3
+ export interface VideoSubtitlePlayerMobileProps {
4
+ /** 播放器挂载的容器 ref */
5
+ playerRef: RefObject<HTMLDivElement | null>;
6
+ /** 字幕数据 */
7
+ subtitles: SubtitleData[];
8
+ /** 当前播放时间(秒) */
9
+ currentTime: number;
10
+ /** 单词 hover 变化时拉取/展示详情(可为弹窗等) */
11
+ onWordHoverChange: (target: HoverTarget | null) => void | Promise<void>;
12
+ /** 单词点击时拉取/展示详情(移动端主要交互) */
13
+ onWordClick: (target: WordClickTarget) => void | Promise<void>;
14
+ className?: string;
15
+ style?: React.CSSProperties;
16
+ }
17
+ /**
18
+ * 移动端视图:上下两栏(视频 + 字幕),无右侧详情区,详情后续以弹窗等形式实现
19
+ */
20
+ export declare const VideoSubtitlePlayerMobile: React.FC<VideoSubtitlePlayerMobileProps>;
@@ -0,0 +1,47 @@
1
+ import { jsx as e } from "react/jsx-runtime";
2
+ import { useCallback as l } from "react";
3
+ import u from "clsx";
4
+ import { SubtitlePlayer as y } from "../subtitle-player/SubtitlePlayer.js";
5
+ import { VideoSubtitlePlayerLayoutMobile as f } from "./layouts/VideoSubtitlePlayerLayoutMobile.js";
6
+ const P = ({
7
+ playerRef: r,
8
+ subtitles: a,
9
+ currentTime: s,
10
+ onWordHoverChange: t,
11
+ onWordClick: i,
12
+ className: c = "",
13
+ style: m
14
+ }) => {
15
+ const n = l(
16
+ async (o) => {
17
+ await t(o);
18
+ },
19
+ [t]
20
+ ), d = l(
21
+ async (o) => {
22
+ await i(o);
23
+ },
24
+ [i]
25
+ ), b = /* @__PURE__ */ e("div", { ref: r, className: "xiping-video-subtitle-player__video" }), p = /* @__PURE__ */ e(
26
+ y,
27
+ {
28
+ subtitles: a,
29
+ currentTime: s,
30
+ mode: "lyrics",
31
+ onWordHoverChange: n,
32
+ onWordClick: d
33
+ }
34
+ );
35
+ return /* @__PURE__ */ e(
36
+ f,
37
+ {
38
+ className: u(c),
39
+ style: m,
40
+ videoSlot: b,
41
+ subtitleSlot: p
42
+ }
43
+ );
44
+ };
45
+ export {
46
+ P as VideoSubtitlePlayerMobile
47
+ };
@@ -0,0 +1,23 @@
1
+ import { default as React, RefObject } from 'react';
2
+ import { SubtitleData, HoverTarget } from '../subtitle-player/SubtitlePlayer';
3
+ import { SubtitleDetail } from './useVideoSubtitleStore';
4
+ export interface VideoSubtitlePlayerPCProps {
5
+ /** 播放器挂载的容器 ref */
6
+ playerRef: RefObject<HTMLDivElement | null>;
7
+ /** 字幕数据 */
8
+ subtitles: SubtitleData[];
9
+ /** 当前播放时间(秒) */
10
+ currentTime: number;
11
+ /** 当前悬停单词的详情 */
12
+ currentDetail: SubtitleDetail | null;
13
+ /** 是否正在加载详情 */
14
+ isLoadingDetail: boolean;
15
+ /** 单词 hover 变化时拉取/展示详情 */
16
+ onWordHoverChange: (target: HoverTarget | null) => void | Promise<void>;
17
+ className?: string;
18
+ style?: React.CSSProperties;
19
+ }
20
+ /**
21
+ * PC 端视图:可拖拽分栏 + 右侧详情区,所有 PC 专属 UI 集中在此
22
+ */
23
+ export declare const VideoSubtitlePlayerPC: React.FC<VideoSubtitlePlayerPCProps>;