@js-empire/emperor-ui 1.2.6 → 1.2.7
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/package.json +2 -1
- package/src/components/atoms/uploader/{avatar-label.tsx → components/avatar-label.tsx} +17 -5
- package/src/components/atoms/uploader/components/index.ts +8 -0
- package/src/components/atoms/uploader/components/upload-file-error-box.tsx +40 -0
- package/src/components/atoms/uploader/{upload-file-label.tsx → components/upload-file-label.tsx} +18 -11
- package/src/components/atoms/uploader/index.ts +1 -8
- package/src/components/atoms/uploader/stories/uploader.stories.tsx +17 -10
- package/src/components/molecules/item-card/index.ts +2 -0
- package/src/components/molecules/item-card/item-actions-buttons.tsx +43 -0
- package/src/components/molecules/item-card/item-actions-overlay.tsx +41 -0
- package/src/components/molecules/item-card/item-card-body.tsx +8 -2
- package/src/components/molecules/item-card/item-card-footer.tsx +22 -1
- package/src/components/molecules/item-card/item-card-header.tsx +8 -2
- package/src/components/molecules/item-card/item-card.tsx +39 -1
- package/src/components/molecules/item-card/stories/item-card.stories.tsx +36 -0
- package/src/components/organisms/deletion-confirmor/deletion-confirmor.tsx +114 -0
- package/src/components/organisms/deletion-confirmor/index.ts +3 -0
- package/src/components/organisms/deletion-confirmor/stories/components.tsx +22 -0
- package/src/components/organisms/deletion-confirmor/stories/deletion-confirmor.stories.tsx +78 -0
- package/src/components/organisms/deletion-confirmor/styles/classes.ts +28 -0
- package/src/components/organisms/deletion-confirmor/styles/index.ts +2 -0
- package/src/components/organisms/deletion-confirmor/styles/styles.ts +4 -0
- package/src/components/organisms/index.ts +1 -0
- package/src/constants/card.tsx +5 -2
- package/src/hooks/use-uploader.tsx +21 -9
- package/src/i18n/locales/atoms/ar.ts +1 -1
- package/src/i18n/locales/atoms/en.ts +1 -1
- package/src/i18n/locales/organisms/ar.ts +4 -0
- package/src/i18n/locales/organisms/en.ts +4 -0
- package/src/mocks/deletion-confirmor.ts +16 -0
- package/src/mocks/index.ts +2 -0
- package/src/mocks/locales/index.ts +1 -0
- package/src/mocks/locales/uploader.ts +33 -0
- package/src/types/components/atoms/uploader.ts +4 -0
- package/src/types/components/molecules/item-card/item-card.ts +14 -4
- package/src/types/components/organisms/deletion-confirmor/deletion-confirmor.ts +22 -0
- package/src/types/components/organisms/deletion-confirmor/index.ts +1 -0
- package/src/types/components/organisms/index.ts +1 -0
- package/src/utils/uploader.ts +25 -7
- package/dist/emperor-ui.js +0 -134
- package/dist/emperor-ui.umd.cjs +0 -77
- package/dist/globals.css +0 -1
- package/dist/icons/emperor-ui-logo.ico +0 -0
- package/dist/images/avatar-female.jpg +0 -0
- package/dist/images/avatar-male.jpg +0 -0
- package/dist/images/emperor-ui-logo.png +0 -0
- package/dist/index-CLEmvl4g.js +0 -290
- package/dist/index-DceZlwg2.js +0 -5
- package/dist/index-KrC7oBFa.js +0 -59874
- package/dist/index.d.ts +0 -1220
- package/dist/src-UW24ZMRV-DfI_MdGD.js +0 -5
- package/src/components/atoms/uploader/upload-file-error-box.tsx +0 -29
- /package/src/components/atoms/uploader/{upload-file-input.tsx → components/upload-file-input.tsx} +0 -0
- /package/src/components/atoms/uploader/{upload-file-listing.tsx → components/upload-file-listing.tsx} +0 -0
- /package/src/components/atoms/uploader/{uploader-title.tsx → components/uploader-title.tsx} +0 -0
- /package/src/components/atoms/uploader/{uploader.tsx → components/uploader.tsx} +0 -0
- /package/src/components/atoms/uploader/{view-image-modal.tsx → components/view-image-modal.tsx} +0 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@js-empire/emperor-ui",
|
|
3
3
|
"description": "They provide the atoms, we provide the empire.",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.7",
|
|
5
5
|
"author": "JS Empire - Mustafa Alhasanat",
|
|
6
6
|
"license": "ISC",
|
|
7
7
|
"type": "module",
|
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
"@heroui/system": "^2.4.27",
|
|
74
74
|
"@heroui/theme": "^2.4.25",
|
|
75
75
|
"@heroui/toast": "^2.0.21",
|
|
76
|
+
"@heroui/tooltip": "^2.2.28",
|
|
76
77
|
"@hookform/resolvers": "^5.2.2",
|
|
77
78
|
"@internationalized/date": "^3.11.0",
|
|
78
79
|
"@storybook/react": "^10.1.8",
|
|
@@ -3,13 +3,15 @@
|
|
|
3
3
|
import { Placeholders } from "@/enums";
|
|
4
4
|
import { Avatar } from "@heroui/avatar";
|
|
5
5
|
import { Spinner } from "@heroui/spinner";
|
|
6
|
-
import { cn } from "@/utils";
|
|
6
|
+
import { cn, mergeUploaderLocale } from "@/utils";
|
|
7
7
|
import { useEmperorUI, useUploaderContext } from "@/hooks";
|
|
8
8
|
import { useState } from "react";
|
|
9
|
+
import { getLocales, Locale } from "@/i18n";
|
|
9
10
|
|
|
10
11
|
export function AvatarLabel() {
|
|
11
12
|
const { config } = useEmperorUI();
|
|
12
13
|
const [draggableMessage, setDraggableMessage] = useState<string | null>(null);
|
|
14
|
+
|
|
13
15
|
const {
|
|
14
16
|
labelId,
|
|
15
17
|
classNames,
|
|
@@ -21,12 +23,22 @@ export function AvatarLabel() {
|
|
|
21
23
|
files,
|
|
22
24
|
isLoading,
|
|
23
25
|
isMulti,
|
|
26
|
+
locales,
|
|
24
27
|
} = useUploaderContext();
|
|
25
28
|
|
|
26
|
-
const
|
|
27
|
-
const lang =
|
|
29
|
+
const configLocales = config?.interLocalization?.locales;
|
|
30
|
+
const lang =
|
|
31
|
+
config?.interLocalization?.lang ||
|
|
32
|
+
config?.interLocalization?.defaultLanguage ||
|
|
33
|
+
"en";
|
|
28
34
|
|
|
29
|
-
const
|
|
35
|
+
const defaultLocale = getLocales(lang);
|
|
36
|
+
const uploaderLocale = mergeUploaderLocale({
|
|
37
|
+
defaultUploaderLocale: defaultLocale.atoms.uploader,
|
|
38
|
+
configUploaderLocale: (configLocales?.[lang] as Locale | undefined)?.atoms
|
|
39
|
+
?.uploader,
|
|
40
|
+
contextUploaderLocale: locales,
|
|
41
|
+
});
|
|
30
42
|
|
|
31
43
|
const handleDrop = (
|
|
32
44
|
event: React.ChangeEvent<HTMLInputElement> &
|
|
@@ -41,7 +53,7 @@ export function AvatarLabel() {
|
|
|
41
53
|
React.DragEvent<HTMLLabelElement>,
|
|
42
54
|
) => {
|
|
43
55
|
event.preventDefault();
|
|
44
|
-
setDraggableMessage(
|
|
56
|
+
setDraggableMessage(uploaderLocale.dropHere);
|
|
45
57
|
};
|
|
46
58
|
|
|
47
59
|
const handleDragLeave = () => {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from "./uploader";
|
|
2
|
+
export * from "./avatar-label";
|
|
3
|
+
export * from "./upload-file-label";
|
|
4
|
+
export * from "./view-image-modal";
|
|
5
|
+
export * from "./upload-file-listing";
|
|
6
|
+
export * from "./upload-file-error-box";
|
|
7
|
+
export * from "./upload-file-input";
|
|
8
|
+
export * from "./uploader-title";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { cn, mergeUploaderLocale } from "@/utils";
|
|
4
|
+
import { useEmperorUI, useUploaderContext } from "@/hooks";
|
|
5
|
+
import { useMemo } from "react";
|
|
6
|
+
import { getLocales, Locale } from "@/i18n";
|
|
7
|
+
|
|
8
|
+
export function UploadFileErrorBox() {
|
|
9
|
+
const { config } = useEmperorUI();
|
|
10
|
+
const { files, isRequired, classNames, errorMessage, locales } =
|
|
11
|
+
useUploaderContext();
|
|
12
|
+
|
|
13
|
+
const configLocales = config?.interLocalization?.locales;
|
|
14
|
+
const lang =
|
|
15
|
+
config?.interLocalization?.lang ||
|
|
16
|
+
config?.interLocalization?.defaultLanguage ||
|
|
17
|
+
"en";
|
|
18
|
+
|
|
19
|
+
const defaultLocale = getLocales(lang);
|
|
20
|
+
const uploaderLocale = mergeUploaderLocale({
|
|
21
|
+
defaultUploaderLocale: defaultLocale.atoms.uploader,
|
|
22
|
+
configUploaderLocale: (configLocales?.[lang] as Locale | undefined)?.atoms
|
|
23
|
+
?.uploader,
|
|
24
|
+
contextUploaderLocale: locales,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const isError = useMemo(
|
|
28
|
+
() => files?.length === 0 && isRequired,
|
|
29
|
+
[files, isRequired],
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
if (isError)
|
|
33
|
+
return (
|
|
34
|
+
<p className={cn("text-[14px] text-danger", classNames?.error)}>
|
|
35
|
+
{errorMessage ?? uploaderLocale.errorUploadingFile}
|
|
36
|
+
</p>
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
return null;
|
|
40
|
+
}
|
package/src/components/atoms/uploader/{upload-file-label.tsx → components/upload-file-label.tsx}
RENAMED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { Spinner } from "@heroui/spinner";
|
|
4
|
-
import { cn } from "@/utils";
|
|
4
|
+
import { cn, mergeUploaderLocale } from "@/utils";
|
|
5
5
|
import { useEmperorUI, useUploaderContext } from "@/hooks";
|
|
6
6
|
import { UploadCloud } from "lucide-react";
|
|
7
7
|
import { useState } from "react";
|
|
8
|
+
import { getLocales, Locale } from "@/i18n";
|
|
8
9
|
|
|
9
10
|
export function UploadFileLabel() {
|
|
10
11
|
const { config } = useEmperorUI();
|
|
@@ -18,12 +19,22 @@ export function UploadFileLabel() {
|
|
|
18
19
|
isLoading,
|
|
19
20
|
isMulti,
|
|
20
21
|
files,
|
|
22
|
+
locales,
|
|
21
23
|
} = useUploaderContext();
|
|
22
24
|
|
|
23
|
-
const
|
|
24
|
-
const lang =
|
|
25
|
+
const configLocales = config?.interLocalization?.locales;
|
|
26
|
+
const lang =
|
|
27
|
+
config?.interLocalization?.lang ||
|
|
28
|
+
config?.interLocalization?.defaultLanguage ||
|
|
29
|
+
"en";
|
|
25
30
|
|
|
26
|
-
const
|
|
31
|
+
const defaultLocale = getLocales(lang);
|
|
32
|
+
const uploaderLocale = mergeUploaderLocale({
|
|
33
|
+
defaultUploaderLocale: defaultLocale.atoms.uploader,
|
|
34
|
+
configUploaderLocale: (configLocales?.[lang] as Locale | undefined)?.atoms
|
|
35
|
+
?.uploader,
|
|
36
|
+
contextUploaderLocale: locales,
|
|
37
|
+
});
|
|
27
38
|
|
|
28
39
|
const handleDrop = (
|
|
29
40
|
event: React.ChangeEvent<HTMLInputElement> &
|
|
@@ -38,7 +49,7 @@ export function UploadFileLabel() {
|
|
|
38
49
|
React.DragEvent<HTMLLabelElement>,
|
|
39
50
|
) => {
|
|
40
51
|
event.preventDefault();
|
|
41
|
-
setDraggableMessage(
|
|
52
|
+
setDraggableMessage(uploaderLocale.dropHere);
|
|
42
53
|
};
|
|
43
54
|
|
|
44
55
|
const handleDragLeave = () => {
|
|
@@ -68,12 +79,8 @@ export function UploadFileLabel() {
|
|
|
68
79
|
<div className="pointer-events-none flex size-full flex-col items-center justify-center gap-2 rounded-md border border-dashed bg-primary/10 px-2 py-8 text-xs">
|
|
69
80
|
<UploadCloud className="size-10 text-primary" />
|
|
70
81
|
|
|
71
|
-
<p className="font-bold">
|
|
72
|
-
|
|
73
|
-
</p>
|
|
74
|
-
<p className="opacity-70">
|
|
75
|
-
{locale?.atoms?.uploader?.selectionTypes || ""}
|
|
76
|
-
</p>
|
|
82
|
+
<p className="font-bold">{uploaderLocale.selectFile}</p>
|
|
83
|
+
<p className="opacity-70">{uploaderLocale.selectionTypes}</p>
|
|
77
84
|
|
|
78
85
|
{draggableMessage && (
|
|
79
86
|
<p className="text-sm font-bold">{draggableMessage}</p>
|
|
@@ -1,8 +1 @@
|
|
|
1
|
-
export * from "./
|
|
2
|
-
export * from "./avatar-label";
|
|
3
|
-
export * from "./upload-file-label";
|
|
4
|
-
export * from "./view-image-modal";
|
|
5
|
-
export * from "./upload-file-listing";
|
|
6
|
-
export * from "./upload-file-error-box";
|
|
7
|
-
export * from "./upload-file-input";
|
|
8
|
-
export * from "./uploader-title";
|
|
1
|
+
export * from "./components";
|
|
@@ -3,6 +3,7 @@ import { Uploader } from "@/components";
|
|
|
3
3
|
import { getStorybookDecorators } from "@/utils";
|
|
4
4
|
import { useUploader } from "@/hooks";
|
|
5
5
|
import { useDisclosure } from "@heroui/modal";
|
|
6
|
+
import { uploaderLocalesMock } from "@/mocks";
|
|
6
7
|
import { LangKey } from "@/i18n";
|
|
7
8
|
|
|
8
9
|
const meta: Meta<typeof Uploader> = {
|
|
@@ -17,16 +18,6 @@ const meta: Meta<typeof Uploader> = {
|
|
|
17
18
|
layout: {
|
|
18
19
|
withScaffold: false,
|
|
19
20
|
},
|
|
20
|
-
interLocalization: {
|
|
21
|
-
locales: {
|
|
22
|
-
[LangKey.ENGLISH]: {
|
|
23
|
-
atoms: {
|
|
24
|
-
uploader: {},
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
[LangKey.ARABIC]: {},
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
21
|
},
|
|
31
22
|
}),
|
|
32
23
|
};
|
|
@@ -192,3 +183,19 @@ export const WithTitle: Story = {
|
|
|
192
183
|
return <Uploader {...uploadProps} title="Upload your image" />;
|
|
193
184
|
},
|
|
194
185
|
};
|
|
186
|
+
|
|
187
|
+
export const WithCustomLocales: Story = {
|
|
188
|
+
args: {
|
|
189
|
+
locales: uploaderLocalesMock[LangKey.ENGLISH],
|
|
190
|
+
},
|
|
191
|
+
render: (args) => {
|
|
192
|
+
const uploadProps = useUploader({
|
|
193
|
+
fileTypes: ["image", "pdf"],
|
|
194
|
+
labelId: "image",
|
|
195
|
+
isRequired: true,
|
|
196
|
+
isMulti: true,
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
return <Uploader {...uploadProps} {...args} />;
|
|
200
|
+
},
|
|
201
|
+
};
|
|
@@ -2,6 +2,8 @@ export * from "./item-card";
|
|
|
2
2
|
export * from "./loading-item";
|
|
3
3
|
export * from "./item-banner";
|
|
4
4
|
export * from "./item-actions-dropdown";
|
|
5
|
+
export * from "./item-actions-buttons";
|
|
6
|
+
export * from "./item-actions-overlay";
|
|
5
7
|
export * from "./item-card-header";
|
|
6
8
|
export * from "./item-card-body";
|
|
7
9
|
export * from "./item-card-footer";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { ItemCardProps } from "@/types";
|
|
4
|
+
import { cn } from "@/utils";
|
|
5
|
+
import { Button } from "@heroui/button";
|
|
6
|
+
|
|
7
|
+
type ItemActionsButtonsProps = Pick<
|
|
8
|
+
ItemCardProps,
|
|
9
|
+
"actions" | "classNames" | "onActionClick"
|
|
10
|
+
> & {
|
|
11
|
+
className?: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export function ItemActionsButtons({
|
|
15
|
+
actions,
|
|
16
|
+
classNames,
|
|
17
|
+
onActionClick,
|
|
18
|
+
className,
|
|
19
|
+
}: ItemActionsButtonsProps) {
|
|
20
|
+
if (!actions || actions.length === 0) return null;
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div
|
|
24
|
+
data-slot="emperor-ui-item-card-actions-buttons"
|
|
25
|
+
className={cn("flex flex-wrap gap-2", classNames?.actions, className)}
|
|
26
|
+
>
|
|
27
|
+
{actions.map(
|
|
28
|
+
({ key, label, className: actionClassName, ...props }, index) => (
|
|
29
|
+
<Button
|
|
30
|
+
key={key ?? index}
|
|
31
|
+
data-slot="emperor-ui-item-card-actions-button"
|
|
32
|
+
size="sm"
|
|
33
|
+
className={cn(classNames?.action, actionClassName)}
|
|
34
|
+
onPress={() => key && onActionClick?.(String(key))}
|
|
35
|
+
{...props}
|
|
36
|
+
>
|
|
37
|
+
{label}
|
|
38
|
+
</Button>
|
|
39
|
+
),
|
|
40
|
+
)}
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { ItemCardProps } from "@/types";
|
|
4
|
+
import { cn } from "@/utils";
|
|
5
|
+
import { Button } from "@heroui/button";
|
|
6
|
+
|
|
7
|
+
type ItemActionsOverlayProps = Pick<
|
|
8
|
+
ItemCardProps,
|
|
9
|
+
"actions" | "classNames" | "onActionClick"
|
|
10
|
+
>;
|
|
11
|
+
|
|
12
|
+
export function ItemActionsOverlay({
|
|
13
|
+
actions,
|
|
14
|
+
classNames,
|
|
15
|
+
onActionClick,
|
|
16
|
+
}: ItemActionsOverlayProps) {
|
|
17
|
+
if (!actions || actions.length === 0) return null;
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div
|
|
21
|
+
data-slot="emperor-ui-item-card-actions-overlay-buttons"
|
|
22
|
+
className={cn("flex flex-col items-center gap-3", classNames?.actions)}
|
|
23
|
+
>
|
|
24
|
+
{actions?.map(
|
|
25
|
+
({ key, label, className: actionClassName, ...props }, index) => {
|
|
26
|
+
return (
|
|
27
|
+
<Button
|
|
28
|
+
key={key ?? index}
|
|
29
|
+
data-slot="emperor-ui-item-card-actions-overlay-button"
|
|
30
|
+
isIconOnly
|
|
31
|
+
radius="full"
|
|
32
|
+
className={cn(classNames?.action, actionClassName)}
|
|
33
|
+
onPress={() => key && onActionClick?.(String(key))}
|
|
34
|
+
{...props}
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
},
|
|
38
|
+
)}
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -17,9 +17,15 @@ export function ItemCardBody({
|
|
|
17
17
|
classNames,
|
|
18
18
|
actions,
|
|
19
19
|
onActionClick,
|
|
20
|
+
actionsViewVariant = "dropdown",
|
|
20
21
|
}: Pick<
|
|
21
22
|
ItemCardProps,
|
|
22
|
-
|
|
23
|
+
| "item"
|
|
24
|
+
| "orientation"
|
|
25
|
+
| "classNames"
|
|
26
|
+
| "actions"
|
|
27
|
+
| "onActionClick"
|
|
28
|
+
| "actionsViewVariant"
|
|
23
29
|
>) {
|
|
24
30
|
return (
|
|
25
31
|
<CardBody
|
|
@@ -56,7 +62,7 @@ export function ItemCardBody({
|
|
|
56
62
|
</p>
|
|
57
63
|
)}
|
|
58
64
|
|
|
59
|
-
{orientation === "horizontal" && (
|
|
65
|
+
{orientation === "horizontal" && actionsViewVariant === "dropdown" && (
|
|
60
66
|
<ItemActionsDropdown
|
|
61
67
|
actions={actions}
|
|
62
68
|
classNames={classNames}
|
|
@@ -5,12 +5,24 @@ import { cn } from "@/utils";
|
|
|
5
5
|
import { itemFooterClasses, itemChipsClasses } from "./styles";
|
|
6
6
|
import { CardFooter } from "@heroui/card";
|
|
7
7
|
import { Chip } from "@heroui/chip";
|
|
8
|
+
import { ItemActionsButtons } from "./item-actions-buttons";
|
|
8
9
|
|
|
9
10
|
export function ItemCardFooter({
|
|
10
11
|
item,
|
|
11
12
|
orientation,
|
|
12
13
|
classNames,
|
|
13
|
-
|
|
14
|
+
actions,
|
|
15
|
+
onActionClick,
|
|
16
|
+
actionsViewVariant = "dropdown",
|
|
17
|
+
}: Pick<
|
|
18
|
+
ItemCardProps,
|
|
19
|
+
| "item"
|
|
20
|
+
| "orientation"
|
|
21
|
+
| "classNames"
|
|
22
|
+
| "actions"
|
|
23
|
+
| "onActionClick"
|
|
24
|
+
| "actionsViewVariant"
|
|
25
|
+
>) {
|
|
14
26
|
return (
|
|
15
27
|
<CardFooter
|
|
16
28
|
data-slot="emperor-ui-item-card-footer"
|
|
@@ -50,6 +62,15 @@ export function ItemCardFooter({
|
|
|
50
62
|
)}
|
|
51
63
|
</menu>
|
|
52
64
|
)}
|
|
65
|
+
|
|
66
|
+
{actionsViewVariant === "buttons" && actions && actions.length > 0 && (
|
|
67
|
+
<ItemActionsButtons
|
|
68
|
+
actions={actions}
|
|
69
|
+
classNames={classNames}
|
|
70
|
+
onActionClick={onActionClick}
|
|
71
|
+
className="ml-auto"
|
|
72
|
+
/>
|
|
73
|
+
)}
|
|
53
74
|
</CardFooter>
|
|
54
75
|
);
|
|
55
76
|
}
|
|
@@ -15,9 +15,15 @@ export function ItemCardHeader({
|
|
|
15
15
|
classNames,
|
|
16
16
|
actions,
|
|
17
17
|
onActionClick,
|
|
18
|
+
actionsViewVariant = "dropdown",
|
|
18
19
|
}: Pick<
|
|
19
20
|
ItemCardProps,
|
|
20
|
-
|
|
21
|
+
| "item"
|
|
22
|
+
| "orientation"
|
|
23
|
+
| "classNames"
|
|
24
|
+
| "actions"
|
|
25
|
+
| "onActionClick"
|
|
26
|
+
| "actionsViewVariant"
|
|
21
27
|
>) {
|
|
22
28
|
return (
|
|
23
29
|
<CardHeader
|
|
@@ -49,7 +55,7 @@ export function ItemCardHeader({
|
|
|
49
55
|
classNames={classNames}
|
|
50
56
|
/>
|
|
51
57
|
|
|
52
|
-
{orientation === "vertical" && (
|
|
58
|
+
{orientation === "vertical" && actionsViewVariant === "dropdown" && (
|
|
53
59
|
<ItemActionsDropdown
|
|
54
60
|
actions={actions}
|
|
55
61
|
classNames={classNames}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
ItemCardActionsViewVariant,
|
|
5
|
+
ItemCardOrientation,
|
|
6
|
+
ItemCardProps,
|
|
7
|
+
} from "@/types";
|
|
4
8
|
import { cn } from "@/utils";
|
|
5
9
|
import { Card } from "@heroui/card";
|
|
6
10
|
import { motion } from "framer-motion";
|
|
@@ -13,6 +17,7 @@ import {
|
|
|
13
17
|
ItemCardFooter,
|
|
14
18
|
} from "@/components";
|
|
15
19
|
import { useWindowSize } from "@/hooks";
|
|
20
|
+
import { ItemActionsOverlay } from "./item-actions-overlay";
|
|
16
21
|
|
|
17
22
|
export function ItemCard({
|
|
18
23
|
variants,
|
|
@@ -24,6 +29,7 @@ export function ItemCard({
|
|
|
24
29
|
hoverEffect = "none",
|
|
25
30
|
onActionClick,
|
|
26
31
|
orientation: defaultOrientation = "vertical",
|
|
32
|
+
actionsViewVariant = "dropdown",
|
|
27
33
|
}: ItemCardProps) {
|
|
28
34
|
const { isExtraSmallDevice } = useWindowSize();
|
|
29
35
|
|
|
@@ -40,11 +46,18 @@ export function ItemCard({
|
|
|
40
46
|
/>
|
|
41
47
|
);
|
|
42
48
|
|
|
49
|
+
const hasActions = actions && actions.length > 0;
|
|
50
|
+
const isDropdownVariant: boolean =
|
|
51
|
+
(actionsViewVariant as ItemCardActionsViewVariant) === "dropdown";
|
|
52
|
+
const isHoverOverlayVariant: boolean =
|
|
53
|
+
(actionsViewVariant as ItemCardActionsViewVariant) === "hover-overlay";
|
|
54
|
+
|
|
43
55
|
return (
|
|
44
56
|
<motion.div
|
|
45
57
|
data-slot="emperor-ui-item-card"
|
|
46
58
|
className={cn(
|
|
47
59
|
itemCardMotionClasses({ orientation }),
|
|
60
|
+
"group",
|
|
48
61
|
classNames?.base,
|
|
49
62
|
className,
|
|
50
63
|
)}
|
|
@@ -56,6 +69,7 @@ export function ItemCard({
|
|
|
56
69
|
data-slot="emperor-ui-item-card-main-wrapper"
|
|
57
70
|
className={cn(
|
|
58
71
|
itemMainWrapperClasses({ orientation }),
|
|
72
|
+
"relative overflow-hidden",
|
|
59
73
|
classNames?.mainWrapper,
|
|
60
74
|
)}
|
|
61
75
|
>
|
|
@@ -65,6 +79,9 @@ export function ItemCard({
|
|
|
65
79
|
classNames={classNames}
|
|
66
80
|
actions={actions}
|
|
67
81
|
onActionClick={onActionClick}
|
|
82
|
+
actionsViewVariant={
|
|
83
|
+
isDropdownVariant ? "dropdown" : actionsViewVariant
|
|
84
|
+
}
|
|
68
85
|
/>
|
|
69
86
|
|
|
70
87
|
<ItemCardBody
|
|
@@ -73,13 +90,34 @@ export function ItemCard({
|
|
|
73
90
|
classNames={classNames}
|
|
74
91
|
actions={actions}
|
|
75
92
|
onActionClick={onActionClick}
|
|
93
|
+
actionsViewVariant={
|
|
94
|
+
isDropdownVariant ? "dropdown" : actionsViewVariant
|
|
95
|
+
}
|
|
76
96
|
/>
|
|
77
97
|
|
|
78
98
|
<ItemCardFooter
|
|
79
99
|
item={item}
|
|
80
100
|
orientation={orientation}
|
|
81
101
|
classNames={classNames}
|
|
102
|
+
actions={actions}
|
|
103
|
+
onActionClick={onActionClick}
|
|
104
|
+
actionsViewVariant={actionsViewVariant}
|
|
82
105
|
/>
|
|
106
|
+
{isHoverOverlayVariant && hasActions && (
|
|
107
|
+
<div
|
|
108
|
+
data-slot="emperor-ui-item-card-actions-hover-overlay"
|
|
109
|
+
className={cn(
|
|
110
|
+
"pointer-events-none absolute inset-0 z-20 flex items-center justify-center bg-black/60 opacity-0",
|
|
111
|
+
"transition-opacity duration-200 group-hover:opacity-100",
|
|
112
|
+
)}
|
|
113
|
+
>
|
|
114
|
+
<ItemActionsOverlay
|
|
115
|
+
actions={actions}
|
|
116
|
+
classNames={classNames}
|
|
117
|
+
onActionClick={onActionClick}
|
|
118
|
+
/>
|
|
119
|
+
</div>
|
|
120
|
+
)}
|
|
83
121
|
</Card>
|
|
84
122
|
</motion.div>
|
|
85
123
|
);
|
|
@@ -117,6 +117,42 @@ export const WithActions: Story = {
|
|
|
117
117
|
},
|
|
118
118
|
};
|
|
119
119
|
|
|
120
|
+
export const WithButtonsActions: Story = {
|
|
121
|
+
args: {
|
|
122
|
+
item: {
|
|
123
|
+
key: String(MOCK_LISTINGS[0]?.id),
|
|
124
|
+
title: MOCK_LISTINGS[0]?.title,
|
|
125
|
+
description: MOCK_LISTINGS[0]?.description,
|
|
126
|
+
image: {
|
|
127
|
+
src: MOCK_LISTINGS[0]?.image || "",
|
|
128
|
+
alt: MOCK_LISTINGS[0]?.title || "",
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
actions: ITEM_CARD_ACTIONS,
|
|
132
|
+
actionsViewVariant: "buttons",
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export const WithHoverOverlayActions: Story = {
|
|
137
|
+
args: {
|
|
138
|
+
item: {
|
|
139
|
+
key: String(MOCK_LISTINGS[0]?.id),
|
|
140
|
+
title: MOCK_LISTINGS[0]?.title,
|
|
141
|
+
description: MOCK_LISTINGS[0]?.description,
|
|
142
|
+
image: {
|
|
143
|
+
src: MOCK_LISTINGS[0]?.image || "",
|
|
144
|
+
alt: MOCK_LISTINGS[0]?.title || "",
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
actions: ITEM_CARD_ACTIONS?.map((action) => ({
|
|
148
|
+
...action,
|
|
149
|
+
variant: "solid",
|
|
150
|
+
size: "lg",
|
|
151
|
+
})),
|
|
152
|
+
actionsViewVariant: "hover-overlay",
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
|
|
120
156
|
export const WithChips: Story = {
|
|
121
157
|
args: {
|
|
122
158
|
item: {
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Button } from "@heroui/button";
|
|
4
|
+
import {
|
|
5
|
+
Modal,
|
|
6
|
+
ModalBody,
|
|
7
|
+
ModalContent,
|
|
8
|
+
ModalFooter,
|
|
9
|
+
ModalHeader,
|
|
10
|
+
} from "@heroui/modal";
|
|
11
|
+
import { Trash2 } from "lucide-react";
|
|
12
|
+
import { Locale } from "@/i18n";
|
|
13
|
+
import { useEmperorUI } from "@/hooks";
|
|
14
|
+
import { cn } from "@/utils";
|
|
15
|
+
import type { DeletionConfirmorProps } from "@/types";
|
|
16
|
+
import {
|
|
17
|
+
deletionConfirmorBodyClasses,
|
|
18
|
+
deletionConfirmorContentClasses,
|
|
19
|
+
deletionConfirmorFooterClasses,
|
|
20
|
+
deletionConfirmorHeaderClasses,
|
|
21
|
+
} from "./styles";
|
|
22
|
+
|
|
23
|
+
export function DeletionConfirmor({
|
|
24
|
+
isOpen,
|
|
25
|
+
onClose,
|
|
26
|
+
title,
|
|
27
|
+
description,
|
|
28
|
+
className,
|
|
29
|
+
classNames,
|
|
30
|
+
confirmProps,
|
|
31
|
+
declineProps,
|
|
32
|
+
}: DeletionConfirmorProps) {
|
|
33
|
+
const { config } = useEmperorUI();
|
|
34
|
+
|
|
35
|
+
const lang = config?.interLocalization?.lang ?? "en";
|
|
36
|
+
const locale = config?.interLocalization?.locales?.[lang] as
|
|
37
|
+
| Locale
|
|
38
|
+
| undefined;
|
|
39
|
+
const deletionConfirmorLocale = locale?.organisms?.deletionConfirmor;
|
|
40
|
+
|
|
41
|
+
const handleDecline = (e?: unknown) => {
|
|
42
|
+
if (typeof declineProps?.onPress === "function") {
|
|
43
|
+
(declineProps.onPress as (e?: unknown) => void)(e);
|
|
44
|
+
}
|
|
45
|
+
onClose();
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<Modal
|
|
50
|
+
placement="center"
|
|
51
|
+
isOpen={isOpen}
|
|
52
|
+
onClose={onClose}
|
|
53
|
+
onOpenChange={(open) => {
|
|
54
|
+
if (!open) onClose();
|
|
55
|
+
}}
|
|
56
|
+
dir={lang === "ar" ? "rtl" : "ltr"}
|
|
57
|
+
classNames={
|
|
58
|
+
className || classNames?.base
|
|
59
|
+
? { base: cn(className, classNames?.base) }
|
|
60
|
+
: undefined
|
|
61
|
+
}
|
|
62
|
+
>
|
|
63
|
+
<ModalContent
|
|
64
|
+
className={cn(deletionConfirmorContentClasses(), classNames?.content)}
|
|
65
|
+
>
|
|
66
|
+
<ModalHeader
|
|
67
|
+
className={cn(deletionConfirmorHeaderClasses(), classNames?.header)}
|
|
68
|
+
>
|
|
69
|
+
{title}
|
|
70
|
+
</ModalHeader>
|
|
71
|
+
|
|
72
|
+
<ModalBody
|
|
73
|
+
className={cn(deletionConfirmorBodyClasses(), classNames?.body)}
|
|
74
|
+
>
|
|
75
|
+
{description}
|
|
76
|
+
</ModalBody>
|
|
77
|
+
|
|
78
|
+
<ModalFooter
|
|
79
|
+
className={cn(deletionConfirmorFooterClasses(), classNames?.footer)}
|
|
80
|
+
>
|
|
81
|
+
<Button
|
|
82
|
+
variant="flat"
|
|
83
|
+
size="sm"
|
|
84
|
+
{...declineProps}
|
|
85
|
+
onPress={handleDecline}
|
|
86
|
+
className={cn(declineProps?.className, classNames?.declineButton)}
|
|
87
|
+
>
|
|
88
|
+
{declineProps?.children ??
|
|
89
|
+
deletionConfirmorLocale?.decline ??
|
|
90
|
+
"Decline"}
|
|
91
|
+
</Button>
|
|
92
|
+
|
|
93
|
+
<Button
|
|
94
|
+
color="danger"
|
|
95
|
+
size="sm"
|
|
96
|
+
{...confirmProps}
|
|
97
|
+
className={cn(confirmProps?.className, classNames?.confirmButton)}
|
|
98
|
+
startContent={
|
|
99
|
+
confirmProps?.isLoading
|
|
100
|
+
? undefined
|
|
101
|
+
: (confirmProps?.startContent ?? (
|
|
102
|
+
<Trash2 className="size-4" aria-hidden />
|
|
103
|
+
))
|
|
104
|
+
}
|
|
105
|
+
>
|
|
106
|
+
{confirmProps?.children ??
|
|
107
|
+
deletionConfirmorLocale?.confirm ??
|
|
108
|
+
"Confirm"}
|
|
109
|
+
</Button>
|
|
110
|
+
</ModalFooter>
|
|
111
|
+
</ModalContent>
|
|
112
|
+
</Modal>
|
|
113
|
+
);
|
|
114
|
+
}
|