linkedunion-design-kit 1.9.2 → 1.9.3
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/app/layout.jsx +13 -0
- package/dist/app/page.jsx +25 -0
- package/dist/build/types/app/layout.d.ts +12 -0
- package/dist/build/types/app/layout.js +22 -0
- package/dist/build/types/app/page.d.ts +12 -0
- package/dist/build/types/app/page.js +22 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/src/components/Accordion/Accordion.stories.jsx +33 -0
- package/dist/src/components/Accordion/accordion.jsx +59 -0
- package/dist/src/components/Alerts/Alert/alert.jsx +152 -0
- package/dist/src/components/Alerts/Alert/alert.stories.jsx +344 -0
- package/dist/src/components/Alerts/AlertDialog/alert-dialog.jsx +170 -0
- package/dist/src/components/Alerts/AlertDialog/alert-dialog.stories.jsx +552 -0
- package/dist/src/components/AppIcons/AndroidIcon.jsx +24 -0
- package/dist/src/components/AppIcons/AppIcon.jsx +29 -0
- package/dist/src/components/AppIcons/AppIcon.stories.jsx +223 -0
- package/dist/src/components/AppIcons/AppleIcon.jsx +31 -0
- package/dist/src/components/AppIcons/PlayStoreIcon.jsx +29 -0
- package/dist/src/components/Avatar/Avatar/Avatar.jsx +45 -0
- package/dist/src/components/Avatar/Avatar/Avatar.stories.jsx +95 -0
- package/dist/src/components/Avatar/Avatar/Avatar.test.jsx +9 -0
- package/dist/src/components/Avatar/AvatarGroup/AvatarGroup.jsx +17 -0
- package/dist/src/components/Avatar/AvatarGroup/AvatarGroup.stories.jsx +32 -0
- package/dist/src/components/Avatar/StatusIndicator/StatusIndicator.jsx +20 -0
- package/dist/src/components/Avatar/StatusIndicator/StatusIndicator.stories.jsx +50 -0
- package/dist/src/components/Badge/Badge.jsx +54 -0
- package/dist/src/components/Badge/Badge.stories.jsx +201 -0
- package/dist/src/components/Button/Button/Button.d.ts +7 -6
- package/dist/src/components/Button/Button/Button.js +32 -9
- package/dist/src/components/Button/Button/Button.jsx +101 -0
- package/dist/src/components/Button/Button/Button.stories.jsx +283 -0
- package/dist/src/components/Button/Button/Button.test.jsx +73 -0
- package/dist/src/components/Button/IconButton/IconButton.jsx +63 -0
- package/dist/src/components/Button/IconButton/IconButton.stories.jsx +128 -0
- package/dist/src/components/Button/IconButton/IconButton.test.jsx +28 -0
- package/dist/src/components/Button/index.js +1 -1
- package/dist/src/components/Card/MultipleNews/MultiNews.jsx +80 -0
- package/dist/src/components/Card/MultipleNews/MultiNews.stories.jsx +104 -0
- package/dist/src/components/Card/PostByCategory/PostByCategory.jsx +60 -0
- package/dist/src/components/Card/PostByCategory/PostByCategory.stories.jsx +106 -0
- package/dist/src/components/Card/SinglePost/SinglePost.jsx +26 -0
- package/dist/src/components/Card/SinglePost/SinglePost.stories.jsx +68 -0
- package/dist/src/components/Card/card.jsx +36 -0
- package/dist/src/components/Card/contactProfile/ContactProfile.jsx +60 -0
- package/dist/src/components/Card/contactProfile/ContactProfile.stories.jsx +103 -0
- package/dist/src/components/Card/photoAlbum/PhotoAlbum.jsx +41 -0
- package/dist/src/components/Card/photoAlbum/PhotoAlbum.stories.jsx +69 -0
- package/dist/src/components/Card/photoGallery/PhotoGallery.jsx +17 -0
- package/dist/src/components/Card/photoGallery/PhotoGallery.stories.jsx +39 -0
- package/dist/src/components/Checkbox/checkbox.jsx +47 -0
- package/dist/src/components/Checkbox/checkbox.stories.jsx +113 -0
- package/dist/src/components/ColorPicker/ColorPicker.jsx +67 -0
- package/dist/src/components/ColorPicker/ColorPicker.stories.jsx +138 -0
- package/dist/src/components/Colors/color.jsx +5 -0
- package/dist/src/components/Colors/color.stories.jsx +20 -0
- package/dist/src/components/Colors/color.test.jsx +23 -0
- package/dist/src/components/Dropdown/Combobox/Combobox.jsx +198 -0
- package/dist/src/components/Dropdown/Combobox/Combobox.stories.jsx +289 -0
- package/dist/src/components/Dropdown/Combobox/utils/renderBadge.jsx +7 -0
- package/dist/src/components/Dropdown/DropdownMenu/DropdownMenu.jsx +102 -0
- package/dist/src/components/Dropdown/DropdownMenu/DropdownMenu.stories.jsx +464 -0
- package/dist/src/components/Dropdown/DropdownMenu/SelectAllSection.jsx +19 -0
- package/dist/src/components/Dropdown/Select.stories.jsx +201 -0
- package/dist/src/components/Dropdown/select.jsx +93 -0
- package/dist/src/components/Icons/LUIcon.jsx +41 -0
- package/dist/src/components/Icons/LUIcon.test.jsx +308 -0
- package/dist/src/components/Icons/stories/IconDropdown.jsx +67 -0
- package/dist/src/components/Icons/stories/IconGallery.jsx +77 -0
- package/dist/src/components/Icons/stories/InteractiveIconSelector.jsx +86 -0
- package/dist/src/components/Icons/stories/LUIcon.stories.jsx +108 -0
- package/dist/src/components/ImageUploader/ImageUploader.stories.jsx +50 -0
- package/dist/src/components/ImageUploader/imageUploader.jsx +94 -0
- package/dist/src/components/Images/LuImage.jsx +19 -0
- package/dist/src/components/Images/LuImage.stories.jsx +154 -0
- package/dist/src/components/Images/LuImage.test.jsx +44 -0
- package/dist/src/components/Input/Input.stories.jsx +250 -0
- package/dist/src/components/Input/input.jsx +110 -0
- package/dist/src/components/Label/Label.jsx +32 -0
- package/dist/src/components/Label/Label.stories.jsx +30 -0
- package/dist/src/components/Pagination/pagination.d.ts +33 -0
- package/dist/src/components/Pagination/pagination.js +68 -0
- package/dist/src/components/Pagination/pagination.jsx +68 -0
- package/dist/src/components/Pagination/pagination.stories.d.ts +74 -0
- package/dist/src/components/Pagination/pagination.stories.js +168 -0
- package/dist/src/components/Pagination/pagination.stories.jsx +114 -0
- package/dist/src/components/RadioGroup/RadioGroup.stories.jsx +146 -0
- package/dist/src/components/RadioGroup/radio-group.jsx +49 -0
- package/dist/src/components/Skeleton/skeleton.d.ts +117 -0
- package/dist/src/components/Skeleton/skeleton.js +140 -0
- package/dist/src/components/Skeleton/skeleton.stories.d.ts +153 -0
- package/dist/src/components/Skeleton/skeleton.stories.js +404 -0
- package/dist/src/components/Slider/Slider.stories.jsx +159 -0
- package/dist/src/components/Slider/slider.jsx +31 -0
- package/dist/src/components/SweetAlert/SweetAlert.jsx +147 -0
- package/dist/src/components/SweetAlert/SweetAlert.stories.jsx +505 -0
- package/dist/src/components/Switch/Switch.stories.jsx +66 -0
- package/dist/src/components/Switch/switch.jsx +61 -0
- package/dist/src/components/Table/Table.d.ts +26 -0
- package/dist/src/components/Table/Table.js +186 -0
- package/dist/src/components/Table/Table.jsx +221 -0
- package/dist/src/components/Table/Table.stories.d.ts +51 -0
- package/dist/src/components/Table/Table.stories.js +408 -0
- package/dist/src/components/Table/Table.stories.jsx +652 -0
- package/dist/src/components/Table/index.d.ts +20 -0
- package/dist/src/components/Table/index.js +20 -0
- package/dist/src/components/Tabs/Tabs.stories.jsx +29 -0
- package/dist/src/components/Tabs/tabs.jsx +32 -0
- package/dist/src/components/Title/Title.jsx +8 -0
- package/dist/src/components/Title/Title.stories.jsx +37 -0
- package/dist/src/components/Title/Title.test.jsx +24 -0
- package/dist/src/components/ToolTip/Tooltip.jsx +18 -0
- package/dist/src/components/ToolTip/Tooltip.stories.jsx +25 -0
- package/dist/src/components/Typography/Body/Body.stories.jsx +34 -0
- package/dist/src/components/Typography/Body/body.jsx +52 -0
- package/dist/src/components/Typography/Caption/Caption.stories.jsx +24 -0
- package/dist/src/components/Typography/Caption/caption.jsx +25 -0
- package/dist/src/components/Typography/Display/Display.stories.jsx +24 -0
- package/dist/src/components/Typography/Display/display.jsx +39 -0
- package/dist/src/components/Typography/Heading/Heading.stories.jsx +37 -0
- package/dist/src/components/Typography/Heading/heading.jsx +53 -0
- package/dist/src/components/ui/avatar.d.ts +3 -10
- package/dist/src/components/ui/avatar.js +12 -27
- package/dist/src/components/ui/avatar.jsx +27 -0
- package/dist/src/components/ui/button.d.ts +10 -0
- package/dist/src/components/ui/button.js +56 -0
- package/dist/src/components/ui/button.jsx +45 -0
- package/dist/src/components/ui/collapsible.d.ts +5 -0
- package/dist/src/components/ui/collapsible.js +5 -0
- package/dist/src/components/ui/collapsible.jsx +5 -0
- package/dist/src/components/ui/command.jsx +67 -0
- package/dist/src/components/ui/dialog.jsx +66 -0
- package/dist/src/components/ui/popover.jsx +33 -0
- package/dist/src/components/ui/tooltip.jsx +38 -0
- package/dist/src/components/ui/typography.jsx +56 -0
- package/dist/src/utils/iconList.d.ts +4 -0
- package/dist/src/utils/iconList.js +4 -0
- package/dist/styles/global.css +139 -0
- package/package.json +1 -1
- package/dist/src/components/Avatar/Avatar/Avatar1.stories.d.ts +0 -17
- package/dist/src/components/Avatar/Avatar/Avatar1.stories.js +0 -68
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { iconList } from "../../../utils/iconList";
|
|
3
|
+
import LUIcon from "../LUIcon";
|
|
4
|
+
import { iconSize, iconWithBgColor } from "../index";
|
|
5
|
+
import { IconDropdown } from "./IconDropdown";
|
|
6
|
+
import { Heading } from "../../../components/Typography/Heading/heading";
|
|
7
|
+
import { Body } from "../../../components/Typography/Body/body";
|
|
8
|
+
import { Label } from "../../../components/Label/Label";
|
|
9
|
+
export var InteractiveIconSelector = function () {
|
|
10
|
+
var _a = useState("info"), selectedIcon = _a[0], setSelectedIcon = _a[1];
|
|
11
|
+
var _b = useState("md"), selectedSize = _b[0], setSelectedSize = _b[1];
|
|
12
|
+
var _c = useState("default"), selectedVariant = _c[0], setSelectedVariant = _c[1];
|
|
13
|
+
var _d = useState("blue"), selectedColor = _d[0], setSelectedColor = _d[1];
|
|
14
|
+
var generateUsageCode = function () {
|
|
15
|
+
var code = "<LUIcon icon=\"".concat(selectedIcon, "\" size=\"").concat(selectedSize, " color=\"").concat(selectedColor, "\"");
|
|
16
|
+
if (selectedVariant === "padded") {
|
|
17
|
+
code += " variant=\"padded\" \"";
|
|
18
|
+
}
|
|
19
|
+
code += " />";
|
|
20
|
+
return code;
|
|
21
|
+
};
|
|
22
|
+
return (<div className="p-5">
|
|
23
|
+
<Heading variant="h3" className="mb-3">
|
|
24
|
+
Interactive Icon Selector
|
|
25
|
+
</Heading>
|
|
26
|
+
<Body variant="body-md" className="mb-6 text-gray-600">
|
|
27
|
+
This demonstrates a custom searchable dropdown that shows icons
|
|
28
|
+
alongside their names.
|
|
29
|
+
</Body>
|
|
30
|
+
|
|
31
|
+
<div className="grid grid-cols-[repeat(auto-fit,minmax(200px,1fr))] gap-4 mb-6">
|
|
32
|
+
<div>
|
|
33
|
+
<Label variant="label-md" className="block mb-2 ">
|
|
34
|
+
Select Icon:
|
|
35
|
+
</Label>
|
|
36
|
+
<IconDropdown value={selectedIcon} onChange={setSelectedIcon} options={Object.keys(iconList).sort()}/>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<div>
|
|
40
|
+
<Label variant="label-md" className="block mb-2 ">
|
|
41
|
+
Size:
|
|
42
|
+
</Label>
|
|
43
|
+
<select value={selectedSize} onChange={function (e) { return setSelectedSize(e.target.value); }} className="w-full p-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
|
44
|
+
{Object.keys(iconSize).map(function (size) { return (<option key={size} value={size}>
|
|
45
|
+
{size}
|
|
46
|
+
</option>); })}
|
|
47
|
+
</select>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<div>
|
|
51
|
+
<Label variant="label-md" className="block mb-2 ">
|
|
52
|
+
Variant:
|
|
53
|
+
</Label>
|
|
54
|
+
<select value={selectedVariant} onChange={function (e) {
|
|
55
|
+
return setSelectedVariant(e.target.value);
|
|
56
|
+
}} className="w-full p-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
|
57
|
+
<option value="default">Default</option>
|
|
58
|
+
<option value="padded">Padded</option>
|
|
59
|
+
</select>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<div>
|
|
63
|
+
<Label variant="label-md" className="block mb-2">
|
|
64
|
+
Color:
|
|
65
|
+
</Label>
|
|
66
|
+
<select value={selectedColor} onChange={function (e) { return setSelectedColor(e.target.value); }} className="w-full p-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
|
67
|
+
{Object.keys(iconWithBgColor).map(function (color) { return (<option key={color} value={color}>
|
|
68
|
+
{color}
|
|
69
|
+
</option>); })}
|
|
70
|
+
</select>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<div className="p-6 border-2 border-dashed border-gray-300 rounded-lg text-center bg-gray-50">
|
|
75
|
+
<Heading variant="h4" className="mb-4">
|
|
76
|
+
Preview:
|
|
77
|
+
</Heading>
|
|
78
|
+
<div className="my-4">
|
|
79
|
+
<LUIcon icon={selectedIcon} size={selectedSize} variant={selectedVariant} color={selectedColor}/>
|
|
80
|
+
</div>
|
|
81
|
+
<div className="font-mono text-sm bg-gray-100 p-2 rounded">
|
|
82
|
+
{generateUsageCode()}
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</div>);
|
|
86
|
+
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { iconList } from "../../../utils/iconList";
|
|
2
|
+
import { InteractiveIconSelector as InteractiveIconSelectorComponent, IconGallery as IconGalleryComponent, } from ".";
|
|
3
|
+
import LUIcon from "../LUIcon";
|
|
4
|
+
import { iconColor, IconShape, iconSize } from "..";
|
|
5
|
+
export default {
|
|
6
|
+
title: "Components/Icon",
|
|
7
|
+
component: LUIcon,
|
|
8
|
+
tags: ["autodocs"],
|
|
9
|
+
argTypes: {
|
|
10
|
+
size: {
|
|
11
|
+
control: { type: "select" },
|
|
12
|
+
options: Object.keys(iconSize),
|
|
13
|
+
description: "Size of the icon",
|
|
14
|
+
},
|
|
15
|
+
icon: {
|
|
16
|
+
control: {
|
|
17
|
+
type: "select",
|
|
18
|
+
labels: Object.fromEntries(Object.keys(iconList)
|
|
19
|
+
.sort()
|
|
20
|
+
.map(function (key) { return [key]; })),
|
|
21
|
+
},
|
|
22
|
+
options: Object.keys(iconList).sort(), // Sort alphabetically for easier finding
|
|
23
|
+
description: "Icon to display (searchable dropdown with formatted labels)",
|
|
24
|
+
},
|
|
25
|
+
variant: {
|
|
26
|
+
control: { type: "select" },
|
|
27
|
+
options: ["default", "padded"],
|
|
28
|
+
description: "Type of the icon",
|
|
29
|
+
},
|
|
30
|
+
shape: {
|
|
31
|
+
control: {
|
|
32
|
+
type: "radio",
|
|
33
|
+
options: Object.keys(IconShape),
|
|
34
|
+
},
|
|
35
|
+
options: Object.keys(IconShape),
|
|
36
|
+
description: "Shape of the padded icon",
|
|
37
|
+
if: { arg: "variant", eq: "padded" },
|
|
38
|
+
},
|
|
39
|
+
color: {
|
|
40
|
+
control: { type: "select" },
|
|
41
|
+
options: Object.keys(iconColor),
|
|
42
|
+
description: "Text color (no background)",
|
|
43
|
+
table: {
|
|
44
|
+
defaultValue: { summary: "inherit" },
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
className: {
|
|
48
|
+
control: { type: "text" },
|
|
49
|
+
description: "Additional CSS classes",
|
|
50
|
+
table: {
|
|
51
|
+
defaultValue: { summary: "" },
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
export var Default = {
|
|
57
|
+
args: {
|
|
58
|
+
size: "md",
|
|
59
|
+
icon: Object.keys(iconList)[0],
|
|
60
|
+
color: "",
|
|
61
|
+
variant: "default",
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
export var IconVariants = function () { return (<div className="flex flex-row space-x-2">
|
|
65
|
+
<LUIcon icon="star" variant="default" size="lg"/>
|
|
66
|
+
<LUIcon icon="star" variant="padded" color="blue" size="lg"/>
|
|
67
|
+
</div>); };
|
|
68
|
+
export var DefaultIconSizes = function () { return (<div className="flex flex-row space-x-2">
|
|
69
|
+
{Object.keys(iconSize).map(function (size) { return (<LUIcon key={size} icon="star" size={size}/>); })}
|
|
70
|
+
</div>); };
|
|
71
|
+
export var PaddedIconSizes = function () { return (<div className="flex gap-2">
|
|
72
|
+
{Object.keys(iconSize).map(function (size) { return (<LUIcon key={size} icon="star" color="blue" size={size} variant="padded"/>); })}
|
|
73
|
+
</div>); };
|
|
74
|
+
export var PaddedIconSizesRounded = function () { return (<div className="flex gap-2">
|
|
75
|
+
{Object.keys(iconSize).map(function (size) { return (<LUIcon key={size} icon="star" color="blue" shape="rounded" size={size} variant="padded"/>); })}
|
|
76
|
+
</div>); };
|
|
77
|
+
export var IconColors = function () { return (<>
|
|
78
|
+
<div className="flex flex-row space-x-2 mb-2">
|
|
79
|
+
{Object.keys(iconColor).map(function (color) { return (<LUIcon key={color} icon="star" size="lg" color={color}/>); })}
|
|
80
|
+
</div>
|
|
81
|
+
<div className="flex flex-row space-x-2">
|
|
82
|
+
{Object.keys(iconColor).map(function (color) { return (<LUIcon key={color} icon="star" variant="padded" size="lg" color={color}/>); })}
|
|
83
|
+
</div>
|
|
84
|
+
</>); };
|
|
85
|
+
// Export stories using separate components for better maintainability
|
|
86
|
+
export var InteractiveIconSelector = function () { return (<InteractiveIconSelectorComponent />); };
|
|
87
|
+
export var IconGallery = function () { return <IconGalleryComponent />; };
|
|
88
|
+
// Set parameters for the stories
|
|
89
|
+
InteractiveIconSelector.parameters = {
|
|
90
|
+
docs: {
|
|
91
|
+
description: {
|
|
92
|
+
story: "Use this interactive tool to select icons with a custom dropdown that shows both the icon and its name. Perfect for developers to quickly find and preview icons.",
|
|
93
|
+
},
|
|
94
|
+
source: {
|
|
95
|
+
code: null, // This hides the source code
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
IconGallery.parameters = {
|
|
100
|
+
docs: {
|
|
101
|
+
description: {
|
|
102
|
+
story: "Browse and search through all available icons. Click on any icon to see a preview and get the usage code.",
|
|
103
|
+
},
|
|
104
|
+
source: {
|
|
105
|
+
code: null, // This hides the source code
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import ImageUploader from "./imageUploader";
|
|
2
|
+
import { Dummy_Image } from "../../utils/constants";
|
|
3
|
+
var meta = {
|
|
4
|
+
title: "Components/ImageUploader",
|
|
5
|
+
component: ImageUploader,
|
|
6
|
+
tags: ["autodocs"],
|
|
7
|
+
argTypes: {
|
|
8
|
+
onChange: { action: "changed" }, // For logging in the Storybook actions panel
|
|
9
|
+
onRemove: { action: "removed" }, // For logging removal actions
|
|
10
|
+
labels: {
|
|
11
|
+
description: "Object containing customizable text labels for UI messages and localization.",
|
|
12
|
+
control: "object",
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
export default meta;
|
|
17
|
+
export var Default = {
|
|
18
|
+
args: {
|
|
19
|
+
value: null,
|
|
20
|
+
onChange: function (previewUrl, file) {
|
|
21
|
+
console.log("Selected file:", file);
|
|
22
|
+
},
|
|
23
|
+
onRemove: function () {
|
|
24
|
+
console.log("Image removed");
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
export var WithRequired = {
|
|
29
|
+
args: {
|
|
30
|
+
value: null,
|
|
31
|
+
required: true,
|
|
32
|
+
onChange: function (previewUrl, file) {
|
|
33
|
+
console.log("Selected file:", file);
|
|
34
|
+
},
|
|
35
|
+
onRemove: function () {
|
|
36
|
+
console.log("Image removed from required uploader");
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
export var WithPreloadedImage = {
|
|
41
|
+
args: {
|
|
42
|
+
value: Dummy_Image,
|
|
43
|
+
onChange: function (previewUrl, file) {
|
|
44
|
+
console.log("Selected file:", file);
|
|
45
|
+
},
|
|
46
|
+
onRemove: function () {
|
|
47
|
+
console.log("Preloaded image removed");
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
import { useDropzone } from "react-dropzone";
|
|
4
|
+
import { cn } from "../../lib/utils";
|
|
5
|
+
import LUIcon from "../Icons/LUIcon";
|
|
6
|
+
import LuImage from "../Images/LuImage";
|
|
7
|
+
import { Body } from "../Typography/Body/body";
|
|
8
|
+
import { Button } from "../Button/Button/Button";
|
|
9
|
+
var ImageUploader = function (_a) {
|
|
10
|
+
var value = _a.value, onChange = _a.onChange, onRemove = _a.onRemove, required = _a.required, className = _a.className, _b = _a.maxFileSizeMB, maxFileSizeMB = _b === void 0 ? 6 : _b, _c = _a.acceptedTypes, acceptedTypes = _c === void 0 ? ["image/png", "image/jpeg", "image/jpg", "image/svg+xml"] : _c, _d = _a.labels, labels = _d === void 0 ? {
|
|
11
|
+
chooseFile: "Choose a file or drag & drop it here",
|
|
12
|
+
supportedFormats: "Supported formats: JPEG, PNG, SVG",
|
|
13
|
+
fileTypeError: "Only JPEG/JPG, PNG, and SVG files are supported",
|
|
14
|
+
fileSizeError: "File size exceeds ".concat(maxFileSizeMB, "MB"),
|
|
15
|
+
imageRequired: "Image is required",
|
|
16
|
+
removeImage: "Remove Image",
|
|
17
|
+
} : _d;
|
|
18
|
+
var _e = useState(null), preview = _e[0], setPreview = _e[1];
|
|
19
|
+
var _f = useState(""), fileError = _f[0], setFileError = _f[1];
|
|
20
|
+
useEffect(function () {
|
|
21
|
+
if (value && typeof value === "string") {
|
|
22
|
+
setPreview(value);
|
|
23
|
+
}
|
|
24
|
+
else if (value instanceof File) {
|
|
25
|
+
setPreview(URL.createObjectURL(value));
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
setPreview(null);
|
|
29
|
+
}
|
|
30
|
+
}, [value]);
|
|
31
|
+
var onDrop = function (acceptedFiles) {
|
|
32
|
+
var file = acceptedFiles[0];
|
|
33
|
+
if (!file)
|
|
34
|
+
return;
|
|
35
|
+
if (!acceptedTypes.includes(file.type)) {
|
|
36
|
+
setFileError(labels === null || labels === void 0 ? void 0 : labels.fileTypeError);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
var sizeMB = file.size / 1024 / 1024;
|
|
40
|
+
if (sizeMB > maxFileSizeMB) {
|
|
41
|
+
setFileError(labels === null || labels === void 0 ? void 0 : labels.fileSizeError);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
var previewUrl = URL.createObjectURL(file);
|
|
45
|
+
setPreview(previewUrl);
|
|
46
|
+
setFileError("");
|
|
47
|
+
onChange(previewUrl, file);
|
|
48
|
+
};
|
|
49
|
+
var removeFile = function () {
|
|
50
|
+
setPreview(null);
|
|
51
|
+
setFileError("");
|
|
52
|
+
onChange(null, null);
|
|
53
|
+
// If onRemove prop is provided, call it after internal cleanup
|
|
54
|
+
if (onRemove) {
|
|
55
|
+
onRemove();
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
var _g = useDropzone({
|
|
59
|
+
onDrop: onDrop,
|
|
60
|
+
multiple: false,
|
|
61
|
+
accept: {
|
|
62
|
+
"image/*": acceptedTypes,
|
|
63
|
+
},
|
|
64
|
+
}), getRootProps = _g.getRootProps, getInputProps = _g.getInputProps;
|
|
65
|
+
return (<div className={cn("flex flex-col items-center", className)}>
|
|
66
|
+
<div {...getRootProps()} className={cn("!border !border-dashed !border-gray-300 !rounded-lg cursor-pointer w-64 !p-2")}>
|
|
67
|
+
<div className="min-h-40 flex items-center justify-center bg-gray-100 !rounded-lg">
|
|
68
|
+
<input {...getInputProps()}/>
|
|
69
|
+
|
|
70
|
+
{preview ? (<div className="relative w-full h-40 !mx-auto overflow-hidden">
|
|
71
|
+
<LuImage src={preview} alt="Uploaded" className="aspect-square object-contain" fill/>
|
|
72
|
+
</div>) : (<div className="text-center text-sm text-muted-foreground">
|
|
73
|
+
<LUIcon icon="upload" size="lg" className="!mx-auto !mb-4"/>
|
|
74
|
+
<Body variant="body-xs-600" className="!px-1">
|
|
75
|
+
{labels === null || labels === void 0 ? void 0 : labels.chooseFile}
|
|
76
|
+
</Body>
|
|
77
|
+
<p className="text-xs text-muted-foreground">
|
|
78
|
+
{labels === null || labels === void 0 ? void 0 : labels.supportedFormats}
|
|
79
|
+
</p>
|
|
80
|
+
</div>)}
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
{fileError && (<p className="text-sm text-red-500 text-center mt-2">{fileError}</p>)}
|
|
84
|
+
|
|
85
|
+
{required && !preview && !fileError && (<p className="text-sm text-red-500 text-center !mt-2">
|
|
86
|
+
{labels === null || labels === void 0 ? void 0 : labels.imageRequired}
|
|
87
|
+
</p>)}
|
|
88
|
+
|
|
89
|
+
{preview && (<Button variant="link" color="red" onClick={removeFile} className="!mt-2">
|
|
90
|
+
{labels === null || labels === void 0 ? void 0 : labels.removeImage}
|
|
91
|
+
</Button>)}
|
|
92
|
+
</div>);
|
|
93
|
+
};
|
|
94
|
+
export default ImageUploader;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import Image from "next/image";
|
|
13
|
+
import { aspectRatio } from ".";
|
|
14
|
+
var LuImage = function (_a) {
|
|
15
|
+
var _b = _a.ratio, ratio = _b === void 0 ? "square" : _b, props = __rest(_a, ["ratio"]);
|
|
16
|
+
// eslint-disable-next-line jsx-a11y/alt-text
|
|
17
|
+
return <Image className={"".concat(aspectRatio[ratio])} {...props}/>;
|
|
18
|
+
};
|
|
19
|
+
export default LuImage;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import LuImage from "./LuImage";
|
|
2
|
+
import { aspectRatio } from ".";
|
|
3
|
+
export default {
|
|
4
|
+
title: "Components/Image",
|
|
5
|
+
component: LuImage,
|
|
6
|
+
argTypes: {
|
|
7
|
+
src: {
|
|
8
|
+
control: "text",
|
|
9
|
+
description: "Image source URL",
|
|
10
|
+
table: {
|
|
11
|
+
type: { summary: "string" },
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
width: {
|
|
15
|
+
control: "number",
|
|
16
|
+
description: "Image width",
|
|
17
|
+
table: {
|
|
18
|
+
type: { summary: "number" },
|
|
19
|
+
defaultValue: { summary: "240" },
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
height: {
|
|
23
|
+
control: "number",
|
|
24
|
+
description: "Image width",
|
|
25
|
+
table: {
|
|
26
|
+
type: { summary: "number" },
|
|
27
|
+
defaultValue: { summary: "240" },
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
alt: {
|
|
31
|
+
control: "text",
|
|
32
|
+
description: "Image alt text",
|
|
33
|
+
table: {
|
|
34
|
+
type: { summary: "string" },
|
|
35
|
+
defaultValue: { summary: "Demo Image" },
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
loader: {
|
|
39
|
+
control: false,
|
|
40
|
+
description: "loader={imageLoader}",
|
|
41
|
+
table: {
|
|
42
|
+
type: { summary: "function" },
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
fill: {
|
|
46
|
+
control: "boolean",
|
|
47
|
+
description: "fill={false}",
|
|
48
|
+
table: {
|
|
49
|
+
type: { summary: "boolean" },
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
sizes: {
|
|
53
|
+
control: "text",
|
|
54
|
+
description: "sizes=(max-width: 768px) 100vw, 33vw",
|
|
55
|
+
table: {
|
|
56
|
+
type: { summary: "string" },
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
quality: {
|
|
60
|
+
control: "number",
|
|
61
|
+
description: "Image quality",
|
|
62
|
+
table: {
|
|
63
|
+
type: { summary: "Integer (1-100)" },
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
priority: {
|
|
67
|
+
control: "boolean",
|
|
68
|
+
description: "priority={false}",
|
|
69
|
+
table: {
|
|
70
|
+
type: { summary: "boolean" },
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
placeholder: {
|
|
74
|
+
control: "select",
|
|
75
|
+
options: ["blur", "empty"],
|
|
76
|
+
description: "placeholder={blur}",
|
|
77
|
+
table: {
|
|
78
|
+
type: { summary: "string" },
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
style: {
|
|
82
|
+
control: "object",
|
|
83
|
+
description: "stye={{ objectFit: contain }}",
|
|
84
|
+
table: {
|
|
85
|
+
type: { summary: "object" },
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
className: { control: "text" },
|
|
89
|
+
onLoad: {
|
|
90
|
+
control: false,
|
|
91
|
+
description: "onLoad={event => done())}",
|
|
92
|
+
table: {
|
|
93
|
+
type: { summary: "function" },
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
onError: {
|
|
97
|
+
description: "onError={event => fail()}",
|
|
98
|
+
table: {
|
|
99
|
+
type: { summary: "function" },
|
|
100
|
+
},
|
|
101
|
+
control: false,
|
|
102
|
+
},
|
|
103
|
+
loading: {
|
|
104
|
+
control: "select",
|
|
105
|
+
options: ["lazy", "eager"],
|
|
106
|
+
description: "Image loading",
|
|
107
|
+
table: {
|
|
108
|
+
type: { summary: "string" },
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
blurDataURL: {
|
|
112
|
+
control: "text",
|
|
113
|
+
description: "blurDataURL=data:image/jpeg...",
|
|
114
|
+
table: {
|
|
115
|
+
type: { summary: "string" },
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
overrideSrc: {
|
|
119
|
+
control: "text",
|
|
120
|
+
description: "overrideSrc=/seo.png",
|
|
121
|
+
table: {
|
|
122
|
+
type: { summary: "string" },
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
ratio: {
|
|
126
|
+
control: "select",
|
|
127
|
+
options: Object.keys(aspectRatio),
|
|
128
|
+
description: "Aspect ratio of the image",
|
|
129
|
+
table: {
|
|
130
|
+
type: { summary: "string" },
|
|
131
|
+
defaultValue: { summary: "square" },
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
var Template = function (args) { return <LuImage {...args}/>; };
|
|
137
|
+
export var _Image = Template.bind({});
|
|
138
|
+
_Image.args = {
|
|
139
|
+
src: "/images/demo-image.jpg",
|
|
140
|
+
ratio: "square",
|
|
141
|
+
width: 240,
|
|
142
|
+
height: 240,
|
|
143
|
+
alt: "Demo Image",
|
|
144
|
+
};
|
|
145
|
+
_Image.argTypes = {
|
|
146
|
+
ratio: {
|
|
147
|
+
control: {
|
|
148
|
+
type: "select",
|
|
149
|
+
labels: Object.keys(aspectRatio),
|
|
150
|
+
},
|
|
151
|
+
options: Object.keys(aspectRatio),
|
|
152
|
+
defaultValue: "square",
|
|
153
|
+
},
|
|
154
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import LuImage from "./LuImage";
|
|
3
|
+
import { aspectRatio } from ".";
|
|
4
|
+
// Mock next/image to render a basic `img` element for testing
|
|
5
|
+
jest.mock("next/image", function () { return ({
|
|
6
|
+
__esModule: true,
|
|
7
|
+
default: function (props) {
|
|
8
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
9
|
+
return <img alt="" {...props}/>;
|
|
10
|
+
},
|
|
11
|
+
}); });
|
|
12
|
+
describe("LuImage component", function () {
|
|
13
|
+
it("renders with default props", function () {
|
|
14
|
+
render(<LuImage src="/test.jpg" width={100} height={100} alt="Demo Image"/>);
|
|
15
|
+
var image = screen.getByAltText("Demo Image");
|
|
16
|
+
expect(image).toBeInTheDocument();
|
|
17
|
+
expect(image).toHaveAttribute("src", "/test.jpg");
|
|
18
|
+
expect(image).toHaveClass("aspect-square");
|
|
19
|
+
});
|
|
20
|
+
it("uses correct aspect ratio class", function () {
|
|
21
|
+
var ratio = "aspect-4/3";
|
|
22
|
+
render(<LuImage src="/test.jpg" width={100} height={100} ratio={ratio} alt="Demo Image"/>);
|
|
23
|
+
var image = screen.getByAltText("Demo Image");
|
|
24
|
+
expect(image).toHaveClass(aspectRatio[ratio]);
|
|
25
|
+
});
|
|
26
|
+
it("accepts custom alt text", function () {
|
|
27
|
+
render(<LuImage src="/test.jpg" width={100} height={100} alt="Custom Alt"/>);
|
|
28
|
+
var image = screen.getByAltText("Custom Alt");
|
|
29
|
+
expect(image).toBeInTheDocument();
|
|
30
|
+
});
|
|
31
|
+
it("accepts additional className", function () {
|
|
32
|
+
render(<LuImage src="/test.jpg" width={100} height={100} className="rounded-full" alt="Demo Image"/>);
|
|
33
|
+
var image = screen.getByAltText("Demo Image");
|
|
34
|
+
expect(image).toHaveClass("rounded-full");
|
|
35
|
+
});
|
|
36
|
+
it("renders with different aspect ratios", function () {
|
|
37
|
+
for (var ratio in aspectRatio) {
|
|
38
|
+
var typedRatio = ratio;
|
|
39
|
+
render(<LuImage key={typedRatio} src="/test.jpg" width={100} height={100} ratio={typedRatio} alt={"Image with ratio ".concat(typedRatio)}/>);
|
|
40
|
+
var image = screen.getByAltText("Image with ratio ".concat(typedRatio));
|
|
41
|
+
expect(image).toHaveClass(aspectRatio[typedRatio]);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
});
|