@zuzjs/ui 0.5.4 → 0.5.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/dist/bin.js +34 -2
- package/dist/comps/accordion.d.ts +12 -0
- package/dist/comps/accordion.js +10 -0
- package/dist/comps/animate.d.ts +1 -1
- package/dist/comps/base.d.ts +4 -13
- package/dist/comps/base.js +3 -2
- package/dist/comps/box.d.ts +5 -2
- package/dist/comps/box.js +7 -3
- package/dist/comps/button.d.ts +4 -5
- package/dist/comps/button.js +14 -3
- package/dist/comps/checkbox.d.ts +1 -1
- package/dist/comps/checkbox.js +19 -0
- package/dist/comps/contextmenu.d.ts +1 -1
- package/dist/comps/cover.d.ts +1 -1
- package/dist/comps/cover.js +15 -0
- package/dist/comps/editor.js +8 -1
- package/dist/comps/form.d.ts +39 -5
- package/dist/comps/form.js +120 -31
- package/dist/comps/grid/index.d.ts +10 -0
- package/dist/comps/grid/index.js +16 -0
- package/dist/comps/heading.d.ts +4 -3
- package/dist/comps/heading.js +12 -6
- package/dist/comps/icon.d.ts +5 -5
- package/dist/comps/icon.js +18 -3
- package/dist/comps/image.d.ts +1 -1
- package/dist/comps/input.d.ts +5 -8
- package/dist/comps/input.js +15 -5
- package/dist/comps/otp/index.d.ts +6 -0
- package/dist/comps/otp/index.js +50 -0
- package/dist/comps/password.d.ts +3 -0
- package/dist/comps/password.js +30 -0
- package/dist/comps/search/index.d.ts +7 -0
- package/dist/comps/search/index.js +46 -0
- package/dist/comps/segmented/index.d.ts +46 -0
- package/dist/comps/segmented/index.js +59 -0
- package/dist/comps/segmented/item.d.ts +8 -0
- package/dist/comps/segmented/item.js +26 -0
- package/dist/comps/select/index.d.ts +15 -0
- package/dist/comps/select/index.js +79 -0
- package/dist/comps/select/select.d.ts +0 -0
- package/dist/comps/select/select.js +1 -0
- package/dist/comps/sheet.d.ts +1 -0
- package/dist/comps/sheet.js +30 -0
- package/dist/comps/span.d.ts +6 -0
- package/dist/comps/span.js +12 -0
- package/dist/comps/spinner.d.ts +1 -1
- package/dist/comps/spinner.js +1 -0
- package/dist/comps/svgicons.d.ts +3 -0
- package/dist/comps/svgicons.js +8 -0
- package/dist/comps/tabview.js +8 -1
- package/dist/comps/textwheel.d.ts +1 -1
- package/dist/comps/textwheel.js +2 -0
- package/dist/comps/useBase/base.types.d.ts +80 -0
- package/dist/comps/useBase/base.types.js +1 -0
- package/dist/comps/useBase/index.d.ts +10 -0
- package/dist/comps/useBase/index.js +62 -0
- package/dist/funs/colors.d.ts +6 -0
- package/dist/funs/colors.js +6 -0
- package/dist/funs/css.d.ts +3 -1
- package/dist/funs/css.js +172 -21
- package/dist/funs/events.d.ts +4 -2
- package/dist/funs/events.js +9 -6
- package/dist/funs/index.d.ts +9 -0
- package/dist/funs/index.js +62 -2
- package/dist/funs/stylesheet.js +15 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useDB.d.ts +25 -0
- package/dist/hooks/useDB.js +101 -0
- package/dist/hooks/useIntersectionObserver.d.ts +1 -1
- package/dist/hooks/useIntersectionObserver.js +28 -11
- package/dist/hooks/useKeyBind.js +1 -0
- package/dist/hooks/useMounted.d.ts +15 -0
- package/dist/hooks/useMounted.js +16 -1
- package/dist/hooks/useToast.d.ts +1 -1
- package/dist/hooks/useToast.js +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +10 -1
- package/dist/styles.css +1 -1
- package/dist/types/enums.d.ts +15 -10
- package/dist/types/enums.js +25 -0
- package/dist/types/interfaces.d.ts +37 -3
- package/package.json +1 -1
- package/dist/comps/select.d.ts +0 -18
- package/dist/comps/select.js +0 -31
package/dist/comps/form.js
CHANGED
|
@@ -1,30 +1,81 @@
|
|
|
1
|
-
"use client";
|
|
2
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { forwardRef, useEffect, useImperativeHandle, useRef, useState
|
|
4
|
-
import
|
|
5
|
-
import
|
|
2
|
+
import { forwardRef, startTransition, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react";
|
|
3
|
+
import Box from "./box";
|
|
4
|
+
import useBase from "./useBase";
|
|
6
5
|
import Sheet from "./sheet";
|
|
7
|
-
import { FORMVALIDATION, SHEET } from "../types/enums";
|
|
8
6
|
import Cover from "./cover";
|
|
7
|
+
import { FORMVALIDATION, SHEET } from "../types/enums";
|
|
8
|
+
import { isEmail, withPost } from "../funs";
|
|
9
|
+
/**
|
|
10
|
+
* {@link Form} is a controlled component designed to handle form data submission, validation, and display of loading or error states.
|
|
11
|
+
* It allows for optional server-side submission through an action endpoint and customizable success/error handling callbacks.
|
|
12
|
+
*
|
|
13
|
+
* The component also provides an interface for controlling loading and error states from a parent component using {@link FormHandler}.
|
|
14
|
+
*
|
|
15
|
+
* @param props - Properties to configure form behavior, validation messages, submission handling, and visual feedback.
|
|
16
|
+
* @param ref - Reference to the {@link FormHandler} interface, exposing methods to control loading and error states from the parent.
|
|
17
|
+
*/
|
|
9
18
|
const Form = forwardRef((props, ref) => {
|
|
10
|
-
const {
|
|
19
|
+
const { name, cover, spinner, errors, action, children, withData, beforeSubmit, onSubmit, onError, onSuccess, ...pops } = props;
|
|
20
|
+
const { className, style, rest } = useBase(pops);
|
|
11
21
|
const [loading, setLoading] = useState(false);
|
|
12
|
-
const [isLoading, startTransition] = useTransition();
|
|
13
|
-
const [sheetType, setSheetType] = useState(SHEET.Default);
|
|
14
22
|
const sheet = useRef(null);
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
23
|
+
const innerRef = useRef(null);
|
|
24
|
+
/**
|
|
25
|
+
* Utility function to select multiple DOM elements within the form based on a CSS query.
|
|
26
|
+
* @param query - CSS selector to match elements inside the form.
|
|
27
|
+
*/
|
|
28
|
+
const _nodes = useCallback((query) => {
|
|
29
|
+
if (innerRef.current)
|
|
30
|
+
return innerRef.current.querySelectorAll(query);
|
|
31
|
+
return [];
|
|
32
|
+
}, [innerRef.current]);
|
|
33
|
+
const _getFields = (el) => {
|
|
34
|
+
return {
|
|
35
|
+
name: el.name || el.getAttribute(`name`) || el.getAttribute(`data-name`),
|
|
36
|
+
required: el.required ? true
|
|
37
|
+
: el.getAttribute(`data-required`) ? el.getAttribute(`data-required`) == `true` : false,
|
|
38
|
+
with: el.with || el.getAttribute(`with`)
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
const _getPinValue = (el) => {
|
|
42
|
+
const _pin = [];
|
|
43
|
+
el.querySelectorAll(`.--input`).forEach((input) => {
|
|
44
|
+
_pin.push(input.value);
|
|
45
|
+
});
|
|
46
|
+
return _pin.join('');
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Validates form fields based on their type and custom attributes.
|
|
50
|
+
*
|
|
51
|
+
* @param el - The element to validate.
|
|
52
|
+
* @returns Whether the element meets the required validation criteria.
|
|
53
|
+
*/
|
|
54
|
+
const _validate = useCallback((el) => {
|
|
55
|
+
const { name: _name, required: _required, with: _with } = _getFields(el);
|
|
56
|
+
if (_required) {
|
|
57
|
+
/**
|
|
58
|
+
* @internal
|
|
59
|
+
* Required field validation */
|
|
19
60
|
if (el.type == `checkbox` && el.checked == false) {
|
|
20
61
|
return false;
|
|
21
62
|
}
|
|
63
|
+
if (el.classList.contains(`--otp`)) {
|
|
64
|
+
const _pin = _getPinValue(el);
|
|
65
|
+
if (_pin == `` || _pin.length < parseInt(el.getAttribute(`data-size`))) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
22
69
|
if (el.classList.contains(`--select`) && el.dataset.value == `-1`) {
|
|
23
70
|
return false;
|
|
24
71
|
}
|
|
25
72
|
if (el.value == ``)
|
|
26
73
|
return false;
|
|
27
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* @internal
|
|
77
|
+
* Additional validation based on `with` attribute
|
|
78
|
+
*/
|
|
28
79
|
if (el.getAttribute(`with`)) {
|
|
29
80
|
let _with = el.getAttribute(`with`);
|
|
30
81
|
if (_with.includes(`@`)) {
|
|
@@ -50,7 +101,7 @@ const Form = forwardRef((props, ref) => {
|
|
|
50
101
|
const _el = document.querySelector(`[name=${field.trim()}]`);
|
|
51
102
|
if (!_el)
|
|
52
103
|
return false;
|
|
53
|
-
console.log(`matching`, _el.name, _el.value, el.name, el.value)
|
|
104
|
+
// console.log(`matching`, _el.name, _el.value, el.name, el.value)
|
|
54
105
|
if (_el && _el.value != el.value) {
|
|
55
106
|
return false;
|
|
56
107
|
}
|
|
@@ -60,47 +111,72 @@ const Form = forwardRef((props, ref) => {
|
|
|
60
111
|
}
|
|
61
112
|
}
|
|
62
113
|
return true;
|
|
63
|
-
};
|
|
64
|
-
|
|
114
|
+
}, [innerRef.current]);
|
|
115
|
+
/**
|
|
116
|
+
* Constructs the form data and validates the fields.
|
|
117
|
+
*
|
|
118
|
+
* @returns Form data object along with validation status and error information.
|
|
119
|
+
*/
|
|
120
|
+
const _buildFormData = useCallback(() => {
|
|
65
121
|
const data = {};
|
|
66
122
|
const payload = {};
|
|
67
123
|
let _error = null;
|
|
68
124
|
let _errorMsg = null;
|
|
69
125
|
Array.from(_nodes(`[name]`))
|
|
70
126
|
.forEach((el) => {
|
|
127
|
+
const { name: _name, required: _required, with: _with } = _getFields(el);
|
|
71
128
|
let valid = true;
|
|
72
|
-
if (
|
|
129
|
+
if (_required || _with)
|
|
73
130
|
valid = _validate(el);
|
|
74
|
-
data[
|
|
131
|
+
data[_name] = {
|
|
75
132
|
valid: valid,
|
|
76
|
-
value: el.classList.contains(`--
|
|
133
|
+
value: el.classList.contains(`--otp`) ? _getPinValue(el)
|
|
134
|
+
: el.classList.contains(`--select`) ? el.dataset.value : el.value
|
|
77
135
|
};
|
|
78
|
-
payload[
|
|
136
|
+
payload[_name] = el.classList.contains(`--otp`) ? _getPinValue(el)
|
|
137
|
+
: el.classList.contains(`--select`) ? el.dataset.value : el.value;
|
|
79
138
|
if (!valid) {
|
|
80
139
|
if (_error == null && errors) {
|
|
81
140
|
_error = el;
|
|
82
|
-
_errorMsg = errors[
|
|
141
|
+
_errorMsg = errors[_name];
|
|
83
142
|
}
|
|
84
143
|
el.classList.add(`input-with-error`);
|
|
85
144
|
}
|
|
86
145
|
else
|
|
87
146
|
el.classList.remove(`input-with-error`);
|
|
88
147
|
});
|
|
89
|
-
if (_error)
|
|
90
|
-
_error
|
|
148
|
+
if (_error) {
|
|
149
|
+
const _nxt = _error;
|
|
150
|
+
if (_nxt.classList.contains(`--otp`)) {
|
|
151
|
+
for (const i of Array.from(_nxt.querySelectorAll(`.--input`))) {
|
|
152
|
+
const input = i;
|
|
153
|
+
if (input.value == ``) {
|
|
154
|
+
input.focus();
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else
|
|
160
|
+
_nxt.focus();
|
|
161
|
+
}
|
|
91
162
|
return {
|
|
92
163
|
error: _error != null,
|
|
93
164
|
errorMsg: _errorMsg || `Fix errors to continue...`,
|
|
94
165
|
data, payload
|
|
95
166
|
};
|
|
96
|
-
};
|
|
97
|
-
|
|
167
|
+
}, [innerRef.current]);
|
|
168
|
+
/**
|
|
169
|
+
* Handler for form submission that validates and processes the form data.
|
|
170
|
+
*/
|
|
171
|
+
const _onSubmit = useCallback(() => {
|
|
98
172
|
const { error, errorMsg, payload } = _buildFormData();
|
|
99
173
|
if (error) {
|
|
100
174
|
sheet.current.show(errorMsg, 4, SHEET.Error);
|
|
101
175
|
}
|
|
102
176
|
else if (action) {
|
|
177
|
+
// If `action` is defined, submit the form data to the specified endpoint
|
|
103
178
|
startTransition(async () => {
|
|
179
|
+
beforeSubmit && beforeSubmit(payload);
|
|
104
180
|
setLoading(true);
|
|
105
181
|
sheet.current.hide();
|
|
106
182
|
withPost(action, { ...payload, ...(withData || {}) })
|
|
@@ -109,11 +185,13 @@ const Form = forwardRef((props, ref) => {
|
|
|
109
185
|
setLoading(false);
|
|
110
186
|
if (onSuccess)
|
|
111
187
|
onSuccess(resp);
|
|
112
|
-
else
|
|
188
|
+
else {
|
|
113
189
|
sheet.current.hide();
|
|
114
|
-
|
|
190
|
+
sheet.current.show(resp.message || `Redirecting..`, 4, SHEET.Success);
|
|
191
|
+
}
|
|
115
192
|
})
|
|
116
193
|
.catch(err => {
|
|
194
|
+
console.warn(`Error occurred while submitting form`, err);
|
|
117
195
|
setLoading(false);
|
|
118
196
|
if (onError)
|
|
119
197
|
onError(err);
|
|
@@ -125,18 +203,21 @@ const Form = forwardRef((props, ref) => {
|
|
|
125
203
|
else {
|
|
126
204
|
onSubmit && onSubmit(payload);
|
|
127
205
|
}
|
|
128
|
-
};
|
|
129
|
-
|
|
206
|
+
}, [action, sheet.current, innerRef.current]);
|
|
207
|
+
/**
|
|
208
|
+
* Initializes the form by adding click event listeners to submit buttons.
|
|
209
|
+
*/
|
|
210
|
+
const _init = useCallback(() => {
|
|
130
211
|
const _submit = _nodes(`[type=submit]`);
|
|
131
212
|
if (!_submit || _submit.length == 0) {
|
|
132
|
-
console.
|
|
213
|
+
console.warn(`You should add at least 1 button with type=\`SUBMIT\``);
|
|
133
214
|
}
|
|
134
215
|
else {
|
|
135
216
|
_submit.forEach(el => {
|
|
136
217
|
el.addEventListener(`click`, _onSubmit);
|
|
137
218
|
});
|
|
138
219
|
}
|
|
139
|
-
};
|
|
220
|
+
}, [innerRef.current]);
|
|
140
221
|
useImperativeHandle(ref, () => ({
|
|
141
222
|
setLoading(mod) {
|
|
142
223
|
if (mod) {
|
|
@@ -149,9 +230,17 @@ const Form = forwardRef((props, ref) => {
|
|
|
149
230
|
},
|
|
150
231
|
hideError() {
|
|
151
232
|
sheet.current.hide();
|
|
233
|
+
},
|
|
234
|
+
init() {
|
|
235
|
+
_init();
|
|
152
236
|
}
|
|
153
237
|
}));
|
|
154
238
|
useEffect(_init, []);
|
|
155
|
-
return _jsxs(
|
|
239
|
+
return _jsxs(Box, { ...{
|
|
240
|
+
className: `${className} rel --form${name ? `-${name.replace(/\s+/g, `-`)}` : ``}`,
|
|
241
|
+
style,
|
|
242
|
+
propsToRemove: [`withData`, `action`, `onSubmit`, `onSuccess`, `onError`],
|
|
243
|
+
...rest
|
|
244
|
+
}, ref: innerRef, children: [_jsx(Sheet, { ref: sheet, as: `toast-form` }), loading && _jsx(Cover, { message: cover ? cover.message || undefined : `working`, ...{ spinner, color: cover ? `color` in cover ? cover.color : `#ffffff` : `#ffffff` } }), children] });
|
|
156
245
|
});
|
|
157
246
|
export default Form;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Props } from "../useBase/base.types";
|
|
2
|
+
export declare enum GRID {
|
|
3
|
+
Default = 0
|
|
4
|
+
}
|
|
5
|
+
declare const Grid: import("react").ForwardRefExoticComponent<Props<"div"> & {
|
|
6
|
+
rows?: number;
|
|
7
|
+
cols?: number;
|
|
8
|
+
gap?: number;
|
|
9
|
+
} & import("react").RefAttributes<HTMLInputElement>>;
|
|
10
|
+
export default Grid;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import Box from "../box";
|
|
4
|
+
import useBase from "../useBase";
|
|
5
|
+
export var GRID;
|
|
6
|
+
(function (GRID) {
|
|
7
|
+
GRID[GRID["Default"] = 0] = "Default";
|
|
8
|
+
})(GRID || (GRID = {}));
|
|
9
|
+
const Grid = forwardRef((props, ref) => {
|
|
10
|
+
const { animate, children, rows, cols, gap, ...pops } = props;
|
|
11
|
+
const { className, style } = useBase(props);
|
|
12
|
+
return _jsx(Box, { style: style, ...{
|
|
13
|
+
className: `--grid grid ${className}`.trim()
|
|
14
|
+
}, children: children });
|
|
15
|
+
});
|
|
16
|
+
export default Grid;
|
package/dist/comps/heading.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { Props } from "./useBase/base.types";
|
|
3
|
+
export interface HeadingProps extends Props<"h1" | "h2" | "h3" | "h4" | "h5" | "h6"> {
|
|
4
4
|
h?: number | string;
|
|
5
5
|
html?: ReactNode | string;
|
|
6
|
-
}
|
|
6
|
+
}
|
|
7
|
+
declare const Heading: import("react").ForwardRefExoticComponent<HeadingProps & import("react").RefAttributes<HTMLHeadingElement>>;
|
|
7
8
|
export default Heading;
|
package/dist/comps/heading.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef } from "react";
|
|
3
|
-
import
|
|
2
|
+
import { createElement, forwardRef } from "react";
|
|
3
|
+
import useBase from "./useBase";
|
|
4
4
|
const Heading = forwardRef((props, ref) => {
|
|
5
|
-
const {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
const { h, html, children, ...pops } = props;
|
|
6
|
+
const { className, style, rest } = useBase(pops);
|
|
7
|
+
const Tag = `h${h || 1}`;
|
|
8
|
+
return createElement(Tag, {
|
|
9
|
+
ref,
|
|
10
|
+
style,
|
|
11
|
+
className,
|
|
12
|
+
...rest,
|
|
13
|
+
children: html ? _jsx("span", { ...{ dangerouslySetInnerHTML: { __html: html } } }) : children
|
|
14
|
+
});
|
|
9
15
|
});
|
|
10
16
|
export default Heading;
|
package/dist/comps/icon.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { Props } from "./useBase/base.types";
|
|
2
|
+
export interface IconProps extends Props<`div`> {
|
|
3
3
|
name: string;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
pathCount?: number;
|
|
5
|
+
}
|
|
6
|
+
declare const Icon: import("react").ForwardRefExoticComponent<IconProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
7
7
|
export default Icon;
|
package/dist/comps/icon.js
CHANGED
|
@@ -1,8 +1,23 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef } from "react";
|
|
3
|
-
import With from "./base";
|
|
3
|
+
// import With, { Props } from "./base";
|
|
4
|
+
import Box from "./box";
|
|
5
|
+
import useBase from "./useBase";
|
|
6
|
+
import Span from "./span";
|
|
4
7
|
const Icon = forwardRef((props, ref) => {
|
|
5
|
-
const {
|
|
6
|
-
|
|
8
|
+
const { name, pathCount, ...pops } = props;
|
|
9
|
+
const { className, style, rest } = useBase(pops);
|
|
10
|
+
return _jsx(Box, { ...{
|
|
11
|
+
className: `${className} icon-${name}`,
|
|
12
|
+
style,
|
|
13
|
+
...rest
|
|
14
|
+
}, children: Array(pathCount || 0).fill(0).map((p, i) => _jsx(Span, { ...{
|
|
15
|
+
className: `path${i + 1}`
|
|
16
|
+
} }, `${name}-layer-${i}`)) });
|
|
17
|
+
// return <With
|
|
18
|
+
// className={`icon-${name}`}
|
|
19
|
+
// as={as}
|
|
20
|
+
// {...rest}
|
|
21
|
+
// ref={ref} />
|
|
7
22
|
});
|
|
8
23
|
export default Icon;
|
package/dist/comps/image.d.ts
CHANGED
package/dist/comps/input.d.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
as?: string;
|
|
7
|
-
animate?: animationProps;
|
|
8
|
-
} & Omit<import("react").DetailedHTMLProps<import("react").InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & import("react").RefAttributes<HTMLInputElement>>;
|
|
1
|
+
import { Props } from "./useBase/base.types";
|
|
2
|
+
export interface InputProps extends Props<`input`> {
|
|
3
|
+
numeric?: boolean;
|
|
4
|
+
}
|
|
5
|
+
declare const Input: import("react").ForwardRefExoticComponent<InputProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
9
6
|
export default Input;
|
package/dist/comps/input.js
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef } from "react";
|
|
3
|
-
import
|
|
2
|
+
import { forwardRef, useEffect } from "react";
|
|
3
|
+
import useBase from "./useBase";
|
|
4
4
|
const Input = forwardRef((props, ref) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
/**
|
|
6
|
+
* @internal
|
|
7
|
+
* const _innerRef = useRef<HTMLInputElement>(null)
|
|
8
|
+
*/
|
|
9
|
+
const { numeric, ...pops } = props;
|
|
10
|
+
const handleInput = (event) => {
|
|
11
|
+
if (numeric) {
|
|
12
|
+
event.currentTarget.value = event.currentTarget.value.replace(/[^0-9.]/g, '').replace(/(\..*?)\..*/g, '$1');
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const { className, style, rest } = useBase(pops);
|
|
16
|
+
useEffect(() => { }, []);
|
|
17
|
+
return _jsx("input", { className: `${className} --input`, style: style, ref: ref, onInput: handleInput, ...rest });
|
|
8
18
|
});
|
|
9
19
|
export default Input;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useEffect, useRef } from "react";
|
|
3
|
+
import Input from "../input";
|
|
4
|
+
import Box from "../box";
|
|
5
|
+
import useBase from "../useBase";
|
|
6
|
+
const OTP = forwardRef((props, ref) => {
|
|
7
|
+
const { animate, size, mask, ...pops } = props;
|
|
8
|
+
const { style } = useBase(props);
|
|
9
|
+
const inputs = useRef([]);
|
|
10
|
+
let name = `pinput`;
|
|
11
|
+
let required = false;
|
|
12
|
+
if (`type` in pops) {
|
|
13
|
+
delete pops.type;
|
|
14
|
+
}
|
|
15
|
+
if (`name` in pops) {
|
|
16
|
+
name = pops.name;
|
|
17
|
+
delete pops.name;
|
|
18
|
+
}
|
|
19
|
+
if (`required` in pops) {
|
|
20
|
+
required = true;
|
|
21
|
+
delete pops.required;
|
|
22
|
+
}
|
|
23
|
+
const handleInput = (event) => {
|
|
24
|
+
const input = event.currentTarget;
|
|
25
|
+
const nextInput = inputs.current[parseInt(input.dataset.index) + 1];
|
|
26
|
+
const prevInput = inputs.current[parseInt(input.dataset.index) - 1];
|
|
27
|
+
if (input.value.length === 1 && nextInput) {
|
|
28
|
+
nextInput.focus();
|
|
29
|
+
}
|
|
30
|
+
else if (input.value.length === 0 && prevInput) {
|
|
31
|
+
prevInput.focus();
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
inputs.current = inputs.current.slice(0, size);
|
|
36
|
+
}, [size]);
|
|
37
|
+
return _jsx(Box, { ...{ name }, "data-required": required, "data-size": size || 4, style: style, ...{
|
|
38
|
+
className: `--otp flex aic rel`
|
|
39
|
+
}, children: Array(size || 4).fill(1).map((a, i) => _jsx(Input, { "data-index": i, ref: (el) => {
|
|
40
|
+
inputs.current[i] = el;
|
|
41
|
+
}, ...{
|
|
42
|
+
numeric: true,
|
|
43
|
+
onChange: handleInput,
|
|
44
|
+
maxLength: 1,
|
|
45
|
+
placeholder: `0`,
|
|
46
|
+
type: mask ? `password` : 'text',
|
|
47
|
+
...pops
|
|
48
|
+
} }, `pin-${i}`)) });
|
|
49
|
+
});
|
|
50
|
+
export default OTP;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useState } from "react";
|
|
3
|
+
import Input from "./input";
|
|
4
|
+
import Box from "./box";
|
|
5
|
+
import Button from "./button";
|
|
6
|
+
import useBase from "./useBase";
|
|
7
|
+
const Icons = {
|
|
8
|
+
on: _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", children: [_jsx("path", { fill: "#333", d: "M12 20.5c-4.299 0-8.24-3.023-10.544-8.086a1 1 0 010-.828C3.759 6.523 7.701 3.5 12 3.5s8.24 3.023 10.544 8.086a1.001 1.001 0 010 .828 18.14 18.14 0 01-1.391 2.52 1 1 0 11-1.666-1.106A15.87 15.87 0 0020.529 12C18.543 7.92 15.379 5.5 12 5.5S5.457 7.92 3.471 12c1.986 4.08 5.15 6.5 8.529 6.5a7.964 7.964 0 005.036-1.92 1 1 0 111.265 1.55A9.94 9.94 0 0112 20.5z" }), _jsx("path", { fill: "#333", d: "M12 16a4.004 4.004 0 01-3.929-4.756 1 1 0 011.965.375A2 2 0 1014 12a2.034 2.034 0 00-2.053-1.999 1.04 1.04 0 01-1.043-.947.963.963 0 01.902-1.05L12 8a4 4 0 010 8z" })] }),
|
|
9
|
+
off: _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", children: [_jsx("path", { fill: "#333", d: "M12 15c-4.132 0-7.98-1.214-10.294-3.249a1 1 0 111.32-1.502C4.986 11.972 8.34 13 12 13s7.014-1.028 8.974-2.751a1 1 0 111.32 1.502C19.98 13.786 16.132 15 12 15z" }), _jsx("path", { fill: "#333", d: "M12 18a1 1 0 01-1-1v-3a1 1 0 012 0v3a1 1 0 01-1 1zM7.749 17.667a.964.964 0 01-.17-.014 1 1 0 01-.817-1.155l.505-2.935a1 1 0 111.97.339l-.504 2.935a1 1 0 01-.984.83zM3.636 16.306a1.001 1.001 0 01-.942-1.336l.978-2.745a1 1 0 111.884.672l-.978 2.745a1 1 0 01-.942.664zM16.251 17.667a1 1 0 01-.984-.83l-.505-2.935a1 1 0 011.97-.339l.506 2.935a1 1 0 01-.816 1.155.964.964 0 01-.17.014zM20.364 16.306a1 1 0 01-.942-.664l-.978-2.745a1 1 0 111.884-.672l.978 2.745a1.001 1.001 0 01-.942 1.336z" })] })
|
|
10
|
+
};
|
|
11
|
+
const Password = forwardRef((props, ref) => {
|
|
12
|
+
const [visible, setVisible] = useState(false);
|
|
13
|
+
const { animate, ...pops } = props;
|
|
14
|
+
const { style } = useBase(props);
|
|
15
|
+
if (`type` in props) {
|
|
16
|
+
delete props[`type`];
|
|
17
|
+
}
|
|
18
|
+
return _jsxs(Box, { style: style, ...{
|
|
19
|
+
className: `--password flex aic rel`
|
|
20
|
+
}, children: [_jsx(Input, { ...{
|
|
21
|
+
ref,
|
|
22
|
+
type: visible ? 'text' : 'password',
|
|
23
|
+
...pops
|
|
24
|
+
} }), _jsx(Button, { ...{
|
|
25
|
+
tabIndex: -1,
|
|
26
|
+
onClick: e => setVisible(prev => !prev),
|
|
27
|
+
className: `--toggle flex aic jcc abs`
|
|
28
|
+
}, children: visible ? Icons.on : Icons.off })] });
|
|
29
|
+
});
|
|
30
|
+
export default Password;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Props } from "../useBase/base.types";
|
|
2
|
+
declare const Search: import("react").ForwardRefExoticComponent<Props<"input"> & {
|
|
3
|
+
onSubmit?: (value: string) => void;
|
|
4
|
+
onChange?: (value: string) => void;
|
|
5
|
+
withStyle?: string;
|
|
6
|
+
} & import("react").RefAttributes<HTMLInputElement>>;
|
|
7
|
+
export default Search;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useEffect, useRef, useState } from "react";
|
|
3
|
+
import Input from "../input";
|
|
4
|
+
import Box from "../box";
|
|
5
|
+
import Button from "../button";
|
|
6
|
+
import useBase from "../useBase";
|
|
7
|
+
import SVGIcons from "../svgicons";
|
|
8
|
+
const Search = forwardRef((props, ref) => {
|
|
9
|
+
const { animate, withStyle, onChange, ...pops } = props;
|
|
10
|
+
const { style } = useBase(pops);
|
|
11
|
+
const { className: searchStyle } = useBase({ as: withStyle || `` });
|
|
12
|
+
const [query, setQuery] = useState(``);
|
|
13
|
+
const innerRef = useRef(null);
|
|
14
|
+
if (`type` in props) {
|
|
15
|
+
delete props[`type`];
|
|
16
|
+
}
|
|
17
|
+
const handleChange = (e) => {
|
|
18
|
+
setQuery(e.target.value);
|
|
19
|
+
onChange?.(e.target.value);
|
|
20
|
+
};
|
|
21
|
+
const handleSubmit = (e) => {
|
|
22
|
+
e.preventDefault();
|
|
23
|
+
if (query.trim() !== ``) {
|
|
24
|
+
setQuery(``);
|
|
25
|
+
onChange?.(``);
|
|
26
|
+
if (innerRef.current) {
|
|
27
|
+
innerRef.current.value = ``;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// onSubmit?.(query)
|
|
31
|
+
};
|
|
32
|
+
useEffect(() => { }, []);
|
|
33
|
+
return _jsxs(Box, { style: style, ...{
|
|
34
|
+
className: `--search flex aic rel ${searchStyle}`.trim()
|
|
35
|
+
}, children: [_jsx(Input, { ...{
|
|
36
|
+
ref: innerRef,
|
|
37
|
+
onChange: handleChange,
|
|
38
|
+
...pops
|
|
39
|
+
} }), _jsx(Button, { ...{
|
|
40
|
+
withLabel: false,
|
|
41
|
+
tabIndex: -1,
|
|
42
|
+
onClick: handleSubmit,
|
|
43
|
+
className: `--send flex aic jcc abs`
|
|
44
|
+
}, children: query !== `` ? SVGIcons.Close : SVGIcons.Search })] });
|
|
45
|
+
});
|
|
46
|
+
export default Search;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Props } from "../useBase/base.types";
|
|
2
|
+
/**
|
|
3
|
+
* Individual segment in the `SelectTabs` component.
|
|
4
|
+
* @typedef {Object} Segment
|
|
5
|
+
* @property {number} index - The index of the segment.
|
|
6
|
+
* @property {string} [icon] - The optional icon to display for the segment.
|
|
7
|
+
* @property {string} [label] - The optional label to display for the segment.
|
|
8
|
+
*/
|
|
9
|
+
export interface Segment {
|
|
10
|
+
tag?: string;
|
|
11
|
+
index: number;
|
|
12
|
+
icon?: string;
|
|
13
|
+
label?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Props for the `SelectTabs` component.
|
|
17
|
+
* @typedef {Object} SegmentProps
|
|
18
|
+
* @extends {Props<'div'>}
|
|
19
|
+
* @property {number} [selected] - The index of the initially selected segment.
|
|
20
|
+
* @property {Segment[]} items - Array of segments to display.
|
|
21
|
+
*/
|
|
22
|
+
export interface SegmentProps extends Props<`div`> {
|
|
23
|
+
selected?: number;
|
|
24
|
+
onSwitch?: (segment: Segment) => void;
|
|
25
|
+
items: Segment[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* `SelectTabs` component is a segmented control that allows switching between segments.
|
|
29
|
+
*
|
|
30
|
+
* @component
|
|
31
|
+
* @param {SegmentProps} props - Props for the segmented control component.
|
|
32
|
+
* @param {React.Ref<HTMLDivElement>} ref - Ref for the root div element.
|
|
33
|
+
* @returns {JSX.Element} The rendered segmented control.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* // Usage example
|
|
37
|
+
* const segments = [
|
|
38
|
+
* { index: 0, label: "Home", icon: "home_icon" },
|
|
39
|
+
* { index: 1, label: "Profile", icon: "profile_icon" },
|
|
40
|
+
* { index: 2, label: "Settings", icon: "settings_icon" }
|
|
41
|
+
* ];
|
|
42
|
+
*
|
|
43
|
+
* <SelectTabs selected={1} items={segments} />
|
|
44
|
+
*/
|
|
45
|
+
declare const Segmented: import("react").ForwardRefExoticComponent<SegmentProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
46
|
+
export default Segmented;
|