@shiflo/ui 0.1.2 → 0.1.3
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.
|
@@ -1,35 +1,30 @@
|
|
|
1
|
-
import { jsxs as k, jsx as
|
|
2
|
-
import { useState as
|
|
1
|
+
import { jsxs as k, jsx as m } from "@emotion/react/jsx-runtime";
|
|
2
|
+
import { useState as f, useEffect as j } from "react";
|
|
3
3
|
import { createPortal as v } from "react-dom";
|
|
4
4
|
import { useTheme as x } from "@emotion/react";
|
|
5
5
|
import r from "@emotion/styled";
|
|
6
|
-
import { motion as
|
|
7
|
-
const C = r(
|
|
6
|
+
import { motion as n } from "motion/react";
|
|
7
|
+
const C = r(n.div)`
|
|
8
8
|
position: fixed;
|
|
9
9
|
top: 0;
|
|
10
10
|
left: 0;
|
|
11
11
|
z-index: 1;
|
|
12
|
-
`, A = r(
|
|
12
|
+
`, A = r(n.div)`
|
|
13
13
|
position: fixed;
|
|
14
14
|
top: 0;
|
|
15
15
|
left: 0;
|
|
16
16
|
width: 100%;
|
|
17
17
|
height: 100%;
|
|
18
|
-
|
|
19
|
-
theme: {
|
|
20
|
-
palette: { common: e }
|
|
21
|
-
}
|
|
22
|
-
}) => e.overlay};
|
|
23
|
-
`, w = r(a.div)`
|
|
18
|
+
`, w = r(n.div)`
|
|
24
19
|
position: fixed;
|
|
25
20
|
width: 100%;
|
|
26
21
|
display: flex;
|
|
27
22
|
justify-content: center;
|
|
28
23
|
align-items: center;
|
|
29
24
|
|
|
30
|
-
${({ placement:
|
|
25
|
+
${({ placement: o }) => {
|
|
31
26
|
const t = {};
|
|
32
|
-
switch (
|
|
27
|
+
switch (o) {
|
|
33
28
|
case "top-left":
|
|
34
29
|
Object.assign(t, {
|
|
35
30
|
top: 0,
|
|
@@ -93,56 +88,56 @@ const C = r(a.div)`
|
|
|
93
88
|
return t;
|
|
94
89
|
}}
|
|
95
90
|
`;
|
|
96
|
-
function
|
|
97
|
-
children:
|
|
91
|
+
function P({
|
|
92
|
+
children: o,
|
|
98
93
|
open: t,
|
|
99
|
-
onClose:
|
|
100
|
-
transitionDuration:
|
|
101
|
-
placement:
|
|
94
|
+
onClose: p,
|
|
95
|
+
transitionDuration: a = 0.2,
|
|
96
|
+
placement: b,
|
|
102
97
|
ref: I,
|
|
103
|
-
onClick:
|
|
104
|
-
hideOverlay:
|
|
105
|
-
...
|
|
98
|
+
onClick: d,
|
|
99
|
+
hideOverlay: s,
|
|
100
|
+
...g
|
|
106
101
|
}) {
|
|
107
102
|
const {
|
|
108
|
-
palette: { common:
|
|
109
|
-
} = x(), [
|
|
110
|
-
|
|
103
|
+
palette: { common: i }
|
|
104
|
+
} = x(), [u, c] = f(!0), [h, l] = f(!1), y = (e) => {
|
|
105
|
+
p?.(), d?.(e);
|
|
111
106
|
}, O = () => {
|
|
112
|
-
t ||
|
|
107
|
+
t || c(!0);
|
|
113
108
|
};
|
|
114
109
|
return j(() => {
|
|
115
|
-
let
|
|
116
|
-
return t ? (
|
|
117
|
-
|
|
118
|
-
})) :
|
|
119
|
-
|
|
110
|
+
let e;
|
|
111
|
+
return t ? (c(!1), e = requestAnimationFrame(() => {
|
|
112
|
+
l(!0);
|
|
113
|
+
})) : l(!1), () => {
|
|
114
|
+
e && cancelAnimationFrame(e);
|
|
120
115
|
};
|
|
121
|
-
}, [t,
|
|
116
|
+
}, [t, a]), u ? null : v(
|
|
122
117
|
/* @__PURE__ */ k(C, { children: [
|
|
123
|
-
/* @__PURE__ */
|
|
118
|
+
/* @__PURE__ */ m(
|
|
124
119
|
A,
|
|
125
120
|
{
|
|
126
|
-
initial: { opacity: 0 },
|
|
121
|
+
initial: { opacity: 0, backgroundColor: s ? "rgba(0, 0, 0, 0)" : i.overlay },
|
|
127
122
|
animate: {
|
|
128
123
|
opacity: h ? 1 : 0,
|
|
129
|
-
backgroundColor:
|
|
124
|
+
backgroundColor: s ? "rgba(0, 0, 0, 0)" : i.overlay
|
|
130
125
|
},
|
|
131
126
|
transition: {
|
|
132
127
|
type: "spring",
|
|
133
|
-
duration:
|
|
128
|
+
duration: a,
|
|
134
129
|
bounce: 0.2
|
|
135
130
|
},
|
|
136
131
|
onAnimationComplete: O,
|
|
137
132
|
onClick: y,
|
|
138
|
-
...
|
|
133
|
+
...g
|
|
139
134
|
}
|
|
140
135
|
),
|
|
141
|
-
/* @__PURE__ */
|
|
136
|
+
/* @__PURE__ */ m(w, { placement: b, children: o })
|
|
142
137
|
] }),
|
|
143
138
|
document.body
|
|
144
139
|
);
|
|
145
140
|
}
|
|
146
141
|
export {
|
|
147
|
-
|
|
142
|
+
P as default
|
|
148
143
|
};
|
package/package.json
CHANGED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
import { jsxs as t, jsx as r } from "@emotion/react/jsx-runtime";
|
|
2
|
-
import { useState as P, useRef as k, useEffect as A } from "react";
|
|
3
|
-
import { useTheme as E } from "@emotion/react";
|
|
4
|
-
import { motion as u, AnimatePresence as C } from "motion/react";
|
|
5
|
-
import s from "../Box/Box.mjs";
|
|
6
|
-
import { FPSChecker as I } from "./FPSMonitor.utils.mjs";
|
|
7
|
-
import e from "../Typography/Typography.mjs";
|
|
8
|
-
function J({
|
|
9
|
-
trigger: R = !1,
|
|
10
|
-
duration: g = 5e3,
|
|
11
|
-
updateInterval: y = 10,
|
|
12
|
-
threshold: p = 55,
|
|
13
|
-
onComplete: v,
|
|
14
|
-
on60FPSAchieved: b
|
|
15
|
-
}) {
|
|
16
|
-
const {
|
|
17
|
-
palette: { neutral: x, primary: o, feedback: n, common: W, border: w, gradient: T },
|
|
18
|
-
spacing: l,
|
|
19
|
-
radius: d
|
|
20
|
-
} = E(), [i, f] = P(null), [c, F] = P(null), h = k(!1), m = k(null);
|
|
21
|
-
A(() => {
|
|
22
|
-
if (!h.current)
|
|
23
|
-
return h.current = !0, F(null), f(null), m.current = new I(
|
|
24
|
-
{ duration: g, callbackInterval: y },
|
|
25
|
-
{
|
|
26
|
-
onUpdate: (a) => {
|
|
27
|
-
f(a);
|
|
28
|
-
},
|
|
29
|
-
onComplete: (a) => {
|
|
30
|
-
h.current = !1, f(a), v?.(a);
|
|
31
|
-
const S = a.averageFPS >= p;
|
|
32
|
-
F(S), b?.(S);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
), m.current.start(), () => {
|
|
36
|
-
m.current && h.current && m.current.stop();
|
|
37
|
-
};
|
|
38
|
-
}, [R, g, y, p, b, v]);
|
|
39
|
-
const $ = () => i ? i.averageFPS >= 60 ? o.main : i.averageFPS >= 30 ? o.light : n.error.main : x[500], B = () => i ? i.averageFPS >= 60 ? "60프레임 달성!" : i.averageFPS >= 30 ? "30프레임 이상" : "30프레임 미만" : "측정 대기 중", j = (a) => a >= 60 ? o.main : a >= 30 ? o.light : n.error.main, O = (a) => Math.min(a / 60 * 100, 100);
|
|
40
|
-
return /* @__PURE__ */ t(
|
|
41
|
-
u.div,
|
|
42
|
-
{
|
|
43
|
-
initial: { opacity: 0, y: 10 },
|
|
44
|
-
animate: { opacity: 1, y: 0 },
|
|
45
|
-
transition: { duration: 0.3, ease: "easeOut" },
|
|
46
|
-
style: {
|
|
47
|
-
padding: l[600],
|
|
48
|
-
border: `1px solid ${w.light}`,
|
|
49
|
-
borderRadius: d[600],
|
|
50
|
-
backgroundColor: W.surface,
|
|
51
|
-
boxShadow: `0 2px 8px ${x[100]}15`,
|
|
52
|
-
position: "relative",
|
|
53
|
-
overflow: "hidden"
|
|
54
|
-
},
|
|
55
|
-
children: [
|
|
56
|
-
/* @__PURE__ */ r(
|
|
57
|
-
"div",
|
|
58
|
-
{
|
|
59
|
-
style: {
|
|
60
|
-
position: "absolute",
|
|
61
|
-
top: 0,
|
|
62
|
-
left: 0,
|
|
63
|
-
right: 0,
|
|
64
|
-
height: "2px",
|
|
65
|
-
background: T.primaryToAccent,
|
|
66
|
-
opacity: 0.6
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
),
|
|
70
|
-
/* @__PURE__ */ r(s, { mb: "600", children: /* @__PURE__ */ r(e, { variant: "heading3", fontWeight: 700, color: "primary.main", mb: "400", children: "FPS 모니터" }) }),
|
|
71
|
-
/* @__PURE__ */ r(C, { children: i && /* @__PURE__ */ r(
|
|
72
|
-
u.div,
|
|
73
|
-
{
|
|
74
|
-
initial: { opacity: 0 },
|
|
75
|
-
animate: { opacity: 1 },
|
|
76
|
-
exit: { opacity: 0 },
|
|
77
|
-
transition: { duration: 0.2 },
|
|
78
|
-
children: /* @__PURE__ */ t(s, { mb: "600", children: [
|
|
79
|
-
/* @__PURE__ */ t(
|
|
80
|
-
e,
|
|
81
|
-
{
|
|
82
|
-
variant: "body1",
|
|
83
|
-
fontWeight: 700,
|
|
84
|
-
mb: "400",
|
|
85
|
-
style: { color: $() },
|
|
86
|
-
children: [
|
|
87
|
-
"상태: ",
|
|
88
|
-
B()
|
|
89
|
-
]
|
|
90
|
-
}
|
|
91
|
-
),
|
|
92
|
-
/* @__PURE__ */ t(s, { mb: "500", children: [
|
|
93
|
-
/* @__PURE__ */ t(e, { variant: "small1", color: "text.secondary", mb: "300", children: [
|
|
94
|
-
"현재 FPS: ",
|
|
95
|
-
i.fps.toFixed(1)
|
|
96
|
-
] }),
|
|
97
|
-
/* @__PURE__ */ r(
|
|
98
|
-
s,
|
|
99
|
-
{
|
|
100
|
-
style: {
|
|
101
|
-
height: "8px",
|
|
102
|
-
backgroundColor: o.alpha[10],
|
|
103
|
-
borderRadius: d[150],
|
|
104
|
-
overflow: "hidden",
|
|
105
|
-
position: "relative"
|
|
106
|
-
},
|
|
107
|
-
children: /* @__PURE__ */ r(
|
|
108
|
-
u.div,
|
|
109
|
-
{
|
|
110
|
-
style: {
|
|
111
|
-
height: "100%",
|
|
112
|
-
backgroundColor: j(i.fps),
|
|
113
|
-
borderRadius: d[150],
|
|
114
|
-
position: "relative"
|
|
115
|
-
},
|
|
116
|
-
initial: { width: 0 },
|
|
117
|
-
animate: { width: `${O(i.fps)}%` },
|
|
118
|
-
transition: { duration: 0.4, ease: "easeOut" }
|
|
119
|
-
}
|
|
120
|
-
)
|
|
121
|
-
}
|
|
122
|
-
)
|
|
123
|
-
] }),
|
|
124
|
-
/* @__PURE__ */ t(
|
|
125
|
-
s,
|
|
126
|
-
{
|
|
127
|
-
mb: "600",
|
|
128
|
-
style: {
|
|
129
|
-
display: "grid",
|
|
130
|
-
gridTemplateColumns: "1fr 1fr",
|
|
131
|
-
gap: l[300],
|
|
132
|
-
backgroundColor: o.alpha[5],
|
|
133
|
-
padding: l[400],
|
|
134
|
-
borderRadius: d[400],
|
|
135
|
-
border: `1px solid ${o.alpha[20]}`
|
|
136
|
-
},
|
|
137
|
-
children: [
|
|
138
|
-
/* @__PURE__ */ t("div", { children: [
|
|
139
|
-
/* @__PURE__ */ r(e, { variant: "small1", color: "text.secondary", children: "평균 FPS" }),
|
|
140
|
-
/* @__PURE__ */ r(e, { variant: "body1", fontWeight: 700, color: "text.primary", children: i.averageFPS.toFixed(1) })
|
|
141
|
-
] }),
|
|
142
|
-
/* @__PURE__ */ t("div", { children: [
|
|
143
|
-
/* @__PURE__ */ r(e, { variant: "small1", color: "text.secondary", children: "최소 FPS" }),
|
|
144
|
-
/* @__PURE__ */ r(e, { variant: "body1", fontWeight: 700, color: "text.primary", children: i.minFPS.toFixed(1) })
|
|
145
|
-
] }),
|
|
146
|
-
/* @__PURE__ */ t("div", { children: [
|
|
147
|
-
/* @__PURE__ */ r(e, { variant: "small1", color: "text.secondary", children: "최대 FPS" }),
|
|
148
|
-
/* @__PURE__ */ r(e, { variant: "body1", fontWeight: 700, color: "text.primary", children: i.maxFPS.toFixed(1) })
|
|
149
|
-
] }),
|
|
150
|
-
/* @__PURE__ */ t("div", { children: [
|
|
151
|
-
/* @__PURE__ */ r(e, { variant: "small1", color: "text.secondary", children: "프레임 수" }),
|
|
152
|
-
/* @__PURE__ */ r(e, { variant: "body1", fontWeight: 700, color: "text.primary", children: i.frameCount })
|
|
153
|
-
] }),
|
|
154
|
-
/* @__PURE__ */ t("div", { style: { gridColumn: "1 / -1" }, children: [
|
|
155
|
-
/* @__PURE__ */ r(e, { variant: "small1", color: "text.secondary", children: "측정 시간" }),
|
|
156
|
-
/* @__PURE__ */ t(e, { variant: "body1", fontWeight: 700, color: "text.primary", children: [
|
|
157
|
-
(i.duration / 1e3).toFixed(1),
|
|
158
|
-
"초"
|
|
159
|
-
] })
|
|
160
|
-
] })
|
|
161
|
-
]
|
|
162
|
-
}
|
|
163
|
-
)
|
|
164
|
-
] })
|
|
165
|
-
}
|
|
166
|
-
) }),
|
|
167
|
-
/* @__PURE__ */ r(C, { children: c !== null && /* @__PURE__ */ t(
|
|
168
|
-
u.div,
|
|
169
|
-
{
|
|
170
|
-
initial: { opacity: 0 },
|
|
171
|
-
animate: { opacity: 1 },
|
|
172
|
-
exit: { opacity: 0 },
|
|
173
|
-
transition: { duration: 0.2 },
|
|
174
|
-
style: {
|
|
175
|
-
width: "100%",
|
|
176
|
-
marginTop: l[600],
|
|
177
|
-
padding: l[400],
|
|
178
|
-
backgroundColor: c ? o.alpha[10] : n.error.light,
|
|
179
|
-
border: `1px solid ${c ? o.main : n.error.main}`,
|
|
180
|
-
borderRadius: d[400],
|
|
181
|
-
color: c ? o.main : n.error.dark,
|
|
182
|
-
position: "relative",
|
|
183
|
-
overflow: "hidden"
|
|
184
|
-
},
|
|
185
|
-
children: [
|
|
186
|
-
/* @__PURE__ */ r(e, { variant: "body1", fontWeight: 700, children: c ? "60프레임 달성!" : "60프레임 미달성" }),
|
|
187
|
-
/* @__PURE__ */ t(e, { variant: "small1", mt: "200", style: { opacity: 0.8 }, children: [
|
|
188
|
-
"임계값: ",
|
|
189
|
-
p,
|
|
190
|
-
"fps"
|
|
191
|
-
] })
|
|
192
|
-
]
|
|
193
|
-
}
|
|
194
|
-
) })
|
|
195
|
-
]
|
|
196
|
-
}
|
|
197
|
-
);
|
|
198
|
-
}
|
|
199
|
-
export {
|
|
200
|
-
J as default
|
|
201
|
-
};
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
class u {
|
|
2
|
-
startTime = 0;
|
|
3
|
-
lastTime = 0;
|
|
4
|
-
frameCount = 0;
|
|
5
|
-
fpsHistory = [];
|
|
6
|
-
animationId = null;
|
|
7
|
-
isRunning = !1;
|
|
8
|
-
options;
|
|
9
|
-
onUpdate;
|
|
10
|
-
onComplete;
|
|
11
|
-
constructor(t = {}, e) {
|
|
12
|
-
this.options = {
|
|
13
|
-
duration: t.duration ?? 5e3,
|
|
14
|
-
// 기본 5초
|
|
15
|
-
sampleSize: t.sampleSize ?? 60,
|
|
16
|
-
// 기본 60프레임 샘플
|
|
17
|
-
callbackInterval: t.callbackInterval ?? 10
|
|
18
|
-
// 기본 10프레임마다 콜백
|
|
19
|
-
}, this.onUpdate = e?.onUpdate, this.onComplete = e?.onComplete;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* FPS 측정 시작
|
|
23
|
-
*/
|
|
24
|
-
start() {
|
|
25
|
-
if (this.isRunning) {
|
|
26
|
-
console.warn("FPS 측정이 이미 실행 중입니다.");
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
this.isRunning = !0, this.startTime = performance.now(), this.lastTime = this.startTime, this.frameCount = 0, this.fpsHistory = [], this.animationId = requestAnimationFrame(this.measure.bind(this));
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* FPS 측정 중지
|
|
33
|
-
*/
|
|
34
|
-
stop() {
|
|
35
|
-
if (!this.isRunning)
|
|
36
|
-
throw new Error("FPS 측정이 실행 중이 아닙니다.");
|
|
37
|
-
return this.isRunning = !1, this.animationId && (cancelAnimationFrame(this.animationId), this.animationId = null), this.getMetrics();
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* 현재 측정 중인지 확인
|
|
41
|
-
*/
|
|
42
|
-
get running() {
|
|
43
|
-
return this.isRunning;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* 현재까지의 측정 결과 반환
|
|
47
|
-
*/
|
|
48
|
-
getMetrics() {
|
|
49
|
-
const e = performance.now() - this.startTime, i = this.frameCount > 0 ? this.frameCount / e * 1e3 : 0, h = this.fpsHistory.length > 0 ? this.fpsHistory.reduce((m, o) => m + o, 0) / this.fpsHistory.length : i, s = this.fpsHistory.length > 0 ? Math.min(...this.fpsHistory) : i, r = this.fpsHistory.length > 0 ? Math.max(...this.fpsHistory) : i;
|
|
50
|
-
return {
|
|
51
|
-
fps: i,
|
|
52
|
-
averageFPS: h,
|
|
53
|
-
minFPS: s,
|
|
54
|
-
maxFPS: r,
|
|
55
|
-
frameCount: this.frameCount,
|
|
56
|
-
duration: e
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
measure(t) {
|
|
60
|
-
if (this.isRunning) {
|
|
61
|
-
if (this.frameCount++, t - this.lastTime >= 1e3) {
|
|
62
|
-
const e = this.frameCount / (t - this.startTime) * 1e3;
|
|
63
|
-
this.fpsHistory.push(e), this.fpsHistory.length > this.options.sampleSize && this.fpsHistory.shift(), this.lastTime = t;
|
|
64
|
-
}
|
|
65
|
-
if (this.frameCount % this.options.callbackInterval === 0 && this.onUpdate?.(this.getMetrics()), t - this.startTime >= this.options.duration) {
|
|
66
|
-
this.stop(), this.onComplete?.(this.getMetrics());
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
this.animationId = requestAnimationFrame(this.measure.bind(this));
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
function f(n = 5e3) {
|
|
74
|
-
return new Promise((t) => {
|
|
75
|
-
new u({ duration: n }, { onComplete: t }).start();
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
function p(n, t = {}) {
|
|
79
|
-
const e = new u(t, { onUpdate: n });
|
|
80
|
-
return e.start(), e;
|
|
81
|
-
}
|
|
82
|
-
function l() {
|
|
83
|
-
return new Promise((n, t) => {
|
|
84
|
-
if (!("PerformanceObserver" in window)) {
|
|
85
|
-
t(new Error("PerformanceObserver를 지원하지 않는 브라우저입니다."));
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
const e = new PerformanceObserver((i) => {
|
|
89
|
-
const s = i.getEntries().filter((r) => r.entryType === "frame");
|
|
90
|
-
if (s.length > 0) {
|
|
91
|
-
const r = s.map((a) => a.duration), o = 1e3 / (r.reduce((a, c) => a + c, 0) / r.length);
|
|
92
|
-
e.disconnect(), n({
|
|
93
|
-
fps: o,
|
|
94
|
-
averageFPS: o,
|
|
95
|
-
minFPS: o,
|
|
96
|
-
maxFPS: o,
|
|
97
|
-
frameCount: s.length,
|
|
98
|
-
duration: s[s.length - 1].startTime - s[0].startTime
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
try {
|
|
103
|
-
e.observe({ entryTypes: ["frame"] }), setTimeout(() => {
|
|
104
|
-
e.disconnect(), t(new Error("측정 시간이 초과되었습니다."));
|
|
105
|
-
}, 3e3);
|
|
106
|
-
} catch (i) {
|
|
107
|
-
t(i);
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
export {
|
|
112
|
-
u as FPSChecker,
|
|
113
|
-
f as measureFPS,
|
|
114
|
-
l as measureFPSWithPerformanceAPI,
|
|
115
|
-
p as monitorFPS
|
|
116
|
-
};
|