@tunjiadeyemi/ui 1.1.0 → 1.3.0
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 +109 -10
- package/dist/index.d.mts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +39 -44
- package/dist/index.mjs +37 -42
- package/dist/styles.css +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,24 +19,33 @@ yarn add @tunjiadeyemi/ui framer-motion lucide-react
|
|
|
19
19
|
First, import the styles in your app's entry point (e.g., `App.tsx` or `main.tsx`):
|
|
20
20
|
|
|
21
21
|
```tsx
|
|
22
|
-
import
|
|
22
|
+
import "@tunjiadeyemi/ui/styles.css";
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
Then use the components:
|
|
26
26
|
|
|
27
27
|
```tsx
|
|
28
|
-
import { Modal } from
|
|
29
|
-
import { useState } from
|
|
28
|
+
import { Modal, Input, Skeleton } from "@tunjiadeyemi/ui";
|
|
29
|
+
import { useState } from "react";
|
|
30
30
|
|
|
31
31
|
function App() {
|
|
32
32
|
const [showModal, setShowModal] = useState(false);
|
|
33
|
+
const [email, setEmail] = useState("");
|
|
33
34
|
|
|
34
35
|
return (
|
|
35
36
|
<>
|
|
37
|
+
<Input
|
|
38
|
+
type="email"
|
|
39
|
+
value={email}
|
|
40
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
41
|
+
placeholder="Enter your email"
|
|
42
|
+
validate={true}
|
|
43
|
+
/>
|
|
44
|
+
|
|
36
45
|
<button onClick={() => setShowModal(true)}>Open Modal</button>
|
|
37
|
-
|
|
38
|
-
<Modal
|
|
39
|
-
showModal={showModal}
|
|
46
|
+
|
|
47
|
+
<Modal
|
|
48
|
+
showModal={showModal}
|
|
40
49
|
onClose={() => setShowModal(false)}
|
|
41
50
|
revealMode="fade"
|
|
42
51
|
className="bg-white p-8 rounded-lg max-w-md"
|
|
@@ -44,24 +53,114 @@ function App() {
|
|
|
44
53
|
<h2 className="text-2xl font-bold mb-4">Modal Title</h2>
|
|
45
54
|
<p>Modal content goes here</p>
|
|
46
55
|
</Modal>
|
|
56
|
+
|
|
57
|
+
<Skeleton width="200px" height="20px" animation="pulse" />
|
|
47
58
|
</>
|
|
48
59
|
);
|
|
49
60
|
}
|
|
50
61
|
```
|
|
51
62
|
|
|
52
|
-
|
|
63
|
+
## Available Components
|
|
53
64
|
|
|
54
|
-
|
|
65
|
+
### Modal
|
|
55
66
|
|
|
56
|
-
A flexible modal component with multiple reveal animations.
|
|
67
|
+
A flexible modal component with multiple reveal animations and optional drag-to-dismiss.
|
|
57
68
|
|
|
58
69
|
**Props:**
|
|
70
|
+
|
|
59
71
|
- `showModal` (boolean): Controls modal visibility
|
|
60
72
|
- `onClose` (function): Callback when modal is closed
|
|
61
|
-
- `revealMode` ('fade' | 'slide-right' | 'slide-bottom'): Animation style
|
|
73
|
+
- `revealMode` ('fade' | 'slide-right' | 'slide-bottom'): Animation style - Default: `'fade'`
|
|
74
|
+
- `isDrag` (boolean): Enable drag to dismiss (for slide-bottom mode) - Default: `false`
|
|
62
75
|
- `className` (string): Custom classes for the modal content
|
|
63
76
|
- `children` (ReactNode): Modal content
|
|
64
77
|
|
|
78
|
+
**Example:**
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
<Modal
|
|
82
|
+
showModal={true}
|
|
83
|
+
onClose={() => console.log("Modal closed")}
|
|
84
|
+
revealMode="slide-bottom"
|
|
85
|
+
isDrag={true}
|
|
86
|
+
className="bg-white p-6 rounded-lg"
|
|
87
|
+
>
|
|
88
|
+
<h2>Your Content</h2>
|
|
89
|
+
</Modal>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Input
|
|
93
|
+
|
|
94
|
+
A customizable input component with built-in validation, password visibility toggle, and OTP support.
|
|
95
|
+
|
|
96
|
+
**Props:**
|
|
97
|
+
|
|
98
|
+
- `type` ('text' | 'email' | 'password' | 'otp' | 'number'): Input type - Default: `'text'`
|
|
99
|
+
- `value` (string): Input value
|
|
100
|
+
- `onChange` (function): Change handler
|
|
101
|
+
- `placeholder` (string): Placeholder text
|
|
102
|
+
- `validate` (boolean): Enable validation - Default: `false`
|
|
103
|
+
- `minLength` (number): Minimum character length
|
|
104
|
+
- `maxLength` (number): Maximum character length
|
|
105
|
+
- `errorMessage` (string): Custom error message
|
|
106
|
+
- `onOtpClick` (function): Callback for OTP button click (when type is 'otp')
|
|
107
|
+
- `className` (string): Additional CSS classes
|
|
108
|
+
- `width` (string): Input width - Default: `'100%'`
|
|
109
|
+
- `height` (string): Input height - Default: `'40px'`
|
|
110
|
+
- `color` (string): Accent color - Default: `'#6B2CE9'`
|
|
111
|
+
- `textColor` (string): Text color - Default: `'white'`
|
|
112
|
+
- `backgroundColor` (string): Background color - Default: `'#1F1F23'`
|
|
113
|
+
- `borderRadius` (string): Border radius - Default: `'10px'`
|
|
114
|
+
|
|
115
|
+
**Example:**
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
<Input
|
|
119
|
+
type="email"
|
|
120
|
+
value={email}
|
|
121
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
122
|
+
placeholder="Enter your email"
|
|
123
|
+
validate={true}
|
|
124
|
+
errorMessage="Please enter a valid email"
|
|
125
|
+
/>
|
|
126
|
+
|
|
127
|
+
<Input
|
|
128
|
+
type="password"
|
|
129
|
+
value={password}
|
|
130
|
+
onChange={(e) => setPassword(e.target.value)}
|
|
131
|
+
minLength={8}
|
|
132
|
+
validate={true}
|
|
133
|
+
/>
|
|
134
|
+
|
|
135
|
+
<Input
|
|
136
|
+
type="otp"
|
|
137
|
+
value={otp}
|
|
138
|
+
onChange={(e) => setOtp(e.target.value)}
|
|
139
|
+
onOtpClick={() => console.log('Send OTP')}
|
|
140
|
+
placeholder="Enter OTP"
|
|
141
|
+
/>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Skeleton
|
|
145
|
+
|
|
146
|
+
A loading placeholder component with multiple variants and animations.
|
|
147
|
+
|
|
148
|
+
**Props:**
|
|
149
|
+
|
|
150
|
+
- `variant` ('text' | 'circular' | 'rectangular'): Skeleton shape - Default: `'rectangular'`
|
|
151
|
+
- `width` (string | number): Width of skeleton - Default: `'100%'`
|
|
152
|
+
- `height` (string | number): Height of skeleton - Default: `'100%'`
|
|
153
|
+
- `animation` ('pulse' | 'wave' | 'none'): Animation type - Default: `'pulse'`
|
|
154
|
+
- `className` (string): Additional CSS classes
|
|
155
|
+
|
|
156
|
+
**Example:**
|
|
157
|
+
|
|
158
|
+
```tsx
|
|
159
|
+
<Skeleton variant="text" width="200px" height="20px" />
|
|
160
|
+
<Skeleton variant="circular" width="50px" height="50px" />
|
|
161
|
+
<Skeleton variant="rectangular" width="100%" height="200px" animation="wave" />
|
|
162
|
+
```
|
|
163
|
+
|
|
65
164
|
## Development
|
|
66
165
|
|
|
67
166
|
```bash
|
package/dist/index.d.mts
CHANGED
|
@@ -13,7 +13,7 @@ interface ModalProps {
|
|
|
13
13
|
declare const Modal: ({ isDrag, showModal, onClose, children, className, revealMode, }: ModalProps) => react_jsx_runtime.JSX.Element;
|
|
14
14
|
|
|
15
15
|
interface TextInputProps {
|
|
16
|
-
type?:
|
|
16
|
+
type?: 'password' | 'otp' | 'text' | 'email' | 'number';
|
|
17
17
|
value?: string;
|
|
18
18
|
onOtpClick?: () => void;
|
|
19
19
|
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
@@ -29,9 +29,11 @@ interface TextInputProps {
|
|
|
29
29
|
borderRadius?: string;
|
|
30
30
|
height?: string;
|
|
31
31
|
width?: string;
|
|
32
|
+
eyeIcon?: React.ReactNode;
|
|
33
|
+
eyeClosedIcon?: React.ReactNode;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
declare const Input: ({ onChange, onOtpClick, validate, type, value, minLength, maxLength, className, placeholder, errorMessage, width, height, color, textColor, borderRadius, backgroundColor, }: TextInputProps) => react_jsx_runtime.JSX.Element;
|
|
36
|
+
declare const Input: ({ onChange, onOtpClick, validate, type, value, minLength, maxLength, className, placeholder, errorMessage, width, height, color, textColor, borderRadius, backgroundColor, eyeIcon, eyeClosedIcon }: TextInputProps) => react_jsx_runtime.JSX.Element;
|
|
35
37
|
|
|
36
38
|
interface SkeletonProps {
|
|
37
39
|
className?: string;
|
|
@@ -43,4 +45,4 @@ interface SkeletonProps {
|
|
|
43
45
|
|
|
44
46
|
declare const Skeleton: ({ className, variant, width, height, animation, }: SkeletonProps) => react_jsx_runtime.JSX.Element;
|
|
45
47
|
|
|
46
|
-
export { Modal, Skeleton
|
|
48
|
+
export { Input, Modal, Skeleton };
|
package/dist/index.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ interface ModalProps {
|
|
|
13
13
|
declare const Modal: ({ isDrag, showModal, onClose, children, className, revealMode, }: ModalProps) => react_jsx_runtime.JSX.Element;
|
|
14
14
|
|
|
15
15
|
interface TextInputProps {
|
|
16
|
-
type?:
|
|
16
|
+
type?: 'password' | 'otp' | 'text' | 'email' | 'number';
|
|
17
17
|
value?: string;
|
|
18
18
|
onOtpClick?: () => void;
|
|
19
19
|
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
@@ -29,9 +29,11 @@ interface TextInputProps {
|
|
|
29
29
|
borderRadius?: string;
|
|
30
30
|
height?: string;
|
|
31
31
|
width?: string;
|
|
32
|
+
eyeIcon?: React.ReactNode;
|
|
33
|
+
eyeClosedIcon?: React.ReactNode;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
declare const Input: ({ onChange, onOtpClick, validate, type, value, minLength, maxLength, className, placeholder, errorMessage, width, height, color, textColor, borderRadius, backgroundColor, }: TextInputProps) => react_jsx_runtime.JSX.Element;
|
|
36
|
+
declare const Input: ({ onChange, onOtpClick, validate, type, value, minLength, maxLength, className, placeholder, errorMessage, width, height, color, textColor, borderRadius, backgroundColor, eyeIcon, eyeClosedIcon }: TextInputProps) => react_jsx_runtime.JSX.Element;
|
|
35
37
|
|
|
36
38
|
interface SkeletonProps {
|
|
37
39
|
className?: string;
|
|
@@ -43,4 +45,4 @@ interface SkeletonProps {
|
|
|
43
45
|
|
|
44
46
|
declare const Skeleton: ({ className, variant, width, height, animation, }: SkeletonProps) => react_jsx_runtime.JSX.Element;
|
|
45
47
|
|
|
46
|
-
export { Modal, Skeleton
|
|
48
|
+
export { Input, Modal, Skeleton };
|
package/dist/index.js
CHANGED
|
@@ -20,9 +20,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
Input: () => Input_default,
|
|
23
24
|
Modal: () => Modal_default,
|
|
24
|
-
Skeleton: () => Skeleton_default
|
|
25
|
-
TextInput: () => Input_default
|
|
25
|
+
Skeleton: () => Skeleton_default
|
|
26
26
|
});
|
|
27
27
|
module.exports = __toCommonJS(index_exports);
|
|
28
28
|
|
|
@@ -138,7 +138,9 @@ var Input = ({
|
|
|
138
138
|
color = "#6B2CE9",
|
|
139
139
|
textColor = "white",
|
|
140
140
|
borderRadius = "10px",
|
|
141
|
-
backgroundColor = "#1F1F23"
|
|
141
|
+
backgroundColor = "#1F1F23",
|
|
142
|
+
eyeIcon = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Eye, { className: "cursor-pointer", size: 18 }),
|
|
143
|
+
eyeClosedIcon = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.EyeClosed, { className: "cursor-pointer", size: 18 })
|
|
142
144
|
}) => {
|
|
143
145
|
const [showPassword, setShowPassword] = (0, import_react.useState)(false);
|
|
144
146
|
const [error, setError] = (0, import_react.useState)(null);
|
|
@@ -226,7 +228,7 @@ var Input = ({
|
|
|
226
228
|
onClick: togglePasswordVisibility,
|
|
227
229
|
className: "absolute right-4 top-1/2 -translate-y-1/2 text-gray-400 hover:text-white transition-colors",
|
|
228
230
|
"aria-label": showPassword ? "Hide password" : "Show password",
|
|
229
|
-
children: showPassword ?
|
|
231
|
+
children: showPassword ? eyeIcon : eyeClosedIcon
|
|
230
232
|
}
|
|
231
233
|
)
|
|
232
234
|
] }),
|
|
@@ -234,44 +236,37 @@ var Input = ({
|
|
|
234
236
|
] });
|
|
235
237
|
} else if (type === "otp") {
|
|
236
238
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { width }, children: [
|
|
237
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
"aria-label": "Resend code",
|
|
269
|
-
children: "Resend code"
|
|
270
|
-
}
|
|
271
|
-
)
|
|
272
|
-
]
|
|
273
|
-
}
|
|
274
|
-
),
|
|
239
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "relative flex items-center gap-4", style: { width: "100%" }, children: [
|
|
240
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
241
|
+
"input",
|
|
242
|
+
{
|
|
243
|
+
type: "number",
|
|
244
|
+
value,
|
|
245
|
+
onChange,
|
|
246
|
+
placeholder,
|
|
247
|
+
style: {
|
|
248
|
+
backgroundColor,
|
|
249
|
+
color: textColor,
|
|
250
|
+
borderRadius,
|
|
251
|
+
height,
|
|
252
|
+
width: "100%"
|
|
253
|
+
},
|
|
254
|
+
className: `border ${error ? "border-red-500" : "border-transparent"} placeholder:text-sm text-sm px-4 pr-28 placeholder:opacity-30 focus:outline-none transition ${className}`,
|
|
255
|
+
onFocus: (e) => !error && (e.target.style.borderColor = color),
|
|
256
|
+
onBlur: (e) => e.target.style.borderColor = error ? "#ef4444" : "transparent"
|
|
257
|
+
}
|
|
258
|
+
),
|
|
259
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
260
|
+
"button",
|
|
261
|
+
{
|
|
262
|
+
type: "button",
|
|
263
|
+
onClick: onOtpClick,
|
|
264
|
+
className: "text-[#A77BFF] cursor-pointer font-medium text-sm w-fit absolute right-4 top-1/2 -translate-y-1/2",
|
|
265
|
+
"aria-label": "Resend code",
|
|
266
|
+
children: "Resend code"
|
|
267
|
+
}
|
|
268
|
+
)
|
|
269
|
+
] }),
|
|
275
270
|
error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-red-500 text-xs mt-1 px-1", children: error })
|
|
276
271
|
] });
|
|
277
272
|
} else {
|
|
@@ -347,7 +342,7 @@ var Skeleton = ({
|
|
|
347
342
|
var Skeleton_default = Skeleton;
|
|
348
343
|
// Annotate the CommonJS export names for ESM import in node:
|
|
349
344
|
0 && (module.exports = {
|
|
345
|
+
Input,
|
|
350
346
|
Modal,
|
|
351
|
-
Skeleton
|
|
352
|
-
TextInput
|
|
347
|
+
Skeleton
|
|
353
348
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -110,7 +110,9 @@ var Input = ({
|
|
|
110
110
|
color = "#6B2CE9",
|
|
111
111
|
textColor = "white",
|
|
112
112
|
borderRadius = "10px",
|
|
113
|
-
backgroundColor = "#1F1F23"
|
|
113
|
+
backgroundColor = "#1F1F23",
|
|
114
|
+
eyeIcon = /* @__PURE__ */ jsx2(Eye, { className: "cursor-pointer", size: 18 }),
|
|
115
|
+
eyeClosedIcon = /* @__PURE__ */ jsx2(EyeClosed, { className: "cursor-pointer", size: 18 })
|
|
114
116
|
}) => {
|
|
115
117
|
const [showPassword, setShowPassword] = useState(false);
|
|
116
118
|
const [error, setError] = useState(null);
|
|
@@ -198,7 +200,7 @@ var Input = ({
|
|
|
198
200
|
onClick: togglePasswordVisibility,
|
|
199
201
|
className: "absolute right-4 top-1/2 -translate-y-1/2 text-gray-400 hover:text-white transition-colors",
|
|
200
202
|
"aria-label": showPassword ? "Hide password" : "Show password",
|
|
201
|
-
children: showPassword ?
|
|
203
|
+
children: showPassword ? eyeIcon : eyeClosedIcon
|
|
202
204
|
}
|
|
203
205
|
)
|
|
204
206
|
] }),
|
|
@@ -206,44 +208,37 @@ var Input = ({
|
|
|
206
208
|
] });
|
|
207
209
|
} else if (type === "otp") {
|
|
208
210
|
return /* @__PURE__ */ jsxs2("div", { style: { width }, children: [
|
|
209
|
-
/* @__PURE__ */ jsxs2(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
"aria-label": "Resend code",
|
|
241
|
-
children: "Resend code"
|
|
242
|
-
}
|
|
243
|
-
)
|
|
244
|
-
]
|
|
245
|
-
}
|
|
246
|
-
),
|
|
211
|
+
/* @__PURE__ */ jsxs2("div", { className: "relative flex items-center gap-4", style: { width: "100%" }, children: [
|
|
212
|
+
/* @__PURE__ */ jsx2(
|
|
213
|
+
"input",
|
|
214
|
+
{
|
|
215
|
+
type: "number",
|
|
216
|
+
value,
|
|
217
|
+
onChange,
|
|
218
|
+
placeholder,
|
|
219
|
+
style: {
|
|
220
|
+
backgroundColor,
|
|
221
|
+
color: textColor,
|
|
222
|
+
borderRadius,
|
|
223
|
+
height,
|
|
224
|
+
width: "100%"
|
|
225
|
+
},
|
|
226
|
+
className: `border ${error ? "border-red-500" : "border-transparent"} placeholder:text-sm text-sm px-4 pr-28 placeholder:opacity-30 focus:outline-none transition ${className}`,
|
|
227
|
+
onFocus: (e) => !error && (e.target.style.borderColor = color),
|
|
228
|
+
onBlur: (e) => e.target.style.borderColor = error ? "#ef4444" : "transparent"
|
|
229
|
+
}
|
|
230
|
+
),
|
|
231
|
+
/* @__PURE__ */ jsx2(
|
|
232
|
+
"button",
|
|
233
|
+
{
|
|
234
|
+
type: "button",
|
|
235
|
+
onClick: onOtpClick,
|
|
236
|
+
className: "text-[#A77BFF] cursor-pointer font-medium text-sm w-fit absolute right-4 top-1/2 -translate-y-1/2",
|
|
237
|
+
"aria-label": "Resend code",
|
|
238
|
+
children: "Resend code"
|
|
239
|
+
}
|
|
240
|
+
)
|
|
241
|
+
] }),
|
|
247
242
|
error && /* @__PURE__ */ jsx2("p", { className: "text-red-500 text-xs mt-1 px-1", children: error })
|
|
248
243
|
] });
|
|
249
244
|
} else {
|
|
@@ -318,7 +313,7 @@ var Skeleton = ({
|
|
|
318
313
|
};
|
|
319
314
|
var Skeleton_default = Skeleton;
|
|
320
315
|
export {
|
|
316
|
+
Input_default as Input,
|
|
321
317
|
Modal_default as Modal,
|
|
322
|
-
Skeleton_default as Skeleton
|
|
323
|
-
Input_default as TextInput
|
|
318
|
+
Skeleton_default as Skeleton
|
|
324
319
|
};
|
package/dist/styles.css
CHANGED