virtual-ui-lib 1.0.37 → 1.0.39

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/index.js CHANGED
@@ -29,6 +29,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
29
  // src/index.js
30
30
  var index_exports = {};
31
31
  __export(index_exports, {
32
+ OtpInput: () => OtpInput,
33
+ StatCard: () => StatCard,
32
34
  ToastNotification: () => ToastNotification
33
35
  });
34
36
  module.exports = __toCommonJS(index_exports);
@@ -126,7 +128,115 @@ var ToastNotification = ({
126
128
  transition: "width 0.1s linear"
127
129
  } })));
128
130
  };
131
+
132
+ // src/components/StatCard/StatCard.jsx
133
+ var import_react2 = __toESM(require("react"));
134
+ var StatCard = ({
135
+ title = "Revenue",
136
+ metric = 1200,
137
+ change = 15,
138
+ bg = "#0f172a",
139
+ accent = "#059669",
140
+ negativeAccent = "#ef4444",
141
+ radius = "16px"
142
+ }) => {
143
+ const [count, setCount] = (0, import_react2.useState)(0);
144
+ (0, import_react2.useEffect)(() => {
145
+ let countUp = 0;
146
+ const interval = setInterval(() => {
147
+ if (countUp < metric) {
148
+ countUp += Math.ceil(metric / 100);
149
+ setCount(countUp);
150
+ } else {
151
+ clearInterval(interval);
152
+ }
153
+ }, 30);
154
+ return () => clearInterval(interval);
155
+ }, [metric]);
156
+ return /* @__PURE__ */ import_react2.default.createElement("div", { style: { background: bg, borderRadius: radius, padding: "24px", width: "300px", color: "white", boxShadow: "0 10px 30px rgba(0,0,0,0.5)", fontFamily: "system-ui, sans-serif", textAlign: "center" } }, /* @__PURE__ */ import_react2.default.createElement("h3", { style: { margin: "0 0 10px", fontSize: "16px", fontWeight: "600" } }, title), /* @__PURE__ */ import_react2.default.createElement("div", { style: { fontSize: "40px", fontWeight: "700" } }, count), /* @__PURE__ */ import_react2.default.createElement("span", { style: {
157
+ display: "inline-block",
158
+ padding: "5px 12px",
159
+ borderRadius: "10px",
160
+ background: change >= 0 ? accent : negativeAccent,
161
+ color: "white",
162
+ fontSize: "14px",
163
+ margin: "10px 0"
164
+ } }, change >= 0 ? "+" + change + "%" : change + "%"), /* @__PURE__ */ import_react2.default.createElement("svg", { style: { marginTop: "12px" }, width: "100%", height: "30", viewBox: "0 0 100 30", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ import_react2.default.createElement("polyline", { fill: "none", stroke: change >= 0 ? accent : negativeAccent, strokeWidth: "2", points: "0,15 10,10 20,20 30,15 40,22 50,8 60,18 70,15 80,18 90,10 100,15" })));
165
+ };
166
+
167
+ // src/components/OtpInput/OtpInput.jsx
168
+ var import_react3 = __toESM(require("react"));
169
+ var OtpInput = ({
170
+ length = 6,
171
+ boxSize = "48px",
172
+ borderColor = "#7c3aed",
173
+ bgColor = "#1e293b",
174
+ textColor = "#f1f5f9",
175
+ radius = "8px",
176
+ onComplete
177
+ }) => {
178
+ const [otp, setOtp] = (0, import_react3.useState)(Array(length).fill(""));
179
+ const inputsRef = (0, import_react3.useRef)([]);
180
+ const handleChange = (index, value) => {
181
+ if (/\d/.test(value) || value === "") {
182
+ const newOtp = [...otp];
183
+ newOtp[index] = value;
184
+ setOtp(newOtp);
185
+ if (value !== "" && index < length - 1) {
186
+ inputsRef.current[index + 1].focus();
187
+ } else if (value === "" && index > 0) {
188
+ inputsRef.current[index - 1].focus();
189
+ }
190
+ if (newOtp.join("").length === length) {
191
+ onComplete(newOtp.join(""));
192
+ }
193
+ }
194
+ };
195
+ const handlePaste = (e) => {
196
+ const pastedData = e.clipboardData.getData("text").slice(0, length).split("");
197
+ const newOtp = Array(length).fill("").map((_, index) => pastedData[index] || "");
198
+ setOtp(newOtp);
199
+ if (newOtp.join("").length === length) {
200
+ onComplete(newOtp.join(""));
201
+ }
202
+ e.preventDefault();
203
+ };
204
+ (0, import_react3.useEffect)(() => {
205
+ inputsRef.current[0].focus();
206
+ }, []);
207
+ return /* @__PURE__ */ import_react3.default.createElement("div", { style: { display: "flex", gap: "10px", justifyContent: "center", padding: "20px", background: bgColor, borderRadius: radius, border: "1px solid rgba(255,255,255,0.1)", boxShadow: "0 4px 20px rgba(0,0,0,0.6)" }, onPaste: handlePaste }, otp.map((value, index) => /* @__PURE__ */ import_react3.default.createElement(
208
+ "input",
209
+ {
210
+ key: index,
211
+ ref: (el) => inputsRef.current[index] = el,
212
+ type: "text",
213
+ maxLength: "1",
214
+ value,
215
+ onChange: (e) => handleChange(index, e.target.value),
216
+ onFocus: (e) => e.target.select(),
217
+ onKeyDown: (e) => {
218
+ if (e.key === "Backspace" && !value && index > 0) {
219
+ inputsRef.current[index - 1].focus();
220
+ }
221
+ },
222
+ style: {
223
+ width: boxSize,
224
+ height: boxSize,
225
+ fontSize: "24px",
226
+ textAlign: "center",
227
+ borderRadius: radius,
228
+ border: `2px solid ${borderColor}`,
229
+ background: bgColor,
230
+ color: textColor,
231
+ transition: "border-color 0.2s",
232
+ outline: "none"
233
+ }
234
+ }
235
+ )), otp.join("").length === length && /* @__PURE__ */ import_react3.default.createElement("span", { style: { color: "#4ade80", fontSize: "20px" } }, "\u2705"));
236
+ };
129
237
  // Annotate the CommonJS export names for ESM import in node:
130
238
  0 && (module.exports = {
239
+ OtpInput,
240
+ StatCard,
131
241
  ToastNotification
132
242
  });
package/dist/index.mjs CHANGED
@@ -91,6 +91,114 @@ var ToastNotification = ({
91
91
  transition: "width 0.1s linear"
92
92
  } })));
93
93
  };
94
+
95
+ // src/components/StatCard/StatCard.jsx
96
+ import React2, { useEffect as useEffect2, useState as useState2 } from "react";
97
+ var StatCard = ({
98
+ title = "Revenue",
99
+ metric = 1200,
100
+ change = 15,
101
+ bg = "#0f172a",
102
+ accent = "#059669",
103
+ negativeAccent = "#ef4444",
104
+ radius = "16px"
105
+ }) => {
106
+ const [count, setCount] = useState2(0);
107
+ useEffect2(() => {
108
+ let countUp = 0;
109
+ const interval = setInterval(() => {
110
+ if (countUp < metric) {
111
+ countUp += Math.ceil(metric / 100);
112
+ setCount(countUp);
113
+ } else {
114
+ clearInterval(interval);
115
+ }
116
+ }, 30);
117
+ return () => clearInterval(interval);
118
+ }, [metric]);
119
+ return /* @__PURE__ */ React2.createElement("div", { style: { background: bg, borderRadius: radius, padding: "24px", width: "300px", color: "white", boxShadow: "0 10px 30px rgba(0,0,0,0.5)", fontFamily: "system-ui, sans-serif", textAlign: "center" } }, /* @__PURE__ */ React2.createElement("h3", { style: { margin: "0 0 10px", fontSize: "16px", fontWeight: "600" } }, title), /* @__PURE__ */ React2.createElement("div", { style: { fontSize: "40px", fontWeight: "700" } }, count), /* @__PURE__ */ React2.createElement("span", { style: {
120
+ display: "inline-block",
121
+ padding: "5px 12px",
122
+ borderRadius: "10px",
123
+ background: change >= 0 ? accent : negativeAccent,
124
+ color: "white",
125
+ fontSize: "14px",
126
+ margin: "10px 0"
127
+ } }, change >= 0 ? "+" + change + "%" : change + "%"), /* @__PURE__ */ React2.createElement("svg", { style: { marginTop: "12px" }, width: "100%", height: "30", viewBox: "0 0 100 30", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ React2.createElement("polyline", { fill: "none", stroke: change >= 0 ? accent : negativeAccent, strokeWidth: "2", points: "0,15 10,10 20,20 30,15 40,22 50,8 60,18 70,15 80,18 90,10 100,15" })));
128
+ };
129
+
130
+ // src/components/OtpInput/OtpInput.jsx
131
+ import React3, { useEffect as useEffect3, useRef, useState as useState3 } from "react";
132
+ var OtpInput = ({
133
+ length = 6,
134
+ boxSize = "48px",
135
+ borderColor = "#7c3aed",
136
+ bgColor = "#1e293b",
137
+ textColor = "#f1f5f9",
138
+ radius = "8px",
139
+ onComplete
140
+ }) => {
141
+ const [otp, setOtp] = useState3(Array(length).fill(""));
142
+ const inputsRef = useRef([]);
143
+ const handleChange = (index, value) => {
144
+ if (/\d/.test(value) || value === "") {
145
+ const newOtp = [...otp];
146
+ newOtp[index] = value;
147
+ setOtp(newOtp);
148
+ if (value !== "" && index < length - 1) {
149
+ inputsRef.current[index + 1].focus();
150
+ } else if (value === "" && index > 0) {
151
+ inputsRef.current[index - 1].focus();
152
+ }
153
+ if (newOtp.join("").length === length) {
154
+ onComplete(newOtp.join(""));
155
+ }
156
+ }
157
+ };
158
+ const handlePaste = (e) => {
159
+ const pastedData = e.clipboardData.getData("text").slice(0, length).split("");
160
+ const newOtp = Array(length).fill("").map((_, index) => pastedData[index] || "");
161
+ setOtp(newOtp);
162
+ if (newOtp.join("").length === length) {
163
+ onComplete(newOtp.join(""));
164
+ }
165
+ e.preventDefault();
166
+ };
167
+ useEffect3(() => {
168
+ inputsRef.current[0].focus();
169
+ }, []);
170
+ return /* @__PURE__ */ React3.createElement("div", { style: { display: "flex", gap: "10px", justifyContent: "center", padding: "20px", background: bgColor, borderRadius: radius, border: "1px solid rgba(255,255,255,0.1)", boxShadow: "0 4px 20px rgba(0,0,0,0.6)" }, onPaste: handlePaste }, otp.map((value, index) => /* @__PURE__ */ React3.createElement(
171
+ "input",
172
+ {
173
+ key: index,
174
+ ref: (el) => inputsRef.current[index] = el,
175
+ type: "text",
176
+ maxLength: "1",
177
+ value,
178
+ onChange: (e) => handleChange(index, e.target.value),
179
+ onFocus: (e) => e.target.select(),
180
+ onKeyDown: (e) => {
181
+ if (e.key === "Backspace" && !value && index > 0) {
182
+ inputsRef.current[index - 1].focus();
183
+ }
184
+ },
185
+ style: {
186
+ width: boxSize,
187
+ height: boxSize,
188
+ fontSize: "24px",
189
+ textAlign: "center",
190
+ borderRadius: radius,
191
+ border: `2px solid ${borderColor}`,
192
+ background: bgColor,
193
+ color: textColor,
194
+ transition: "border-color 0.2s",
195
+ outline: "none"
196
+ }
197
+ }
198
+ )), otp.join("").length === length && /* @__PURE__ */ React3.createElement("span", { style: { color: "#4ade80", fontSize: "20px" } }, "\u2705"));
199
+ };
94
200
  export {
201
+ OtpInput,
202
+ StatCard,
95
203
  ToastNotification
96
204
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "virtual-ui-lib",
3
- "version": "1.0.37",
3
+ "version": "1.0.39",
4
4
  "description": "Virtual UI React Component Library",
5
5
  "author": "Ankush",
6
6
  "license": "ISC",