@vrobots/storybook 0.1.57 → 0.1.59
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/package.json +9 -9
- package/dist/src/components/Breadcrumbs.js +2 -4
- package/dist/src/components/form/FileUploader.d.ts +12 -0
- package/dist/src/components/form/FileUploader.js +59 -0
- package/dist/src/components/form/index.d.ts +2 -0
- package/dist/src/components/form/index.js +3 -0
- package/dist/src/components/index.d.ts +1 -0
- package/dist/src/components/index.js +1 -0
- package/dist/src/stories/FileUploader.stories.d.ts +15 -0
- package/dist/src/stories/FileUploader.stories.js +24 -0
- package/package.json +9 -9
package/dist/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vrobots/storybook",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.59",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@chakra-ui/react": "^3.32.0",
|
|
22
22
|
"@emotion/react": "^11.14.0",
|
|
23
|
-
"@storybook/addon-themes": "^10.2.
|
|
23
|
+
"@storybook/addon-themes": "^10.2.16",
|
|
24
24
|
"axios": "^1.13.4",
|
|
25
25
|
"motion": "^12.34.0",
|
|
26
26
|
"next-themes": "^0.4.6",
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
"react-icons": "^5.6.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@chromatic-com/storybook": "^5.0.
|
|
37
|
+
"@chromatic-com/storybook": "^5.0.1",
|
|
38
38
|
"@eslint/js": "^9.39.1",
|
|
39
|
-
"@storybook/addon-a11y": "^10.2.
|
|
40
|
-
"@storybook/addon-docs": "^10.2.
|
|
41
|
-
"@storybook/addon-vitest": "^10.2.
|
|
42
|
-
"@storybook/react-vite": "^10.2.
|
|
39
|
+
"@storybook/addon-a11y": "^10.2.16",
|
|
40
|
+
"@storybook/addon-docs": "^10.2.16",
|
|
41
|
+
"@storybook/addon-vitest": "^10.2.16",
|
|
42
|
+
"@storybook/react-vite": "^10.2.16",
|
|
43
43
|
"@types/node": "^24.10.1",
|
|
44
44
|
"@types/react": "^19.2.5",
|
|
45
45
|
"@types/react-dom": "^19.2.3",
|
|
@@ -50,11 +50,11 @@
|
|
|
50
50
|
"eslint": "^9.39.1",
|
|
51
51
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
52
52
|
"eslint-plugin-react-refresh": "^0.4.24",
|
|
53
|
-
"eslint-plugin-storybook": "^10.2.
|
|
53
|
+
"eslint-plugin-storybook": "^10.2.16",
|
|
54
54
|
"globals": "^16.5.0",
|
|
55
55
|
"playwright": "^1.58.1",
|
|
56
56
|
"rimraf": "^6.1.2",
|
|
57
|
-
"storybook": "^10.2.
|
|
57
|
+
"storybook": "^10.2.16",
|
|
58
58
|
"ts-node": "^10.9.2",
|
|
59
59
|
"typescript": "~5.9.3",
|
|
60
60
|
"typescript-eslint": "^8.46.4",
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { HStack, Link, Text } from "@chakra-ui/react";
|
|
4
|
-
import { useSelectedColorSchema } from "../hooks/useSelectedColorSchema";
|
|
5
4
|
export const Breadcrumbs = React.forwardRef(({ breadcrumbs }, ref) => {
|
|
6
|
-
const { color } = useSelectedColorSchema('blue');
|
|
7
5
|
if (!!breadcrumbs) {
|
|
8
6
|
const crumbs = breadcrumbs.map(({ title, nav, color: itemColor }, key) => {
|
|
9
7
|
if (!!nav) {
|
|
10
|
-
return (_jsxs(HStack, { children: [_jsx(Link, { href: nav, color: itemColor ||
|
|
8
|
+
return (_jsxs(HStack, { children: [_jsx(Link, { href: nav, color: itemColor || 'blue.500', whiteSpace: 'nowrap', wordBreak: 'break-word', fontSize: 'sm', truncate: true, children: title }), _jsx(Text, { ml: 2, mr: 2, fontSize: 'sm', children: ">" })] }, `${title}-${key}`));
|
|
11
9
|
}
|
|
12
|
-
return (_jsx(Text, { whiteSpace: 'nowrap', wordBreak: 'break-word', color:
|
|
10
|
+
return (_jsx(Text, { whiteSpace: 'nowrap', wordBreak: 'break-word', color: 'gray.500', fontSize: 'sm', truncate: true, children: title }, `${title}-${key}`));
|
|
13
11
|
});
|
|
14
12
|
return (_jsx(HStack, { width: '100%', flex: `0 1 auto`, ref: ref, children: crumbs }));
|
|
15
13
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { CardRootProps } from "@chakra-ui/react";
|
|
2
|
+
export interface IFileUploaderProps extends CardRootProps {
|
|
3
|
+
title?: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
buttonLabel?: string;
|
|
6
|
+
helperText?: string;
|
|
7
|
+
accept?: string;
|
|
8
|
+
multiple?: boolean;
|
|
9
|
+
onFilesSelected?: (files: File[]) => void;
|
|
10
|
+
}
|
|
11
|
+
declare const FileUploader: ({ title, description, buttonLabel, helperText, accept, multiple, onFilesSelected, ...props }: IFileUploaderProps) => import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export default FileUploader;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useState } from "react";
|
|
3
|
+
import { Box, Button, Card, List, Text } from "@chakra-ui/react";
|
|
4
|
+
const parseAcceptRules = (accept) => {
|
|
5
|
+
if (!accept)
|
|
6
|
+
return [];
|
|
7
|
+
return accept
|
|
8
|
+
.split(",")
|
|
9
|
+
.map((rule) => rule.trim().toLowerCase())
|
|
10
|
+
.filter(Boolean);
|
|
11
|
+
};
|
|
12
|
+
const fileMatchesRule = (file, rule) => {
|
|
13
|
+
if (rule === "*/*")
|
|
14
|
+
return true;
|
|
15
|
+
if (rule.endsWith("/*")) {
|
|
16
|
+
const mimeFamily = rule.replace("/*", "");
|
|
17
|
+
return file.type.toLowerCase().startsWith(`${mimeFamily}/`);
|
|
18
|
+
}
|
|
19
|
+
if (rule.startsWith(".")) {
|
|
20
|
+
return file.name.toLowerCase().endsWith(rule);
|
|
21
|
+
}
|
|
22
|
+
return file.type.toLowerCase() === rule;
|
|
23
|
+
};
|
|
24
|
+
const filterFilesByAccept = (files, accept) => {
|
|
25
|
+
const rules = parseAcceptRules(accept);
|
|
26
|
+
if (!rules.length)
|
|
27
|
+
return files;
|
|
28
|
+
return files.filter((file) => rules.some((rule) => fileMatchesRule(file, rule)));
|
|
29
|
+
};
|
|
30
|
+
const FileUploader = ({ title, description, buttonLabel, helperText, accept, multiple = true, onFilesSelected, ...props }) => {
|
|
31
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
32
|
+
const [files, setFiles] = useState([]);
|
|
33
|
+
const fileInputRef = useRef(null);
|
|
34
|
+
const handleFiles = (nextFiles) => {
|
|
35
|
+
const acceptedFiles = filterFilesByAccept(nextFiles, accept);
|
|
36
|
+
const normalizedFiles = multiple ? acceptedFiles : acceptedFiles.slice(0, 1);
|
|
37
|
+
setFiles(normalizedFiles);
|
|
38
|
+
onFilesSelected?.(normalizedFiles);
|
|
39
|
+
};
|
|
40
|
+
const handleFileInputChange = (event) => {
|
|
41
|
+
const selectedFiles = Array.from(event.target.files ?? []);
|
|
42
|
+
handleFiles(selectedFiles);
|
|
43
|
+
event.target.value = "";
|
|
44
|
+
};
|
|
45
|
+
const handleDrag = (isDragging) => (event) => {
|
|
46
|
+
event.preventDefault();
|
|
47
|
+
event.stopPropagation();
|
|
48
|
+
setIsDragging(isDragging);
|
|
49
|
+
};
|
|
50
|
+
const handleDrop = (event) => {
|
|
51
|
+
event.preventDefault();
|
|
52
|
+
event.stopPropagation();
|
|
53
|
+
setIsDragging(false);
|
|
54
|
+
const droppedFiles = Array.from(event.dataTransfer.files ?? []);
|
|
55
|
+
handleFiles(droppedFiles);
|
|
56
|
+
};
|
|
57
|
+
return (_jsx(Card.Root, { ...props, children: _jsxs(Card.Body, { children: [_jsx(Card.Title, { children: title || "Upload Files" }), !!description && _jsx(Card.Description, { children: description }), _jsxs(Box, { mt: 4, p: 6, borderWidth: "2px", borderStyle: "dashed", borderColor: isDragging ? "teal.500" : "border.emphasized", borderRadius: "md", bg: isDragging ? "teal.subtle" : "bg.muted", textAlign: "center", transition: "background 0.2s ease, border-color 0.2s ease", onDragEnter: handleDrag(true), onDragOver: handleDrag(true), onDragLeave: handleDrag(false), onDrop: handleDrop, children: [_jsx(Text, { fontWeight: "medium", children: "Drag and drop files here" }), _jsx(Text, { fontSize: "sm", color: "fg.muted", mt: 1, children: "or click the button below to browse from your device" }), _jsx("input", { ref: fileInputRef, type: "file", hidden: true, accept: accept, multiple: multiple, onChange: handleFileInputChange }), _jsx(Button, { mt: 4, onClick: () => fileInputRef.current?.click(), children: buttonLabel || "Choose Files" }), !!helperText && (_jsx(Text, { fontSize: "xs", color: "fg.muted", mt: 3, children: helperText }))] }), files.length > 0 && (_jsxs(Box, { mt: 4, children: [_jsx(Text, { fontSize: "sm", fontWeight: "medium", mb: 2, children: "Selected Files" }), _jsx(List.Root, { gap: "1", children: files.map((file) => (_jsx(List.Item, { children: file.name }, `${file.name}-${file.size}`))) })] }))] }) }));
|
|
58
|
+
};
|
|
59
|
+
export default FileUploader;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export * from "./Login";
|
|
2
2
|
export * from "./SecondFactorAuth";
|
|
3
|
+
export * from "./FileUploader";
|
|
3
4
|
declare const Form: {
|
|
4
5
|
(): null;
|
|
5
6
|
Login: ({ title, description, onLogin, ...props }: import("./Login").ILoginProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
7
|
SecondFactorAuth: ({ title, description, onSecondFactorAuth, onResendAuthCode, ...props }: import("./SecondFactorAuth").ISecondFactorAuthProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
FileUploader: ({ title, description, buttonLabel, helperText, accept, multiple, onFilesSelected, ...props }: import("./FileUploader").IFileUploaderProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
9
|
};
|
|
8
10
|
export default Form;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import Login from "./Login";
|
|
2
2
|
import SecondFactorAuth from "./SecondFactorAuth";
|
|
3
|
+
import FileUploader from "./FileUploader";
|
|
3
4
|
export * from "./Login";
|
|
4
5
|
export * from "./SecondFactorAuth";
|
|
6
|
+
export * from "./FileUploader";
|
|
5
7
|
const Form = () => null;
|
|
6
8
|
Form.Login = Login;
|
|
7
9
|
Form.SecondFactorAuth = SecondFactorAuth;
|
|
10
|
+
Form.FileUploader = FileUploader;
|
|
8
11
|
export default Form;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { StoryObj } from '@storybook/react-vite';
|
|
2
|
+
declare const meta: {
|
|
3
|
+
title: string;
|
|
4
|
+
component: ({ title, description, buttonLabel, helperText, accept, multiple, onFilesSelected, ...props }: import("../components").IFileUploaderProps) => import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
tags: string[];
|
|
6
|
+
parameters: {
|
|
7
|
+
layout: string;
|
|
8
|
+
};
|
|
9
|
+
args: {
|
|
10
|
+
title: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
export default meta;
|
|
14
|
+
type Story = StoryObj<typeof meta>;
|
|
15
|
+
export declare const Component: Story;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Form } from '../components';
|
|
2
|
+
const meta = {
|
|
3
|
+
title: 'Forms/FileUploader',
|
|
4
|
+
component: Form.FileUploader,
|
|
5
|
+
tags: ['autodocs'],
|
|
6
|
+
parameters: {
|
|
7
|
+
layout: 'fullscreen',
|
|
8
|
+
},
|
|
9
|
+
args: {
|
|
10
|
+
title: 'File Uploader',
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
export default meta;
|
|
14
|
+
export const Component = {
|
|
15
|
+
args: {
|
|
16
|
+
title: 'Upload Files',
|
|
17
|
+
description: 'Drag and drop files in the area below, or choose files from your device.',
|
|
18
|
+
buttonLabel: 'Browse Files',
|
|
19
|
+
helperText: 'Accepted: image/*, .pdf',
|
|
20
|
+
accept: 'image/*',
|
|
21
|
+
multiple: true,
|
|
22
|
+
onFilesSelected: (files) => console.log(files),
|
|
23
|
+
}
|
|
24
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vrobots/storybook",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.59",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@chakra-ui/react": "^3.32.0",
|
|
22
22
|
"@emotion/react": "^11.14.0",
|
|
23
|
-
"@storybook/addon-themes": "^10.2.
|
|
23
|
+
"@storybook/addon-themes": "^10.2.16",
|
|
24
24
|
"axios": "^1.13.4",
|
|
25
25
|
"motion": "^12.34.0",
|
|
26
26
|
"next-themes": "^0.4.6",
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
"react-icons": "^5.6.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@chromatic-com/storybook": "^5.0.
|
|
37
|
+
"@chromatic-com/storybook": "^5.0.1",
|
|
38
38
|
"@eslint/js": "^9.39.1",
|
|
39
|
-
"@storybook/addon-a11y": "^10.2.
|
|
40
|
-
"@storybook/addon-docs": "^10.2.
|
|
41
|
-
"@storybook/addon-vitest": "^10.2.
|
|
42
|
-
"@storybook/react-vite": "^10.2.
|
|
39
|
+
"@storybook/addon-a11y": "^10.2.16",
|
|
40
|
+
"@storybook/addon-docs": "^10.2.16",
|
|
41
|
+
"@storybook/addon-vitest": "^10.2.16",
|
|
42
|
+
"@storybook/react-vite": "^10.2.16",
|
|
43
43
|
"@types/node": "^24.10.1",
|
|
44
44
|
"@types/react": "^19.2.5",
|
|
45
45
|
"@types/react-dom": "^19.2.3",
|
|
@@ -50,11 +50,11 @@
|
|
|
50
50
|
"eslint": "^9.39.1",
|
|
51
51
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
52
52
|
"eslint-plugin-react-refresh": "^0.4.24",
|
|
53
|
-
"eslint-plugin-storybook": "^10.2.
|
|
53
|
+
"eslint-plugin-storybook": "^10.2.16",
|
|
54
54
|
"globals": "^16.5.0",
|
|
55
55
|
"playwright": "^1.58.1",
|
|
56
56
|
"rimraf": "^6.1.2",
|
|
57
|
-
"storybook": "^10.2.
|
|
57
|
+
"storybook": "^10.2.16",
|
|
58
58
|
"ts-node": "^10.9.2",
|
|
59
59
|
"typescript": "~5.9.3",
|
|
60
60
|
"typescript-eslint": "^8.46.4",
|