@shiflo/ui 0.0.19 → 0.1.1
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/dist/components/BottomSheet/BottomSheet.d.ts +1 -1
- package/dist/components/BottomSheet/BottomSheet.mjs +61 -76
- package/dist/components/BottomSheet/BottomSheet.typing.d.ts +4 -2
- package/dist/components/Box/Box.mjs +16 -21
- package/dist/components/Box/Box.typing.d.ts +4 -4
- package/dist/components/Button/Button.d.ts +1 -1
- package/dist/components/Button/Button.mjs +176 -86
- package/dist/components/Button/Button.typing.d.ts +7 -2
- package/dist/components/Dialog/Dialog.d.ts +1 -1
- package/dist/components/Dialog/Dialog.mjs +34 -32
- package/dist/components/Dialog/Dialog.typing.d.ts +3 -2
- package/dist/components/FPSMonitor/FPSMonitor.d.ts +11 -0
- package/dist/components/FPSMonitor/FPSMonitor.mjs +201 -0
- package/dist/components/FPSMonitor/FPSMonitor.utils.d.ts +69 -0
- package/dist/components/FPSMonitor/FPSMonitor.utils.mjs +116 -0
- package/dist/components/FPSMonitor/index.d.ts +3 -0
- package/dist/components/FPSMonitor/index.mjs +4 -0
- package/dist/components/Icon/Icon.d.ts +1 -1
- package/dist/components/Icon/Icon.mjs +2 -2
- package/dist/components/Icon/Icon.typing.d.ts +4 -4
- package/dist/components/Overlay/Overlay.d.ts +1 -1
- package/dist/components/Overlay/Overlay.mjs +45 -42
- package/dist/components/Overlay/Overlay.typing.d.ts +2 -3
- package/dist/components/Snackbar/Snackbar.mjs +64 -60
- package/dist/components/Snackbar/Snackbar.typing.d.ts +3 -3
- package/dist/components/Switch/Switch.d.ts +1 -1
- package/dist/components/Switch/Switch.mjs +53 -40
- package/dist/components/Switch/Switch.typing.d.ts +3 -3
- package/dist/components/Tag/Tag.d.ts +1 -1
- package/dist/components/Tag/Tag.mjs +13 -14
- package/dist/components/Tag/Tag.typing.d.ts +2 -2
- package/dist/components/TextField/TextField.d.ts +1 -1
- package/dist/components/TextField/TextField.mjs +24 -30
- package/dist/components/TextField/TextField.typing.d.ts +3 -3
- package/dist/components/Typography/Typography.mjs +21 -26
- package/dist/components/Typography/Typography.typing.d.ts +4 -4
- package/dist/components/index.d.ts +23 -0
- package/dist/components/index.mjs +24 -0
- package/dist/theme/GlobalStyle.d.ts +1 -1
- package/dist/theme/GlobalStyle.mjs +69 -38
- package/dist/theme/ThemeProvider.d.ts +1 -1
- package/dist/theme/ThemeProvider.mjs +10 -16
- package/dist/theme/dark.d.ts +2 -2
- package/dist/theme/dark.mjs +19 -2
- package/dist/theme/light.d.ts +2 -2
- package/dist/theme/light.mjs +28 -11
- package/dist/theme/typing.d.ts +87 -68
- package/dist/typings/utility.d.ts +3 -2
- package/dist/utils/getUtilityProps.mjs +9 -9
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.mjs +8 -0
- package/package.json +27 -24
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { useState as
|
|
3
|
-
import g from "
|
|
4
|
-
import y from "
|
|
5
|
-
|
|
1
|
+
import { jsx as m } from "@emotion/react/jsx-runtime";
|
|
2
|
+
import { useState as d, useRef as u, useEffect as h } from "react";
|
|
3
|
+
import g from "@emotion/styled";
|
|
4
|
+
import { motion as y } from "motion/react";
|
|
5
|
+
import $ from "../Overlay/Overlay.mjs";
|
|
6
|
+
const x = g(y.div)`
|
|
6
7
|
width: calc(100% - ${({ theme: { spacing: e } }) => e[800]});
|
|
7
8
|
max-width: ${({ maxWidth: e = "375px" }) => e};
|
|
8
9
|
max-height: calc(100% - ${({ theme: { spacing: e } }) => e[800]});
|
|
@@ -15,24 +16,18 @@ const x = g.div`
|
|
|
15
16
|
palette: { common: e }
|
|
16
17
|
}
|
|
17
18
|
}) => e.background};
|
|
18
|
-
transition:
|
|
19
|
-
transform ${({ transitionDuration: e }) => `${e}ms`}
|
|
20
|
-
${({ ease: e }) => e === "in" ? "ease-out" : "ease-in"},
|
|
21
|
-
opacity ${({ transitionDuration: e }) => `${e}ms`}
|
|
22
|
-
${({ ease: e }) => e === "in" ? "ease-out" : "ease-in"},
|
|
23
|
-
background-color 0.2s;
|
|
24
19
|
`;
|
|
25
|
-
function
|
|
20
|
+
function F({
|
|
26
21
|
open: e,
|
|
27
|
-
onClose:
|
|
28
|
-
children:
|
|
29
|
-
transitionDuration: a =
|
|
22
|
+
onClose: l,
|
|
23
|
+
children: n,
|
|
24
|
+
transitionDuration: a = 0.2,
|
|
30
25
|
onClick: o,
|
|
31
|
-
style:
|
|
26
|
+
style: b,
|
|
32
27
|
maxWidth: c = "375px",
|
|
33
|
-
...
|
|
28
|
+
...s
|
|
34
29
|
}) {
|
|
35
|
-
const [r, i] =
|
|
30
|
+
const [r, i] = d(!1), f = u(null), p = (t) => {
|
|
36
31
|
t.stopPropagation(), typeof o == "function" && o(t);
|
|
37
32
|
};
|
|
38
33
|
return h(() => {
|
|
@@ -42,33 +37,40 @@ function O({
|
|
|
42
37
|
}) : i(!1), () => {
|
|
43
38
|
t && cancelAnimationFrame(t);
|
|
44
39
|
};
|
|
45
|
-
}, [e]), /* @__PURE__ */
|
|
46
|
-
|
|
40
|
+
}, [e]), /* @__PURE__ */ m(
|
|
41
|
+
$,
|
|
47
42
|
{
|
|
48
|
-
ref:
|
|
43
|
+
ref: f,
|
|
49
44
|
open: e,
|
|
50
|
-
onClose:
|
|
45
|
+
onClose: l,
|
|
51
46
|
transitionDuration: a,
|
|
52
47
|
placement: "center-middle",
|
|
53
|
-
children: /* @__PURE__ */
|
|
48
|
+
children: /* @__PURE__ */ m(
|
|
54
49
|
x,
|
|
55
50
|
{
|
|
56
|
-
ease: e ? "in" : "out",
|
|
57
51
|
transitionDuration: a,
|
|
58
52
|
maxWidth: c,
|
|
59
|
-
onClick:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
opacity: r ? 1 : 0,
|
|
64
|
-
...l
|
|
53
|
+
onClick: p,
|
|
54
|
+
initial: {
|
|
55
|
+
scale: 0.9,
|
|
56
|
+
opacity: 0
|
|
65
57
|
},
|
|
66
|
-
|
|
58
|
+
animate: {
|
|
59
|
+
scale: r ? 1 : 0.9,
|
|
60
|
+
opacity: r ? 1 : 0
|
|
61
|
+
},
|
|
62
|
+
transition: {
|
|
63
|
+
type: "spring",
|
|
64
|
+
duration: a,
|
|
65
|
+
damping: 10
|
|
66
|
+
},
|
|
67
|
+
...s,
|
|
68
|
+
children: n
|
|
67
69
|
}
|
|
68
70
|
)
|
|
69
71
|
}
|
|
70
72
|
);
|
|
71
73
|
}
|
|
72
74
|
export {
|
|
73
|
-
|
|
75
|
+
F as default
|
|
74
76
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PropsWithChildren } from 'react';
|
|
2
2
|
import { UtilityProps } from '../../typings/utility';
|
|
3
|
-
|
|
3
|
+
import { HTMLMotionProps } from 'motion/react';
|
|
4
|
+
export interface DialogProps extends PropsWithChildren<HTMLMotionProps<"div"> & Pick<UtilityProps, "css">> {
|
|
4
5
|
open?: boolean;
|
|
5
6
|
onClose?: () => void;
|
|
6
7
|
transitionDuration?: number;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FPSMetrics } from './FPSMonitor.utils';
|
|
2
|
+
export interface FPSMonitorProps {
|
|
3
|
+
trigger?: boolean;
|
|
4
|
+
duration?: number;
|
|
5
|
+
updateInterval?: number;
|
|
6
|
+
threshold?: number;
|
|
7
|
+
onComplete?: (metrics: FPSMetrics) => void;
|
|
8
|
+
on60FPSAchieved?: (achieved: boolean) => void;
|
|
9
|
+
}
|
|
10
|
+
declare function FPSMonitor({ trigger, duration, updateInterval, threshold, onComplete, on60FPSAchieved }: FPSMonitorProps): import("@emotion/react/jsx-runtime").JSX.Element;
|
|
11
|
+
export default FPSMonitor;
|
|
@@ -0,0 +1,201 @@
|
|
|
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
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export interface FPSMetrics {
|
|
2
|
+
fps: number;
|
|
3
|
+
averageFPS: number;
|
|
4
|
+
minFPS: number;
|
|
5
|
+
maxFPS: number;
|
|
6
|
+
frameCount: number;
|
|
7
|
+
duration: number;
|
|
8
|
+
}
|
|
9
|
+
export interface FPSOptions {
|
|
10
|
+
/** 측정 지속 시간 (밀리초) */
|
|
11
|
+
duration?: number;
|
|
12
|
+
/** 평균 FPS 계산을 위한 샘플 수 */
|
|
13
|
+
sampleSize?: number;
|
|
14
|
+
/** 콜백 함수 호출 간격 (프레임 수) */
|
|
15
|
+
callbackInterval?: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* requestAnimationFrame을 사용한 FPS 측정기
|
|
19
|
+
*/
|
|
20
|
+
export declare class FPSChecker {
|
|
21
|
+
private startTime;
|
|
22
|
+
private lastTime;
|
|
23
|
+
private frameCount;
|
|
24
|
+
private fpsHistory;
|
|
25
|
+
private animationId;
|
|
26
|
+
private isRunning;
|
|
27
|
+
private options;
|
|
28
|
+
private onUpdate?;
|
|
29
|
+
private onComplete?;
|
|
30
|
+
constructor(options?: FPSOptions, callbacks?: {
|
|
31
|
+
onUpdate?: (metrics: FPSMetrics) => void;
|
|
32
|
+
onComplete?: (metrics: FPSMetrics) => void;
|
|
33
|
+
});
|
|
34
|
+
/**
|
|
35
|
+
* FPS 측정 시작
|
|
36
|
+
*/
|
|
37
|
+
start(): void;
|
|
38
|
+
/**
|
|
39
|
+
* FPS 측정 중지
|
|
40
|
+
*/
|
|
41
|
+
stop(): FPSMetrics;
|
|
42
|
+
/**
|
|
43
|
+
* 현재 측정 중인지 확인
|
|
44
|
+
*/
|
|
45
|
+
get running(): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* 현재까지의 측정 결과 반환
|
|
48
|
+
*/
|
|
49
|
+
getMetrics(): FPSMetrics;
|
|
50
|
+
private measure;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 간단한 FPS 측정 함수
|
|
54
|
+
* @param duration 측정 지속 시간 (밀리초)
|
|
55
|
+
* @returns Promise<FPSMetrics>
|
|
56
|
+
*/
|
|
57
|
+
export declare function measureFPS(duration?: number): Promise<FPSMetrics>;
|
|
58
|
+
/**
|
|
59
|
+
* 실시간 FPS 모니터링 함수
|
|
60
|
+
* @param onUpdate FPS 업데이트 콜백
|
|
61
|
+
* @param options 측정 옵션
|
|
62
|
+
* @returns FPSChecker 인스턴스
|
|
63
|
+
*/
|
|
64
|
+
export declare function monitorFPS(onUpdate: (metrics: FPSMetrics) => void, options?: FPSOptions): FPSChecker;
|
|
65
|
+
/**
|
|
66
|
+
* Performance API를 사용한 프레임레이트 측정
|
|
67
|
+
* 더 정확하지만 브라우저 지원이 제한적
|
|
68
|
+
*/
|
|
69
|
+
export declare function measureFPSWithPerformanceAPI(): Promise<FPSMetrics>;
|
|
@@ -0,0 +1,116 @@
|
|
|
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
|
+
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { IconProps } from './Icon.typing';
|
|
2
|
-
declare function Icon({ ref, name, width, height, ...props }: IconProps): import("react").JSX.Element[] | null | undefined;
|
|
2
|
+
declare function Icon({ ref, name, width, height, ...props }: IconProps): import("@emotion/react/jsx-runtime").JSX.Element[] | null | undefined;
|
|
3
3
|
export default Icon;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { jsx as m } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as m } from "@emotion/react/jsx-runtime";
|
|
2
2
|
import { Children as p, isValidElement as l } from "react";
|
|
3
3
|
import { S as a } from "../../assets/icons/index.ts-Bfm0GTNS.js";
|
|
4
|
-
import c from "
|
|
4
|
+
import c from "@emotion/styled";
|
|
5
5
|
import d from "../../utils/getValueByPath.mjs";
|
|
6
6
|
const f = c.svg`
|
|
7
7
|
transition:
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ComponentPropsWithRef } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { ShifloTheme } from '../../theme/typing';
|
|
3
|
+
import { RecursionPath } from '../../typings/utility';
|
|
4
4
|
import type * as Svgs from "../../assets/icons";
|
|
5
|
-
export interface BaseIconProps
|
|
5
|
+
export interface BaseIconProps {
|
|
6
6
|
name: keyof typeof Svgs;
|
|
7
|
-
color?: RecursionPath<
|
|
7
|
+
color?: RecursionPath<ShifloTheme["palette"]> | "inherit";
|
|
8
8
|
width?: number;
|
|
9
9
|
height?: number;
|
|
10
10
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { OverlayProps } from './Overlay.typing';
|
|
2
|
-
declare function Overlay({ children, open, onClose, transitionDuration, placement,
|
|
2
|
+
declare function Overlay({ children, open, onClose, transitionDuration, placement, ref, onClick, hideOverlay, ...props }: OverlayProps): import('react').ReactPortal | null;
|
|
3
3
|
export default Overlay;
|