@spacesync/client 0.1.1 → 0.1.2
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,11 +1,14 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
-
declare function ImagePickerField({ label, value,
|
|
3
|
+
declare function ImagePickerField({ label, value, onFileSelected, onRemove, description, previewAlt, disabled, }: {
|
|
4
4
|
label?: string;
|
|
5
|
+
/** Preview URL supplied by the parent (`blob:`, signed HTTPS, or empty). */
|
|
5
6
|
value?: string;
|
|
6
|
-
|
|
7
|
+
onFileSelected: (file: File) => void;
|
|
8
|
+
onRemove?: () => void;
|
|
7
9
|
description?: string;
|
|
8
10
|
previewAlt?: string;
|
|
11
|
+
disabled?: boolean;
|
|
9
12
|
}): React.JSX.Element;
|
|
10
13
|
|
|
11
14
|
export { ImagePickerField };
|
|
@@ -7,19 +7,17 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
|
7
7
|
function ImagePickerField({
|
|
8
8
|
label = "Image",
|
|
9
9
|
value,
|
|
10
|
-
|
|
10
|
+
onFileSelected,
|
|
11
|
+
onRemove,
|
|
11
12
|
description,
|
|
12
|
-
previewAlt = "Selected image"
|
|
13
|
+
previewAlt = "Selected image",
|
|
14
|
+
disabled = false
|
|
13
15
|
}) {
|
|
14
16
|
const inputRef = useRef(null);
|
|
15
17
|
const handleFileChange = (files) => {
|
|
16
18
|
const file = files?.[0];
|
|
17
|
-
if (!file) return;
|
|
18
|
-
|
|
19
|
-
reader.onload = () => {
|
|
20
|
-
if (typeof reader.result === "string") onChange(reader.result);
|
|
21
|
-
};
|
|
22
|
-
reader.readAsDataURL(file);
|
|
19
|
+
if (!file || disabled) return;
|
|
20
|
+
onFileSelected(file);
|
|
23
21
|
};
|
|
24
22
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
25
23
|
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-muted-foreground", children: label }),
|
|
@@ -32,6 +30,7 @@ function ImagePickerField({
|
|
|
32
30
|
type: "button",
|
|
33
31
|
variant: "link",
|
|
34
32
|
size: "sm",
|
|
33
|
+
disabled,
|
|
35
34
|
onClick: () => inputRef.current?.click(),
|
|
36
35
|
className: "h-auto gap-1.5 p-0 text-xs font-medium text-blue-600 dark:text-blue-400",
|
|
37
36
|
children: [
|
|
@@ -40,32 +39,34 @@ function ImagePickerField({
|
|
|
40
39
|
]
|
|
41
40
|
}
|
|
42
41
|
),
|
|
43
|
-
/* @__PURE__ */ jsxs(
|
|
42
|
+
onRemove ? /* @__PURE__ */ jsxs(
|
|
44
43
|
Button,
|
|
45
44
|
{
|
|
46
45
|
type: "button",
|
|
47
46
|
variant: "link",
|
|
48
47
|
size: "sm",
|
|
49
|
-
|
|
48
|
+
disabled,
|
|
49
|
+
onClick: onRemove,
|
|
50
50
|
className: "h-auto gap-1.5 p-0 text-xs font-medium text-red-600",
|
|
51
51
|
children: [
|
|
52
52
|
/* @__PURE__ */ jsx(Trash2, { size: 13 }),
|
|
53
53
|
"Remove"
|
|
54
54
|
]
|
|
55
55
|
}
|
|
56
|
-
)
|
|
56
|
+
) : null
|
|
57
57
|
] })
|
|
58
58
|
] }) : /* @__PURE__ */ jsxs(
|
|
59
59
|
Button,
|
|
60
60
|
{
|
|
61
61
|
type: "button",
|
|
62
62
|
variant: "outline",
|
|
63
|
+
disabled,
|
|
63
64
|
onClick: () => inputRef.current?.click(),
|
|
64
65
|
className: "flex aspect-[4/3] h-auto max-w-sm w-full flex-col items-center justify-center gap-2 rounded-xl border-dashed bg-muted/50 px-4 py-5 text-center shadow-none hover:border-blue-300 hover:bg-blue-50/30 dark:hover:bg-blue-950/25",
|
|
65
66
|
children: [
|
|
66
67
|
/* @__PURE__ */ jsx("span", { className: "flex h-9 w-9 items-center justify-center rounded-xl border border-border bg-card", children: /* @__PURE__ */ jsx(Upload, { size: 15, className: "text-muted-foreground" }) }),
|
|
67
68
|
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-foreground", children: "Choose image" }),
|
|
68
|
-
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-normal text-muted-foreground whitespace-normal", children: description ?? "JPG, PNG
|
|
69
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-normal text-muted-foreground whitespace-normal", children: description ?? "JPG, PNG, WebP or GIF." })
|
|
69
70
|
]
|
|
70
71
|
}
|
|
71
72
|
),
|
|
@@ -75,6 +76,7 @@ function ImagePickerField({
|
|
|
75
76
|
ref: inputRef,
|
|
76
77
|
type: "file",
|
|
77
78
|
accept: "image/*",
|
|
79
|
+
disabled,
|
|
78
80
|
className: "hidden",
|
|
79
81
|
onChange: (event) => {
|
|
80
82
|
handleFileChange(event.target.files);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/files/image-picker-field.tsx"],"names":[],"mappings":";;;;;;AAIO,SAAS,gBAAA,CAAiB;AAAA,EAC/B,KAAA,GAAQ,OAAA;AAAA,EACR,KAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA,GAAa;
|
|
1
|
+
{"version":3,"sources":["../src/files/image-picker-field.tsx"],"names":[],"mappings":"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","file":"image-picker-field.js","sourcesContent":["import { useRef } from \"react\";\nimport { ImagePlus, Trash2, Upload } from \"lucide-react\";\nimport { Button } from \"../ui/button\";\n\nexport function ImagePickerField({\n label = \"Image\",\n value,\n onFileSelected,\n onRemove,\n description,\n previewAlt = \"Selected image\",\n disabled = false,\n}: {\n label?: string;\n /** Preview URL supplied by the parent (`blob:`, signed HTTPS, or empty). */\n value?: string;\n onFileSelected: (file: File) => void;\n onRemove?: () => void;\n description?: string;\n previewAlt?: string;\n disabled?: boolean;\n}) {\n const inputRef = useRef<HTMLInputElement>(null);\n\n const handleFileChange = (files: FileList | null) => {\n const file = files?.[0];\n if (!file || disabled) return;\n onFileSelected(file);\n };\n\n return (\n <div className=\"flex flex-col gap-1.5\">\n <label className=\"text-xs font-medium text-muted-foreground\">{label}</label>\n {value ? (\n <div className=\"max-w-sm overflow-hidden rounded-xl border border-border bg-card\">\n <img src={value} alt={previewAlt} className=\"aspect-[4/3] w-full object-cover\" />\n <div className=\"flex items-center justify-between gap-2 border-t border-border px-3 py-2\">\n <Button\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n disabled={disabled}\n onClick={() => inputRef.current?.click()}\n className=\"h-auto gap-1.5 p-0 text-xs font-medium text-blue-600 dark:text-blue-400\"\n >\n <ImagePlus size={13} />\n Change image\n </Button>\n {onRemove ? (\n <Button\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n disabled={disabled}\n onClick={onRemove}\n className=\"h-auto gap-1.5 p-0 text-xs font-medium text-red-600\"\n >\n <Trash2 size={13} />\n Remove\n </Button>\n ) : null}\n </div>\n </div>\n ) : (\n <Button\n type=\"button\"\n variant=\"outline\"\n disabled={disabled}\n onClick={() => inputRef.current?.click()}\n className=\"flex aspect-[4/3] h-auto max-w-sm w-full flex-col items-center justify-center gap-2 rounded-xl border-dashed bg-muted/50 px-4 py-5 text-center shadow-none hover:border-blue-300 hover:bg-blue-50/30 dark:hover:bg-blue-950/25\"\n >\n <span className=\"flex h-9 w-9 items-center justify-center rounded-xl border border-border bg-card\">\n <Upload size={15} className=\"text-muted-foreground\" />\n </span>\n <span className=\"text-xs font-medium text-foreground\">Choose image</span>\n <span className=\"text-[11px] font-normal text-muted-foreground whitespace-normal\">\n {description ?? \"JPG, PNG, WebP or GIF.\"}\n </span>\n </Button>\n )}\n <input\n ref={inputRef}\n type=\"file\"\n accept=\"image/*\"\n disabled={disabled}\n className=\"hidden\"\n onChange={(event) => {\n handleFileChange(event.target.files);\n event.target.value = \"\";\n }}\n />\n </div>\n );\n}\n"]}
|