@greatapps/common 1.1.787 → 1.1.789
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/components/account/AccountModals.mjs +3 -6
- package/dist/components/account/AccountModals.mjs.map +1 -1
- package/dist/components/account/DisableTwoFactorAuthModal.mjs +2 -3
- package/dist/components/account/DisableTwoFactorAuthModal.mjs.map +1 -1
- package/dist/components/account/TwoFactorAuthModal.mjs +4 -5
- package/dist/components/account/TwoFactorAuthModal.mjs.map +1 -1
- package/dist/components/account/sections/MyProfileSection.mjs +2 -5
- package/dist/components/account/sections/MyProfileSection.mjs.map +1 -1
- package/dist/components/layouts/UsersSelectorPopover.mjs +1 -1
- package/dist/components/layouts/UsersSelectorPopover.mjs.map +1 -1
- package/dist/components/modals/ModalManager.mjs +2 -5
- package/dist/components/modals/ModalManager.mjs.map +1 -1
- package/dist/components/modals/promo/AiCreditsOfferModal/AiCreditsOfferModal.mjs +2 -3
- package/dist/components/modals/promo/AiCreditsOfferModal/AiCreditsOfferModal.mjs.map +1 -1
- package/dist/components/ui/overlay/Dialog.mjs +6 -7
- package/dist/components/ui/overlay/Dialog.mjs.map +1 -1
- package/dist/components/ui/overlay/Popover.mjs +3 -3
- package/dist/components/ui/overlay/Popover.mjs.map +1 -1
- package/dist/components/ui/overlay/Sheet.mjs +6 -6
- package/dist/components/ui/overlay/Sheet.mjs.map +1 -1
- package/dist/components/ui/overlay/layers.mjs +44 -18
- package/dist/components/ui/overlay/layers.mjs.map +1 -1
- package/dist/components/widgets/ImageUpload/ImageCropModal.mjs +6 -6
- package/dist/components/widgets/ImageUpload/ImageCropModal.mjs.map +1 -1
- package/dist/components/widgets/ImageUpload/ImageTooSmallModal.mjs +2 -3
- package/dist/components/widgets/ImageUpload/ImageTooSmallModal.mjs.map +1 -1
- package/dist/components/widgets/ImageUpload/ImageUpload.mjs +2 -4
- package/dist/components/widgets/ImageUpload/ImageUpload.mjs.map +1 -1
- package/dist/index.mjs +3 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -7
- package/src/components/account/AccountModals.tsx +3 -9
- package/src/components/account/DisableTwoFactorAuthModal.tsx +55 -58
- package/src/components/account/TwoFactorAuthModal.tsx +147 -152
- package/src/components/account/sections/MyProfileSection.tsx +2 -6
- package/src/components/layouts/UsersSelectorPopover.tsx +1 -6
- package/src/components/modals/ModalManager.tsx +3 -9
- package/src/components/modals/promo/AiCreditsOfferModal/AiCreditsOfferModal.tsx +8 -12
- package/src/components/ui/overlay/Dialog.tsx +33 -39
- package/src/components/ui/overlay/Popover.tsx +16 -15
- package/src/components/ui/overlay/Sheet.tsx +50 -56
- package/src/components/ui/overlay/layers.tsx +45 -73
- package/src/components/widgets/ImageUpload/ImageCropModal.tsx +7 -11
- package/src/components/widgets/ImageUpload/ImageTooSmallModal.tsx +20 -23
- package/src/components/widgets/ImageUpload/ImageUpload.tsx +11 -15
- package/src/index.ts +1 -1
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import * as React from "react";
|
|
4
3
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
5
4
|
import { IconX } from "@tabler/icons-react";
|
|
6
5
|
import { cn } from "../../../infra/utils/clsx";
|
|
7
|
-
import {
|
|
6
|
+
import { OverlayLayerContext, useDialogLayer, useOverlayLayer } from "./layers";
|
|
8
7
|
function Dialog({
|
|
9
8
|
...props
|
|
10
9
|
}) {
|
|
11
|
-
|
|
12
|
-
return /* @__PURE__ */ jsx(DialogDepthContext.Provider, { value: depth + 1, children: /* @__PURE__ */ jsx(DialogPrimitive.Root, { "data-slot": "dialog", ...props }) });
|
|
10
|
+
return /* @__PURE__ */ jsx(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
|
|
13
11
|
}
|
|
14
12
|
function DialogTrigger({
|
|
15
13
|
...props
|
|
@@ -52,12 +50,13 @@ function DialogContent({
|
|
|
52
50
|
hideOverlay = false,
|
|
53
51
|
...props
|
|
54
52
|
}) {
|
|
55
|
-
const layer =
|
|
56
|
-
return /* @__PURE__ */ jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [
|
|
53
|
+
const { layer, presenceRef } = useOverlayLayer();
|
|
54
|
+
return /* @__PURE__ */ jsx(OverlayLayerContext.Provider, { value: layer, children: /* @__PURE__ */ jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [
|
|
57
55
|
!hideOverlay && /* @__PURE__ */ jsx(DialogOverlay, { className: overlayClassName }),
|
|
58
56
|
/* @__PURE__ */ jsxs(
|
|
59
57
|
DialogPrimitive.Content,
|
|
60
58
|
{
|
|
59
|
+
ref: presenceRef,
|
|
61
60
|
"data-slot": "dialog-content",
|
|
62
61
|
className: cn(
|
|
63
62
|
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
|
|
@@ -81,7 +80,7 @@ function DialogContent({
|
|
|
81
80
|
]
|
|
82
81
|
}
|
|
83
82
|
)
|
|
84
|
-
] });
|
|
83
|
+
] }) });
|
|
85
84
|
}
|
|
86
85
|
function DialogHeader({ className, ...props }) {
|
|
87
86
|
return /* @__PURE__ */ jsx(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/ui/overlay/Dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { IconX } from '@tabler/icons-react';\nimport { cn } from \"../../../infra/utils/clsx\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/ui/overlay/Dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { IconX } from '@tabler/icons-react';\nimport { cn } from \"../../../infra/utils/clsx\";\nimport { OverlayLayerContext, useDialogLayer, useOverlayLayer } from \"./layers\";\n\nfunction Dialog({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Root>) {\n return <DialogPrimitive.Root data-slot=\"dialog\" {...props} />;\n}\n\nfunction DialogTrigger({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {\n return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />;\n}\n\nfunction DialogPortal({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Portal>) {\n return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />;\n}\n\nfunction DialogClose({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Close>) {\n return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />;\n}\n\nfunction DialogOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {\n const layer = useDialogLayer();\n return (\n <DialogPrimitive.Overlay\n data-slot=\"dialog-overlay\"\n className={cn(\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 bg-black/50\",\n layer.overlay,\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DialogContent({\n className,\n children,\n showCloseButton = true,\n overlayClassName,\n hideOverlay = false,\n ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {\n showCloseButton?: boolean;\n overlayClassName?: string;\n hideOverlay?: boolean;\n}) {\n const { layer, presenceRef } = useOverlayLayer();\n return (\n <OverlayLayerContext.Provider value={layer}>\n <DialogPortal data-slot=\"dialog-portal\">\n {!hideOverlay && <DialogOverlay className={overlayClassName} />}\n <DialogPrimitive.Content\n ref={presenceRef}\n data-slot=\"dialog-content\"\n className={cn(\n \"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg\",\n layer.content,\n className,\n )}\n {...props}\n >\n {children}\n {showCloseButton && (\n <div className=\"absolute top-0.5 right-0\">\n <div className=\"p-4\">\n <DialogPrimitive.Close\n data-slot=\"dialog-close\"\n className=\"hover:cursor-pointer flex size-8 items-center justify-center rounded-lg p-2 text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-950 focus:outline-none\"\n >\n <IconX className=\"size-[18px]\" />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n </div>\n </div>\n )}\n </DialogPrimitive.Content>\n </DialogPortal>\n </OverlayLayerContext.Provider>\n );\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"dialog-header\"\n className={cn(\n \"p-5 flex flex-col gap-2 text-center sm:text-left\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DialogFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"dialog-footer\"\n className={cn(\n \"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DialogTitle({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Title>) {\n return (\n <DialogPrimitive.Title\n data-slot=\"dialog-title\"\n className={cn(\"text-lg leading-none font-semibold\", className)}\n {...props}\n />\n );\n}\n\nfunction DialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n return (\n <DialogPrimitive.Description\n data-slot=\"dialog-description\"\n className={cn(\"text-muted-foreground text-sm\", className)}\n {...props}\n />\n );\n}\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n};\n"],"mappings":"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","names":[]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
4
4
|
import { cn } from "../../../infra/utils/clsx";
|
|
5
|
-
import { useDialogLayer } from "./layers";
|
|
5
|
+
import { OVERLAY_LAYERS, OverlayLayerContext, ROOT_LAYER, useDialogLayer } from "./layers";
|
|
6
6
|
function Popover({
|
|
7
7
|
...props
|
|
8
8
|
}) {
|
|
@@ -20,7 +20,7 @@ function PopoverContent({
|
|
|
20
20
|
...props
|
|
21
21
|
}) {
|
|
22
22
|
const layer = useDialogLayer();
|
|
23
|
-
return /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
|
|
23
|
+
return /* @__PURE__ */ jsx(OverlayLayerContext.Provider, { value: layer === ROOT_LAYER ? OVERLAY_LAYERS[0] : layer, children: /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
|
|
24
24
|
PopoverPrimitive.Content,
|
|
25
25
|
{
|
|
26
26
|
"data-slot": "popover-content",
|
|
@@ -33,7 +33,7 @@ function PopoverContent({
|
|
|
33
33
|
),
|
|
34
34
|
...props
|
|
35
35
|
}
|
|
36
|
-
) });
|
|
36
|
+
) }) });
|
|
37
37
|
}
|
|
38
38
|
function PopoverAnchor({
|
|
39
39
|
...props
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/ui/overlay/Popover.tsx"],"sourcesContent":["'use client';\n\n\"use client\"\n\nimport * as React from \"react\"\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\"\nimport { cn } from \"../../../infra/utils/clsx\"\nimport { useDialogLayer } from \"./layers\"\n\nfunction Popover({\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Root>) {\n return <PopoverPrimitive.Root data-slot=\"popover\" {...props} />\n}\n\nfunction PopoverTrigger({\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {\n return <PopoverPrimitive.Trigger data-slot=\"popover-trigger\" {...props} />\n}\n\nfunction PopoverContent({\n className,\n align = \"center\",\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Content>) {\n
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/ui/overlay/Popover.tsx"],"sourcesContent":["'use client';\n\n\"use client\"\n\nimport * as React from \"react\"\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\"\nimport { cn } from \"../../../infra/utils/clsx\"\nimport { OVERLAY_LAYERS, OverlayLayerContext, ROOT_LAYER, useDialogLayer } from \"./layers\"\n\nfunction Popover({\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Root>) {\n return <PopoverPrimitive.Root data-slot=\"popover\" {...props} />\n}\n\nfunction PopoverTrigger({\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {\n return <PopoverPrimitive.Trigger data-slot=\"popover-trigger\" {...props} />\n}\n\nfunction PopoverContent({\n className,\n align = \"center\",\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Content>) {\n const layer = useDialogLayer()\n return (\n <OverlayLayerContext.Provider value={layer === ROOT_LAYER ? OVERLAY_LAYERS[0] : layer}>\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n data-slot=\"popover-content\"\n align={align}\n sideOffset={sideOffset}\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden\",\n layer.popover,\n className\n )}\n {...props}\n />\n </PopoverPrimitive.Portal>\n </OverlayLayerContext.Provider>\n )\n}\n\nfunction PopoverAnchor({\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {\n return <PopoverPrimitive.Anchor data-slot=\"popover-anchor\" {...props} />\n}\n\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }\n"],"mappings":";AAYS;AAPT,YAAY,sBAAsB;AAClC,SAAS,UAAU;AACnB,SAAS,gBAAgB,qBAAqB,YAAY,sBAAsB;AAEhF,SAAS,QAAQ;AAAA,EACf,GAAG;AACL,GAAuD;AACrD,SAAO,oBAAC,iBAAiB,MAAjB,EAAsB,aAAU,WAAW,GAAG,OAAO;AAC/D;AAEA,SAAS,eAAe;AAAA,EACtB,GAAG;AACL,GAA0D;AACxD,SAAO,oBAAC,iBAAiB,SAAjB,EAAyB,aAAU,mBAAmB,GAAG,OAAO;AAC1E;AAEA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,GAAG;AACL,GAA0D;AACxD,QAAM,QAAQ,eAAe;AAC7B,SACE,oBAAC,oBAAoB,UAApB,EAA6B,OAAO,UAAU,aAAa,eAAe,CAAC,IAAI,OAC9E,8BAAC,iBAAiB,QAAjB,EACC;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV;AAAA,MACA;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA,MAAM;AAAA,QACN;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN,GACF,GACF;AAEJ;AAEA,SAAS,cAAc;AAAA,EACrB,GAAG;AACL,GAAyD;AACvD,SAAO,oBAAC,iBAAiB,QAAjB,EAAwB,aAAU,kBAAkB,GAAG,OAAO;AACxE;","names":[]}
|
|
@@ -5,15 +5,14 @@ import * as SheetPrimitive from "@radix-ui/react-dialog";
|
|
|
5
5
|
import { IconX } from "@tabler/icons-react";
|
|
6
6
|
import { cn } from "../../../infra/utils/clsx";
|
|
7
7
|
import { hideCrisp, showCrisp } from "../../embeds/CrispEmbed";
|
|
8
|
-
import {
|
|
8
|
+
import { OverlayLayerContext, useDialogLayer, useOverlayLayer } from "./layers";
|
|
9
9
|
function Sheet({ onOpenChange, modal = false, ...props }) {
|
|
10
10
|
const handleOpenChange = React.useCallback((open) => {
|
|
11
11
|
if (open) hideCrisp();
|
|
12
12
|
else showCrisp();
|
|
13
13
|
onOpenChange?.(open);
|
|
14
14
|
}, [onOpenChange]);
|
|
15
|
-
|
|
16
|
-
return /* @__PURE__ */ jsx(DialogDepthContext.Provider, { value: depth + 1, children: /* @__PURE__ */ jsx(SheetPrimitive.Root, { "data-slot": "sheet", modal, onOpenChange: handleOpenChange, ...props }) });
|
|
15
|
+
return /* @__PURE__ */ jsx(SheetPrimitive.Root, { "data-slot": "sheet", modal, onOpenChange: handleOpenChange, ...props });
|
|
17
16
|
}
|
|
18
17
|
function SheetTrigger({
|
|
19
18
|
...props
|
|
@@ -56,12 +55,13 @@ function SheetContent({
|
|
|
56
55
|
noAnimation = false,
|
|
57
56
|
...props
|
|
58
57
|
}) {
|
|
59
|
-
const layer =
|
|
60
|
-
return /* @__PURE__ */ jsxs(SheetPortal, { children: [
|
|
58
|
+
const { layer, presenceRef } = useOverlayLayer();
|
|
59
|
+
return /* @__PURE__ */ jsx(OverlayLayerContext.Provider, { value: layer, children: /* @__PURE__ */ jsxs(SheetPortal, { children: [
|
|
61
60
|
/* @__PURE__ */ jsx(SheetOverlay, { className: noAnimation ? "!animate-none" : void 0 }),
|
|
62
61
|
/* @__PURE__ */ jsxs(
|
|
63
62
|
SheetPrimitive.Content,
|
|
64
63
|
{
|
|
64
|
+
ref: presenceRef,
|
|
65
65
|
"data-slot": "sheet-content",
|
|
66
66
|
onInteractOutside: (e) => e.preventDefault(),
|
|
67
67
|
onPointerDownOutside: (e) => e.preventDefault(),
|
|
@@ -96,7 +96,7 @@ function SheetContent({
|
|
|
96
96
|
]
|
|
97
97
|
}
|
|
98
98
|
)
|
|
99
|
-
] });
|
|
99
|
+
] }) });
|
|
100
100
|
}
|
|
101
101
|
function SheetHeader({ className, ...props }) {
|
|
102
102
|
return /* @__PURE__ */ jsx(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/ui/overlay/Sheet.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport * as SheetPrimitive from \"@radix-ui/react-dialog\";\nimport { IconX } from '@tabler/icons-react';\nimport { cn } from \"../../../infra/utils/clsx\";\nimport { hideCrisp, showCrisp } from \"../../embeds/CrispEmbed\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/ui/overlay/Sheet.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport * as SheetPrimitive from \"@radix-ui/react-dialog\";\nimport { IconX } from '@tabler/icons-react';\nimport { cn } from \"../../../infra/utils/clsx\";\nimport { hideCrisp, showCrisp } from \"../../embeds/CrispEmbed\";\nimport { OverlayLayerContext, useDialogLayer, useOverlayLayer } from \"./layers\";\n\nfunction Sheet({ onOpenChange, modal = false, ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {\n const handleOpenChange = React.useCallback((open: boolean) => {\n if (open) hideCrisp();\n else showCrisp();\n onOpenChange?.(open);\n }, [onOpenChange]);\n\n return <SheetPrimitive.Root data-slot=\"sheet\" modal={modal} onOpenChange={handleOpenChange} {...props} />;\n}\n\nfunction SheetTrigger({\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {\n return <SheetPrimitive.Trigger data-slot=\"sheet-trigger\" {...props} />;\n}\n\nfunction SheetClose({\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Close>) {\n return <SheetPrimitive.Close data-slot=\"sheet-close\" {...props} />;\n}\n\nfunction SheetPortal({\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Portal>) {\n return <SheetPrimitive.Portal data-slot=\"sheet-portal\" {...props} />;\n}\n\nfunction SheetOverlay({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n const layer = useDialogLayer();\n return (\n <SheetPrimitive.Close tabIndex={-1} asChild>\n <div\n data-slot=\"sheet-overlay\"\n className={cn(\n \"animate-in fade-in-0 fixed inset-0 bg-black/50 cursor-default\",\n layer.overlay,\n className,\n )}\n {...props}\n />\n </SheetPrimitive.Close>\n );\n}\n\nfunction SheetContent({\n className,\n children,\n side = \"right\",\n showCloseButton = true,\n noAnimation = false,\n ...props\n}: React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content> & {\n side?: \"top\" | \"right\" | \"bottom\" | \"left\";\n showCloseButton?: boolean;\n noAnimation?: boolean;\n}) {\n const { layer, presenceRef } = useOverlayLayer();\n return (\n <OverlayLayerContext.Provider value={layer}>\n <SheetPortal>\n <SheetOverlay className={noAnimation ? \"!animate-none\" : undefined} />\n <SheetPrimitive.Content\n ref={presenceRef}\n data-slot=\"sheet-content\"\n onInteractOutside={(e) => e.preventDefault()}\n onPointerDownOutside={(e) => e.preventDefault()}\n className={cn(\n \"bg-background fixed flex flex-col gap-4 shadow-lg\",\n layer.content,\n !noAnimation &&\n \"data-[state=open]:animate-in data-[state=closed]:animate-out transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500\",\n !noAnimation &&\n side === \"right\" &&\n \"data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right\",\n !noAnimation &&\n side === \"left\" &&\n \"data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left\",\n !noAnimation &&\n side === \"top\" &&\n \"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top\",\n !noAnimation &&\n side === \"bottom\" &&\n \"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom\",\n side === \"right\" &&\n \"inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm\",\n side === \"left\" &&\n \"inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm\",\n side === \"top\" && \"inset-x-0 top-0 h-auto border-b\",\n side === \"bottom\" && \"inset-x-0 bottom-0 h-auto border-t\",\n className,\n )}\n {...props}\n >\n {children}\n {showCloseButton && (\n <SheetPrimitive.Close\n data-slot=\"sheet-close\"\n className=\"absolute top-3 right-3 hover:cursor-pointer flex size-8 items-center justify-center rounded-lg p-2 text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-950 focus:outline-none\"\n >\n <IconX className=\"size-[18px]\" />\n <span className=\"sr-only\">Close</span>\n </SheetPrimitive.Close>\n )}\n </SheetPrimitive.Content>\n </SheetPortal>\n </OverlayLayerContext.Provider>\n );\n}\n\nfunction SheetHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sheet-header\"\n className={cn(\"flex flex-col gap-1.5 p-4\", className)}\n {...props}\n />\n );\n}\n\nfunction SheetFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sheet-footer\"\n className={cn(\"mt-auto flex flex-col gap-2 p-4\", className)}\n {...props}\n />\n );\n}\n\nfunction SheetTitle({\n className,\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Title>) {\n return (\n <SheetPrimitive.Title\n data-slot=\"sheet-title\"\n className={cn(\"text-foreground font-semibold\", className)}\n {...props}\n />\n );\n}\n\nfunction SheetDescription({\n className,\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Description>) {\n return (\n <SheetPrimitive.Description\n data-slot=\"sheet-description\"\n className={cn(\"text-muted-foreground text-sm\", className)}\n {...props}\n />\n );\n}\n\nexport {\n Sheet,\n SheetTrigger,\n SheetClose,\n SheetContent,\n SheetHeader,\n SheetFooter,\n SheetTitle,\n SheetDescription,\n};\n"],"mappings":"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","names":[]}
|
|
@@ -1,35 +1,61 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx } from "react/jsx-runtime";
|
|
3
2
|
import * as React from "react";
|
|
4
|
-
const
|
|
3
|
+
const OVERLAY_LAYERS = [
|
|
5
4
|
{ overlay: "z-[1000]", content: "z-[1001]", popover: "z-[1002]", tooltip: "z-[1003]" },
|
|
6
5
|
{ overlay: "z-[1010]", content: "z-[1011]", popover: "z-[1012]", tooltip: "z-[1013]" },
|
|
7
6
|
{ overlay: "z-[1020]", content: "z-[1021]", popover: "z-[1022]", tooltip: "z-[1023]" },
|
|
8
7
|
{ overlay: "z-[1030]", content: "z-[1031]", popover: "z-[1032]", tooltip: "z-[1033]" },
|
|
9
8
|
{ overlay: "z-[1040]", content: "z-[1041]", popover: "z-[1042]", tooltip: "z-[1043]" },
|
|
10
|
-
{ overlay: "z-[1050]", content: "z-[1051]", popover: "z-[1052]", tooltip: "z-[1053]" }
|
|
9
|
+
{ overlay: "z-[1050]", content: "z-[1051]", popover: "z-[1052]", tooltip: "z-[1053]" },
|
|
10
|
+
{ overlay: "z-[1060]", content: "z-[1061]", popover: "z-[1062]", tooltip: "z-[1063]" },
|
|
11
|
+
{ overlay: "z-[1070]", content: "z-[1071]", popover: "z-[1072]", tooltip: "z-[1073]" }
|
|
11
12
|
];
|
|
12
13
|
const ROOT_LAYER = { overlay: "z-[1000]", content: "z-[1001]", popover: "z-[1002]", tooltip: "z-50" };
|
|
13
|
-
const
|
|
14
|
-
const
|
|
14
|
+
const openOverlays = /* @__PURE__ */ new Set();
|
|
15
|
+
const overlayListeners = /* @__PURE__ */ new Set();
|
|
16
|
+
let saturationWarned = false;
|
|
17
|
+
function subscribeOverlays(onStoreChange) {
|
|
18
|
+
overlayListeners.add(onStoreChange);
|
|
19
|
+
return () => {
|
|
20
|
+
overlayListeners.delete(onStoreChange);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const OverlayLayerContext = React.createContext(ROOT_LAYER);
|
|
24
|
+
function useOverlayLayer() {
|
|
25
|
+
const token = React.useRef({});
|
|
26
|
+
const rank = React.useSyncExternalStore(
|
|
27
|
+
subscribeOverlays,
|
|
28
|
+
() => Math.max(Array.from(openOverlays).indexOf(token.current), 0),
|
|
29
|
+
() => 0
|
|
30
|
+
);
|
|
31
|
+
const presenceRef = React.useCallback(() => {
|
|
32
|
+
openOverlays.add(token.current);
|
|
33
|
+
overlayListeners.forEach((notify) => notify());
|
|
34
|
+
if (process.env.NODE_ENV !== "production" && openOverlays.size > OVERLAY_LAYERS.length && !saturationWarned) {
|
|
35
|
+
saturationWarned = true;
|
|
36
|
+
console.warn(
|
|
37
|
+
`[great-lib-common] ${openOverlays.size} overlays visiveis, mas a escala de z so tem ${OVERLAY_LAYERS.length} faixas. Deste nivel em diante todos dividem a ultima faixa e o overlay de cima cai sob o conteudo de baixo. Se o empilhamento for legitimo, adicione uma faixa em ui/overlay/layers.tsx.`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
return () => {
|
|
41
|
+
openOverlays.delete(token.current);
|
|
42
|
+
overlayListeners.forEach((notify) => notify());
|
|
43
|
+
};
|
|
44
|
+
}, []);
|
|
45
|
+
return { layer: OVERLAY_LAYERS[Math.min(rank, OVERLAY_LAYERS.length - 1)], presenceRef };
|
|
46
|
+
}
|
|
15
47
|
function useDialogLayer() {
|
|
16
|
-
|
|
17
|
-
if (depth <= 0) return ROOT_LAYER;
|
|
18
|
-
if (depth > DIALOG_LAYERS.length && process.env.NODE_ENV !== "production" && !saturationWarned.has(depth)) {
|
|
19
|
-
saturationWarned.add(depth);
|
|
20
|
-
console.warn(
|
|
21
|
-
`[great-lib-common] ${depth} modais empilhados, mas a escala de z so tem ${DIALOG_LAYERS.length} faixas. Deste nivel em diante todos dividem a ultima faixa e o overlay de cima cai sob o conteudo de baixo. Se o empilhamento for legitimo, adicione uma faixa em ui/overlay/layers.tsx.`
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
return DIALOG_LAYERS[Math.min(depth - 1, DIALOG_LAYERS.length - 1)];
|
|
48
|
+
return React.useContext(OverlayLayerContext);
|
|
25
49
|
}
|
|
26
50
|
function DialogLayer({ children }) {
|
|
27
|
-
|
|
28
|
-
return /* @__PURE__ */ jsx(DialogDepthContext.Provider, { value: depth + 1, children });
|
|
51
|
+
return children;
|
|
29
52
|
}
|
|
30
53
|
export {
|
|
31
|
-
DialogDepthContext,
|
|
32
54
|
DialogLayer,
|
|
33
|
-
|
|
55
|
+
OVERLAY_LAYERS,
|
|
56
|
+
OverlayLayerContext,
|
|
57
|
+
ROOT_LAYER,
|
|
58
|
+
useDialogLayer,
|
|
59
|
+
useOverlayLayer
|
|
34
60
|
};
|
|
35
61
|
//# sourceMappingURL=layers.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/ui/overlay/layers.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/ui/overlay/layers.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\nexport const OVERLAY_LAYERS = [\n { overlay: \"z-[1000]\", content: \"z-[1001]\", popover: \"z-[1002]\", tooltip: \"z-[1003]\" },\n { overlay: \"z-[1010]\", content: \"z-[1011]\", popover: \"z-[1012]\", tooltip: \"z-[1013]\" },\n { overlay: \"z-[1020]\", content: \"z-[1021]\", popover: \"z-[1022]\", tooltip: \"z-[1023]\" },\n { overlay: \"z-[1030]\", content: \"z-[1031]\", popover: \"z-[1032]\", tooltip: \"z-[1033]\" },\n { overlay: \"z-[1040]\", content: \"z-[1041]\", popover: \"z-[1042]\", tooltip: \"z-[1043]\" },\n { overlay: \"z-[1050]\", content: \"z-[1051]\", popover: \"z-[1052]\", tooltip: \"z-[1053]\" },\n { overlay: \"z-[1060]\", content: \"z-[1061]\", popover: \"z-[1062]\", tooltip: \"z-[1063]\" },\n { overlay: \"z-[1070]\", content: \"z-[1071]\", popover: \"z-[1072]\", tooltip: \"z-[1073]\" },\n] as const;\n\nexport const ROOT_LAYER = { overlay: \"z-[1000]\", content: \"z-[1001]\", popover: \"z-[1002]\", tooltip: \"z-50\" } as const;\n\nexport type DialogLayerClasses = (typeof OVERLAY_LAYERS)[number] | typeof ROOT_LAYER;\n\nconst openOverlays = new Set<object>();\nconst overlayListeners = new Set<() => void>();\nlet saturationWarned = false;\n\nfunction subscribeOverlays(onStoreChange: () => void) {\n overlayListeners.add(onStoreChange);\n return () => {\n overlayListeners.delete(onStoreChange);\n };\n}\n\nexport const OverlayLayerContext = React.createContext<DialogLayerClasses>(ROOT_LAYER);\n\nexport function useOverlayLayer() {\n const token = React.useRef({});\n const rank = React.useSyncExternalStore(\n subscribeOverlays,\n () => Math.max(Array.from(openOverlays).indexOf(token.current), 0),\n () => 0,\n );\n\n const presenceRef = React.useCallback(() => {\n openOverlays.add(token.current);\n overlayListeners.forEach((notify) => notify());\n if (process.env.NODE_ENV !== \"production\" && openOverlays.size > OVERLAY_LAYERS.length && !saturationWarned) {\n saturationWarned = true;\n console.warn(\n `[great-lib-common] ${openOverlays.size} overlays visiveis, mas a escala de z so tem ${OVERLAY_LAYERS.length} faixas. ` +\n `Deste nivel em diante todos dividem a ultima faixa e o overlay de cima cai sob o conteudo de baixo. ` +\n `Se o empilhamento for legitimo, adicione uma faixa em ui/overlay/layers.tsx.`,\n );\n }\n return () => {\n openOverlays.delete(token.current);\n overlayListeners.forEach((notify) => notify());\n };\n }, []);\n\n return { layer: OVERLAY_LAYERS[Math.min(rank, OVERLAY_LAYERS.length - 1)], presenceRef };\n}\n\nexport function useDialogLayer(): DialogLayerClasses {\n return React.useContext(OverlayLayerContext);\n}\n\nexport function DialogLayer({ children }: { children: React.ReactNode }) {\n return children;\n}\n"],"mappings":";AAEA,YAAY,WAAW;AAEhB,MAAM,iBAAiB;AAAA,EAC5B,EAAE,SAAS,YAAY,SAAS,YAAY,SAAS,YAAY,SAAS,WAAW;AAAA,EACrF,EAAE,SAAS,YAAY,SAAS,YAAY,SAAS,YAAY,SAAS,WAAW;AAAA,EACrF,EAAE,SAAS,YAAY,SAAS,YAAY,SAAS,YAAY,SAAS,WAAW;AAAA,EACrF,EAAE,SAAS,YAAY,SAAS,YAAY,SAAS,YAAY,SAAS,WAAW;AAAA,EACrF,EAAE,SAAS,YAAY,SAAS,YAAY,SAAS,YAAY,SAAS,WAAW;AAAA,EACrF,EAAE,SAAS,YAAY,SAAS,YAAY,SAAS,YAAY,SAAS,WAAW;AAAA,EACrF,EAAE,SAAS,YAAY,SAAS,YAAY,SAAS,YAAY,SAAS,WAAW;AAAA,EACrF,EAAE,SAAS,YAAY,SAAS,YAAY,SAAS,YAAY,SAAS,WAAW;AACvF;AAEO,MAAM,aAAa,EAAE,SAAS,YAAY,SAAS,YAAY,SAAS,YAAY,SAAS,OAAO;AAI3G,MAAM,eAAe,oBAAI,IAAY;AACrC,MAAM,mBAAmB,oBAAI,IAAgB;AAC7C,IAAI,mBAAmB;AAEvB,SAAS,kBAAkB,eAA2B;AACpD,mBAAiB,IAAI,aAAa;AAClC,SAAO,MAAM;AACX,qBAAiB,OAAO,aAAa;AAAA,EACvC;AACF;AAEO,MAAM,sBAAsB,MAAM,cAAkC,UAAU;AAE9E,SAAS,kBAAkB;AAChC,QAAM,QAAQ,MAAM,OAAO,CAAC,CAAC;AAC7B,QAAM,OAAO,MAAM;AAAA,IACjB;AAAA,IACA,MAAM,KAAK,IAAI,MAAM,KAAK,YAAY,EAAE,QAAQ,MAAM,OAAO,GAAG,CAAC;AAAA,IACjE,MAAM;AAAA,EACR;AAEA,QAAM,cAAc,MAAM,YAAY,MAAM;AAC1C,iBAAa,IAAI,MAAM,OAAO;AAC9B,qBAAiB,QAAQ,CAAC,WAAW,OAAO,CAAC;AAC7C,QAAI,QAAQ,IAAI,aAAa,gBAAgB,aAAa,OAAO,eAAe,UAAU,CAAC,kBAAkB;AAC3G,yBAAmB;AACnB,cAAQ;AAAA,QACN,sBAAsB,aAAa,IAAI,gDAAgD,eAAe,MAAM;AAAA,MAG9G;AAAA,IACF;AACA,WAAO,MAAM;AACX,mBAAa,OAAO,MAAM,OAAO;AACjC,uBAAiB,QAAQ,CAAC,WAAW,OAAO,CAAC;AAAA,IAC/C;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,OAAO,eAAe,KAAK,IAAI,MAAM,eAAe,SAAS,CAAC,CAAC,GAAG,YAAY;AACzF;AAEO,SAAS,iBAAqC;AACnD,SAAO,MAAM,WAAW,mBAAmB;AAC7C;AAEO,SAAS,YAAY,EAAE,SAAS,GAAkC;AACvE,SAAO;AACT;","names":[]}
|
|
@@ -162,7 +162,7 @@ function ImageCropModal({
|
|
|
162
162
|
const translate = useTranslations();
|
|
163
163
|
const imgRef = useRef(null);
|
|
164
164
|
const [crop, setCrop] = useState();
|
|
165
|
-
const [
|
|
165
|
+
const [displayScale, setDisplayScale] = useState(0);
|
|
166
166
|
const [imageStatus, setImageStatus] = useState("loading");
|
|
167
167
|
const onImageLoadCallbackRef = useRef(onImageLoadCallback);
|
|
168
168
|
useEffect(() => {
|
|
@@ -179,7 +179,6 @@ function ImageCropModal({
|
|
|
179
179
|
img.onload = () => {
|
|
180
180
|
if (cancelled) return;
|
|
181
181
|
const { naturalWidth, naturalHeight } = img;
|
|
182
|
-
setImageSize({ width: naturalWidth, height: naturalHeight });
|
|
183
182
|
onImageLoadCallbackRef.current?.(naturalWidth, naturalHeight);
|
|
184
183
|
const tooSmall = minWidth !== void 0 && naturalWidth < minWidth || minHeight !== void 0 && naturalHeight < minHeight;
|
|
185
184
|
setImageStatus(tooSmall ? "too-small" : "ok");
|
|
@@ -194,7 +193,8 @@ function ImageCropModal({
|
|
|
194
193
|
};
|
|
195
194
|
}, [open, imageSrc, minWidth, minHeight]);
|
|
196
195
|
const onCropImgLoad = (e) => {
|
|
197
|
-
const { naturalWidth, naturalHeight } = e.currentTarget;
|
|
196
|
+
const { naturalWidth, naturalHeight, width } = e.currentTarget;
|
|
197
|
+
setDisplayScale(width / naturalWidth);
|
|
198
198
|
const initialCrop = centerCrop(
|
|
199
199
|
makeAspectCrop(
|
|
200
200
|
{ unit: "%", width: 90 },
|
|
@@ -207,8 +207,8 @@ function ImageCropModal({
|
|
|
207
207
|
);
|
|
208
208
|
setCrop(initialCrop);
|
|
209
209
|
};
|
|
210
|
-
const minCropWidth = minWidth &&
|
|
211
|
-
const minCropHeight = minHeight &&
|
|
210
|
+
const minCropWidth = minWidth && displayScale > 0 ? minWidth * displayScale : void 0;
|
|
211
|
+
const minCropHeight = minHeight && displayScale > 0 ? minHeight * displayScale : void 0;
|
|
212
212
|
const handleConfirm = () => {
|
|
213
213
|
if (imgRef.current && crop) {
|
|
214
214
|
onConfirm(imgRef.current, crop);
|
|
@@ -246,7 +246,7 @@ function ImageCropModal({
|
|
|
246
246
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
247
247
|
/* @__PURE__ */ jsx(DialogHeader, { className: "p-5", children: /* @__PURE__ */ jsx(DialogTitle, { className: "text-center text-[16px]!", children: translate("common.imageUpload.cropTitle") }) }),
|
|
248
248
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 px-5 pb-5", children: [
|
|
249
|
-
/* @__PURE__ */ jsx("div", { className: "flex justify-center overflow-hidden rounded-lg min-h-[200px]", children: imageStatus === "ok" && /* @__PURE__ */ jsx(
|
|
249
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-center overflow-hidden rounded-lg min-h-[200px]", children: imageStatus === "ok" && /* @__PURE__ */ jsx(
|
|
250
250
|
ReactCrop,
|
|
251
251
|
{
|
|
252
252
|
crop,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/widgets/ImageUpload/ImageCropModal.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useRef, useState } from 'react'\nimport { useTranslations } from 'next-intl'\nimport ReactCrop, {\n type Crop,\n centerCrop,\n makeAspectCrop,\n} from 'react-image-crop'\nimport 'react-image-crop/dist/ReactCrop.css'\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '../../ui/overlay/Dialog'\nimport { Button } from '../../ui/buttons/Button'\n\n// CSS customizado para grid pontilhado fino e círculo\nconst baseCropStyles = `\n .custom-crop-area .ReactCrop__crop-selection {\n border: 2px solid white !important;\n box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.5) !important;\n }\n\n /* Grid de 9 quadrados - linhas pontilhadas finas */\n .custom-crop-area .ReactCrop__crop-selection .crop-grid {\n position: absolute;\n inset: 0;\n pointer-events: none;\n }\n\n .custom-crop-area .ReactCrop__crop-selection .crop-grid-line {\n position: absolute;\n background: repeating-linear-gradient(\n to right,\n rgba(255, 255, 255, 0.5) 0,\n rgba(255, 255, 255, 0.5) 4px,\n transparent 4px,\n transparent 8px\n );\n }\n\n .custom-crop-area .ReactCrop__crop-selection .crop-grid-line.horizontal {\n left: 0;\n right: 0;\n height: 1px;\n }\n\n .custom-crop-area .ReactCrop__crop-selection .crop-grid-line.vertical {\n top: 0;\n bottom: 0;\n width: 1px;\n background: repeating-linear-gradient(\n to bottom,\n rgba(255, 255, 255, 0.5) 0,\n rgba(255, 255, 255, 0.5) 4px,\n transparent 4px,\n transparent 8px\n );\n }\n\n .custom-crop-area .ReactCrop__crop-selection .crop-grid-line.h1 { top: 33.33%; }\n .custom-crop-area .ReactCrop__crop-selection .crop-grid-line.h2 { top: 66.66%; }\n .custom-crop-area .ReactCrop__crop-selection .crop-grid-line.v1 { left: 33.33%; }\n .custom-crop-area .ReactCrop__crop-selection .crop-grid-line.v2 { left: 66.66%; }\n\n /* Círculo inscrito */\n .custom-crop-area.with-circle .ReactCrop__crop-selection .crop-circle {\n position: absolute;\n inset: 0;\n border: 1px dashed rgba(255, 255, 255, 0.6);\n border-radius: 50%;\n pointer-events: none;\n }\n\n /* Ocultar handles das laterais (manter só os 4 cantos) */\n .custom-crop-area .ReactCrop__drag-handle.ord-n,\n .custom-crop-area .ReactCrop__drag-handle.ord-s,\n .custom-crop-area .ReactCrop__drag-handle.ord-e,\n .custom-crop-area .ReactCrop__drag-handle.ord-w {\n display: none !important;\n }\n\n /* Estilizar handles dos cantos — indicador preto em L nos cantos */\n .custom-crop-area .ReactCrop__drag-handle.ord-nw,\n .custom-crop-area .ReactCrop__drag-handle.ord-ne,\n .custom-crop-area .ReactCrop__drag-handle.ord-sw,\n .custom-crop-area .ReactCrop__drag-handle.ord-se {\n width: 20px;\n height: 20px;\n background: transparent !important;\n border: none !important;\n }\n\n .custom-crop-area .ReactCrop__drag-handle.ord-nw::after,\n .custom-crop-area .ReactCrop__drag-handle.ord-ne::after,\n .custom-crop-area .ReactCrop__drag-handle.ord-sw::after,\n .custom-crop-area .ReactCrop__drag-handle.ord-se::after {\n content: '';\n position: absolute;\n width: 22px;\n height: 22px;\n border-color: white;\n border-style: solid;\n border-width: 0;\n }\n\n .custom-crop-area .ReactCrop__drag-handle.ord-nw::after {\n top: -2px; left: -2px;\n border-top-width: 4px;\n border-left-width: 4px;\n }\n\n .custom-crop-area .ReactCrop__drag-handle.ord-ne::after {\n top: -2px; right: -2px;\n border-top-width: 4px;\n border-right-width: 4px;\n }\n\n .custom-crop-area .ReactCrop__drag-handle.ord-sw::after {\n bottom: -2px; left: -2px;\n border-bottom-width: 4px;\n border-left-width: 4px;\n }\n\n .custom-crop-area .ReactCrop__drag-handle.ord-se::after {\n bottom: -2px; right: -2px;\n border-bottom-width: 4px;\n border-right-width: 4px;\n }\n\n /* Desabilitar drag da imagem de fundo */\n .custom-crop-area img {\n pointer-events: none;\n user-select: none;\n -webkit-user-drag: none;\n /* Xadrez de transparência: fica atrás dos pixels da imagem, então só\n aparece onde a imagem é transparente. Imagens opacas cobrem o padrão. */\n background-color: #fff;\n background-image:\n linear-gradient(45deg, #ccc 25%, transparent 25%),\n linear-gradient(-45deg, #ccc 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, #ccc 75%),\n linear-gradient(-45deg, transparent 75%, #ccc 75%);\n background-size: 16px 16px;\n background-position: 0 0, 0 8px, 8px -8px, -8px 0;\n }\n`\n\ninterface ImageCropModalProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n imageSrc: string\n aspectRatio: number\n onConfirm: (image: HTMLImageElement, crop: Crop) => void\n onCancel?: () => void\n onImageLoad?: (naturalWidth: number, naturalHeight: number) => void\n showCircleGuide?: boolean\n minWidth?: number\n minHeight?: number\n /**\n * Nome do arquivo atual, usado na mensagem da variante \"imagem muito pequena\".\n * Opcional — se ausente, a mensagem cai num texto genérico.\n */\n fileName?: string\n /**\n * Callback disparado quando o usuário clica em \"Enviar outra\" na variante\n * \"imagem muito pequena\". Normalmente abre um file input. Se não for passado,\n * o botão \"Enviar outra\" é escondido.\n */\n onSelectAnother?: () => void\n}\n\ntype ImageStatus = 'loading' | 'too-small' | 'ok'\n\nexport function ImageCropModal({\n open,\n onOpenChange,\n imageSrc,\n aspectRatio,\n onConfirm,\n onCancel,\n onImageLoad: onImageLoadCallback,\n showCircleGuide,\n minWidth,\n minHeight,\n fileName,\n onSelectAnother,\n}: ImageCropModalProps) {\n const translate = useTranslations()\n const imgRef = useRef<HTMLImageElement>(null)\n const [crop, setCrop] = useState<Crop>()\n const [imageSize, setImageSize] = useState({ width: 0, height: 0 })\n const [imageStatus, setImageStatus] = useState<ImageStatus>('loading')\n\n // Ref pra callback externo — evita re-rodar o effect de preload toda vez que\n // a identidade do callback muda.\n const onImageLoadCallbackRef = useRef(onImageLoadCallback)\n useEffect(() => {\n onImageLoadCallbackRef.current = onImageLoadCallback\n })\n\n // Pre-carrega a imagem fora do DOM pra medir dimensões ANTES de montar\n // o ReactCrop. Assim conseguimos decidir entre a variante de crop e a\n // variante \"imagem muito pequena\" sem flash de UI.\n useEffect(() => {\n if (!open || !imageSrc) {\n setImageStatus('loading')\n return\n }\n\n setImageStatus('loading')\n let cancelled = false\n\n const img = new window.Image()\n img.onload = () => {\n if (cancelled) return\n const { naturalWidth, naturalHeight } = img\n setImageSize({ width: naturalWidth, height: naturalHeight })\n onImageLoadCallbackRef.current?.(naturalWidth, naturalHeight)\n\n const tooSmall =\n (minWidth !== undefined && naturalWidth < minWidth) ||\n (minHeight !== undefined && naturalHeight < minHeight)\n setImageStatus(tooSmall ? 'too-small' : 'ok')\n }\n img.onerror = () => {\n if (cancelled) return\n setImageStatus('too-small')\n }\n img.src = imageSrc\n\n return () => {\n cancelled = true\n }\n }, [open, imageSrc, minWidth, minHeight])\n\n // Inicializa o crop quando o <img> do ReactCrop monta. A imagem já está em\n // cache vinda do preload, então carrega instantâneo.\n const onCropImgLoad = (e: React.SyntheticEvent<HTMLImageElement>) => {\n const { naturalWidth, naturalHeight } = e.currentTarget\n const initialCrop = centerCrop(\n makeAspectCrop(\n { unit: '%', width: 90 },\n aspectRatio,\n naturalWidth,\n naturalHeight\n ),\n naturalWidth,\n naturalHeight\n )\n setCrop(initialCrop)\n }\n\n // Calcula tamanho mínimo em porcentagem baseado nas dimensões mínimas em pixels\n const minCropWidth = minWidth && imageSize.width > 0\n ? Math.min((minWidth / imageSize.width) * 100, 100)\n : undefined\n const minCropHeight = minHeight && imageSize.height > 0\n ? Math.min((minHeight / imageSize.height) * 100, 100)\n : undefined\n\n const handleConfirm = () => {\n if (imgRef.current && crop) {\n onConfirm(imgRef.current, crop)\n }\n }\n\n const handleCancel = () => {\n onCancel?.()\n onOpenChange(false)\n }\n\n // Determina se deve mostrar círculo (aspect ratio 1:1 por padrão)\n const shouldShowCircle = showCircleGuide ?? aspectRatio === 1\n\n // Renderiza grid, círculo e bolinhas dentro da área de crop\n const renderSelectionAddon = () => (\n <>\n {/* Grid de 9 quadrados com linhas pontilhadas */}\n <div className=\"crop-grid\">\n <div className=\"crop-grid-line horizontal h1\" />\n <div className=\"crop-grid-line horizontal h2\" />\n <div className=\"crop-grid-line vertical v1\" />\n <div className=\"crop-grid-line vertical v2\" />\n </div>\n {/* Círculo inscrito */}\n {shouldShowCircle && <div className=\"crop-circle\" />}\n </>\n )\n\n const dimensionText =\n minWidth !== undefined && minHeight !== undefined\n ? `${minWidth}x${minHeight}px`\n : null\n\n const isTooSmall = imageStatus === 'too-small'\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <style>{baseCropStyles}</style>\n <DialogContent\n className={\n isTooSmall\n ? 'w-full md:w-[480px]! lg:w-[480px]! max-w-[480px]! max-[480px]:w-[calc(100%-32px)] p-0 gap-0'\n : 'w-full md:w-[650px]! lg:w-[650px]! max-w-[650px]! max-[650px]:w-[calc(100%-32px)] p-0 gap-0'\n }\n >\n {isTooSmall ? (\n <>\n <DialogHeader className=\"p-5\">\n <DialogTitle className=\"text-center text-[16px]!\">\n {dimensionText\n ? translate('common.imageUpload.tooSmallTitleWithDimension', { dimensionText })\n : translate('common.imageUpload.tooSmallTitleGeneric')}\n </DialogTitle>\n </DialogHeader>\n\n <div className=\"px-5 pb-5\">\n <p className=\"paragraph-small-regular text-zinc-600 text-center\">\n {fileName && dimensionText\n ? translate('common.imageUpload.tooSmallBodyFileWithDimension', { fileName, dimensionText })\n : fileName && !dimensionText\n ? translate('common.imageUpload.tooSmallBodyFileGeneric', { fileName })\n : !fileName && dimensionText\n ? translate('common.imageUpload.tooSmallBodyNoFileWithDimension', { dimensionText })\n : translate('common.imageUpload.tooSmallBodyNoFileGeneric')}\n </p>\n </div>\n\n <DialogFooter className=\"flex-row! items-center justify-start! gap-3 p-5 border-t border-zinc-200\">\n {onSelectAnother && <Button onClick={onSelectAnother}>{translate('common.imageUpload.sendAnother')}</Button>}\n <Button variant=\"secondary\" onClick={handleCancel}>\n {translate('common.actions.cancel')}\n </Button>\n </DialogFooter>\n </>\n ) : (\n <>\n <DialogHeader className=\"p-5\">\n <DialogTitle className=\"text-center text-[16px]!\">\n {translate('common.imageUpload.cropTitle')}\n </DialogTitle>\n </DialogHeader>\n\n <div className=\"flex flex-col gap-4 px-5 pb-5\">\n <div className=\"flex justify-center overflow-hidden rounded-lg min-h-[200px]\">\n {imageStatus === 'ok' && (\n <ReactCrop\n crop={crop}\n onChange={(c: Crop) => setCrop(c)}\n aspect={aspectRatio}\n className={`max-h-[50vh] custom-crop-area ${shouldShowCircle ? 'with-circle' : ''}`}\n keepSelection\n minWidth={minCropWidth}\n minHeight={minCropHeight}\n renderSelectionAddon={renderSelectionAddon}\n >\n <img\n ref={imgRef}\n src={imageSrc}\n alt={translate('common.imageUpload.cropAlt')}\n onLoad={onCropImgLoad}\n draggable={false}\n className=\"max-h-[50vh] object-contain select-none\"\n />\n </ReactCrop>\n )}\n </div>\n\n <p className=\"paragraph-small-regular text-zinc-500 text-center\">\n {translate('common.imageUpload.cropHint')}\n </p>\n </div>\n\n <DialogFooter className=\"flex-row! items-center justify-start! gap-3 p-5 border-t border-zinc-200\">\n <Button onClick={handleConfirm} disabled={imageStatus !== 'ok' || !crop}>\n {translate('common.actions.confirm')}\n </Button>\n <Button variant=\"secondary\" onClick={handleCancel}>\n {translate('common.actions.cancel')}\n </Button>\n </DialogFooter>\n </>\n )}\n </DialogContent>\n </Dialog>\n )\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/widgets/ImageUpload/ImageCropModal.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useRef, useState } from 'react'\nimport { useTranslations } from 'next-intl'\nimport ReactCrop, {\n type Crop,\n centerCrop,\n makeAspectCrop,\n} from 'react-image-crop'\nimport 'react-image-crop/dist/ReactCrop.css'\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '../../ui/overlay/Dialog'\nimport { Button } from '../../ui/buttons/Button'\n\n// CSS customizado para grid pontilhado fino e círculo\nconst baseCropStyles = `\n .custom-crop-area .ReactCrop__crop-selection {\n border: 2px solid white !important;\n box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.5) !important;\n }\n\n /* Grid de 9 quadrados - linhas pontilhadas finas */\n .custom-crop-area .ReactCrop__crop-selection .crop-grid {\n position: absolute;\n inset: 0;\n pointer-events: none;\n }\n\n .custom-crop-area .ReactCrop__crop-selection .crop-grid-line {\n position: absolute;\n background: repeating-linear-gradient(\n to right,\n rgba(255, 255, 255, 0.5) 0,\n rgba(255, 255, 255, 0.5) 4px,\n transparent 4px,\n transparent 8px\n );\n }\n\n .custom-crop-area .ReactCrop__crop-selection .crop-grid-line.horizontal {\n left: 0;\n right: 0;\n height: 1px;\n }\n\n .custom-crop-area .ReactCrop__crop-selection .crop-grid-line.vertical {\n top: 0;\n bottom: 0;\n width: 1px;\n background: repeating-linear-gradient(\n to bottom,\n rgba(255, 255, 255, 0.5) 0,\n rgba(255, 255, 255, 0.5) 4px,\n transparent 4px,\n transparent 8px\n );\n }\n\n .custom-crop-area .ReactCrop__crop-selection .crop-grid-line.h1 { top: 33.33%; }\n .custom-crop-area .ReactCrop__crop-selection .crop-grid-line.h2 { top: 66.66%; }\n .custom-crop-area .ReactCrop__crop-selection .crop-grid-line.v1 { left: 33.33%; }\n .custom-crop-area .ReactCrop__crop-selection .crop-grid-line.v2 { left: 66.66%; }\n\n /* Círculo inscrito */\n .custom-crop-area.with-circle .ReactCrop__crop-selection .crop-circle {\n position: absolute;\n inset: 0;\n border: 1px dashed rgba(255, 255, 255, 0.6);\n border-radius: 50%;\n pointer-events: none;\n }\n\n /* Ocultar handles das laterais (manter só os 4 cantos) */\n .custom-crop-area .ReactCrop__drag-handle.ord-n,\n .custom-crop-area .ReactCrop__drag-handle.ord-s,\n .custom-crop-area .ReactCrop__drag-handle.ord-e,\n .custom-crop-area .ReactCrop__drag-handle.ord-w {\n display: none !important;\n }\n\n /* Estilizar handles dos cantos — indicador preto em L nos cantos */\n .custom-crop-area .ReactCrop__drag-handle.ord-nw,\n .custom-crop-area .ReactCrop__drag-handle.ord-ne,\n .custom-crop-area .ReactCrop__drag-handle.ord-sw,\n .custom-crop-area .ReactCrop__drag-handle.ord-se {\n width: 20px;\n height: 20px;\n background: transparent !important;\n border: none !important;\n }\n\n .custom-crop-area .ReactCrop__drag-handle.ord-nw::after,\n .custom-crop-area .ReactCrop__drag-handle.ord-ne::after,\n .custom-crop-area .ReactCrop__drag-handle.ord-sw::after,\n .custom-crop-area .ReactCrop__drag-handle.ord-se::after {\n content: '';\n position: absolute;\n width: 22px;\n height: 22px;\n border-color: white;\n border-style: solid;\n border-width: 0;\n }\n\n .custom-crop-area .ReactCrop__drag-handle.ord-nw::after {\n top: -2px; left: -2px;\n border-top-width: 4px;\n border-left-width: 4px;\n }\n\n .custom-crop-area .ReactCrop__drag-handle.ord-ne::after {\n top: -2px; right: -2px;\n border-top-width: 4px;\n border-right-width: 4px;\n }\n\n .custom-crop-area .ReactCrop__drag-handle.ord-sw::after {\n bottom: -2px; left: -2px;\n border-bottom-width: 4px;\n border-left-width: 4px;\n }\n\n .custom-crop-area .ReactCrop__drag-handle.ord-se::after {\n bottom: -2px; right: -2px;\n border-bottom-width: 4px;\n border-right-width: 4px;\n }\n\n /* Desabilitar drag da imagem de fundo */\n .custom-crop-area img {\n pointer-events: none;\n user-select: none;\n -webkit-user-drag: none;\n /* Xadrez de transparência: fica atrás dos pixels da imagem, então só\n aparece onde a imagem é transparente. Imagens opacas cobrem o padrão. */\n background-color: #fff;\n background-image:\n linear-gradient(45deg, #ccc 25%, transparent 25%),\n linear-gradient(-45deg, #ccc 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, #ccc 75%),\n linear-gradient(-45deg, transparent 75%, #ccc 75%);\n background-size: 16px 16px;\n background-position: 0 0, 0 8px, 8px -8px, -8px 0;\n }\n`\n\ninterface ImageCropModalProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n imageSrc: string\n aspectRatio: number\n onConfirm: (image: HTMLImageElement, crop: Crop) => void\n onCancel?: () => void\n onImageLoad?: (naturalWidth: number, naturalHeight: number) => void\n showCircleGuide?: boolean\n minWidth?: number\n minHeight?: number\n /**\n * Nome do arquivo atual, usado na mensagem da variante \"imagem muito pequena\".\n * Opcional — se ausente, a mensagem cai num texto genérico.\n */\n fileName?: string\n /**\n * Callback disparado quando o usuário clica em \"Enviar outra\" na variante\n * \"imagem muito pequena\". Normalmente abre um file input. Se não for passado,\n * o botão \"Enviar outra\" é escondido.\n */\n onSelectAnother?: () => void\n}\n\ntype ImageStatus = 'loading' | 'too-small' | 'ok'\n\nexport function ImageCropModal({\n open,\n onOpenChange,\n imageSrc,\n aspectRatio,\n onConfirm,\n onCancel,\n onImageLoad: onImageLoadCallback,\n showCircleGuide,\n minWidth,\n minHeight,\n fileName,\n onSelectAnother,\n}: ImageCropModalProps) {\n const translate = useTranslations()\n const imgRef = useRef<HTMLImageElement>(null)\n const [crop, setCrop] = useState<Crop>()\n const [displayScale, setDisplayScale] = useState(0)\n const [imageStatus, setImageStatus] = useState<ImageStatus>('loading')\n\n // Ref pra callback externo — evita re-rodar o effect de preload toda vez que\n // a identidade do callback muda.\n const onImageLoadCallbackRef = useRef(onImageLoadCallback)\n useEffect(() => {\n onImageLoadCallbackRef.current = onImageLoadCallback\n })\n\n // Pre-carrega a imagem fora do DOM pra medir dimensões ANTES de montar\n // o ReactCrop. Assim conseguimos decidir entre a variante de crop e a\n // variante \"imagem muito pequena\" sem flash de UI.\n useEffect(() => {\n if (!open || !imageSrc) {\n setImageStatus('loading')\n return\n }\n\n setImageStatus('loading')\n let cancelled = false\n\n const img = new window.Image()\n img.onload = () => {\n if (cancelled) return\n const { naturalWidth, naturalHeight } = img\n onImageLoadCallbackRef.current?.(naturalWidth, naturalHeight)\n\n const tooSmall =\n (minWidth !== undefined && naturalWidth < minWidth) ||\n (minHeight !== undefined && naturalHeight < minHeight)\n setImageStatus(tooSmall ? 'too-small' : 'ok')\n }\n img.onerror = () => {\n if (cancelled) return\n setImageStatus('too-small')\n }\n img.src = imageSrc\n\n return () => {\n cancelled = true\n }\n }, [open, imageSrc, minWidth, minHeight])\n\n // Inicializa o crop quando o <img> do ReactCrop monta. A imagem já está em\n // cache vinda do preload, então carrega instantâneo.\n const onCropImgLoad = (e: React.SyntheticEvent<HTMLImageElement>) => {\n const { naturalWidth, naturalHeight, width } = e.currentTarget\n setDisplayScale(width / naturalWidth)\n const initialCrop = centerCrop(\n makeAspectCrop(\n { unit: '%', width: 90 },\n aspectRatio,\n naturalWidth,\n naturalHeight\n ),\n naturalWidth,\n naturalHeight\n )\n setCrop(initialCrop)\n }\n\n // minWidth/minHeight do ReactCrop são pixels da imagem já renderizada na tela.\n const minCropWidth = minWidth && displayScale > 0 ? minWidth * displayScale : undefined\n const minCropHeight = minHeight && displayScale > 0 ? minHeight * displayScale : undefined\n\n const handleConfirm = () => {\n if (imgRef.current && crop) {\n onConfirm(imgRef.current, crop)\n }\n }\n\n const handleCancel = () => {\n onCancel?.()\n onOpenChange(false)\n }\n\n // Determina se deve mostrar círculo (aspect ratio 1:1 por padrão)\n const shouldShowCircle = showCircleGuide ?? aspectRatio === 1\n\n // Renderiza grid, círculo e bolinhas dentro da área de crop\n const renderSelectionAddon = () => (\n <>\n {/* Grid de 9 quadrados com linhas pontilhadas */}\n <div className=\"crop-grid\">\n <div className=\"crop-grid-line horizontal h1\" />\n <div className=\"crop-grid-line horizontal h2\" />\n <div className=\"crop-grid-line vertical v1\" />\n <div className=\"crop-grid-line vertical v2\" />\n </div>\n {/* Círculo inscrito */}\n {shouldShowCircle && <div className=\"crop-circle\" />}\n </>\n )\n\n const dimensionText =\n minWidth !== undefined && minHeight !== undefined\n ? `${minWidth}x${minHeight}px`\n : null\n\n const isTooSmall = imageStatus === 'too-small'\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <style>{baseCropStyles}</style>\n <DialogContent\n className={\n isTooSmall\n ? 'w-full md:w-[480px]! lg:w-[480px]! max-w-[480px]! max-[480px]:w-[calc(100%-32px)] p-0 gap-0'\n : 'w-full md:w-[650px]! lg:w-[650px]! max-w-[650px]! max-[650px]:w-[calc(100%-32px)] p-0 gap-0'\n }\n >\n {isTooSmall ? (\n <>\n <DialogHeader className=\"p-5\">\n <DialogTitle className=\"text-center text-[16px]!\">\n {dimensionText\n ? translate('common.imageUpload.tooSmallTitleWithDimension', { dimensionText })\n : translate('common.imageUpload.tooSmallTitleGeneric')}\n </DialogTitle>\n </DialogHeader>\n\n <div className=\"px-5 pb-5\">\n <p className=\"paragraph-small-regular text-zinc-600 text-center\">\n {fileName && dimensionText\n ? translate('common.imageUpload.tooSmallBodyFileWithDimension', { fileName, dimensionText })\n : fileName && !dimensionText\n ? translate('common.imageUpload.tooSmallBodyFileGeneric', { fileName })\n : !fileName && dimensionText\n ? translate('common.imageUpload.tooSmallBodyNoFileWithDimension', { dimensionText })\n : translate('common.imageUpload.tooSmallBodyNoFileGeneric')}\n </p>\n </div>\n\n <DialogFooter className=\"flex-row! items-center justify-start! gap-3 p-5 border-t border-zinc-200\">\n {onSelectAnother && <Button onClick={onSelectAnother}>{translate('common.imageUpload.sendAnother')}</Button>}\n <Button variant=\"secondary\" onClick={handleCancel}>\n {translate('common.actions.cancel')}\n </Button>\n </DialogFooter>\n </>\n ) : (\n <>\n <DialogHeader className=\"p-5\">\n <DialogTitle className=\"text-center text-[16px]!\">\n {translate('common.imageUpload.cropTitle')}\n </DialogTitle>\n </DialogHeader>\n\n <div className=\"flex flex-col gap-4 px-5 pb-5\">\n <div className=\"flex items-center justify-center overflow-hidden rounded-lg min-h-[200px]\">\n {imageStatus === 'ok' && (\n <ReactCrop\n crop={crop}\n onChange={(c: Crop) => setCrop(c)}\n aspect={aspectRatio}\n className={`max-h-[50vh] custom-crop-area ${shouldShowCircle ? 'with-circle' : ''}`}\n keepSelection\n minWidth={minCropWidth}\n minHeight={minCropHeight}\n renderSelectionAddon={renderSelectionAddon}\n >\n <img\n ref={imgRef}\n src={imageSrc}\n alt={translate('common.imageUpload.cropAlt')}\n onLoad={onCropImgLoad}\n draggable={false}\n className=\"max-h-[50vh] object-contain select-none\"\n />\n </ReactCrop>\n )}\n </div>\n\n <p className=\"paragraph-small-regular text-zinc-500 text-center\">\n {translate('common.imageUpload.cropHint')}\n </p>\n </div>\n\n <DialogFooter className=\"flex-row! items-center justify-start! gap-3 p-5 border-t border-zinc-200\">\n <Button onClick={handleConfirm} disabled={imageStatus !== 'ok' || !crop}>\n {translate('common.actions.confirm')}\n </Button>\n <Button variant=\"secondary\" onClick={handleCancel}>\n {translate('common.actions.cancel')}\n </Button>\n </DialogFooter>\n </>\n )}\n </DialogContent>\n </Dialog>\n )\n}\n"],"mappings":"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","names":[]}
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
DialogHeader,
|
|
9
9
|
DialogTitle
|
|
10
10
|
} from "../../ui/overlay/Dialog";
|
|
11
|
-
import { DialogLayer } from "../../ui/overlay/layers";
|
|
12
11
|
import { Button } from "../../ui/buttons/Button";
|
|
13
12
|
function ImageTooSmallModal({
|
|
14
13
|
open,
|
|
@@ -21,14 +20,14 @@ function ImageTooSmallModal({
|
|
|
21
20
|
}) {
|
|
22
21
|
const translate = useTranslations();
|
|
23
22
|
const dimensionText = `${minWidth}x${minHeight}px`;
|
|
24
|
-
return /* @__PURE__ */ jsx(
|
|
23
|
+
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { className: "w-full md:w-[480px]! lg:w-[480px]! max-w-[480px]! max-[480px]:w-[calc(100%-32px)] p-0 gap-0", children: [
|
|
25
24
|
/* @__PURE__ */ jsx(DialogHeader, { className: "p-5", children: /* @__PURE__ */ jsx(DialogTitle, { className: "text-center text-[16px]!", children: translate("common.imageUpload.tooSmallTitleWithDimension", { dimensionText }) }) }),
|
|
26
25
|
/* @__PURE__ */ jsx("div", { className: "px-5 pb-5", children: /* @__PURE__ */ jsx("p", { className: "paragraph-small-regular text-zinc-600 text-center", children: translate("common.imageUpload.tooSmallBodyFileWithDimension", { fileName, dimensionText }) }) }),
|
|
27
26
|
/* @__PURE__ */ jsxs(DialogFooter, { className: "flex-row! items-center justify-start! gap-3 p-5 border-t border-zinc-200", children: [
|
|
28
27
|
/* @__PURE__ */ jsx(Button, { onClick: onSelectAnother, children: translate("common.imageUpload.sendAnother") }),
|
|
29
28
|
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: onCancel, children: translate("common.actions.cancel") })
|
|
30
29
|
] })
|
|
31
|
-
] }) })
|
|
30
|
+
] }) });
|
|
32
31
|
}
|
|
33
32
|
export {
|
|
34
33
|
ImageTooSmallModal
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/widgets/ImageUpload/ImageTooSmallModal.tsx"],"sourcesContent":["'use client'\n\nimport { useTranslations } from 'next-intl'\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '../../ui/overlay/Dialog'\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/widgets/ImageUpload/ImageTooSmallModal.tsx"],"sourcesContent":["'use client'\n\nimport { useTranslations } from 'next-intl'\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '../../ui/overlay/Dialog'\nimport { Button } from '../../ui/buttons/Button'\n\ninterface ImageTooSmallModalProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n fileName: string\n minWidth: number\n minHeight: number\n onSelectAnother: () => void\n onCancel: () => void\n}\n\nexport function ImageTooSmallModal({\n open,\n onOpenChange,\n fileName,\n minWidth,\n minHeight,\n onSelectAnother,\n onCancel,\n}: ImageTooSmallModalProps) {\n const translate = useTranslations()\n const dimensionText = `${minWidth}x${minHeight}px`\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"w-full md:w-[480px]! lg:w-[480px]! max-w-[480px]! max-[480px]:w-[calc(100%-32px)] p-0 gap-0\">\n <DialogHeader className=\"p-5\">\n <DialogTitle className=\"text-center text-[16px]!\">\n {translate('common.imageUpload.tooSmallTitleWithDimension', { dimensionText })}\n </DialogTitle>\n </DialogHeader>\n\n <div className=\"px-5 pb-5\">\n <p className=\"paragraph-small-regular text-zinc-600 text-center\">\n {translate('common.imageUpload.tooSmallBodyFileWithDimension', { fileName, dimensionText })}\n </p>\n </div>\n\n <DialogFooter className=\"flex-row! items-center justify-start! gap-3 p-5 border-t border-zinc-200\">\n <Button onClick={onSelectAnother}>{translate('common.imageUpload.sendAnother')}</Button>\n <Button variant=\"secondary\" onClick={onCancel}>\n {translate('common.actions.cancel')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n"],"mappings":";AAsCU,cAWF,YAXE;AApCV,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,cAAc;AAYhB,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,YAAY,gBAAgB;AAClC,QAAM,gBAAgB,GAAG,QAAQ,IAAI,SAAS;AAE9C,SACE,oBAAC,UAAO,MAAY,cAClB,+BAAC,iBAAc,WAAU,+FACvB;AAAA,wBAAC,gBAAa,WAAU,OACtB,8BAAC,eAAY,WAAU,4BACpB,oBAAU,iDAAiD,EAAE,cAAc,CAAC,GAC/E,GACF;AAAA,IAEA,oBAAC,SAAI,WAAU,aACb,8BAAC,OAAE,WAAU,qDACV,oBAAU,oDAAoD,EAAE,UAAU,cAAc,CAAC,GAC5F,GACF;AAAA,IAEA,qBAAC,gBAAa,WAAU,4EACtB;AAAA,0BAAC,UAAO,SAAS,iBAAkB,oBAAU,gCAAgC,GAAE;AAAA,MAC/E,oBAAC,UAAO,SAAQ,aAAY,SAAS,UAClC,oBAAU,uBAAuB,GACpC;AAAA,OACF;AAAA,KACF,GACF;AAEJ;","names":[]}
|
|
@@ -4,7 +4,6 @@ import { useRef } from "react";
|
|
|
4
4
|
import { useImageUpload } from "../../../modules/images/hooks/use-image-upload.hook";
|
|
5
5
|
import { ACCEPTED_IMAGE_FORMATS_STRING } from "../../../modules/images/constants/image.constants";
|
|
6
6
|
import { ImageCropModal } from "./ImageCropModal";
|
|
7
|
-
import { DialogLayer } from "../../ui/overlay/layers";
|
|
8
7
|
import { Button } from "../../ui/buttons/Button";
|
|
9
8
|
function ImageUpload({
|
|
10
9
|
config,
|
|
@@ -106,8 +105,7 @@ function ImageUpload({
|
|
|
106
105
|
]
|
|
107
106
|
}
|
|
108
107
|
),
|
|
109
|
-
originalImage &&
|
|
110
|
-
/* @__PURE__ */ jsx(DialogLayer, { children: /* @__PURE__ */ jsx(
|
|
108
|
+
originalImage && /* @__PURE__ */ jsx(
|
|
111
109
|
ImageCropModal,
|
|
112
110
|
{
|
|
113
111
|
open: showCropModal,
|
|
@@ -120,7 +118,7 @@ function ImageUpload({
|
|
|
120
118
|
fileName,
|
|
121
119
|
onSelectAnother: () => inputRef.current?.click()
|
|
122
120
|
}
|
|
123
|
-
)
|
|
121
|
+
)
|
|
124
122
|
] });
|
|
125
123
|
}
|
|
126
124
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/widgets/ImageUpload/ImageUpload.tsx"],"sourcesContent":["'use client'\n\nimport { useRef } from 'react'\nimport { useImageUpload } from '../../../modules/images/hooks/use-image-upload.hook'\nimport { ACCEPTED_IMAGE_FORMATS_STRING } from '../../../modules/images/constants/image.constants'\nimport { ImageCropModal } from './ImageCropModal'\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/widgets/ImageUpload/ImageUpload.tsx"],"sourcesContent":["'use client'\n\nimport { useRef } from 'react'\nimport { useImageUpload } from '../../../modules/images/hooks/use-image-upload.hook'\nimport { ACCEPTED_IMAGE_FORMATS_STRING } from '../../../modules/images/constants/image.constants'\nimport { ImageCropModal } from './ImageCropModal'\nimport { Button } from '../../ui/buttons/Button'\nimport type { ImageConfig } from '../../../modules/images/types/image.type'\n\ninterface ImageUploadProps {\n config: ImageConfig\n value?: string\n onChange?: (value: string) => void\n onError?: (error: string) => void\n className?: string\n}\n\nexport function ImageUpload({\n config,\n value,\n onChange,\n onError,\n className,\n}: ImageUploadProps) {\n const inputRef = useRef<HTMLInputElement>(null)\n\n const {\n originalImage,\n croppedPreview,\n showCropModal,\n isProcessing,\n fileName,\n handleFileSelect,\n handleCropConfirm,\n setShowCropModal,\n clear,\n } = useImageUpload({\n config,\n onSuccess: (base64) => onChange?.(base64),\n onError,\n })\n\n const displayImage = croppedPreview || value\n\n return (\n <div className={className}>\n <input\n ref={inputRef}\n type=\"file\"\n accept={ACCEPTED_IMAGE_FORMATS_STRING}\n className=\"hidden\"\n onChange={(e) => {\n const file = e.target.files?.[0]\n if (file) handleFileSelect(file)\n e.target.value = ''\n }}\n />\n\n {displayImage ? (\n <div className=\"relative\">\n <div\n className=\"overflow-hidden rounded-lg border border-gray-200\"\n style={{ aspectRatio: config.aspectRatio }}\n >\n <img\n src={displayImage}\n alt=\"Preview\"\n className=\"w-full h-full object-cover\"\n />\n </div>\n\n <div className=\"flex gap-2 mt-2\">\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => inputRef.current?.click()}\n disabled={isProcessing}\n >\n Trocar\n </Button>\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => {\n clear()\n onChange?.('')\n }}\n disabled={isProcessing}\n >\n Remover\n </Button>\n </div>\n\n {isProcessing && (\n <p className=\"paragraph-small-regular text-gray-500 mt-2\">\n Processando...\n </p>\n )}\n </div>\n ) : (\n <button\n type=\"button\"\n onClick={() => inputRef.current?.click()}\n className=\"w-full border-2 border-dashed border-gray-300 rounded-lg p-8 text-center hover:border-gray-400 transition-colors\"\n style={{ aspectRatio: config.aspectRatio }}\n >\n <p className=\"paragraph-medium-regular text-gray-600\">\n Clique para enviar imagem\n </p>\n <p className=\"paragraph-small-regular text-gray-400 mt-1\">\n Tamanho recomendado: {config.width} x {config.height} pixels\n </p>\n </button>\n )}\n\n {originalImage && (\n <ImageCropModal\n open={showCropModal}\n onOpenChange={setShowCropModal}\n imageSrc={originalImage}\n aspectRatio={config.aspectRatio}\n onConfirm={handleCropConfirm}\n minWidth={config.width}\n minHeight={config.height}\n fileName={fileName}\n onSelectAnother={() => inputRef.current?.click()}\n />\n )}\n </div>\n )\n}\n"],"mappings":";AA8CM,cAyBI,YAzBJ;AA5CN,SAAS,cAAc;AACvB,SAAS,sBAAsB;AAC/B,SAAS,qCAAqC;AAC9C,SAAS,sBAAsB;AAC/B,SAAS,cAAc;AAWhB,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,WAAW,OAAyB,IAAI;AAE9C,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,eAAe;AAAA,IACjB;AAAA,IACA,WAAW,CAAC,WAAW,WAAW,MAAM;AAAA,IACxC;AAAA,EACF,CAAC;AAED,QAAM,eAAe,kBAAkB;AAEvC,SACE,qBAAC,SAAI,WACH;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,MAAK;AAAA,QACL,QAAQ;AAAA,QACR,WAAU;AAAA,QACV,UAAU,CAAC,MAAM;AACf,gBAAM,OAAO,EAAE,OAAO,QAAQ,CAAC;AAC/B,cAAI,KAAM,kBAAiB,IAAI;AAC/B,YAAE,OAAO,QAAQ;AAAA,QACnB;AAAA;AAAA,IACF;AAAA,IAEC,eACC,qBAAC,SAAI,WAAU,YACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO,EAAE,aAAa,OAAO,YAAY;AAAA,UAEzC;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,KAAI;AAAA,cACJ,WAAU;AAAA;AAAA,UACZ;AAAA;AAAA,MACF;AAAA,MAEA,qBAAC,SAAI,WAAU,mBACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAS,MAAM,SAAS,SAAS,MAAM;AAAA,YACvC,UAAU;AAAA,YACX;AAAA;AAAA,QAED;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAS,MAAM;AACb,oBAAM;AACN,yBAAW,EAAE;AAAA,YACf;AAAA,YACA,UAAU;AAAA,YACX;AAAA;AAAA,QAED;AAAA,SACF;AAAA,MAEC,gBACC,oBAAC,OAAE,WAAU,8CAA6C,4BAE1D;AAAA,OAEJ,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,SAAS,SAAS,MAAM;AAAA,QACvC,WAAU;AAAA,QACV,OAAO,EAAE,aAAa,OAAO,YAAY;AAAA,QAEzC;AAAA,8BAAC,OAAE,WAAU,0CAAyC,uCAEtD;AAAA,UACA,qBAAC,OAAE,WAAU,8CAA6C;AAAA;AAAA,YAClC,OAAO;AAAA,YAAM;AAAA,YAAI,OAAO;AAAA,YAAO;AAAA,aACvD;AAAA;AAAA;AAAA,IACF;AAAA,IAGD,iBACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,cAAc;AAAA,QACd,UAAU;AAAA,QACV,aAAa,OAAO;AAAA,QACpB,WAAW;AAAA,QACX,UAAU,OAAO;AAAA,QACjB,WAAW,OAAO;AAAA,QAClB;AAAA,QACA,iBAAiB,MAAM,SAAS,SAAS,MAAM;AAAA;AAAA,IACjD;AAAA,KAEJ;AAEJ;","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -344,7 +344,7 @@ import {
|
|
|
344
344
|
DialogTitle,
|
|
345
345
|
DialogTrigger
|
|
346
346
|
} from "./components/ui/overlay/Dialog";
|
|
347
|
-
import { DialogLayer, useDialogLayer } from "./components/ui/overlay/layers";
|
|
347
|
+
import { DialogLayer, OverlayLayerContext, useDialogLayer, useOverlayLayer } from "./components/ui/overlay/layers";
|
|
348
348
|
import {
|
|
349
349
|
Popover,
|
|
350
350
|
PopoverTrigger,
|
|
@@ -626,6 +626,7 @@ export {
|
|
|
626
626
|
NotificationPageContent,
|
|
627
627
|
NotificationsPopover,
|
|
628
628
|
OverdueInvoiceBanner,
|
|
629
|
+
OverlayLayerContext,
|
|
629
630
|
PAGES_QUERY_KEY,
|
|
630
631
|
PAYMENT_METHOD_CARD,
|
|
631
632
|
PAYMENT_METHOD_PIX,
|
|
@@ -853,6 +854,7 @@ export {
|
|
|
853
854
|
useMobileNavbarSheet,
|
|
854
855
|
useModalManager,
|
|
855
856
|
useNavigationFallback,
|
|
857
|
+
useOverlayLayer,
|
|
856
858
|
usePaidPlanRequiredModal,
|
|
857
859
|
useParams,
|
|
858
860
|
default16 as usePasswordVisibility,
|