@idem.agency/react-player 0.0.6
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.
- package/README.md +30 -0
- package/dist/index-1pgUfxhC.js +60 -0
- package/dist/index-BKNjwSFg.js +76 -0
- package/dist/index-Cu3vJcLM.js +44 -0
- package/dist/index-Dnbs5lXl.js +138 -0
- package/dist/index-DsBO-KZz.js +40 -0
- package/dist/react-player.css +1 -0
- package/dist/react-player.d.ts +35 -0
- package/dist/react-player.js +4 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# React Player
|
|
2
|
+
|
|
3
|
+
`React Player` — компонент для воспроизведения видео.
|
|
4
|
+
Он анализирует переданную ссылку и автоматически выбирает подходящий плеер.
|
|
5
|
+
Если ссылка не поддерживается, используется стандартный HTML-тег `<video>`.
|
|
6
|
+
|
|
7
|
+
## Поддерживаемые плееры
|
|
8
|
+
- **YouTube** — ссылка берётся через кнопку «Поделиться»;
|
|
9
|
+
- **RuTube** — ссылка берётся из атрибута `src` тега `<iframe>`, доступного в коде вставки при выборе «Поделиться»;
|
|
10
|
+
- **VK** — используется прямая ссылка на видео.
|
|
11
|
+
|
|
12
|
+
## Превью
|
|
13
|
+
Можно указать изображение-превью, которое будет отображаться до загрузки плеера.
|
|
14
|
+
|
|
15
|
+
## Стили
|
|
16
|
+
Импорт из /dist/react-player.css
|
|
17
|
+
|
|
18
|
+
## Пропсы
|
|
19
|
+
- preview - ссылка на изображение, необязательно
|
|
20
|
+
- url - ссылка на видео, обязательный
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
type TPlayer = {
|
|
24
|
+
preview?: {
|
|
25
|
+
src: string;
|
|
26
|
+
alt: string;
|
|
27
|
+
};
|
|
28
|
+
url: string;
|
|
29
|
+
}
|
|
30
|
+
```
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { jsx as l } from "react/jsx-runtime";
|
|
2
|
+
import { useRef as s, useImperativeHandle as p, useEffect as y } from "react";
|
|
3
|
+
import { u as f } from "./index-Dnbs5lXl.js";
|
|
4
|
+
const m = (t) => {
|
|
5
|
+
const n = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/, o = t.match(n);
|
|
6
|
+
return o && o[7].length === 11 ? o[7] : "";
|
|
7
|
+
}, w = async () => await new Promise((t) => {
|
|
8
|
+
if (window.YT)
|
|
9
|
+
t(window.YT);
|
|
10
|
+
else {
|
|
11
|
+
const n = "https://www.youtube.com/iframe_api", r = Array.from(document.querySelectorAll("script")).find((e) => e.src === n) ?? document.createElement("script");
|
|
12
|
+
if (r.src) {
|
|
13
|
+
const e = setInterval(() => {
|
|
14
|
+
window.YT?.PlayerState && (t(window.YT), clearInterval(e));
|
|
15
|
+
}, 300);
|
|
16
|
+
setTimeout(() => {
|
|
17
|
+
clearInterval(e);
|
|
18
|
+
}, 6e4);
|
|
19
|
+
} else {
|
|
20
|
+
r.src = n;
|
|
21
|
+
const e = document.getElementsByTagName("script")[0];
|
|
22
|
+
e.parentNode && e.parentNode.insertBefore(r, e), window.onYouTubeIframeAPIReady = () => {
|
|
23
|
+
t(window.YT);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}), Y = ({
|
|
28
|
+
className: t,
|
|
29
|
+
ref: n,
|
|
30
|
+
url: o
|
|
31
|
+
}) => {
|
|
32
|
+
const r = s(null), e = s(null), i = f(), u = (a) => {
|
|
33
|
+
e.current = a.target, i({
|
|
34
|
+
type: "canplay"
|
|
35
|
+
});
|
|
36
|
+
}, d = () => {
|
|
37
|
+
e.current?.playVideo && e.current.playVideo();
|
|
38
|
+
};
|
|
39
|
+
return p(n, () => ({
|
|
40
|
+
play: d
|
|
41
|
+
})), y(() => {
|
|
42
|
+
if (!r.current) return;
|
|
43
|
+
const a = m(o);
|
|
44
|
+
w().then((c) => {
|
|
45
|
+
new c.Player(r.current, {
|
|
46
|
+
width: "100%",
|
|
47
|
+
height: "100%",
|
|
48
|
+
videoId: a,
|
|
49
|
+
events: {
|
|
50
|
+
onReady: u
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}).catch((c) => {
|
|
54
|
+
console.error(c);
|
|
55
|
+
});
|
|
56
|
+
}, []), /* @__PURE__ */ l("div", { className: t, ref: r });
|
|
57
|
+
};
|
|
58
|
+
export {
|
|
59
|
+
Y as default
|
|
60
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { jsx as d } from "react/jsx-runtime";
|
|
2
|
+
import { useRef as a, useImperativeHandle as l, useEffect as u } from "react";
|
|
3
|
+
import { u as p } from "./index-Dnbs5lXl.js";
|
|
4
|
+
const m = async () => new Promise((t, n) => {
|
|
5
|
+
if (window.VK?.VideoPlayer) {
|
|
6
|
+
t(window.VK);
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const o = "https://vk.com/js/api/videoplayer.js";
|
|
10
|
+
if (Array.from(document.scripts).find(
|
|
11
|
+
(r) => r.src === o
|
|
12
|
+
)) {
|
|
13
|
+
const r = setInterval(() => {
|
|
14
|
+
window.VK?.VideoPlayer && (clearInterval(r), t(window.VK));
|
|
15
|
+
}, 300);
|
|
16
|
+
setTimeout(() => {
|
|
17
|
+
clearInterval(r), n(new Error("VK Video API timeout"));
|
|
18
|
+
}, 15e3);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const e = document.createElement("script");
|
|
22
|
+
e.src = o, e.async = !0, e.onload = () => {
|
|
23
|
+
const r = () => {
|
|
24
|
+
window.VK?.VideoPlayer ? t(window.VK) : setTimeout(r, 300);
|
|
25
|
+
};
|
|
26
|
+
r();
|
|
27
|
+
}, e.onerror = () => {
|
|
28
|
+
n(new Error("Failed to load VK Video API"));
|
|
29
|
+
};
|
|
30
|
+
const c = document.getElementsByTagName("script")[0];
|
|
31
|
+
c.parentNode?.insertBefore(e, c);
|
|
32
|
+
}), f = (t) => {
|
|
33
|
+
const n = /^https:\/\/vkvideo\.ru\/video(-\d+)_(\d+)$/, o = t.match(n);
|
|
34
|
+
if (!o)
|
|
35
|
+
throw new Error(`Некорректный формат ссылки ${t}`);
|
|
36
|
+
const i = o[1], e = o[2];
|
|
37
|
+
return `https://vkvideo.ru/video_ext.php?oid=${i}&id=${e}`;
|
|
38
|
+
}, h = ({
|
|
39
|
+
className: t,
|
|
40
|
+
ref: n,
|
|
41
|
+
url: o
|
|
42
|
+
}) => {
|
|
43
|
+
const i = a(null), e = a(null), c = p(), r = () => {
|
|
44
|
+
e.current && e.current.play?.();
|
|
45
|
+
};
|
|
46
|
+
return l(n, () => ({
|
|
47
|
+
play: r
|
|
48
|
+
})), u(() => {
|
|
49
|
+
if (i.current)
|
|
50
|
+
return m().then((s) => {
|
|
51
|
+
e.current = s.VideoPlayer(i.current), c({ type: "canplay" });
|
|
52
|
+
}).catch((s) => {
|
|
53
|
+
console.error(s);
|
|
54
|
+
}), () => {
|
|
55
|
+
e.current && e.current.destroy();
|
|
56
|
+
};
|
|
57
|
+
}, []), /* @__PURE__ */ d(
|
|
58
|
+
"iframe",
|
|
59
|
+
{
|
|
60
|
+
className: t,
|
|
61
|
+
width: "100%",
|
|
62
|
+
height: "100%",
|
|
63
|
+
ref: i,
|
|
64
|
+
src: `${f(o)}&js_api=1`,
|
|
65
|
+
allow: "autoplay; fullscreen; accelerometer; gyroscope; picture-in-picture; encrypted-media",
|
|
66
|
+
"data-testid": "embed-iframe",
|
|
67
|
+
frameBorder: "0",
|
|
68
|
+
scrolling: "no",
|
|
69
|
+
title: "player",
|
|
70
|
+
allowFullScreen: !0
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
export {
|
|
75
|
+
h as default
|
|
76
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsx as y } from "react/jsx-runtime";
|
|
2
|
+
import { u as d, P as t } from "./index-Dnbs5lXl.js";
|
|
3
|
+
import { useRef as i, useImperativeHandle as P } from "react";
|
|
4
|
+
const v = ({
|
|
5
|
+
className: n,
|
|
6
|
+
ref: r,
|
|
7
|
+
url: s
|
|
8
|
+
}) => {
|
|
9
|
+
const e = i(null), o = d(), a = () => {
|
|
10
|
+
o({
|
|
11
|
+
type: t.hideButton
|
|
12
|
+
});
|
|
13
|
+
}, l = () => {
|
|
14
|
+
o({
|
|
15
|
+
type: t.showButton
|
|
16
|
+
});
|
|
17
|
+
}, c = () => {
|
|
18
|
+
o({
|
|
19
|
+
type: t.canplay
|
|
20
|
+
});
|
|
21
|
+
}, u = () => {
|
|
22
|
+
e.current && (a(), e.current.play().catch((p) => {
|
|
23
|
+
console.error(p);
|
|
24
|
+
}));
|
|
25
|
+
};
|
|
26
|
+
return P(r, () => ({
|
|
27
|
+
play: u
|
|
28
|
+
})), /* @__PURE__ */ y(
|
|
29
|
+
"video",
|
|
30
|
+
{
|
|
31
|
+
className: n,
|
|
32
|
+
ref: e,
|
|
33
|
+
controls: !0,
|
|
34
|
+
src: s,
|
|
35
|
+
preload: "auto",
|
|
36
|
+
onPlay: a,
|
|
37
|
+
onPause: l,
|
|
38
|
+
onCanPlay: c
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
export {
|
|
43
|
+
v as default
|
|
44
|
+
};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { jsx as s, jsxs as y } from "react/jsx-runtime";
|
|
2
|
+
import { createContext as d, useContext as v, useReducer as _, lazy as p, useMemo as $, useRef as C } from "react";
|
|
3
|
+
const n = {
|
|
4
|
+
show: "show",
|
|
5
|
+
hide: "hide",
|
|
6
|
+
showButton: "showButton",
|
|
7
|
+
hideButton: "hideButton",
|
|
8
|
+
canplay: "canplay"
|
|
9
|
+
}, P = {
|
|
10
|
+
showButton: !1,
|
|
11
|
+
showPreview: !0,
|
|
12
|
+
canplay: !1
|
|
13
|
+
}, k = (e, t) => {
|
|
14
|
+
const { type: r } = t;
|
|
15
|
+
switch (r) {
|
|
16
|
+
case n.show:
|
|
17
|
+
return { ...e, showButton: !0, showPreview: !0 };
|
|
18
|
+
case n.hide:
|
|
19
|
+
return { ...e, showButton: !1, showPreview: !1 };
|
|
20
|
+
case n.showButton:
|
|
21
|
+
return { ...e, showButton: !0 };
|
|
22
|
+
case n.hideButton:
|
|
23
|
+
return { ...e, showButton: !1 };
|
|
24
|
+
case n.canplay:
|
|
25
|
+
return { ...e, canplay: !0, showButton: !0 };
|
|
26
|
+
default:
|
|
27
|
+
return e;
|
|
28
|
+
}
|
|
29
|
+
}, m = d(P), b = d(() => {
|
|
30
|
+
}), N = ({ children: e }) => {
|
|
31
|
+
const [t, r] = _(k, P);
|
|
32
|
+
return /* @__PURE__ */ s(m.Provider, { value: t, children: /* @__PURE__ */ s(b.Provider, { value: r, children: e }) });
|
|
33
|
+
}, E = () => {
|
|
34
|
+
const e = v(m);
|
|
35
|
+
if (e === void 0)
|
|
36
|
+
throw new Error("usePlayerState нужно использовать внутри PlayerProvider");
|
|
37
|
+
return e;
|
|
38
|
+
}, R = () => {
|
|
39
|
+
const e = v(b);
|
|
40
|
+
if (e === void 0)
|
|
41
|
+
throw new Error("usePlayerDispatch нужно использовать внутри PlayerProvider");
|
|
42
|
+
return e;
|
|
43
|
+
}, S = "idmrp-button-play", T = {
|
|
44
|
+
parent: S
|
|
45
|
+
}, g = ({
|
|
46
|
+
className: e,
|
|
47
|
+
onClick: t
|
|
48
|
+
}) => /* @__PURE__ */ s(
|
|
49
|
+
"button",
|
|
50
|
+
{
|
|
51
|
+
className: [T.parent, e].join(" "),
|
|
52
|
+
type: "button",
|
|
53
|
+
onClick: t
|
|
54
|
+
}
|
|
55
|
+
), c = "idmrp-player-preview", u = {
|
|
56
|
+
parent: c,
|
|
57
|
+
wrapper: `${c}__wrapper`,
|
|
58
|
+
button: `${c}__button`,
|
|
59
|
+
preview: `${c}__preview`,
|
|
60
|
+
player: `${c}__player`
|
|
61
|
+
}, j = ({
|
|
62
|
+
className: e,
|
|
63
|
+
preview: t,
|
|
64
|
+
onPlay: r,
|
|
65
|
+
children: a
|
|
66
|
+
}) => {
|
|
67
|
+
const { showButton: i, showPreview: l, canplay: f } = E(), B = R(), x = () => {
|
|
68
|
+
f && (B({
|
|
69
|
+
type: n.hide
|
|
70
|
+
}), r && r());
|
|
71
|
+
};
|
|
72
|
+
return /* @__PURE__ */ y("div", { className: [u.parent, e].join(" "), children: [
|
|
73
|
+
(i || t && l) && /* @__PURE__ */ y(
|
|
74
|
+
"div",
|
|
75
|
+
{
|
|
76
|
+
className: u.wrapper,
|
|
77
|
+
onClick: x,
|
|
78
|
+
children: [
|
|
79
|
+
i && /* @__PURE__ */ s(
|
|
80
|
+
g,
|
|
81
|
+
{
|
|
82
|
+
className: u.button
|
|
83
|
+
}
|
|
84
|
+
),
|
|
85
|
+
t && l && /* @__PURE__ */ s("img", { className: u.preview, src: t.src, alt: t.alt ?? "preview" })
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
),
|
|
89
|
+
/* @__PURE__ */ s("div", { className: u.player, children: a })
|
|
90
|
+
] });
|
|
91
|
+
}, o = {
|
|
92
|
+
youtube: "youtube",
|
|
93
|
+
rutube: "rutube",
|
|
94
|
+
video: "video",
|
|
95
|
+
vk: "vk"
|
|
96
|
+
}, D = {
|
|
97
|
+
[o.youtube]: p(async () => await import("./index-1pgUfxhC.js")),
|
|
98
|
+
[o.rutube]: p(async () => await import("./index-DsBO-KZz.js")),
|
|
99
|
+
[o.video]: p(async () => await import("./index-Cu3vJcLM.js")),
|
|
100
|
+
[o.vk]: p(async () => await import("./index-BKNjwSFg.js"))
|
|
101
|
+
}, V = (e) => {
|
|
102
|
+
const t = /^(?:https?:\/\/)?(?:m\.|www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/, r = /^(?:https?:\/\/)?(?:rutu\.be\/|rutube\.ru(\/play\/))/, a = /^(?:https?:\/\/)?(?:www\.|m\.)?(?:vk\.com|vkvideo\.ru)\/.+$/;
|
|
103
|
+
return r.test(e) ? o.rutube : t.test(e) ? o.youtube : a.test(e) ? o.vk : o.video;
|
|
104
|
+
}, w = "idmrp-player", h = {
|
|
105
|
+
parent: w,
|
|
106
|
+
player: `${w}__player`
|
|
107
|
+
}, A = ({
|
|
108
|
+
url: e,
|
|
109
|
+
preview: t
|
|
110
|
+
}) => {
|
|
111
|
+
const r = $(() => {
|
|
112
|
+
const l = V(e);
|
|
113
|
+
return D[l];
|
|
114
|
+
}, [e]), a = C(null), i = () => {
|
|
115
|
+
a.current && a.current.play();
|
|
116
|
+
};
|
|
117
|
+
return /* @__PURE__ */ s(
|
|
118
|
+
j,
|
|
119
|
+
{
|
|
120
|
+
className: h.parent,
|
|
121
|
+
preview: t,
|
|
122
|
+
onPlay: i,
|
|
123
|
+
children: /* @__PURE__ */ s(
|
|
124
|
+
r,
|
|
125
|
+
{
|
|
126
|
+
className: h.player,
|
|
127
|
+
ref: a,
|
|
128
|
+
url: e
|
|
129
|
+
}
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
}, Y = (e) => /* @__PURE__ */ s(N, { children: /* @__PURE__ */ s(A, { ...e }) });
|
|
134
|
+
export {
|
|
135
|
+
n as P,
|
|
136
|
+
Y as a,
|
|
137
|
+
R as u
|
|
138
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as i } from "react/jsx-runtime";
|
|
2
|
+
import { u as p } from "./index-Dnbs5lXl.js";
|
|
3
|
+
import { useRef as c, useImperativeHandle as f, useEffect as l } from "react";
|
|
4
|
+
const w = ({
|
|
5
|
+
className: t,
|
|
6
|
+
ref: a,
|
|
7
|
+
url: s
|
|
8
|
+
}) => {
|
|
9
|
+
const e = c(null), n = p(), o = () => {
|
|
10
|
+
e.current && e.current.contentWindow?.postMessage(JSON.stringify({
|
|
11
|
+
type: "player:play",
|
|
12
|
+
data: {}
|
|
13
|
+
}), "*");
|
|
14
|
+
};
|
|
15
|
+
return f(a, () => ({
|
|
16
|
+
play: o
|
|
17
|
+
})), l(() => {
|
|
18
|
+
const r = (u) => {
|
|
19
|
+
if (!e.current) return;
|
|
20
|
+
JSON.parse(u.data).type === "player:ready" && n({ type: "canplay" });
|
|
21
|
+
};
|
|
22
|
+
return window.addEventListener("message", r), () => {
|
|
23
|
+
window.removeEventListener("message", r);
|
|
24
|
+
};
|
|
25
|
+
}, []), /* @__PURE__ */ i(
|
|
26
|
+
"iframe",
|
|
27
|
+
{
|
|
28
|
+
className: t,
|
|
29
|
+
ref: e,
|
|
30
|
+
width: "100%",
|
|
31
|
+
height: "100%",
|
|
32
|
+
src: s,
|
|
33
|
+
allowFullScreen: !0,
|
|
34
|
+
frameBorder: "0"
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
export {
|
|
39
|
+
w as default
|
|
40
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.idmrp-button-play{--idmrp-button-play-size: 3.375rem;--idmrp-button-play-bg: #2D3C31;--idmrp-button-play-triangle-color: #E3DFD7;position:relative;width:var(--idmrp-button-play-size);min-width:var(--idmrp-button-play-size);height:var(--idmrp-button-play-size);background-color:var(--idmrp-button-play-bg);border-radius:50%}.idmrp-button-play:before{content:"";position:absolute;top:50%;left:58%;border:.3125rem solid transparent;border-left:.5625rem solid var(--idmrp-button-play-triangle-color);transform:translate(-50%,-50%)}.idmrp-player-preview{position:relative;width:100%;height:100%;object-fit:cover}.idmrp-player-preview .idmrp-player-preview__wrapper{position:absolute;inset:0;cursor:pointer}.idmrp-player-preview .idmrp-player-preview__button{z-index:2;position:absolute;top:50%;left:50%;transform:translate(-50%) translateY(-50%)}.idmrp-player-preview .idmrp-player-preview__preview{z-index:1;position:absolute;top:0;left:0;width:100%;height:100%;object-fit:cover}.idmrp-player-preview .idmrp-player-preview__player{width:100%;height:100%}.idmrp-player .idmrp-player__player{display:block;width:100%;height:100%;object-fit:cover;object-position:center}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
|
|
3
|
+
declare type FCClass<P = object> = React.FC<P & React.PropsWithChildren & {
|
|
4
|
+
className?: string;
|
|
5
|
+
}>;
|
|
6
|
+
|
|
7
|
+
export declare const Player: FCClass<TPlayer>;
|
|
8
|
+
|
|
9
|
+
export declare type TPlayer = {
|
|
10
|
+
/** Превью для видео */
|
|
11
|
+
preview?: TPlayerPreview['preview'];
|
|
12
|
+
/** Ссылка на видео */
|
|
13
|
+
url: TPlayerBase['url'];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
declare type TPlayerBase = {
|
|
17
|
+
ref: RefObject<TPlayerBaseMethods | null>;
|
|
18
|
+
url: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
declare type TPlayerBaseMethods = {
|
|
22
|
+
play: () => void;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
declare type TPlayerPreview = {
|
|
26
|
+
preview?: {
|
|
27
|
+
/** Адрес изображения */
|
|
28
|
+
src: string;
|
|
29
|
+
/** Альт изображения */
|
|
30
|
+
alt: string;
|
|
31
|
+
};
|
|
32
|
+
onPlay?: () => void;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export { }
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@idem.agency/react-player",
|
|
3
|
+
"version": "0.0.6",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"author": "@barabel324",
|
|
6
|
+
"main": "./dist/react-player.js",
|
|
7
|
+
"types": "./dist/react-player.d.ts",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/react-player.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"dev": "vite",
|
|
21
|
+
"build": "tsc -b && vite build",
|
|
22
|
+
"lint": "eslint .",
|
|
23
|
+
"preview": "vite preview",
|
|
24
|
+
"prepublishOnly": "npm run build"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"react": "19.2.3",
|
|
28
|
+
"react-dom": "19.2.3"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@eslint/js": "9.39.2",
|
|
32
|
+
"@microsoft/api-extractor": "7.55.2",
|
|
33
|
+
"@types/node": "25.0.9",
|
|
34
|
+
"@types/react": "19.2.9",
|
|
35
|
+
"@types/react-dom": "19.2.3",
|
|
36
|
+
"@vitejs/plugin-react": "5.1.2",
|
|
37
|
+
"eslint": "9.39.2",
|
|
38
|
+
"eslint-plugin-react-hooks": "7.0.1",
|
|
39
|
+
"eslint-plugin-react-refresh": "0.4.26",
|
|
40
|
+
"globals": "17.0.0",
|
|
41
|
+
"react": "19.2.3",
|
|
42
|
+
"react-dom": "19.2.3",
|
|
43
|
+
"sass-embedded": "1.97.2",
|
|
44
|
+
"typescript": "5.9.3",
|
|
45
|
+
"typescript-eslint": "8.53.1",
|
|
46
|
+
"unplugin-dts": "1.0.0-beta.6",
|
|
47
|
+
"vite": "7.3.1"
|
|
48
|
+
},
|
|
49
|
+
"gitHead": "0a18b8cd441ad4a319fc8a3b536246b8c42a84be"
|
|
50
|
+
}
|