@zauru-sdk/components 1.0.113 → 1.0.115
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/CHANGELOG.md +16 -0
- package/dist/Form/ReactZodForm/index.d.ts +1 -0
- package/dist/SidePanel/index.d.ts +21 -0
- package/dist/cjs/Form/DatePicker/index.js +1 -1
- package/dist/cjs/Form/ReactZodForm/index.js +2 -2
- package/dist/cjs/Form/SelectField/index.js +16 -6
- package/dist/cjs/Form/TextField/index.js +4 -2
- package/dist/cjs/Form/TimePicker/index.js +1 -1
- package/dist/cjs/SidePanel/index.js +48 -0
- package/dist/cjs/index.js +1 -0
- package/dist/esm/Form/DatePicker/index.js +2 -2
- package/dist/esm/Form/ReactZodForm/index.js +2 -2
- package/dist/esm/Form/SelectField/index.js +16 -6
- package/dist/esm/Form/TextField/index.js +4 -2
- package/dist/esm/Form/TimePicker/index.js +1 -1
- package/dist/esm/SidePanel/index.js +46 -0
- package/dist/esm/index.js +1 -0
- package/dist/index.d.ts +1 -0
- package/package.json +4 -4
- package/src/Form/DatePicker/index.tsx +2 -2
- package/src/Form/ReactZodForm/index.tsx +3 -0
- package/src/Form/SelectField/index.tsx +19 -9
- package/src/Form/TextField/index.tsx +4 -2
- package/src/Form/TimePicker/index.tsx +1 -1
- package/src/SidePanel/index.tsx +153 -0
- package/src/index.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.0.115](https://github.com/intuitiva/zauru-typescript-sdk/compare/v1.0.114...v1.0.115) (2024-09-26)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @zauru-sdk/components
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [1.0.114](https://github.com/intuitiva/zauru-typescript-sdk/compare/v1.0.113...v1.0.114) (2024-09-25)
|
|
15
|
+
|
|
16
|
+
**Note:** Version bump only for package @zauru-sdk/components
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
6
22
|
## [1.0.113](https://github.com/intuitiva/zauru-typescript-sdk/compare/v1.0.112...v1.0.113) (2024-09-25)
|
|
7
23
|
|
|
8
24
|
**Note:** Version bump only for package @zauru-sdk/components
|
|
@@ -7,6 +7,7 @@ type Props = {
|
|
|
7
7
|
onSubmit?: SubmitHandler<FieldValues>;
|
|
8
8
|
id?: string;
|
|
9
9
|
method?: "post" | "put" | "delete" | "patch";
|
|
10
|
+
className?: string;
|
|
10
11
|
};
|
|
11
12
|
export declare const ReactZodForm: (props: Props) => import("react/jsx-runtime").JSX.Element;
|
|
12
13
|
export default ReactZodForm;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React, { ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* SidePanel Component
|
|
4
|
+
*
|
|
5
|
+
* This component creates a collapsible side panel that can be toggled open and closed.
|
|
6
|
+
*
|
|
7
|
+
* @param {ReactNode} children - The content to be displayed inside the side panel.
|
|
8
|
+
* @param {boolean} [closeOnClickOutside=true] - If true, the panel will close when clicking outside of it.
|
|
9
|
+
* @param {number} [widthPercentage=25] - The width of the panel as a percentage of the viewport width.
|
|
10
|
+
* @param {string} [buttonIcon="chevron"] - The icon to use for the toggle button. Can be "chevron", "filter", or a custom ReactNode.
|
|
11
|
+
*
|
|
12
|
+
* @returns A toggleable side panel component.
|
|
13
|
+
*/
|
|
14
|
+
interface SidePanelProps {
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
closeOnClickOutside?: boolean;
|
|
17
|
+
widthPercentage?: number;
|
|
18
|
+
buttonIcon?: "chevron" | "filter" | ReactNode;
|
|
19
|
+
}
|
|
20
|
+
declare const SidePanel: React.FC<SidePanelProps>;
|
|
21
|
+
export default SidePanel;
|
|
@@ -26,7 +26,7 @@ const FormDatePicker = (props) => {
|
|
|
26
26
|
setValue("");
|
|
27
27
|
onChange && onChange("");
|
|
28
28
|
};
|
|
29
|
-
return ((0, jsx_runtime_1.jsxs)(
|
|
29
|
+
return ((0, jsx_runtime_1.jsxs)("div", { children: [title && ((0, jsx_runtime_1.jsxs)("label", { htmlFor: error ? `${name}-error` : `${name}-success`, className: `block text-sm font-medium ${textColor} ${className}`, children: [title, required && (0, jsx_runtime_1.jsx)("span", { className: "text-red-500", children: "*" })] })), (0, jsx_runtime_1.jsxs)("div", { className: "flex relative items-center", children: [(0, jsx_runtime_1.jsx)("div", { className: "absolute left-0 flex items-center pl-3 pointer-events-none", children: (0, jsx_runtime_1.jsx)(icons_1.CalendarIconSVG, {}) }), (0, jsx_runtime_1.jsx)("input", { id: id, tabIndex: tabIndex, type: "date", value: value ?? "", pattern: "\\d{4}-\\d{2}-\\d{2}", className: `${bgColor} ${borderColor} ${textColor} text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full pl-10 p-2.5`, ...(register ?? {}), name: name, onChange: (e) => {
|
|
30
30
|
setValue(e.target.value);
|
|
31
31
|
onChange && onChange(e.target.value);
|
|
32
32
|
if (register) {
|
|
@@ -8,7 +8,7 @@ const react_hook_form_1 = require("react-hook-form");
|
|
|
8
8
|
const zod_2 = require("zod");
|
|
9
9
|
const emptySchema = zod_2.z.any();
|
|
10
10
|
const ReactZodForm = (props) => {
|
|
11
|
-
const { children, method = "post", schema = emptySchema, onSubmit, id, } = props;
|
|
11
|
+
const { children, method = "post", schema = emptySchema, onSubmit, id, className, } = props;
|
|
12
12
|
const submit = (0, react_1.useSubmit)();
|
|
13
13
|
const methods = (0, react_hook_form_1.useForm)({
|
|
14
14
|
resolver: (0, zod_1.zodResolver)(schema),
|
|
@@ -23,7 +23,7 @@ const ReactZodForm = (props) => {
|
|
|
23
23
|
submit(event?.target, { method });
|
|
24
24
|
}
|
|
25
25
|
};
|
|
26
|
-
return ((0, jsx_runtime_1.jsx)(react_hook_form_1.FormProvider, { ...methods, children: (0, jsx_runtime_1.jsx)(react_1.Form, { onSubmit: methods.handleSubmit(handleSubmit), method: method, id: id, children: children }) }));
|
|
26
|
+
return ((0, jsx_runtime_1.jsx)(react_hook_form_1.FormProvider, { ...methods, children: (0, jsx_runtime_1.jsx)(react_1.Form, { onSubmit: methods.handleSubmit(handleSubmit), method: method, id: id, className: className, children: children }) }));
|
|
27
27
|
};
|
|
28
28
|
exports.ReactZodForm = ReactZodForm;
|
|
29
29
|
exports.default = exports.ReactZodForm;
|
|
@@ -31,7 +31,7 @@ const SelectField = (props) => {
|
|
|
31
31
|
const isReadOnly = disabled || readOnly;
|
|
32
32
|
const bgColor = isReadOnly ? "bg-gray-200" : `bg-${color}-50`;
|
|
33
33
|
const textColor = isReadOnly ? "text-gray-500" : `text-${color}-900`;
|
|
34
|
-
const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-
|
|
34
|
+
const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-200`;
|
|
35
35
|
(0, react_1.useEffect)(() => {
|
|
36
36
|
setFilteredOptions(options);
|
|
37
37
|
}, [options]);
|
|
@@ -45,7 +45,9 @@ const SelectField = (props) => {
|
|
|
45
45
|
if (defaultValue) {
|
|
46
46
|
setValue(defaultValue);
|
|
47
47
|
setInputValue(defaultValue.label);
|
|
48
|
-
setFormValue
|
|
48
|
+
if (setFormValue) {
|
|
49
|
+
setFormValue(name || "", defaultValue.value);
|
|
50
|
+
}
|
|
49
51
|
}
|
|
50
52
|
document.addEventListener("mousedown", handleClickOutside);
|
|
51
53
|
return () => {
|
|
@@ -69,13 +71,17 @@ const SelectField = (props) => {
|
|
|
69
71
|
: [...valueMulti, option];
|
|
70
72
|
setValueMulti(newValue);
|
|
71
73
|
onChangeMulti && onChangeMulti(newValue);
|
|
72
|
-
|
|
74
|
+
if (setFormValue) {
|
|
75
|
+
setFormValue(name || "", newValue.map((v) => v.value));
|
|
76
|
+
}
|
|
73
77
|
}
|
|
74
78
|
else {
|
|
75
79
|
setValue(option);
|
|
76
80
|
setInputValue(option.label);
|
|
77
81
|
onChange && onChange(option);
|
|
78
|
-
setFormValue
|
|
82
|
+
if (setFormValue) {
|
|
83
|
+
setFormValue(name || "", option.value);
|
|
84
|
+
}
|
|
79
85
|
}
|
|
80
86
|
setIsOpen(false);
|
|
81
87
|
};
|
|
@@ -83,12 +89,16 @@ const SelectField = (props) => {
|
|
|
83
89
|
if (isMulti) {
|
|
84
90
|
setValueMulti([]);
|
|
85
91
|
onChangeMulti && onChangeMulti([]);
|
|
86
|
-
setFormValue
|
|
92
|
+
if (setFormValue) {
|
|
93
|
+
setFormValue(name || "", []);
|
|
94
|
+
}
|
|
87
95
|
}
|
|
88
96
|
else {
|
|
89
97
|
setValue(null);
|
|
90
98
|
onChange && onChange(null);
|
|
91
|
-
setFormValue
|
|
99
|
+
if (setFormValue) {
|
|
100
|
+
setFormValue(name || "", "");
|
|
101
|
+
}
|
|
92
102
|
}
|
|
93
103
|
setInputValue("");
|
|
94
104
|
};
|
|
@@ -21,9 +21,11 @@ const TextField = (props) => {
|
|
|
21
21
|
const isReadOnly = disabled || readOnly;
|
|
22
22
|
const bgColor = isReadOnly ? "bg-gray-200" : `bg-${color}-50`;
|
|
23
23
|
const textColor = isReadOnly ? "text-gray-500" : `text-${color}-900`;
|
|
24
|
-
const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-
|
|
24
|
+
const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-200`;
|
|
25
25
|
(0, react_1.useEffect)(() => {
|
|
26
|
-
setOnFormValue
|
|
26
|
+
if (setOnFormValue) {
|
|
27
|
+
setOnFormValue(name ?? "-1", defaultValue);
|
|
28
|
+
}
|
|
27
29
|
setValue(defaultValue);
|
|
28
30
|
}, [defaultValue]);
|
|
29
31
|
const handleInputChange = (event) => {
|
|
@@ -17,7 +17,7 @@ const FormTimePicker = (props) => {
|
|
|
17
17
|
const color = error ? "red" : "gray";
|
|
18
18
|
const isReadOnly = disabled;
|
|
19
19
|
const bgColor = isReadOnly ? "bg-gray-200" : `bg-${color}-50`;
|
|
20
|
-
const textColor = isReadOnly ? "text-gray-500" : `text-${color}-
|
|
20
|
+
const textColor = isReadOnly ? "text-gray-500" : `text-${color}-900`;
|
|
21
21
|
const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-200`;
|
|
22
22
|
(0, react_1.useEffect)(() => {
|
|
23
23
|
setValue(defaultValue);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const framer_motion_1 = require("framer-motion");
|
|
6
|
+
// SVG icon for the left-pointing chevron
|
|
7
|
+
const ChevronLeftIcon = () => ((0, jsx_runtime_1.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", className: "h-6 w-6", children: (0, jsx_runtime_1.jsx)("path", { fillRule: "evenodd", d: "M7.72 12.53a.75.75 0 010-1.06l7.5-7.5a.75.75 0 111.06 1.06L9.31 12l6.97 6.97a.75.75 0 11-1.06 1.06l-7.5-7.5z", clipRule: "evenodd" }) }));
|
|
8
|
+
// SVG icon for the right-pointing chevron
|
|
9
|
+
const ChevronRightIcon = () => ((0, jsx_runtime_1.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", className: "h-6 w-6", children: (0, jsx_runtime_1.jsx)("path", { fillRule: "evenodd", d: "M16.28 11.47a.75.75 0 010 1.06l-7.5 7.5a.75.75 0 01-1.06-1.06L14.69 12 7.72 5.03a.75.75 0 011.06-1.06l7.5 7.5z", clipRule: "evenodd" }) }));
|
|
10
|
+
// SVG icon for the filter (bars filter icon)
|
|
11
|
+
const FilterIcon = () => ((0, jsx_runtime_1.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", className: "h-6 w-6", children: (0, jsx_runtime_1.jsx)("path", { fillRule: "evenodd", d: "M3 6a1 1 0 011-1h16a1 1 0 110 2H4a1 1 0 01-1-1zm0 6a1 1 0 011-1h10a1 1 0 110 2H4a1 1 0 01-1-1zm0 6a1 1 0 011-1h4a1 1 0 110 2H4a1 1 0 01-1-1z", clipRule: "evenodd" }) }));
|
|
12
|
+
const SidePanel = ({ children, closeOnClickOutside = true, widthPercentage = 25, buttonIcon = "chevron", }) => {
|
|
13
|
+
const [isOpen, setIsOpen] = (0, react_1.useState)(false);
|
|
14
|
+
const panelRef = (0, react_1.useRef)(null);
|
|
15
|
+
const togglePanel = () => {
|
|
16
|
+
setIsOpen(!isOpen);
|
|
17
|
+
};
|
|
18
|
+
(0, react_1.useEffect)(() => {
|
|
19
|
+
const handleClickOutside = (event) => {
|
|
20
|
+
if (closeOnClickOutside &&
|
|
21
|
+
panelRef.current &&
|
|
22
|
+
!panelRef.current.contains(event.target)) {
|
|
23
|
+
setIsOpen(false);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
27
|
+
return () => {
|
|
28
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
29
|
+
};
|
|
30
|
+
}, [closeOnClickOutside]);
|
|
31
|
+
const renderIcon = () => {
|
|
32
|
+
if (typeof buttonIcon === "string") {
|
|
33
|
+
switch (buttonIcon) {
|
|
34
|
+
case "chevron":
|
|
35
|
+
return isOpen ? (0, jsx_runtime_1.jsx)(ChevronRightIcon, {}) : (0, jsx_runtime_1.jsx)(ChevronLeftIcon, {});
|
|
36
|
+
case "filter":
|
|
37
|
+
return (0, jsx_runtime_1.jsx)(FilterIcon, {});
|
|
38
|
+
default:
|
|
39
|
+
return (0, jsx_runtime_1.jsx)(ChevronLeftIcon, {});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
return buttonIcon;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { children: isOpen && ((0, jsx_runtime_1.jsxs)(framer_motion_1.motion.div, { ref: panelRef, initial: { x: "100%" }, animate: { x: 0 }, exit: { x: "100%" }, transition: { type: "spring", stiffness: 300, damping: 30 }, className: "fixed top-0 right-0 h-full bg-white shadow-lg z-[9999] overflow-y-auto", style: { width: `${widthPercentage}%` }, children: [(0, jsx_runtime_1.jsx)("button", { onClick: togglePanel, className: "absolute top-4 left-4 p-2 rounded-full bg-gray-200 hover:bg-gray-300 transition-colors", children: (0, jsx_runtime_1.jsx)(ChevronRightIcon, {}) }), (0, jsx_runtime_1.jsx)("div", { className: "p-6 mt-16", children: children })] })) }), !isOpen && ((0, jsx_runtime_1.jsx)("button", { onClick: togglePanel, className: "fixed top-1/2 right-0 transform -translate-y-1/2 bg-indigo-600 text-white p-3 rounded-l-lg shadow-md hover:bg-indigo-700 transition-colors z-[10000]", children: renderIcon() }))] }));
|
|
47
|
+
};
|
|
48
|
+
exports.default = SidePanel;
|
package/dist/cjs/index.js
CHANGED
|
@@ -40,3 +40,4 @@ __exportStar(require("./WithTooltip/index.js"), exports);
|
|
|
40
40
|
__exportStar(require("./Wizards/index.js"), exports);
|
|
41
41
|
__exportStar(require("./Zendesk/index.js"), exports);
|
|
42
42
|
__exportStar(require("./HOC/ValidateEmployeeAccess/index.js"), exports);
|
|
43
|
+
__exportStar(require("./SidePanel/index.js"), exports);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from "react";
|
|
3
3
|
import { CalendarIconSVG, CloseSvgIcon, IdeaIconSVG } from "@zauru-sdk/icons";
|
|
4
4
|
import { useFormContext } from "react-hook-form";
|
|
@@ -23,7 +23,7 @@ export const FormDatePicker = (props) => {
|
|
|
23
23
|
setValue("");
|
|
24
24
|
onChange && onChange("");
|
|
25
25
|
};
|
|
26
|
-
return (_jsxs(
|
|
26
|
+
return (_jsxs("div", { children: [title && (_jsxs("label", { htmlFor: error ? `${name}-error` : `${name}-success`, className: `block text-sm font-medium ${textColor} ${className}`, children: [title, required && _jsx("span", { className: "text-red-500", children: "*" })] })), _jsxs("div", { className: "flex relative items-center", children: [_jsx("div", { className: "absolute left-0 flex items-center pl-3 pointer-events-none", children: _jsx(CalendarIconSVG, {}) }), _jsx("input", { id: id, tabIndex: tabIndex, type: "date", value: value ?? "", pattern: "\\d{4}-\\d{2}-\\d{2}", className: `${bgColor} ${borderColor} ${textColor} text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full pl-10 p-2.5`, ...(register ?? {}), name: name, onChange: (e) => {
|
|
27
27
|
setValue(e.target.value);
|
|
28
28
|
onChange && onChange(e.target.value);
|
|
29
29
|
if (register) {
|
|
@@ -5,7 +5,7 @@ import { FormProvider, useForm, } from "react-hook-form";
|
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
const emptySchema = z.any();
|
|
7
7
|
export const ReactZodForm = (props) => {
|
|
8
|
-
const { children, method = "post", schema = emptySchema, onSubmit, id, } = props;
|
|
8
|
+
const { children, method = "post", schema = emptySchema, onSubmit, id, className, } = props;
|
|
9
9
|
const submit = useSubmit();
|
|
10
10
|
const methods = useForm({
|
|
11
11
|
resolver: zodResolver(schema),
|
|
@@ -20,6 +20,6 @@ export const ReactZodForm = (props) => {
|
|
|
20
20
|
submit(event?.target, { method });
|
|
21
21
|
}
|
|
22
22
|
};
|
|
23
|
-
return (_jsx(FormProvider, { ...methods, children: _jsx(Form, { onSubmit: methods.handleSubmit(handleSubmit), method: method, id: id, children: children }) }));
|
|
23
|
+
return (_jsx(FormProvider, { ...methods, children: _jsx(Form, { onSubmit: methods.handleSubmit(handleSubmit), method: method, id: id, className: className, children: children }) }));
|
|
24
24
|
};
|
|
25
25
|
export default ReactZodForm;
|
|
@@ -28,7 +28,7 @@ export const SelectField = (props) => {
|
|
|
28
28
|
const isReadOnly = disabled || readOnly;
|
|
29
29
|
const bgColor = isReadOnly ? "bg-gray-200" : `bg-${color}-50`;
|
|
30
30
|
const textColor = isReadOnly ? "text-gray-500" : `text-${color}-900`;
|
|
31
|
-
const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-
|
|
31
|
+
const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-200`;
|
|
32
32
|
useEffect(() => {
|
|
33
33
|
setFilteredOptions(options);
|
|
34
34
|
}, [options]);
|
|
@@ -42,7 +42,9 @@ export const SelectField = (props) => {
|
|
|
42
42
|
if (defaultValue) {
|
|
43
43
|
setValue(defaultValue);
|
|
44
44
|
setInputValue(defaultValue.label);
|
|
45
|
-
setFormValue
|
|
45
|
+
if (setFormValue) {
|
|
46
|
+
setFormValue(name || "", defaultValue.value);
|
|
47
|
+
}
|
|
46
48
|
}
|
|
47
49
|
document.addEventListener("mousedown", handleClickOutside);
|
|
48
50
|
return () => {
|
|
@@ -66,13 +68,17 @@ export const SelectField = (props) => {
|
|
|
66
68
|
: [...valueMulti, option];
|
|
67
69
|
setValueMulti(newValue);
|
|
68
70
|
onChangeMulti && onChangeMulti(newValue);
|
|
69
|
-
|
|
71
|
+
if (setFormValue) {
|
|
72
|
+
setFormValue(name || "", newValue.map((v) => v.value));
|
|
73
|
+
}
|
|
70
74
|
}
|
|
71
75
|
else {
|
|
72
76
|
setValue(option);
|
|
73
77
|
setInputValue(option.label);
|
|
74
78
|
onChange && onChange(option);
|
|
75
|
-
setFormValue
|
|
79
|
+
if (setFormValue) {
|
|
80
|
+
setFormValue(name || "", option.value);
|
|
81
|
+
}
|
|
76
82
|
}
|
|
77
83
|
setIsOpen(false);
|
|
78
84
|
};
|
|
@@ -80,12 +86,16 @@ export const SelectField = (props) => {
|
|
|
80
86
|
if (isMulti) {
|
|
81
87
|
setValueMulti([]);
|
|
82
88
|
onChangeMulti && onChangeMulti([]);
|
|
83
|
-
setFormValue
|
|
89
|
+
if (setFormValue) {
|
|
90
|
+
setFormValue(name || "", []);
|
|
91
|
+
}
|
|
84
92
|
}
|
|
85
93
|
else {
|
|
86
94
|
setValue(null);
|
|
87
95
|
onChange && onChange(null);
|
|
88
|
-
setFormValue
|
|
96
|
+
if (setFormValue) {
|
|
97
|
+
setFormValue(name || "", "");
|
|
98
|
+
}
|
|
89
99
|
}
|
|
90
100
|
setInputValue("");
|
|
91
101
|
};
|
|
@@ -18,9 +18,11 @@ export const TextField = (props) => {
|
|
|
18
18
|
const isReadOnly = disabled || readOnly;
|
|
19
19
|
const bgColor = isReadOnly ? "bg-gray-200" : `bg-${color}-50`;
|
|
20
20
|
const textColor = isReadOnly ? "text-gray-500" : `text-${color}-900`;
|
|
21
|
-
const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-
|
|
21
|
+
const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-200`;
|
|
22
22
|
useEffect(() => {
|
|
23
|
-
setOnFormValue
|
|
23
|
+
if (setOnFormValue) {
|
|
24
|
+
setOnFormValue(name ?? "-1", defaultValue);
|
|
25
|
+
}
|
|
24
26
|
setValue(defaultValue);
|
|
25
27
|
}, [defaultValue]);
|
|
26
28
|
const handleInputChange = (event) => {
|
|
@@ -14,7 +14,7 @@ export const FormTimePicker = (props) => {
|
|
|
14
14
|
const color = error ? "red" : "gray";
|
|
15
15
|
const isReadOnly = disabled;
|
|
16
16
|
const bgColor = isReadOnly ? "bg-gray-200" : `bg-${color}-50`;
|
|
17
|
-
const textColor = isReadOnly ? "text-gray-500" : `text-${color}-
|
|
17
|
+
const textColor = isReadOnly ? "text-gray-500" : `text-${color}-900`;
|
|
18
18
|
const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-200`;
|
|
19
19
|
useEffect(() => {
|
|
20
20
|
setValue(defaultValue);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useRef } from "react";
|
|
3
|
+
import { motion, AnimatePresence } from "framer-motion";
|
|
4
|
+
// SVG icon for the left-pointing chevron
|
|
5
|
+
const ChevronLeftIcon = () => (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", className: "h-6 w-6", children: _jsx("path", { fillRule: "evenodd", d: "M7.72 12.53a.75.75 0 010-1.06l7.5-7.5a.75.75 0 111.06 1.06L9.31 12l6.97 6.97a.75.75 0 11-1.06 1.06l-7.5-7.5z", clipRule: "evenodd" }) }));
|
|
6
|
+
// SVG icon for the right-pointing chevron
|
|
7
|
+
const ChevronRightIcon = () => (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", className: "h-6 w-6", children: _jsx("path", { fillRule: "evenodd", d: "M16.28 11.47a.75.75 0 010 1.06l-7.5 7.5a.75.75 0 01-1.06-1.06L14.69 12 7.72 5.03a.75.75 0 011.06-1.06l7.5 7.5z", clipRule: "evenodd" }) }));
|
|
8
|
+
// SVG icon for the filter (bars filter icon)
|
|
9
|
+
const FilterIcon = () => (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", className: "h-6 w-6", children: _jsx("path", { fillRule: "evenodd", d: "M3 6a1 1 0 011-1h16a1 1 0 110 2H4a1 1 0 01-1-1zm0 6a1 1 0 011-1h10a1 1 0 110 2H4a1 1 0 01-1-1zm0 6a1 1 0 011-1h4a1 1 0 110 2H4a1 1 0 01-1-1z", clipRule: "evenodd" }) }));
|
|
10
|
+
const SidePanel = ({ children, closeOnClickOutside = true, widthPercentage = 25, buttonIcon = "chevron", }) => {
|
|
11
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
12
|
+
const panelRef = useRef(null);
|
|
13
|
+
const togglePanel = () => {
|
|
14
|
+
setIsOpen(!isOpen);
|
|
15
|
+
};
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const handleClickOutside = (event) => {
|
|
18
|
+
if (closeOnClickOutside &&
|
|
19
|
+
panelRef.current &&
|
|
20
|
+
!panelRef.current.contains(event.target)) {
|
|
21
|
+
setIsOpen(false);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
25
|
+
return () => {
|
|
26
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
27
|
+
};
|
|
28
|
+
}, [closeOnClickOutside]);
|
|
29
|
+
const renderIcon = () => {
|
|
30
|
+
if (typeof buttonIcon === "string") {
|
|
31
|
+
switch (buttonIcon) {
|
|
32
|
+
case "chevron":
|
|
33
|
+
return isOpen ? _jsx(ChevronRightIcon, {}) : _jsx(ChevronLeftIcon, {});
|
|
34
|
+
case "filter":
|
|
35
|
+
return _jsx(FilterIcon, {});
|
|
36
|
+
default:
|
|
37
|
+
return _jsx(ChevronLeftIcon, {});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
return buttonIcon;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
return (_jsxs(_Fragment, { children: [_jsx(AnimatePresence, { children: isOpen && (_jsxs(motion.div, { ref: panelRef, initial: { x: "100%" }, animate: { x: 0 }, exit: { x: "100%" }, transition: { type: "spring", stiffness: 300, damping: 30 }, className: "fixed top-0 right-0 h-full bg-white shadow-lg z-[9999] overflow-y-auto", style: { width: `${widthPercentage}%` }, children: [_jsx("button", { onClick: togglePanel, className: "absolute top-4 left-4 p-2 rounded-full bg-gray-200 hover:bg-gray-300 transition-colors", children: _jsx(ChevronRightIcon, {}) }), _jsx("div", { className: "p-6 mt-16", children: children })] })) }), !isOpen && (_jsx("button", { onClick: togglePanel, className: "fixed top-1/2 right-0 transform -translate-y-1/2 bg-indigo-600 text-white p-3 rounded-l-lg shadow-md hover:bg-indigo-700 transition-colors z-[10000]", children: renderIcon() }))] }));
|
|
45
|
+
};
|
|
46
|
+
export default SidePanel;
|
package/dist/esm/index.js
CHANGED
package/dist/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zauru-sdk/components",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.115",
|
|
4
4
|
"description": "Componentes reutilizables en las WebApps de Zauru.",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"@zauru-sdk/hooks": "^1.0.112",
|
|
39
39
|
"@zauru-sdk/icons": "^1.0.60",
|
|
40
40
|
"@zauru-sdk/types": "^1.0.109",
|
|
41
|
-
"@zauru-sdk/utils": "^1.0.
|
|
42
|
-
"framer-motion": "^11.0
|
|
41
|
+
"@zauru-sdk/utils": "^1.0.115",
|
|
42
|
+
"framer-motion": "^11.7.0",
|
|
43
43
|
"jsonwebtoken": "^9.0.2",
|
|
44
44
|
"react": "^18.2.0",
|
|
45
45
|
"react-data-table-component": "^7.6.2",
|
|
@@ -50,5 +50,5 @@
|
|
|
50
50
|
"styled-components": "^5.3.5",
|
|
51
51
|
"zod": "^3.23.8"
|
|
52
52
|
},
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "9a49125d2c7974621d59f96389b9e08e3fa68dc9"
|
|
54
54
|
}
|
|
@@ -61,7 +61,7 @@ export const FormDatePicker = (props: Props) => {
|
|
|
61
61
|
};
|
|
62
62
|
|
|
63
63
|
return (
|
|
64
|
-
|
|
64
|
+
<div>
|
|
65
65
|
{title && (
|
|
66
66
|
<label
|
|
67
67
|
htmlFor={error ? `${name}-error` : `${name}-success`}
|
|
@@ -130,6 +130,6 @@ export const FormDatePicker = (props: Props) => {
|
|
|
130
130
|
{hint}
|
|
131
131
|
</p>
|
|
132
132
|
)}
|
|
133
|
-
|
|
133
|
+
</div>
|
|
134
134
|
);
|
|
135
135
|
};
|
|
@@ -15,6 +15,7 @@ type Props = {
|
|
|
15
15
|
onSubmit?: SubmitHandler<FieldValues>;
|
|
16
16
|
id?: string;
|
|
17
17
|
method?: "post" | "put" | "delete" | "patch";
|
|
18
|
+
className?: string;
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
const emptySchema = z.any();
|
|
@@ -26,6 +27,7 @@ export const ReactZodForm = (props: Props) => {
|
|
|
26
27
|
schema = emptySchema,
|
|
27
28
|
onSubmit,
|
|
28
29
|
id,
|
|
30
|
+
className,
|
|
29
31
|
} = props;
|
|
30
32
|
|
|
31
33
|
const submit = useSubmit();
|
|
@@ -49,6 +51,7 @@ export const ReactZodForm = (props: Props) => {
|
|
|
49
51
|
onSubmit={methods.handleSubmit(handleSubmit)}
|
|
50
52
|
method={method}
|
|
51
53
|
id={id}
|
|
54
|
+
className={className}
|
|
52
55
|
>
|
|
53
56
|
{children}
|
|
54
57
|
</Form>
|
|
@@ -79,7 +79,7 @@ export const SelectField = (props: Props) => {
|
|
|
79
79
|
const isReadOnly = disabled || readOnly;
|
|
80
80
|
const bgColor = isReadOnly ? "bg-gray-200" : `bg-${color}-50`;
|
|
81
81
|
const textColor = isReadOnly ? "text-gray-500" : `text-${color}-900`;
|
|
82
|
-
const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-
|
|
82
|
+
const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-200`;
|
|
83
83
|
|
|
84
84
|
useEffect(() => {
|
|
85
85
|
setFilteredOptions(options);
|
|
@@ -98,7 +98,9 @@ export const SelectField = (props: Props) => {
|
|
|
98
98
|
if (defaultValue) {
|
|
99
99
|
setValue(defaultValue);
|
|
100
100
|
setInputValue(defaultValue.label);
|
|
101
|
-
setFormValue
|
|
101
|
+
if (setFormValue) {
|
|
102
|
+
setFormValue(name || "", defaultValue.value);
|
|
103
|
+
}
|
|
102
104
|
}
|
|
103
105
|
|
|
104
106
|
document.addEventListener("mousedown", handleClickOutside);
|
|
@@ -129,15 +131,19 @@ export const SelectField = (props: Props) => {
|
|
|
129
131
|
: [...valueMulti, option];
|
|
130
132
|
setValueMulti(newValue);
|
|
131
133
|
onChangeMulti && onChangeMulti(newValue);
|
|
132
|
-
setFormValue
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
if (setFormValue) {
|
|
135
|
+
setFormValue(
|
|
136
|
+
name || "",
|
|
137
|
+
newValue.map((v) => v.value)
|
|
138
|
+
);
|
|
139
|
+
}
|
|
136
140
|
} else {
|
|
137
141
|
setValue(option);
|
|
138
142
|
setInputValue(option.label);
|
|
139
143
|
onChange && onChange(option);
|
|
140
|
-
setFormValue
|
|
144
|
+
if (setFormValue) {
|
|
145
|
+
setFormValue(name || "", option.value);
|
|
146
|
+
}
|
|
141
147
|
}
|
|
142
148
|
setIsOpen(false);
|
|
143
149
|
};
|
|
@@ -146,11 +152,15 @@ export const SelectField = (props: Props) => {
|
|
|
146
152
|
if (isMulti) {
|
|
147
153
|
setValueMulti([]);
|
|
148
154
|
onChangeMulti && onChangeMulti([]);
|
|
149
|
-
setFormValue
|
|
155
|
+
if (setFormValue) {
|
|
156
|
+
setFormValue(name || "", []);
|
|
157
|
+
}
|
|
150
158
|
} else {
|
|
151
159
|
setValue(null);
|
|
152
160
|
onChange && onChange(null);
|
|
153
|
-
setFormValue
|
|
161
|
+
if (setFormValue) {
|
|
162
|
+
setFormValue(name || "", "");
|
|
163
|
+
}
|
|
154
164
|
}
|
|
155
165
|
setInputValue("");
|
|
156
166
|
};
|
|
@@ -68,10 +68,12 @@ export const TextField = (props: Props) => {
|
|
|
68
68
|
const isReadOnly = disabled || readOnly;
|
|
69
69
|
const bgColor = isReadOnly ? "bg-gray-200" : `bg-${color}-50`;
|
|
70
70
|
const textColor = isReadOnly ? "text-gray-500" : `text-${color}-900`;
|
|
71
|
-
const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-
|
|
71
|
+
const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-200`;
|
|
72
72
|
|
|
73
73
|
useEffect(() => {
|
|
74
|
-
setOnFormValue
|
|
74
|
+
if (setOnFormValue) {
|
|
75
|
+
setOnFormValue(name ?? "-1", defaultValue);
|
|
76
|
+
}
|
|
75
77
|
setValue(defaultValue);
|
|
76
78
|
}, [defaultValue]);
|
|
77
79
|
|
|
@@ -45,7 +45,7 @@ export const FormTimePicker = (props: Props) => {
|
|
|
45
45
|
|
|
46
46
|
const isReadOnly = disabled;
|
|
47
47
|
const bgColor = isReadOnly ? "bg-gray-200" : `bg-${color}-50`;
|
|
48
|
-
const textColor = isReadOnly ? "text-gray-500" : `text-${color}-
|
|
48
|
+
const textColor = isReadOnly ? "text-gray-500" : `text-${color}-900`;
|
|
49
49
|
const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-200`;
|
|
50
50
|
|
|
51
51
|
useEffect(() => {
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import React, { useState, ReactNode, useEffect, useRef } from "react";
|
|
2
|
+
import { motion, AnimatePresence } from "framer-motion";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* SidePanel Component
|
|
6
|
+
*
|
|
7
|
+
* This component creates a collapsible side panel that can be toggled open and closed.
|
|
8
|
+
*
|
|
9
|
+
* @param {ReactNode} children - The content to be displayed inside the side panel.
|
|
10
|
+
* @param {boolean} [closeOnClickOutside=true] - If true, the panel will close when clicking outside of it.
|
|
11
|
+
* @param {number} [widthPercentage=25] - The width of the panel as a percentage of the viewport width.
|
|
12
|
+
* @param {string} [buttonIcon="chevron"] - The icon to use for the toggle button. Can be "chevron", "filter", or a custom ReactNode.
|
|
13
|
+
*
|
|
14
|
+
* @returns A toggleable side panel component.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
interface SidePanelProps {
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
closeOnClickOutside?: boolean;
|
|
20
|
+
widthPercentage?: number;
|
|
21
|
+
buttonIcon?: "chevron" | "filter" | ReactNode;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// SVG icon for the left-pointing chevron
|
|
25
|
+
const ChevronLeftIcon = () => (
|
|
26
|
+
<svg
|
|
27
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
28
|
+
viewBox="0 0 24 24"
|
|
29
|
+
fill="currentColor"
|
|
30
|
+
className="h-6 w-6"
|
|
31
|
+
>
|
|
32
|
+
<path
|
|
33
|
+
fillRule="evenodd"
|
|
34
|
+
d="M7.72 12.53a.75.75 0 010-1.06l7.5-7.5a.75.75 0 111.06 1.06L9.31 12l6.97 6.97a.75.75 0 11-1.06 1.06l-7.5-7.5z"
|
|
35
|
+
clipRule="evenodd"
|
|
36
|
+
/>
|
|
37
|
+
</svg>
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
// SVG icon for the right-pointing chevron
|
|
41
|
+
const ChevronRightIcon = () => (
|
|
42
|
+
<svg
|
|
43
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
44
|
+
viewBox="0 0 24 24"
|
|
45
|
+
fill="currentColor"
|
|
46
|
+
className="h-6 w-6"
|
|
47
|
+
>
|
|
48
|
+
<path
|
|
49
|
+
fillRule="evenodd"
|
|
50
|
+
d="M16.28 11.47a.75.75 0 010 1.06l-7.5 7.5a.75.75 0 01-1.06-1.06L14.69 12 7.72 5.03a.75.75 0 011.06-1.06l7.5 7.5z"
|
|
51
|
+
clipRule="evenodd"
|
|
52
|
+
/>
|
|
53
|
+
</svg>
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
// SVG icon for the filter (bars filter icon)
|
|
57
|
+
const FilterIcon = () => (
|
|
58
|
+
<svg
|
|
59
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
60
|
+
viewBox="0 0 24 24"
|
|
61
|
+
fill="currentColor"
|
|
62
|
+
className="h-6 w-6"
|
|
63
|
+
>
|
|
64
|
+
<path
|
|
65
|
+
fillRule="evenodd"
|
|
66
|
+
d="M3 6a1 1 0 011-1h16a1 1 0 110 2H4a1 1 0 01-1-1zm0 6a1 1 0 011-1h10a1 1 0 110 2H4a1 1 0 01-1-1zm0 6a1 1 0 011-1h4a1 1 0 110 2H4a1 1 0 01-1-1z"
|
|
67
|
+
clipRule="evenodd"
|
|
68
|
+
/>
|
|
69
|
+
</svg>
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const SidePanel: React.FC<SidePanelProps> = ({
|
|
73
|
+
children,
|
|
74
|
+
closeOnClickOutside = true,
|
|
75
|
+
widthPercentage = 25,
|
|
76
|
+
buttonIcon = "chevron",
|
|
77
|
+
}) => {
|
|
78
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
79
|
+
const panelRef = useRef<HTMLDivElement>(null);
|
|
80
|
+
|
|
81
|
+
const togglePanel = () => {
|
|
82
|
+
setIsOpen(!isOpen);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
const handleClickOutside = (event: MouseEvent) => {
|
|
87
|
+
if (
|
|
88
|
+
closeOnClickOutside &&
|
|
89
|
+
panelRef.current &&
|
|
90
|
+
!panelRef.current.contains(event.target as Node)
|
|
91
|
+
) {
|
|
92
|
+
setIsOpen(false);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
97
|
+
return () => {
|
|
98
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
99
|
+
};
|
|
100
|
+
}, [closeOnClickOutside]);
|
|
101
|
+
|
|
102
|
+
const renderIcon = () => {
|
|
103
|
+
if (typeof buttonIcon === "string") {
|
|
104
|
+
switch (buttonIcon) {
|
|
105
|
+
case "chevron":
|
|
106
|
+
return isOpen ? <ChevronRightIcon /> : <ChevronLeftIcon />;
|
|
107
|
+
case "filter":
|
|
108
|
+
return <FilterIcon />;
|
|
109
|
+
default:
|
|
110
|
+
return <ChevronLeftIcon />;
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
return buttonIcon;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<>
|
|
119
|
+
<AnimatePresence>
|
|
120
|
+
{isOpen && (
|
|
121
|
+
<motion.div
|
|
122
|
+
ref={panelRef}
|
|
123
|
+
initial={{ x: "100%" }}
|
|
124
|
+
animate={{ x: 0 }}
|
|
125
|
+
exit={{ x: "100%" }}
|
|
126
|
+
transition={{ type: "spring", stiffness: 300, damping: 30 }}
|
|
127
|
+
className="fixed top-0 right-0 h-full bg-white shadow-lg z-[9999] overflow-y-auto"
|
|
128
|
+
style={{ width: `${widthPercentage}%` }}
|
|
129
|
+
>
|
|
130
|
+
<button
|
|
131
|
+
onClick={togglePanel}
|
|
132
|
+
className="absolute top-4 left-4 p-2 rounded-full bg-gray-200 hover:bg-gray-300 transition-colors"
|
|
133
|
+
>
|
|
134
|
+
<ChevronRightIcon />
|
|
135
|
+
</button>
|
|
136
|
+
<div className="p-6 mt-16">{children}</div>
|
|
137
|
+
</motion.div>
|
|
138
|
+
)}
|
|
139
|
+
</AnimatePresence>
|
|
140
|
+
|
|
141
|
+
{!isOpen && (
|
|
142
|
+
<button
|
|
143
|
+
onClick={togglePanel}
|
|
144
|
+
className="fixed top-1/2 right-0 transform -translate-y-1/2 bg-indigo-600 text-white p-3 rounded-l-lg shadow-md hover:bg-indigo-700 transition-colors z-[10000]"
|
|
145
|
+
>
|
|
146
|
+
{renderIcon()}
|
|
147
|
+
</button>
|
|
148
|
+
)}
|
|
149
|
+
</>
|
|
150
|
+
);
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export default SidePanel;
|
package/src/index.ts
CHANGED