@xiping/react-components 1.0.52 → 1.0.54

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 (27) hide show
  1. package/dist/cjs/components/image-compare/ImageCompare.d.ts +6 -0
  2. package/dist/cjs/components/image-compare/ImageCompare.js +1 -1
  3. package/dist/cjs/components/subtitle-player/CurrentMode.d.ts +2 -0
  4. package/dist/cjs/components/subtitle-player/CurrentMode.js +2 -2
  5. package/dist/cjs/components/subtitle-player/LyricsMode.d.ts +2 -0
  6. package/dist/cjs/components/subtitle-player/LyricsMode.js +2 -2
  7. package/dist/cjs/components/subtitle-player/SubtitlePlayer.d.ts +34 -0
  8. package/dist/cjs/components/subtitle-player/SubtitlePlayer.js +1 -1
  9. package/dist/cjs/components/subtitle-player/utils.d.ts +1 -0
  10. package/dist/cjs/components/subtitle-player/utils.js +1 -1
  11. package/dist/cjs/react-components.css +1 -1
  12. package/dist/es/components/image-compare/ImageCompare.d.ts +6 -0
  13. package/dist/es/components/image-compare/ImageCompare.js +86 -67
  14. package/dist/es/components/subtitle-player/CurrentMode.d.ts +2 -0
  15. package/dist/es/components/subtitle-player/CurrentMode.js +25 -22
  16. package/dist/es/components/subtitle-player/LyricsMode.d.ts +2 -0
  17. package/dist/es/components/subtitle-player/LyricsMode.js +46 -43
  18. package/dist/es/components/subtitle-player/SubtitlePlayer.d.ts +34 -0
  19. package/dist/es/components/subtitle-player/SubtitlePlayer.js +146 -98
  20. package/dist/es/components/subtitle-player/utils.d.ts +1 -0
  21. package/dist/es/components/subtitle-player/utils.js +7 -6
  22. package/dist/es/react-components.css +1 -1
  23. package/package.json +16 -16
  24. package/dist/cjs/components/toast/index.d.ts +0 -4
  25. package/dist/cjs/components/translate/Translate.d.ts +0 -5
  26. package/dist/es/components/toast/index.d.ts +0 -4
  27. package/dist/es/components/translate/Translate.d.ts +0 -5
@@ -1,52 +1,54 @@
1
- import { jsx as d, jsxs as W } from "react/jsx-runtime";
2
- import { useMemo as u, useRef as O, useState as j, useEffect as _, useCallback as T } from "react";
3
- import { parseSRT as S, parseVTT as v } from "../../packages/subtitle/lib/src/parser.js";
4
- import { srtToJson as k, vttToJson as z } from "../../packages/subtitle/lib/src/json-converter.js";
5
- import C from "clsx";
6
- import { CurrentMode as D } from "./CurrentMode.js";
7
- import { LyricsMode as F } from "./LyricsMode.js";
8
- import { getCurrentSubtitleEntry as G, timeStringToSeconds as A } from "./utils.js";
1
+ import { jsx as S, jsxs as z } from "react/jsx-runtime";
2
+ import { useMemo as h, useRef as F, useState as k, useEffect as G, useCallback as u } from "react";
3
+ import { parseSRT as w, parseVTT as v } from "../../packages/subtitle/lib/src/parser.js";
4
+ import { srtToJson as V, vttToJson as q } from "../../packages/subtitle/lib/src/json-converter.js";
5
+ import K from "clsx";
6
+ import { CurrentMode as Q } from "./CurrentMode.js";
7
+ import { LyricsMode as U } from "./LyricsMode.js";
8
+ import { getCurrentSubtitleEntry as X, timeStringToSeconds as A } from "./utils.js";
9
9
  /* empty css */
10
- const H = ({
11
- subtitles: i,
12
- currentTime: m,
13
- mode: f = "current",
14
- className: B = "",
10
+ const ot = ({
11
+ subtitles: p,
12
+ currentTime: f,
13
+ mode: m = "current",
14
+ className: D = "",
15
15
  style: J,
16
16
  onWordHoverChange: a,
17
- renderWordOverlay: h
17
+ renderWordOverlay: d,
18
+ onWordClick: y,
19
+ onSubtitleClick: T
18
20
  }) => {
19
- const l = u(
20
- () => Array.isArray(i) ? i : [i],
21
- [i]
22
- ), y = O(null), [c, x] = j(null), [g, E] = j([]);
23
- _(() => {
21
+ const i = h(
22
+ () => Array.isArray(p) ? p : [p],
23
+ [p]
24
+ ), l = F(null), [s, E] = k(null), [R, M] = k([]);
25
+ G(() => {
24
26
  let r = !0;
25
- async function s() {
27
+ async function c() {
26
28
  try {
27
- const t = await Promise.all(
28
- l.map(async (e) => {
29
+ const e = await Promise.all(
30
+ i.map(async (t) => {
29
31
  try {
30
- const n = e.language || "zh", o = e.type === "srt" ? await k(e.content, n) : await z(e.content, n);
32
+ const n = t.language || "zh", o = t.type === "srt" ? await V(t.content, n) : await q(t.content, n);
31
33
  return {
32
34
  entries: JSON.parse(o),
33
- label: e.label
35
+ label: t.label
34
36
  };
35
37
  } catch (n) {
36
38
  return console.error("字幕解析失败:", n), {
37
- entries: e.type === "srt" ? S(e.content) : v(e.content),
38
- label: e.label
39
+ entries: t.type === "srt" ? w(t.content) : v(t.content),
40
+ label: t.label
39
41
  };
40
42
  }
41
43
  })
42
44
  );
43
- r && E(t);
44
- } catch (t) {
45
- if (console.error("加载字幕失败:", t), r) {
46
- const e = l.map((n) => {
45
+ r && M(e);
46
+ } catch (e) {
47
+ if (console.error("加载字幕失败:", e), r) {
48
+ const t = i.map((n) => {
47
49
  try {
48
50
  return {
49
- entries: n.type === "srt" ? S(n.content) : v(n.content),
51
+ entries: n.type === "srt" ? w(n.content) : v(n.content),
50
52
  label: n.label
51
53
  };
52
54
  } catch (o) {
@@ -56,35 +58,35 @@ const H = ({
56
58
  };
57
59
  }
58
60
  });
59
- E(e);
61
+ M(t);
60
62
  }
61
63
  }
62
64
  }
63
- return s(), () => {
65
+ return c(), () => {
64
66
  r = !1;
65
67
  };
66
- }, [l]);
67
- const p = u(() => g.length > 0 ? g : l.map((r) => {
68
+ }, [i]);
69
+ const g = h(() => R.length > 0 ? R : i.map((r) => {
68
70
  try {
69
71
  return {
70
- entries: r.type === "srt" ? S(r.content) : v(r.content),
72
+ entries: r.type === "srt" ? w(r.content) : v(r.content),
71
73
  label: r.label
72
74
  };
73
- } catch (s) {
74
- return console.error("字幕解析失败:", s), {
75
+ } catch (c) {
76
+ return console.error("字幕解析失败:", c), {
75
77
  entries: [],
76
78
  label: r.label
77
79
  };
78
80
  }
79
- }), [g, l]), L = u(() => p.map(({ entries: r, label: s }) => ({
80
- entry: G(r, m),
81
- label: s,
81
+ }), [R, i]), L = h(() => g.map(({ entries: r, label: c }) => ({
82
+ entry: X(r, f),
83
+ label: c,
82
84
  entries: r
83
85
  // 保留所有条目用于歌词模式
84
- })), [p, m]), P = u(() => {
86
+ })), [g, f]), W = h(() => {
85
87
  const r = [];
86
- p.forEach(({ entries: e, label: n }) => {
87
- e.forEach((o) => {
88
+ g.forEach(({ entries: t, label: n }) => {
89
+ t.forEach((o) => {
88
90
  r.push({
89
91
  entry: o,
90
92
  label: n,
@@ -92,86 +94,132 @@ const H = ({
92
94
  endTime: A(o.endTime)
93
95
  });
94
96
  });
95
- }), r.sort((e, n) => e.startTime - n.startTime);
96
- const s = [];
97
- let t = [];
98
- for (const e of r)
99
- if (t.length === 0)
100
- t.push(e);
97
+ }), r.sort((t, n) => t.startTime - n.startTime);
98
+ const c = [];
99
+ let e = [];
100
+ for (const t of r)
101
+ if (e.length === 0)
102
+ e.push(t);
101
103
  else {
102
- const n = t[t.length - 1];
103
- e.startTime <= n.endTime ? t.push(e) : (s.push(t), t = [e]);
104
+ const n = e[e.length - 1];
105
+ t.startTime <= n.endTime ? e.push(t) : (c.push(e), e = [t]);
104
106
  }
105
- return t.length > 0 && s.push(t), s;
106
- }, [p]), R = T(
107
- (r, s) => {
108
- const t = r.currentTarget.getBoundingClientRect(), e = y.current?.getBoundingClientRect(), n = e !== void 0 ? new DOMRect(
109
- t.left - e.left,
110
- t.top - e.top,
111
- t.width,
112
- t.height
113
- ) : t, o = {
114
- ...s,
107
+ return e.length > 0 && c.push(e), c;
108
+ }, [g]), b = u(
109
+ (r, c) => {
110
+ const e = r.currentTarget.getBoundingClientRect(), t = l.current?.getBoundingClientRect(), n = t !== void 0 ? new DOMRect(
111
+ e.left - t.left,
112
+ e.top - t.top,
113
+ e.width,
114
+ e.height
115
+ ) : e, o = {
116
+ ...c,
115
117
  rect: n,
116
118
  element: r.currentTarget
117
119
  };
118
- x(o), a?.(o);
120
+ E(o), a?.(o);
119
121
  },
120
122
  [a]
121
- ), w = T(() => {
122
- x(null), a?.(null);
123
- }, [a]), M = T(
124
- (r, s) => (t, e, n) => ({
125
- onMouseEnter: (o) => R(o, {
126
- word: t,
127
- wordIndex: e,
123
+ ), x = u(() => {
124
+ E(null), a?.(null);
125
+ }, [a]), B = u(
126
+ (r, c) => {
127
+ if (!y) return;
128
+ r.stopPropagation();
129
+ const e = r.currentTarget.getBoundingClientRect(), t = l.current?.getBoundingClientRect(), n = t !== void 0 ? new DOMRect(
130
+ e.left - t.left,
131
+ e.top - t.top,
132
+ e.width,
133
+ e.height
134
+ ) : e, o = {
135
+ type: "word",
136
+ ...c,
137
+ rect: n,
138
+ element: r.currentTarget
139
+ };
140
+ y(o);
141
+ },
142
+ [y]
143
+ ), C = u(
144
+ (r, c, e) => {
145
+ if (!T || r.target.closest(".xiping-subtitle-word"))
146
+ return;
147
+ const n = r.currentTarget.getBoundingClientRect(), o = l.current?.getBoundingClientRect(), j = o !== void 0 ? new DOMRect(
148
+ n.left - o.left,
149
+ n.top - o.top,
150
+ n.width,
151
+ n.height
152
+ ) : n, _ = {
153
+ type: "subtitle",
154
+ entry: c,
155
+ label: e,
156
+ rect: j,
157
+ element: r.currentTarget
158
+ };
159
+ T(_);
160
+ },
161
+ [T]
162
+ ), N = u(
163
+ (r, c) => (e, t, n) => ({
164
+ onMouseEnter: (o) => b(o, {
165
+ word: e,
166
+ wordIndex: t,
128
167
  lineIndex: n,
129
168
  entry: r,
130
- label: s
169
+ label: c
131
170
  }),
132
- onMouseLeave: w
171
+ onMouseLeave: x,
172
+ onClick: (o) => B(o, {
173
+ word: e,
174
+ wordIndex: t,
175
+ lineIndex: n,
176
+ entry: r,
177
+ label: c
178
+ })
133
179
  }),
134
- [R, w]
135
- ), b = h && c ? /* @__PURE__ */ d(
180
+ [b, x, B]
181
+ ), O = d && s ? /* @__PURE__ */ S(
136
182
  "div",
137
183
  {
138
184
  className: "xiping-subtitle-player__hover-overlay",
139
185
  style: {
140
- left: c.rect.x + c.rect.width / 2,
141
- top: c.rect.y + c.rect.height
186
+ left: s.rect.x + s.rect.width / 2,
187
+ top: s.rect.y + s.rect.height
142
188
  },
143
- children: h(c)
189
+ children: d(s)
144
190
  }
145
- ) : null, N = !!(h || a);
146
- return /* @__PURE__ */ W(
191
+ ) : null, P = !!(d || a);
192
+ return /* @__PURE__ */ z(
147
193
  "div",
148
194
  {
149
- ref: y,
150
- className: C(
195
+ ref: l,
196
+ className: K(
151
197
  "xiping-subtitle-player",
152
- f === "lyrics" ? "xiping-subtitle-player--lyrics" : "xiping-subtitle-player--current",
153
- B
198
+ m === "lyrics" ? "xiping-subtitle-player--lyrics" : "xiping-subtitle-player--current",
199
+ D
154
200
  ),
155
201
  style: J,
156
202
  children: [
157
- f === "current" && /* @__PURE__ */ d(
158
- D,
203
+ m === "current" && /* @__PURE__ */ S(
204
+ Q,
159
205
  {
160
206
  currentEntries: L,
161
- wordHoverFactory: M,
162
- enableWordHover: N,
163
- overlayNode: b
207
+ wordHoverFactory: N,
208
+ enableWordHover: P,
209
+ overlayNode: O,
210
+ onSubtitleClick: C
164
211
  }
165
212
  ),
166
- f === "lyrics" && /* @__PURE__ */ d(
167
- F,
213
+ m === "lyrics" && /* @__PURE__ */ S(
214
+ U,
168
215
  {
169
- groupedEntriesByTime: P,
170
- currentTime: m,
171
- wordHoverFactory: M,
172
- enableWordHover: N,
173
- overlayNode: b,
174
- containerRef: y
216
+ groupedEntriesByTime: W,
217
+ currentTime: f,
218
+ wordHoverFactory: N,
219
+ enableWordHover: P,
220
+ overlayNode: O,
221
+ containerRef: l,
222
+ onSubtitleClick: C
175
223
  }
176
224
  )
177
225
  ]
@@ -179,6 +227,6 @@ const H = ({
179
227
  );
180
228
  };
181
229
  export {
182
- H as SubtitlePlayer,
183
- H as default
230
+ ot as SubtitlePlayer,
231
+ ot as default
184
232
  };
@@ -18,6 +18,7 @@ export declare function getCurrentSubtitleEntry(entries: SubtitleEntry[], curren
18
18
  export type WordHoverHandlerFactory = (word: string, wordIndex: number, lineIndex: number) => {
19
19
  onMouseEnter: React.MouseEventHandler<HTMLSpanElement>;
20
20
  onMouseLeave: React.MouseEventHandler<HTMLSpanElement>;
21
+ onClick?: React.MouseEventHandler<HTMLSpanElement>;
21
22
  } | undefined;
22
23
  /**
23
24
  * 将文本按照分词结果分割并渲染,并返回消耗到的分词下标
@@ -24,28 +24,29 @@ function T(t, e, n, r, a) {
24
24
  const s = [];
25
25
  let i = 0;
26
26
  for (let o = n; o < e.length; o++) {
27
- const c = e[o], l = t.substring(i).indexOf(c);
28
- if (l === -1)
27
+ const c = e[o], f = t.substring(i).indexOf(c);
28
+ if (f === -1)
29
29
  return {
30
30
  nodes: s.length > 0 ? s : t,
31
31
  nextWordIndex: o
32
32
  };
33
- const u = i + l;
33
+ const u = i + f;
34
34
  if (u > i) {
35
35
  const g = t.substring(i, u);
36
36
  g && s.push(
37
37
  /* @__PURE__ */ d("span", { className: "xiping-subtitle-word-before", children: g }, `before-${r}-${o}`)
38
38
  );
39
39
  }
40
- const f = a?.(c, o, r);
40
+ const l = a?.(c, o, r);
41
41
  if (s.push(
42
42
  /* @__PURE__ */ d(
43
43
  "span",
44
44
  {
45
45
  className: "xiping-subtitle-word",
46
46
  "data-word": c,
47
- onMouseEnter: f?.onMouseEnter,
48
- onMouseLeave: f?.onMouseLeave,
47
+ onMouseEnter: l?.onMouseEnter,
48
+ onMouseLeave: l?.onMouseLeave,
49
+ onClick: l?.onClick,
49
50
  children: c
50
51
  },
51
52
  `word-${r}-${o}`