@majapisoftwares/ui 4.3.10 → 4.3.12
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.
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import { type ReactNode } from "react";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
className?: string;
|
|
5
|
-
type?: "single" | "multiple";
|
|
6
|
-
}): import("react").JSX.Element;
|
|
1
|
+
import { type ComponentProps, type ReactNode } from "react";
|
|
2
|
+
import * as RAccordion from "@radix-ui/react-accordion";
|
|
3
|
+
declare function Accordion({ children, className, ...props }: ComponentProps<typeof RAccordion.Root>): import("react").JSX.Element;
|
|
7
4
|
declare namespace Accordion {
|
|
8
5
|
var Item: typeof AccordionItem;
|
|
9
6
|
}
|
|
@@ -2,8 +2,8 @@ import { ChevronUpIcon } from "@heroicons/react/20/solid";
|
|
|
2
2
|
import { useId } from "react";
|
|
3
3
|
import * as RAccordion from "@radix-ui/react-accordion";
|
|
4
4
|
import clsx from "../../utils/clsx";
|
|
5
|
-
export default function Accordion({ children, className,
|
|
6
|
-
return (<RAccordion.Root
|
|
5
|
+
export default function Accordion({ children, className, ...props }) {
|
|
6
|
+
return (<RAccordion.Root {...props} className={clsx("flex flex-col gap-2", className)} {...(props.type === "single" ? { collapsible: true } : {})}>
|
|
7
7
|
{children}
|
|
8
8
|
</RAccordion.Root>);
|
|
9
9
|
}
|
|
@@ -4,9 +4,9 @@ export type PictureCropInputRef = {
|
|
|
4
4
|
handleCrop: () => Promise<void>;
|
|
5
5
|
completedCrop: PixelCrop | undefined;
|
|
6
6
|
};
|
|
7
|
-
export default function PictureCropInput({ value, onChange, loading, className, previewSizeClassNames, previewContainerClassName, cropButtonClassName, aspect, ref, }: {
|
|
8
|
-
value
|
|
9
|
-
onChange: (value
|
|
7
|
+
export default function PictureCropInput({ value, onChange, loading, className, previewSizeClassNames, previewContainerClassName, cropButtonClassName, aspect, ref, label, }: {
|
|
8
|
+
value?: string;
|
|
9
|
+
onChange: (value?: string) => void;
|
|
10
10
|
loading?: boolean;
|
|
11
11
|
className?: string;
|
|
12
12
|
previewSizeClassNames?: string;
|
|
@@ -14,4 +14,5 @@ export default function PictureCropInput({ value, onChange, loading, className,
|
|
|
14
14
|
cropButtonClassName?: string;
|
|
15
15
|
aspect?: number;
|
|
16
16
|
ref?: RefObject<PictureCropInputRef | null>;
|
|
17
|
+
label?: string;
|
|
17
18
|
}): import("react").JSX.Element;
|
|
@@ -9,12 +9,14 @@ import clsx from "clsx";
|
|
|
9
9
|
import { CheckIcon, TrashIcon } from "@heroicons/react/20/solid";
|
|
10
10
|
import Tooltip from "../Tooltip";
|
|
11
11
|
import { useLatest } from "react-use";
|
|
12
|
-
|
|
12
|
+
import { defaultLabelClassName } from "../Input";
|
|
13
|
+
export default function PictureCropInput({ value, onChange, loading, className, previewSizeClassNames = "h-52 w-52", previewContainerClassName, cropButtonClassName, aspect = 1, ref, label, }) {
|
|
13
14
|
const id = useId();
|
|
14
15
|
const [src, setSrc] = useState();
|
|
15
16
|
const [crop, setCrop] = useState();
|
|
16
17
|
const cropRef = useLatest(crop);
|
|
17
18
|
const [completedCrop, setCompletedCrop] = useState();
|
|
19
|
+
const completedCropRef = useLatest(completedCrop);
|
|
18
20
|
const previewCanvasRef = useRef(null);
|
|
19
21
|
const imgRef = useRef(null);
|
|
20
22
|
const parentRef = useRef(null);
|
|
@@ -87,9 +89,22 @@ export default function PictureCropInput({ value, onChange, loading, className,
|
|
|
87
89
|
});
|
|
88
90
|
return URL.createObjectURL(blob);
|
|
89
91
|
}, [completedCrop]);
|
|
92
|
+
const handleClear = useCallback(() => {
|
|
93
|
+
setCrop(undefined);
|
|
94
|
+
setSrc(undefined);
|
|
95
|
+
setCompletedCrop(undefined);
|
|
96
|
+
onChange(undefined);
|
|
97
|
+
}, [onChange]);
|
|
90
98
|
const handleCrop = useCallback(async () => {
|
|
91
|
-
|
|
99
|
+
try {
|
|
100
|
+
onChange(await cropToBlobUrl());
|
|
101
|
+
}
|
|
102
|
+
catch (e) {
|
|
103
|
+
console.error(e);
|
|
104
|
+
}
|
|
105
|
+
setCrop(undefined);
|
|
92
106
|
setSrc(undefined);
|
|
107
|
+
setCompletedCrop(undefined);
|
|
93
108
|
}, [cropToBlobUrl, onChange]);
|
|
94
109
|
useEffect(() => {
|
|
95
110
|
if (ref) {
|
|
@@ -98,56 +113,62 @@ export default function PictureCropInput({ value, onChange, loading, className,
|
|
|
98
113
|
completedCrop,
|
|
99
114
|
};
|
|
100
115
|
}
|
|
101
|
-
}, [completedCrop, handleCrop, ref]);
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
116
|
+
}, [completedCrop, completedCropRef, handleCrop, ref]);
|
|
117
|
+
return (<div ref={parentRef} className={className}>
|
|
118
|
+
{label && (<label htmlFor={id} className={defaultLabelClassName}>
|
|
119
|
+
{label}
|
|
120
|
+
</label>)}
|
|
121
|
+
<div className="flex gap-2">
|
|
122
|
+
{loading && <Skeleton className={previewSizeClassNames}/>}
|
|
123
|
+
{src && (<>
|
|
124
|
+
<ReactCrop crop={crop} onChange={(c) => setCrop(c)} onComplete={(c) => setCompletedCrop(c)} aspect={aspect} minWidth={50 * aspect} minHeight={50 * aspect} className="max-h-96 max-w-96" keepSelection>
|
|
125
|
+
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
126
|
+
<img alt="Picture" src={src}
|
|
112
127
|
// className="h-96 w-96 object-contain"
|
|
113
128
|
ref={imgRef}/>
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
129
|
+
</ReactCrop>
|
|
130
|
+
{completedCrop && (<div className={clsx("flex flex-col gap-2", previewContainerClassName)}>
|
|
131
|
+
<canvas ref={previewCanvasRef} className={previewSizeClassNames} style={{
|
|
117
132
|
objectFit: "cover",
|
|
118
133
|
}}/>
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
</Button>
|
|
123
|
-
<Tooltip content="Clear">
|
|
124
|
-
<Button onClick={handleClear} variant="text" icon>
|
|
125
|
-
<TrashIcon />
|
|
134
|
+
<div className="flex gap-2">
|
|
135
|
+
<Button onClick={handleCrop} className={clsx("w-full", cropButtonClassName)} leading={<CheckIcon />}>
|
|
136
|
+
Crop
|
|
126
137
|
</Button>
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
138
|
+
<Tooltip content="Clear">
|
|
139
|
+
<Button onClick={handleClear} variant="text" icon>
|
|
140
|
+
<TrashIcon />
|
|
141
|
+
</Button>
|
|
142
|
+
</Tooltip>
|
|
143
|
+
</div>
|
|
144
|
+
</div>)}
|
|
145
|
+
</>)}
|
|
146
|
+
{!src && (<>
|
|
147
|
+
{value && (<div className={clsx("flex shrink-0 rounded-sm", previewSizeClassNames)} style={{
|
|
133
148
|
background: value
|
|
134
149
|
? `center / cover url(${value})`
|
|
135
150
|
: undefined,
|
|
136
151
|
}}/>)}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
</div>
|
|
142
|
-
<div className="flex flex-col items-start gap-1.5">
|
|
143
|
-
<div className="text-gray-10 text-sm font-medium">
|
|
144
|
-
{value ? "Change" : "Select"} picture
|
|
152
|
+
<input type="file" id={id} className="hidden" onChange={onFileSelect} accept=".jpg,.jpeg,.png"/>
|
|
153
|
+
<Button variant="outlined" className="mb-auto flex items-center gap-3 p-2" onClick={() => document.getElementById(id)?.click()}>
|
|
154
|
+
<div className="flex h-12 w-12 items-center justify-center rounded-sm border border-zinc-800 p-3">
|
|
155
|
+
<PhotoIcon />
|
|
145
156
|
</div>
|
|
146
|
-
<div className="
|
|
147
|
-
|
|
157
|
+
<div className="flex flex-col items-start gap-1.5">
|
|
158
|
+
<div className="text-gray-10 text-sm font-medium">
|
|
159
|
+
{value ? "Change" : "Select"} picture
|
|
160
|
+
</div>
|
|
161
|
+
<div className="text-xs text-zinc-500">
|
|
162
|
+
JPG, PNG - Max size 10MB
|
|
163
|
+
</div>
|
|
148
164
|
</div>
|
|
149
|
-
</
|
|
150
|
-
|
|
151
|
-
|
|
165
|
+
</Button>
|
|
166
|
+
{value && (<Tooltip content="Clear">
|
|
167
|
+
<Button onClick={handleClear} variant="text" icon className="mb-auto">
|
|
168
|
+
<TrashIcon />
|
|
169
|
+
</Button>
|
|
170
|
+
</Tooltip>)}
|
|
171
|
+
</>)}
|
|
172
|
+
</div>
|
|
152
173
|
</div>);
|
|
153
174
|
}
|
package/package.json
CHANGED