@xiping/react-components 1.0.55 → 1.0.57

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 (147) hide show
  1. package/dist/cjs/components/blur-text/BlurText.d.ts +16 -0
  2. package/dist/cjs/components/blur-text/BlurText.js +1 -0
  3. package/dist/cjs/components/blur-text/index.d.ts +2 -0
  4. package/dist/cjs/components/button/Button.css +1 -0
  5. package/dist/cjs/components/button/Button.js +1 -1
  6. package/dist/cjs/components/comic-text/ComicText.css +1 -0
  7. package/dist/cjs/components/comic-text/ComicText.js +2 -2
  8. package/dist/cjs/components/dock/Duck.css +1 -0
  9. package/dist/cjs/components/dock/Duck.d.ts +2 -4
  10. package/dist/cjs/components/dock/Duck.js +1 -1
  11. package/dist/cjs/components/flip-text/FlipText.css +1 -0
  12. package/dist/cjs/components/flip-text/FlipText.js +1 -1
  13. package/dist/cjs/components/gradient-text/index.css +1 -0
  14. package/dist/cjs/components/gradient-text/index.js +1 -1
  15. package/dist/cjs/components/hyper-text/HyperText.css +1 -0
  16. package/dist/cjs/components/hyper-text/index.js +1 -1
  17. package/dist/cjs/components/image-compare/ImageCompare.css +1 -0
  18. package/dist/cjs/components/image-compare/ImageCompare.d.ts +4 -2
  19. package/dist/cjs/components/image-compare/ImageCompare.js +1 -1
  20. package/dist/cjs/components/image-viewer/ImageThumbnails.css +1 -0
  21. package/dist/cjs/components/image-viewer/ImageThumbnails.js +1 -1
  22. package/dist/cjs/components/image-viewer/ImageViewer.css +1 -0
  23. package/dist/cjs/components/image-viewer/ImageViewer.js +1 -1
  24. package/dist/cjs/components/message/Message.css +1 -0
  25. package/dist/cjs/components/message/Message.js +1 -1
  26. package/dist/cjs/components/pointer/Pointer.css +1 -0
  27. package/dist/cjs/components/pointer/Pointer.js +1 -1
  28. package/dist/cjs/components/scratch-to-reveal/ScratchToReveal.css +1 -0
  29. package/dist/cjs/components/scratch-to-reveal/ScratchToReveal.js +1 -1
  30. package/dist/cjs/components/shimmer-button/ShimmerButton.css +1 -0
  31. package/dist/cjs/components/shimmer-button/ShimmerButton.js +1 -1
  32. package/dist/cjs/components/shiny-button/ShinyButton.css +1 -0
  33. package/dist/cjs/components/shiny-button/ShinyButton.js +1 -1
  34. package/dist/cjs/components/shiny-text/ShinyText.css +1 -0
  35. package/dist/cjs/components/shiny-text/ShinyText.d.ts +16 -0
  36. package/dist/cjs/components/shiny-text/ShinyText.js +1 -0
  37. package/dist/cjs/components/shiny-text/index.d.ts +2 -0
  38. package/dist/cjs/components/sparkles-text/SparklesText.css +1 -0
  39. package/dist/cjs/components/sparkles-text/SparklesText.js +1 -1
  40. package/dist/cjs/components/split-text/SplitText.css +1 -0
  41. package/dist/cjs/components/split-text/SplitText.js +1 -1
  42. package/dist/cjs/components/subtitle-player/CurrentMode.css +1 -0
  43. package/dist/cjs/components/subtitle-player/CurrentMode.d.ts +2 -0
  44. package/dist/cjs/components/subtitle-player/CurrentMode.js +2 -2
  45. package/dist/cjs/components/subtitle-player/LyricsMode.css +1 -0
  46. package/dist/cjs/components/subtitle-player/LyricsMode.d.ts +2 -0
  47. package/dist/cjs/components/subtitle-player/LyricsMode.js +2 -2
  48. package/dist/cjs/components/subtitle-player/SubtitlePlayer.css +1 -0
  49. package/dist/cjs/components/subtitle-player/SubtitlePlayer.d.ts +2 -0
  50. package/dist/cjs/components/subtitle-player/SubtitlePlayer.js +1 -1
  51. package/dist/cjs/components/text-animate/TextAnimate.css +1 -0
  52. package/dist/cjs/components/text-animate/TextAnimate.js +2 -2
  53. package/dist/cjs/components/text-type/TextType.css +1 -0
  54. package/dist/cjs/components/text-type/TextType.js +1 -1
  55. package/dist/cjs/components/txt-reader/index.module.css +1 -0
  56. package/dist/cjs/components/txt-reader/index.module.css.js +1 -1
  57. package/dist/cjs/components/typing-animation/index.css +1 -0
  58. package/dist/cjs/components/typing-animation/index.js +1 -1
  59. package/dist/cjs/components/variable-proximity/index.css +1 -0
  60. package/dist/cjs/components/variable-proximity/index.js +1 -1
  61. package/dist/cjs/components/video-dialog/VideoDialog.css +1 -0
  62. package/dist/cjs/components/video-dialog/VideoDialog.js +1 -1
  63. package/dist/cjs/components/video-subtitle-player/VideoSubtitlePlayer.css +1 -0
  64. package/dist/cjs/components/video-subtitle-player/VideoSubtitlePlayer.js +1 -1
  65. package/dist/cjs/index.d.ts +2 -1
  66. package/dist/cjs/index.js +1 -1
  67. package/dist/cjs/llms.txt +2 -13
  68. package/dist/cjs/node_modules/.pnpm/xgplayer@3.0.23_core-js@3.47.0/node_modules/xgplayer/dist/index.min.css +1 -0
  69. package/dist/es/components/blur-text/BlurText.d.ts +16 -0
  70. package/dist/es/components/blur-text/BlurText.js +77 -0
  71. package/dist/es/components/blur-text/index.d.ts +2 -0
  72. package/dist/es/components/button/Button.css +1 -0
  73. package/dist/es/components/button/Button.js +35 -46
  74. package/dist/es/components/comic-text/ComicText.css +1 -0
  75. package/dist/es/components/comic-text/ComicText.js +13 -12
  76. package/dist/es/components/dock/Duck.css +1 -0
  77. package/dist/es/components/dock/Duck.d.ts +2 -4
  78. package/dist/es/components/dock/Duck.js +60 -64
  79. package/dist/es/components/flip-text/FlipText.css +1 -0
  80. package/dist/es/components/flip-text/FlipText.js +8 -8
  81. package/dist/es/components/gradient-text/index.css +1 -0
  82. package/dist/es/components/gradient-text/index.js +9 -8
  83. package/dist/es/components/hyper-text/HyperText.css +1 -0
  84. package/dist/es/components/hyper-text/index.js +16 -13
  85. package/dist/es/components/image-compare/ImageCompare.css +1 -0
  86. package/dist/es/components/image-compare/ImageCompare.d.ts +4 -2
  87. package/dist/es/components/image-compare/ImageCompare.js +55 -48
  88. package/dist/es/components/image-viewer/ImageThumbnails.css +1 -0
  89. package/dist/es/components/image-viewer/ImageThumbnails.js +41 -42
  90. package/dist/es/components/image-viewer/ImageViewer.css +1 -0
  91. package/dist/es/components/image-viewer/ImageViewer.js +34 -35
  92. package/dist/es/components/message/Message.css +1 -0
  93. package/dist/es/components/message/Message.js +65 -54
  94. package/dist/es/components/pointer/Pointer.css +1 -0
  95. package/dist/es/components/pointer/Pointer.js +23 -25
  96. package/dist/es/components/scratch-to-reveal/ScratchToReveal.css +1 -0
  97. package/dist/es/components/scratch-to-reveal/ScratchToReveal.js +17 -16
  98. package/dist/es/components/shimmer-button/ShimmerButton.css +1 -0
  99. package/dist/es/components/shimmer-button/ShimmerButton.js +8 -8
  100. package/dist/es/components/shiny-button/ShinyButton.css +1 -0
  101. package/dist/es/components/shiny-button/ShinyButton.js +13 -13
  102. package/dist/es/components/shiny-text/ShinyText.css +1 -0
  103. package/dist/es/components/shiny-text/ShinyText.d.ts +16 -0
  104. package/dist/es/components/shiny-text/ShinyText.js +76 -0
  105. package/dist/es/components/shiny-text/index.d.ts +2 -0
  106. package/dist/es/components/sparkles-text/SparklesText.css +1 -0
  107. package/dist/es/components/sparkles-text/SparklesText.js +14 -14
  108. package/dist/es/components/split-text/SplitText.css +1 -0
  109. package/dist/es/components/split-text/SplitText.js +1 -1
  110. package/dist/es/components/subtitle-player/CurrentMode.css +1 -0
  111. package/dist/es/components/subtitle-player/CurrentMode.d.ts +2 -0
  112. package/dist/es/components/subtitle-player/CurrentMode.js +75 -40
  113. package/dist/es/components/subtitle-player/LyricsMode.css +1 -0
  114. package/dist/es/components/subtitle-player/LyricsMode.d.ts +2 -0
  115. package/dist/es/components/subtitle-player/LyricsMode.js +139 -68
  116. package/dist/es/components/subtitle-player/SubtitlePlayer.css +1 -0
  117. package/dist/es/components/subtitle-player/SubtitlePlayer.d.ts +2 -0
  118. package/dist/es/components/subtitle-player/SubtitlePlayer.js +63 -60
  119. package/dist/es/components/text-animate/TextAnimate.css +1 -0
  120. package/dist/es/components/text-animate/TextAnimate.js +57 -55
  121. package/dist/es/components/text-type/TextType.css +1 -0
  122. package/dist/es/components/text-type/TextType.js +24 -19
  123. package/dist/es/components/txt-reader/index.module.css +1 -0
  124. package/dist/es/components/txt-reader/index.module.css.js +1 -1
  125. package/dist/es/components/typing-animation/index.css +1 -0
  126. package/dist/es/components/typing-animation/index.js +12 -12
  127. package/dist/es/components/variable-proximity/index.css +1 -0
  128. package/dist/es/components/variable-proximity/index.js +19 -18
  129. package/dist/es/components/video-dialog/VideoDialog.css +1 -0
  130. package/dist/es/components/video-dialog/VideoDialog.js +1 -1
  131. package/dist/es/components/video-subtitle-player/VideoSubtitlePlayer.css +1 -0
  132. package/dist/es/components/video-subtitle-player/VideoSubtitlePlayer.js +100 -93
  133. package/dist/es/index.d.ts +2 -1
  134. package/dist/es/index.js +59 -60
  135. package/dist/es/llms.txt +2 -13
  136. package/dist/es/node_modules/.pnpm/xgplayer@3.0.23_core-js@3.47.0/node_modules/xgplayer/dist/index.min.css +1 -0
  137. package/package.json +14 -12
  138. package/dist/cjs/components/animated-list/AnimatedList.d.ts +0 -9
  139. package/dist/cjs/components/animated-list/AnimatedList.js +0 -1
  140. package/dist/cjs/components/animated-list/index.d.ts +0 -1
  141. package/dist/cjs/react-components.css +0 -1
  142. package/dist/cjs/utils/utils.js +0 -1
  143. package/dist/es/components/animated-list/AnimatedList.d.ts +0 -9
  144. package/dist/es/components/animated-list/AnimatedList.js +0 -44
  145. package/dist/es/components/animated-list/index.d.ts +0 -1
  146. package/dist/es/react-components.css +0 -1
  147. package/dist/es/utils/utils.js +0 -8
@@ -0,0 +1,16 @@
1
+ import { default as React } from 'react';
2
+ interface ShinyTextProps {
3
+ text: string;
4
+ disabled?: boolean;
5
+ speed?: number;
6
+ className?: string;
7
+ color?: string;
8
+ shineColor?: string;
9
+ spread?: number;
10
+ yoyo?: boolean;
11
+ pauseOnHover?: boolean;
12
+ direction?: 'left' | 'right';
13
+ delay?: number;
14
+ }
15
+ declare const ShinyText: React.FC<ShinyTextProps>;
16
+ export default ShinyText;
@@ -0,0 +1,76 @@
1
+ import { jsx as L } from "react/jsx-runtime";
2
+ import { useState as W, useRef as d, useEffect as j, useCallback as y } from "react";
3
+ import { useMotionValue as v, useAnimationFrame as z, useTransform as A, motion as B } from "motion/react";
4
+ import './ShinyText.css';/* empty css */
5
+ const G = ({
6
+ text: T,
7
+ disabled: k = !1,
8
+ speed: $ = 2,
9
+ className: x = "",
10
+ color: u = "#b5b5b5",
11
+ shineColor: h = "#ffffff",
12
+ spread: C = 120,
13
+ yoyo: M = !1,
14
+ pauseOnHover: l = !1,
15
+ direction: f = "left",
16
+ delay: D = 0
17
+ }) => {
18
+ const [R, p] = W(!1), e = v(0), a = d(0), c = d(null), r = d(f === "left" ? 1 : -1), t = $ * 1e3, b = D * 1e3;
19
+ z((o) => {
20
+ if (k || R) {
21
+ c.current = null;
22
+ return;
23
+ }
24
+ if (c.current === null) {
25
+ c.current = o;
26
+ return;
27
+ }
28
+ const I = o - c.current;
29
+ if (c.current = o, a.current += I, M) {
30
+ const s = t + b, i = s * 2, n = a.current % i;
31
+ if (n < t) {
32
+ const m = n / t * 100;
33
+ e.set(r.current === 1 ? m : 100 - m);
34
+ } else if (n < s)
35
+ e.set(r.current === 1 ? 100 : 0);
36
+ else if (n < s + t) {
37
+ const g = 100 - (n - s) / t * 100;
38
+ e.set(r.current === 1 ? g : 100 - g);
39
+ } else
40
+ e.set(r.current === 1 ? 0 : 100);
41
+ } else {
42
+ const s = t + b, i = a.current % s;
43
+ if (i < t) {
44
+ const n = i / t * 100;
45
+ e.set(r.current === 1 ? n : 100 - n);
46
+ } else
47
+ e.set(r.current === 1 ? 100 : 0);
48
+ }
49
+ }), j(() => {
50
+ r.current = f === "left" ? 1 : -1, a.current = 0, e.set(0);
51
+ }, [f]);
52
+ const S = A(e, (o) => `${150 - o * 2}% center`), E = y(() => {
53
+ l && p(!0);
54
+ }, [l]), P = y(() => {
55
+ l && p(!1);
56
+ }, [l]), F = {
57
+ backgroundImage: `linear-gradient(${C}deg, ${u} 0%, ${u} 35%, ${h} 50%, ${u} 65%, ${u} 100%)`,
58
+ backgroundSize: "200% auto",
59
+ WebkitBackgroundClip: "text",
60
+ backgroundClip: "text",
61
+ WebkitTextFillColor: "transparent"
62
+ };
63
+ return /* @__PURE__ */ L(
64
+ B.span,
65
+ {
66
+ className: `shiny-text ${x}`,
67
+ style: { ...F, backgroundPosition: S },
68
+ onMouseEnter: E,
69
+ onMouseLeave: P,
70
+ children: T
71
+ }
72
+ );
73
+ };
74
+ export {
75
+ G as default
76
+ };
@@ -0,0 +1,2 @@
1
+ import { default as ShinyText } from './ShinyText';
2
+ export { ShinyText };
@@ -0,0 +1 @@
1
+ .xiping-sparkle{pointer-events:none;position:absolute;z-index:20}.xiping-sparkles-text{font-size:3.75rem;font-weight:700}.xiping-sparkles-text-wrapper{position:relative;display:inline-block}
@@ -2,19 +2,19 @@
2
2
  import { jsx as r, jsxs as g } from "react/jsx-runtime";
3
3
  import { motion as k } from "motion/react";
4
4
  import { useState as L, useEffect as S } from "react";
5
- import { cn as y } from "../../utils/utils.js";
6
- /* empty css */
7
- const M = ({ id: i, x: t, y: o, color: s, delay: c, scale: l }) => /* @__PURE__ */ r(
5
+ import y from "clsx";
6
+ import './SparklesText.css';/* empty css */
7
+ const M = ({ id: i, x: t, y: o, color: s, delay: l, scale: c }) => /* @__PURE__ */ r(
8
8
  k.svg,
9
9
  {
10
10
  className: "xiping-sparkle",
11
11
  initial: { opacity: 0, left: t, top: o },
12
12
  animate: {
13
13
  opacity: [0, 1, 0],
14
- scale: [0, l, 0],
14
+ scale: [0, c, 0],
15
15
  rotate: [75, 120, 150]
16
16
  },
17
- transition: { duration: 0.8, repeat: 1 / 0, delay: c },
17
+ transition: { duration: 0.8, repeat: 1 / 0, delay: l },
18
18
  width: "21",
19
19
  height: "21",
20
20
  viewBox: "0 0 21 21",
@@ -32,19 +32,19 @@ const M = ({ id: i, x: t, y: o, color: s, delay: c, scale: l }) => /* @__PURE__
32
32
  colors: t = { first: "#9E7AFF", second: "#FE8BBB" },
33
33
  className: o,
34
34
  sparklesCount: s = 10,
35
- ...c
35
+ ...l
36
36
  }) => {
37
- const [l, p] = L([]);
37
+ const [c, p] = L([]);
38
38
  return S(() => {
39
- const a = () => {
40
- const e = `${Math.random() * 100}%`, n = `${Math.random() * 100}%`, h = Math.random() > 0.5 ? t.first : t.second, x = Math.random() * 2, C = Math.random() * 1 + 0.3, u = Math.random() * 10 + 5;
41
- return { id: `${e}-${n}-${Date.now()}`, x: e, y: n, color: h, delay: x, scale: C, lifespan: u };
39
+ const n = () => {
40
+ const e = `${Math.random() * 100}%`, a = `${Math.random() * 100}%`, h = Math.random() > 0.5 ? t.first : t.second, x = Math.random() * 2, C = Math.random() * 1 + 0.3, u = Math.random() * 10 + 5;
41
+ return { id: `${e}-${a}-${Date.now()}`, x: e, y: a, color: h, delay: x, scale: C, lifespan: u };
42
42
  }, d = () => {
43
- const e = Array.from({ length: s }, a);
43
+ const e = Array.from({ length: s }, n);
44
44
  p(e);
45
45
  }, m = () => {
46
46
  p(
47
- (e) => e.map((n) => n.lifespan <= 0 ? a() : { ...n, lifespan: n.lifespan - 0.1 })
47
+ (e) => e.map((a) => a.lifespan <= 0 ? n() : { ...a, lifespan: a.lifespan - 0.1 })
48
48
  );
49
49
  };
50
50
  d();
@@ -54,13 +54,13 @@ const M = ({ id: i, x: t, y: o, color: s, delay: c, scale: l }) => /* @__PURE__
54
54
  "div",
55
55
  {
56
56
  className: y("xiping-sparkles-text", o),
57
- ...c,
57
+ ...l,
58
58
  style: {
59
59
  "--sparkles-first-color": `${t.first}`,
60
60
  "--sparkles-second-color": `${t.second}`
61
61
  },
62
62
  children: /* @__PURE__ */ g("span", { className: "xiping-sparkles-text-wrapper", children: [
63
- l.map((a) => /* @__PURE__ */ r(M, { ...a }, a.id)),
63
+ c.map((n) => /* @__PURE__ */ r(M, { ...n }, n.id)),
64
64
  /* @__PURE__ */ r("strong", { children: i })
65
65
  ] })
66
66
  }
@@ -0,0 +1 @@
1
+ .xiping-split-parent{overflow:hidden;display:inline-block;white-space:normal}
@@ -4,7 +4,7 @@ import { gsap as i } from "gsap";
4
4
  import { ScrollTrigger as N } from "gsap/ScrollTrigger";
5
5
  import { SplitText as S } from "gsap/SplitText";
6
6
  import j from "clsx";
7
- /* empty css */
7
+ import './SplitText.css';/* empty css */
8
8
  i.registerPlugin(N, S);
9
9
  const A = ({
10
10
  text: l,
@@ -0,0 +1 @@
1
+ .xiping-subtitle-player__current-item{display:flex;flex-direction:column;gap:.25rem;transition:all .2s ease}.xiping-subtitle-player__current-label{font-size:.75rem;font-weight:600;color:#ffffffb3;text-transform:uppercase;letter-spacing:.05em;margin-bottom:.25rem}.xiping-subtitle-player__current-text{font-size:1rem;font-weight:500;text-shadow:0 2px 4px rgba(0,0,0,.5)}.xiping-subtitle-player__current-line{margin:.25rem 0}.xiping-subtitle-player__current-line:first-child{margin-top:0}.xiping-subtitle-player__current-line:last-child{margin-bottom:0}.xiping-subtitle-player__current-hover-layer{position:absolute;inset:0;pointer-events:none}@media(max-width:768px){.xiping-subtitle-player__current-text{font-size:.9rem}}
@@ -15,6 +15,8 @@ export interface CurrentModeProps {
15
15
  overlayNode: React.ReactNode;
16
16
  /** 整条字幕点击处理器 */
17
17
  onSubtitleClick?: (event: React.MouseEvent<HTMLDivElement>, entry: SubtitleEntry, label?: string) => void;
18
+ /** 文本对齐方式 */
19
+ textAlign?: "left" | "center";
18
20
  }
19
21
  /**
20
22
  * 当前模式组件:只显示当前时间对应的字幕
@@ -1,43 +1,78 @@
1
- import { jsxs as p, Fragment as h, jsx as r } from "react/jsx-runtime";
2
- import { renderTextWithWords as x } from "./utils.js";
3
- const N = ({
4
- currentEntries: a,
5
- wordHoverFactory: u,
6
- enableWordHover: d,
7
- overlayNode: c,
8
- onSubtitleClick: t
9
- }) => a.some(({ entry: i }) => i !== null) ? /* @__PURE__ */ p(h, { children: [
10
- a.map(({ entry: i, label: s }, m) => i ? /* @__PURE__ */ p(
11
- "div",
12
- {
13
- className: "xiping-subtitle-player__item",
14
- "data-label": s || void 0,
15
- onClick: t ? (e) => t(e, i, s) : void 0,
16
- style: t ? { cursor: "pointer" } : void 0,
17
- children: [
18
- s && /* @__PURE__ */ r("span", { className: "xiping-subtitle-player__label", children: s }),
19
- /* @__PURE__ */ r("div", { className: "xiping-subtitle-player__text", children: (() => {
20
- let e = 0;
21
- return i.text.split(`
22
- `).map((n, l) => {
23
- if (!i.words || i.words.length === 0)
24
- return /* @__PURE__ */ r("div", { className: "xiping-subtitle-player__line", children: n }, l);
25
- const o = x(
26
- n,
27
- i.words,
28
- e,
29
- l,
30
- d ? u(i, s) : void 0
31
- );
32
- return e = o.nextWordIndex, /* @__PURE__ */ r("div", { className: "xiping-subtitle-player__line", children: o.nodes }, l);
33
- });
34
- })() })
35
- ]
36
- },
37
- m
38
- ) : null),
39
- d && /* @__PURE__ */ r("div", { className: "xiping-subtitle-player__hover-layer", children: c })
1
+ import { jsxs as u, Fragment as v, jsx as r } from "react/jsx-runtime";
2
+ import { renderTextWithWords as g } from "./utils.js";
3
+ import './CurrentMode.css';/* empty css */
4
+ const C = ({
5
+ currentEntries: l,
6
+ wordHoverFactory: p,
7
+ enableWordHover: o,
8
+ overlayNode: a,
9
+ onSubtitleClick: i,
10
+ textAlign: x = "left"
11
+ }) => l.some(({ entry: e }) => e !== null) ? /* @__PURE__ */ u(v, { children: [
12
+ l.map(({ entry: e, label: n }) => {
13
+ if (!e)
14
+ return null;
15
+ const h = e.text.split(`
16
+ `), m = o ? p(e, n) : void 0, _ = h.reduce(
17
+ (t, d, s) => {
18
+ if (!e.words || e.words.length === 0)
19
+ return t.content.push(
20
+ /* @__PURE__ */ r(
21
+ "div",
22
+ {
23
+ className: "xiping-subtitle-player__current-line",
24
+ children: d
25
+ },
26
+ s
27
+ )
28
+ ), t;
29
+ const c = g(
30
+ d,
31
+ e.words,
32
+ t.nextWordIndex,
33
+ s,
34
+ m
35
+ );
36
+ return t.content.push(
37
+ /* @__PURE__ */ r(
38
+ "div",
39
+ {
40
+ className: "xiping-subtitle-player__current-line",
41
+ children: c.nodes
42
+ },
43
+ s
44
+ )
45
+ ), {
46
+ content: t.content,
47
+ nextWordIndex: c.nextWordIndex
48
+ };
49
+ },
50
+ { content: [], nextWordIndex: 0 }
51
+ ).content;
52
+ return /* @__PURE__ */ u(
53
+ "div",
54
+ {
55
+ className: "xiping-subtitle-player__current-item",
56
+ "data-label": n || void 0,
57
+ onClick: i ? (t) => i(t, e, n) : void 0,
58
+ style: i ? { cursor: "pointer" } : void 0,
59
+ children: [
60
+ n && /* @__PURE__ */ r("span", { className: "xiping-subtitle-player__current-label", children: n }),
61
+ /* @__PURE__ */ r(
62
+ "div",
63
+ {
64
+ className: "xiping-subtitle-player__current-text",
65
+ style: { textAlign: x },
66
+ children: _
67
+ }
68
+ )
69
+ ]
70
+ },
71
+ `${e.index}-${n || ""}`
72
+ );
73
+ }),
74
+ o && /* @__PURE__ */ r("div", { className: "xiping-subtitle-player__current-hover-layer", children: a })
40
75
  ] }) : null;
41
76
  export {
42
- N as CurrentMode
77
+ C as CurrentMode
43
78
  };
@@ -0,0 +1 @@
1
+ .xiping-subtitle-player__lyrics-time{font-size:.7rem;font-weight:500;color:#ffffff80;font-family:Monaco,Menlo,Ubuntu Mono,monospace;margin-bottom:.25rem;-webkit-user-select:none;-moz-user-select:none;user-select:none}.xiping-subtitle-player__lyrics-item{display:flex;flex-direction:column;gap:.25rem;transition:all .2s ease}.xiping-subtitle-player__lyrics-item--active{color:#fbbf24;font-weight:600;transition:all .3s ease;position:relative}.xiping-subtitle-player__lyrics-item--active:before{content:"";position:absolute;left:-1rem;top:50%;transform:translateY(-50%);width:4px;height:92%;background:#fbbf24;border-radius:2px}.xiping-subtitle-player__lyrics-item--past{opacity:.5;color:#fff9}.xiping-subtitle-player__lyrics-label{font-size:.75rem;font-weight:600;color:#ffffffb3;text-transform:uppercase;letter-spacing:.05em;margin-bottom:.25rem}.xiping-subtitle-player__lyrics-text{font-size:1rem;font-weight:500;text-shadow:0 2px 4px rgba(0,0,0,.5)}.xiping-subtitle-player__lyrics-line{margin:.25rem 0}.xiping-subtitle-player__lyrics-line:first-child{margin-top:0}.xiping-subtitle-player__lyrics-line:last-child{margin-bottom:0}.xiping-subtitle-player__lyrics-hover-layer{position:absolute;inset:0;pointer-events:none}.xiping-subtitle-player--lyrics{max-height:600px;overflow-y:auto;gap:.5rem;scroll-behavior:smooth}.xiping-subtitle-player--lyrics::-webkit-scrollbar{width:8px}.xiping-subtitle-player--lyrics::-webkit-scrollbar-track{background:#ffffff1a;border-radius:4px}.xiping-subtitle-player--lyrics::-webkit-scrollbar-thumb{background:#ffffff4d;border-radius:4px}.xiping-subtitle-player--lyrics::-webkit-scrollbar-thumb:hover{background:#ffffff80}.xiping-subtitle-player__group{display:flex;flex-direction:column;gap:.5rem;width:100%;border-radius:.5rem;padding:.5rem;margin:-.5rem;transition:all .2s ease}.xiping-subtitle-player__group:hover{background-color:#ffffff1a}.xiping-subtitle-player__group:hover .xiping-subtitle-player__lyrics-item{transform:translate(4px)}.xiping-subtitle-player__group:hover .xiping-subtitle-player__lyrics-item--active{background-color:#fbbf2426}.xiping-subtitle-player__lyrics-item--active .xiping-subtitle-word{color:#fbbf24;font-weight:600}@media(max-width:768px){.xiping-subtitle-player__lyrics-text{font-size:.9rem}}
@@ -21,6 +21,8 @@ export interface LyricsModeProps {
21
21
  containerRef: React.RefObject<HTMLDivElement | null>;
22
22
  /** 整条字幕点击处理器 */
23
23
  onSubtitleClick?: (event: React.MouseEvent<HTMLDivElement>, entry: SubtitleEntry, label?: string) => void;
24
+ /** 文本对齐方式 */
25
+ textAlign?: "left" | "center";
24
26
  }
25
27
  /**
26
28
  * 歌词模式组件:显示全部字幕并高亮当前字幕
@@ -1,81 +1,152 @@
1
- import { jsxs as v, Fragment as j, jsx as s } from "react/jsx-runtime";
2
- import { useRef as F, useEffect as S } from "react";
3
- import W from "clsx";
4
- import { secondsToTimeString as $, renderTextWithWords as A } from "./utils.js";
5
- const P = ({
6
- groupedEntriesByTime: y,
7
- currentTime: o,
8
- wordHoverFactory: N,
9
- enableWordHover: u,
10
- overlayNode: b,
11
- containerRef: n,
12
- onSubtitleClick: c
1
+ import { jsxs as $, Fragment as K, jsx as c } from "react/jsx-runtime";
2
+ import { useRef as W, useMemo as I, useEffect as b, useCallback as j } from "react";
3
+ import A from "clsx";
4
+ import { secondsToTimeString as H, renderTextWithWords as L } from "./utils.js";
5
+ import './LyricsMode.css';/* empty css */
6
+ const M = ({
7
+ entry: t,
8
+ label: s,
9
+ endTime: v,
10
+ currentTime: _,
11
+ isActive: y,
12
+ isFirstItem: u,
13
+ timeString: g,
14
+ textAlign: N,
15
+ enableWordHover: d,
16
+ wordHoverFactory: h,
17
+ onSubtitleClick: n,
18
+ itemRef: e
13
19
  }) => {
14
- const a = F(null);
15
- return S(() => {
16
- if (a.current && n.current) {
17
- const e = n.current, r = a.current, p = r.offsetTop, m = e.clientHeight, t = r.clientHeight, i = p - m / 2 + t / 2;
20
+ const r = _ > v, i = j(
21
+ (m) => {
22
+ n && n(m, t, s);
23
+ },
24
+ [n, t, s]
25
+ ), o = I(
26
+ () => d ? h(t, s) : void 0,
27
+ [d, h, t, s]
28
+ ), l = I(() => t.text.split(`
29
+ `).reduce(
30
+ (p, x, a) => {
31
+ if (!t.words || t.words.length === 0)
32
+ return p.content.push(
33
+ /* @__PURE__ */ c(
34
+ "div",
35
+ {
36
+ className: "xiping-subtitle-player__lyrics-line",
37
+ children: x
38
+ },
39
+ a
40
+ )
41
+ ), p;
42
+ const f = L(
43
+ x,
44
+ t.words,
45
+ p.nextWordIndex,
46
+ a,
47
+ o
48
+ );
49
+ return p.content.push(
50
+ /* @__PURE__ */ c(
51
+ "div",
52
+ {
53
+ className: "xiping-subtitle-player__lyrics-line",
54
+ children: f.nodes
55
+ },
56
+ a
57
+ )
58
+ ), {
59
+ content: p.content,
60
+ nextWordIndex: f.nextWordIndex
61
+ };
62
+ },
63
+ { content: [], nextWordIndex: 0 }
64
+ ).content, [t.text, t.words, o]);
65
+ return /* @__PURE__ */ $(
66
+ "div",
67
+ {
68
+ ref: e,
69
+ className: A("xiping-subtitle-player__lyrics-item", {
70
+ "xiping-subtitle-player__lyrics-item--active": y,
71
+ "xiping-subtitle-player__lyrics-item--past": r
72
+ }),
73
+ "data-label": s || void 0,
74
+ onClick: n ? i : void 0,
75
+ style: n ? { cursor: "pointer" } : void 0,
76
+ children: [
77
+ u && g && /* @__PURE__ */ c("span", { className: "xiping-subtitle-player__lyrics-time", children: g }),
78
+ s && /* @__PURE__ */ c("span", { className: "xiping-subtitle-player__lyrics-label", children: s }),
79
+ /* @__PURE__ */ c(
80
+ "div",
81
+ {
82
+ className: "xiping-subtitle-player__lyrics-text",
83
+ style: { textAlign: N },
84
+ children: l
85
+ }
86
+ )
87
+ ]
88
+ }
89
+ );
90
+ }, q = ({
91
+ groupedEntriesByTime: t,
92
+ currentTime: s,
93
+ wordHoverFactory: v,
94
+ enableWordHover: _,
95
+ overlayNode: y,
96
+ containerRef: u,
97
+ onSubtitleClick: g,
98
+ textAlign: N = "left"
99
+ }) => {
100
+ const d = W(null), h = W(null), n = I(() => {
101
+ for (let e = 0; e < t.length; e++) {
102
+ const r = t[e];
103
+ for (let i = 0; i < r.length; i++) {
104
+ const { startTime: o, endTime: l } = r[i];
105
+ if (s >= o && s <= l)
106
+ return `${e}-${i}`;
107
+ }
108
+ }
109
+ return null;
110
+ }, [t, s]);
111
+ return b(() => {
112
+ if (n && n !== h.current && d.current && u.current) {
113
+ const e = u.current, r = d.current, i = r.offsetTop, o = e.clientHeight, l = r.clientHeight, m = i - o / 2 + l / 2;
18
114
  e.scrollTo({
19
- top: i,
115
+ top: m,
20
116
  behavior: "smooth"
21
- });
117
+ }), h.current = n;
22
118
  }
23
- }, [o, n]), /* @__PURE__ */ v(j, { children: [
24
- y.map((e, r) => {
25
- const p = e[0]?.startTime ?? 0, m = $(p);
26
- return /* @__PURE__ */ s("div", { className: "xiping-subtitle-player__group", children: e.map(({ entry: t, label: i, startTime: T, endTime: _ }, g) => {
27
- const h = o >= T && o <= _, w = o > _, H = g === 0;
28
- let x = 0;
29
- return /* @__PURE__ */ v(
30
- "div",
119
+ }, [n, u]), /* @__PURE__ */ $(K, { children: [
120
+ t.map((e, r) => {
121
+ const i = e[0];
122
+ if (!i)
123
+ return null;
124
+ const o = H(i.startTime);
125
+ return /* @__PURE__ */ c("div", { className: "xiping-subtitle-player__group", children: e.map(({ entry: l, label: m, startTime: p, endTime: x }, a) => {
126
+ const f = s >= p && s <= x, w = `${r}-${a}`;
127
+ return /* @__PURE__ */ c(
128
+ M,
31
129
  {
32
- ref: h ? a : null,
33
- className: W("xiping-subtitle-player__item", {
34
- "xiping-subtitle-player__item--active": h,
35
- "xiping-subtitle-player__item--past": w
36
- }),
37
- "data-label": i || void 0,
38
- onClick: c ? (l) => c(l, t, i) : void 0,
39
- style: c ? { cursor: "pointer" } : void 0,
40
- children: [
41
- H && /* @__PURE__ */ s("span", { className: "xiping-subtitle-player__time", children: m }),
42
- i && /* @__PURE__ */ s("span", { className: "xiping-subtitle-player__label", children: i }),
43
- /* @__PURE__ */ s("div", { className: "xiping-subtitle-player__text", children: t.text.split(`
44
- `).map((l, d) => {
45
- if (!t.words || t.words.length === 0)
46
- return /* @__PURE__ */ s(
47
- "div",
48
- {
49
- className: "xiping-subtitle-player__line",
50
- children: l
51
- },
52
- d
53
- );
54
- const f = A(
55
- l,
56
- t.words,
57
- x,
58
- d,
59
- u ? N(t, i) : void 0
60
- );
61
- return x = f.nextWordIndex, /* @__PURE__ */ s(
62
- "div",
63
- {
64
- className: "xiping-subtitle-player__line",
65
- children: f.nodes
66
- },
67
- d
68
- );
69
- }) })
70
- ]
130
+ entry: l,
131
+ label: m,
132
+ endTime: x,
133
+ currentTime: s,
134
+ isActive: f,
135
+ isFirstItem: a === 0,
136
+ timeString: a === 0 ? o : void 0,
137
+ textAlign: N,
138
+ enableWordHover: _,
139
+ wordHoverFactory: v,
140
+ onSubtitleClick: g,
141
+ itemRef: f ? d : void 0
71
142
  },
72
- `${r}-${g}`
143
+ w
73
144
  );
74
145
  }) }, r);
75
146
  }),
76
- u && /* @__PURE__ */ s("div", { className: "xiping-subtitle-player__hover-layer", children: b })
147
+ _ && /* @__PURE__ */ c("div", { className: "xiping-subtitle-player__lyrics-hover-layer", children: y })
77
148
  ] });
78
149
  };
79
150
  export {
80
- P as LyricsMode
151
+ q as LyricsMode
81
152
  };
@@ -0,0 +1 @@
1
+ .xiping-subtitle-player{display:flex;flex-direction:column;gap:.75rem;padding:1rem;background:#000000bf;border-radius:.5rem;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);color:#fff;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;line-height:1.6;max-width:100%;box-sizing:border-box;position:relative}.xiping-subtitle-player__hover-overlay{position:absolute;transform:translate(-50%,.5rem);z-index:10;pointer-events:auto}.xiping-subtitle-player:has(.xiping-subtitle-player__current-item:only-child){align-items:center}.xiping-subtitle-player:has(.xiping-subtitle-player__current-item:not(:only-child)){align-items:flex-start}.xiping-subtitle-word{display:inline-block;position:relative;transition:all .2s ease;padding:0 .05em;margin:0 .05em;border-radius:2px}.xiping-subtitle-word:hover{background-color:#ffffff1a;transform:translateY(-1px)}.xiping-subtitle-word-before,.xiping-subtitle-word-after{display:inline}@media(max-width:768px){.xiping-subtitle-player{padding:.75rem;font-size:.9rem}}
@@ -19,6 +19,8 @@ export interface SubtitlePlayerProps {
19
19
  currentTime: number;
20
20
  /** 显示模式:'current' 只显示当前字幕,'lyrics' 显示全部字幕并高亮当前 */
21
21
  mode?: SubtitleDisplayMode;
22
+ /** 文本对齐方式:'left' 左对齐,'center' 居中,默认为 'left' */
23
+ textAlign?: "left" | "center";
22
24
  /** 自定义类名 */
23
25
  className?: string;
24
26
  /** 自定义样式 */