@mailstep/design-system 0.13.2 → 0.13.4

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.
Files changed (31) hide show
  1. package/package.json +1 -1
  2. package/ui/Blocks/ImageList/ImageList.js +13 -6
  3. package/ui/Blocks/ImageList/components/AddPhoto/index.d.ts +0 -1
  4. package/ui/Blocks/ImageList/components/AddPhoto/index.js +5 -9
  5. package/ui/Blocks/ImageList/components/AddPhoto/styles.d.ts +1 -4
  6. package/ui/Blocks/ImageList/components/AddPhoto/styles.js +2 -2
  7. package/ui/Blocks/ImageList/components/CloseButton/index.js +2 -2
  8. package/ui/Blocks/ImageList/components/CloseButton/styles.js +12 -7
  9. package/ui/Blocks/ImageList/components/ImageElement/index.d.ts +2 -0
  10. package/ui/Blocks/ImageList/components/ImageElement/index.js +9 -7
  11. package/ui/Blocks/ImageList/components/ImageElement/styles.d.ts +3 -5
  12. package/ui/Blocks/ImageList/components/ImageElement/styles.js +23 -15
  13. package/ui/Blocks/ImageList/styles.d.ts +0 -1
  14. package/ui/Blocks/ImageList/styles.js +1 -1
  15. package/ui/Blocks/ImageList/types.d.ts +3 -0
  16. package/ui/Blocks/LightBox/LightBox.js +38 -20
  17. package/ui/Blocks/LightBox/components/DownloadButton/index.d.ts +8 -0
  18. package/ui/Blocks/LightBox/components/DownloadButton/index.js +21 -0
  19. package/ui/Blocks/LightBox/components/DownloadButton/styles.d.ts +3 -0
  20. package/ui/Blocks/LightBox/components/DownloadButton/styles.js +22 -0
  21. package/ui/Blocks/LightBox/hooks/useImageDownload.d.ts +10 -0
  22. package/ui/Blocks/LightBox/hooks/useImageDownload.js +19 -0
  23. package/ui/Blocks/LightBox/styles.d.ts +1 -0
  24. package/ui/Blocks/LightBox/styles.js +6 -1
  25. package/ui/Blocks/LightBox/types.d.ts +4 -0
  26. package/ui/Blocks/LightBox/utils/downloadImage.d.ts +7 -0
  27. package/ui/Blocks/LightBox/utils/downloadImage.js +21 -0
  28. package/ui/Blocks/LightBox/utils/getImageFileName.d.ts +7 -0
  29. package/ui/Blocks/LightBox/utils/getImageFileName.js +8 -0
  30. package/ui/Forms/DatePicker/Datetime/components/DateRepeater.js +9 -3
  31. package/ui/Forms/DatePicker/styles.js +4 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mailstep/design-system",
3
- "version": "0.13.2",
3
+ "version": "0.13.4",
4
4
  "license": "ISC",
5
5
  "type": "module",
6
6
  "main": "./ui/index.js",
@@ -1,4 +1,5 @@
1
1
  import Icon from "../../Elements/Icon/Icon.js";
2
+ import { useImageDownload } from "../LightBox/hooks/useImageDownload.js";
2
3
  import { useLightBox } from "../LightBox/hooks/useLightBox.js";
3
4
  import LightBox_default from "../LightBox/index.js";
4
5
  import { AddPhoto } from "./components/AddPhoto/index.js";
@@ -11,7 +12,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
11
12
  import { x } from "@xstyled/styled-components";
12
13
  import { useDraggable } from "react-use-draggable-scroll";
13
14
  //#region packages/ui/Blocks/ImageList/ImageList.tsx
14
- const ImageList = ({ onImageUpload, onImageRemove, onImageClick, lightBoxAction, lightBoxActionTitle, images, isDisabled, selectable, max }) => {
15
+ const ImageList = ({ onImageUpload, onImageRemove, onImageClick, lightBoxAction, lightBoxActionTitle, images, isDisabled, selectable, max, downloadable, onImageDownload, downloadTitle }) => {
15
16
  const ref = useRef(null);
16
17
  const { events } = useDraggable(ref, { isMounted: !!images?.length });
17
18
  const { isLightBoxOpen, onCloseLightBox, onOpenLightBox, lightBoxData } = useLightBox();
@@ -24,20 +25,22 @@ const ImageList = ({ onImageUpload, onImageRemove, onImageClick, lightBoxAction,
24
25
  max,
25
26
  total: images?.length
26
27
  });
28
+ const { getDownloadHandler } = useImageDownload({
29
+ downloadable,
30
+ onImageDownload
31
+ });
27
32
  return /* @__PURE__ */ jsxs(x.div, {
28
33
  display: "flex",
29
34
  alignItems: "center",
30
35
  children: [
31
36
  /* @__PURE__ */ jsx(AddPhoto, {
32
37
  onImageUpload,
33
- isDisabled,
34
- hasRemove: !!onImageRemove
38
+ isDisabled
35
39
  }),
36
40
  hasControls && /* @__PURE__ */ jsx(Control, {
37
41
  onClick: moveList(-1),
38
42
  isLeft: true,
39
43
  isDisabled: position === 0,
40
- hasRemove: !!onImageRemove,
41
44
  children: /* @__PURE__ */ jsx(Icon, {
42
45
  icon: "lessThen",
43
46
  size: "24px"
@@ -49,6 +52,8 @@ const ImageList = ({ onImageUpload, onImageRemove, onImageClick, lightBoxAction,
49
52
  children: images.map((item, index) => /* @__PURE__ */ jsx(ImageElement, {
50
53
  imageUrl: item.smallUrl ?? item.url,
51
54
  onImageRemove: onImageRemove?.(item.id),
55
+ onImageDownload: getDownloadHandler(item),
56
+ downloadTitle,
52
57
  onClick: handleOnClick(item, index),
53
58
  isDisabled,
54
59
  label: item?.label,
@@ -59,7 +64,6 @@ const ImageList = ({ onImageUpload, onImageRemove, onImageClick, lightBoxAction,
59
64
  hasControls && /* @__PURE__ */ jsx(Control, {
60
65
  onClick: moveList(1),
61
66
  isDisabled: !!images && !!max && position >= images?.length - max,
62
- hasRemove: !!onImageRemove,
63
67
  children: /* @__PURE__ */ jsx(Icon, {
64
68
  icon: "greaterThan",
65
69
  size: "24px"
@@ -71,7 +75,10 @@ const ImageList = ({ onImageUpload, onImageRemove, onImageClick, lightBoxAction,
71
75
  onCloseLightBox,
72
76
  lightBoxAction,
73
77
  lightBoxActionTitle,
74
- images
78
+ images,
79
+ downloadable,
80
+ onImageDownload,
81
+ downloadTitle
75
82
  })
76
83
  ]
77
84
  });
@@ -3,7 +3,6 @@ import { type ImageUploadProps } from '../../types';
3
3
  type AddPhotoProps = {
4
4
  onImageUpload?: (props: ImageUploadProps) => Promise<void>;
5
5
  isDisabled?: boolean;
6
- hasRemove?: boolean;
7
6
  };
8
7
  export declare const AddPhoto: FC<AddPhotoProps>;
9
8
  export {};
@@ -6,12 +6,11 @@ import { useImageUpload } from "./hooks/useImageUpload.js";
6
6
  import { Container, ErrorWrapper, HiddenInput, Wrapper } from "./styles.js";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
8
  //#region packages/ui/Blocks/ImageList/components/AddPhoto/index.tsx
9
- const AddPhoto = ({ onImageUpload, isDisabled, hasRemove }) => {
9
+ const AddPhoto = ({ onImageUpload, isDisabled }) => {
10
10
  const { handleImageUpload, hasInvalidFormat } = useImageUpload({ onImageUpload });
11
11
  if (!onImageUpload) return null;
12
12
  return /* @__PURE__ */ jsxs(Wrapper, { children: [/* @__PURE__ */ jsxs(Container, {
13
13
  isDisabled,
14
- hasRemove,
15
14
  children: [/* @__PURE__ */ jsx(HiddenInput, {
16
15
  disabled: isDisabled,
17
16
  onChange: handleImageUpload,
@@ -22,13 +21,10 @@ const AddPhoto = ({ onImageUpload, isDisabled, hasRemove }) => {
22
21
  width: "36",
23
22
  height: "36"
24
23
  })]
25
- }), hasInvalidFormat && /* @__PURE__ */ jsx(ErrorWrapper, {
26
- hasRemove,
27
- children: /* @__PURE__ */ jsx(ErrorMessage, {
28
- appearance: "inline",
29
- children: "Unsupported file format"
30
- })
31
- })] });
24
+ }), hasInvalidFormat && /* @__PURE__ */ jsx(ErrorWrapper, { children: /* @__PURE__ */ jsx(ErrorMessage, {
25
+ appearance: "inline",
26
+ children: "Unsupported file format"
27
+ }) })] });
32
28
  };
33
29
  //#endregion
34
30
  export { AddPhoto };
@@ -1,9 +1,6 @@
1
1
  export declare const Container: import("styled-components").StyledComponent<"div", import("@xstyled/styled-components").Theme, {
2
2
  isDisabled?: boolean;
3
- hasRemove?: boolean;
4
3
  }, never>;
5
4
  export declare const HiddenInput: import("styled-components").StyledComponent<"input", import("@xstyled/styled-components").Theme, {}, never>;
6
5
  export declare const Wrapper: import("styled-components").StyledComponent<"div", import("@xstyled/styled-components").Theme, {}, never>;
7
- export declare const ErrorWrapper: import("styled-components").StyledComponent<"div", import("@xstyled/styled-components").Theme, {
8
- hasRemove?: boolean;
9
- }, never>;
6
+ export declare const ErrorWrapper: import("styled-components").StyledComponent<"div", import("@xstyled/styled-components").Theme, {}, never>;
@@ -3,6 +3,7 @@ import styled$1, { th } from "@xstyled/styled-components";
3
3
  const Container = styled$1.div`
4
4
  position: relative;
5
5
  flex-shrink: 0;
6
+ box-sizing: border-box;
6
7
  transition: all 0.2s linear;
7
8
  height: 85px !important;
8
9
  width: 85px !important;
@@ -15,7 +16,6 @@ const Container = styled$1.div`
15
16
  cursor: pointer;
16
17
  margin-right: 15px;
17
18
  opacity: ${({ isDisabled }) => isDisabled ? .6 : 1};
18
- margin-top: ${({ hasRemove }) => hasRemove ? "15px" : ""};
19
19
  `;
20
20
  const HiddenInput = styled$1.input`
21
21
  opacity: 0;
@@ -32,7 +32,7 @@ const Wrapper = styled$1.div`
32
32
  `;
33
33
  const ErrorWrapper = styled$1.div`
34
34
  position: absolute;
35
- top: ${({ hasRemove }) => hasRemove ? "100px" : "85px"};
35
+ top: 85px;
36
36
  left: 0;
37
37
  width: 85px;
38
38
  line-height: 1.2;
@@ -9,8 +9,8 @@ const CloseButton = ({ onImageRemove, isDisabled }) => {
9
9
  isDisabled,
10
10
  children: /* @__PURE__ */ jsx(Icon, {
11
11
  icon: "close",
12
- size: "22px",
13
- fill: isDisabled ? "magenta60" : "red1"
12
+ size: "14px",
13
+ fill: "gray1"
14
14
  })
15
15
  });
16
16
  };
@@ -2,17 +2,22 @@ import styled$1, { th } from "@xstyled/styled-components";
2
2
  //#region packages/ui/Blocks/ImageList/components/CloseButton/styles.ts
3
3
  const Container = styled$1.div`
4
4
  position: absolute;
5
- top: 0;
6
- right: 0;
7
- width: 30px;
8
- height: 30px;
9
- background-color: ${({ isDisabled }) => th.color(isDisabled ? "bgLightGray1" : "red20")};
5
+ top: 2px;
6
+ right: 2px;
7
+ width: 24px;
8
+ height: 24px;
9
+ background-color: ${th.color("bgLightGray1")};
10
10
  border-radius: 50%;
11
11
  display: flex;
12
12
  align-items: center;
13
13
  justify-content: center;
14
- cursor: pointer;
15
- transition: all 0.2s linear;
14
+ cursor: ${({ isDisabled }) => isDisabled ? "default" : "pointer"};
15
+ opacity: ${({ isDisabled }) => isDisabled ? .5 : .8};
16
+ transition: opacity 0.2s linear;
17
+
18
+ &:hover {
19
+ opacity: ${({ isDisabled }) => isDisabled ? .5 : 1};
20
+ }
16
21
  `;
17
22
  //#endregion
18
23
  export { Container };
@@ -2,6 +2,8 @@ import { type FC } from 'react';
2
2
  interface ImageElementProps {
3
3
  label?: string;
4
4
  onImageRemove?: () => void;
5
+ onImageDownload?: () => void;
6
+ downloadTitle?: string;
5
7
  onClick: () => void;
6
8
  imageUrl: string | undefined;
7
9
  isDisabled?: boolean;
@@ -1,26 +1,28 @@
1
+ import { DownloadButton } from "../../../LightBox/components/DownloadButton/index.js";
1
2
  import { CloseButton } from "../CloseButton/index.js";
2
3
  import { ImageTag } from "../ImageTag/index.js";
3
- import { Image, ImageWrapper } from "./styles.js";
4
+ import { DownloadButtonWrapper, Image, ImageWrapper } from "./styles.js";
4
5
  import { jsx, jsxs } from "react/jsx-runtime";
5
6
  //#region packages/ui/Blocks/ImageList/components/ImageElement/index.tsx
6
- const ImageElement = ({ label, onImageRemove, isDisabled, onClick, imageUrl, selected, visible }) => {
7
+ const ImageElement = ({ label, onImageRemove, onImageDownload, downloadTitle, isDisabled, onClick, imageUrl, selected, visible }) => {
7
8
  if (!imageUrl) return null;
8
9
  return /* @__PURE__ */ jsxs(ImageWrapper, {
9
10
  visible,
10
- hasImageRemove: !!onImageRemove,
11
+ selected,
11
12
  children: [
12
13
  /* @__PURE__ */ jsx(Image, {
13
14
  src: imageUrl,
14
15
  alt: "",
15
- width: "85px",
16
- height: "85px",
17
- onClick,
18
- selected
16
+ onClick
19
17
  }),
20
18
  onImageRemove && /* @__PURE__ */ jsx(CloseButton, {
21
19
  onImageRemove,
22
20
  isDisabled
23
21
  }),
22
+ onImageDownload && /* @__PURE__ */ jsx(DownloadButtonWrapper, { children: /* @__PURE__ */ jsx(DownloadButton, {
23
+ onImageDownload,
24
+ title: downloadTitle
25
+ }) }),
24
26
  /* @__PURE__ */ jsx(ImageTag, { label })
25
27
  ]
26
28
  });
@@ -1,8 +1,6 @@
1
- export declare const Container: import("styled-components").StyledComponent<"div", import("@xstyled/styled-components").Theme, {}, never>;
2
- export declare const Image: import("styled-components").StyledComponent<"img", import("@xstyled/styled-components").Theme, {
3
- selected?: boolean;
4
- }, never>;
5
1
  export declare const ImageWrapper: import("styled-components").StyledComponent<"div", import("@xstyled/styled-components").Theme, {
6
2
  visible: boolean;
7
- hasImageRemove: boolean;
3
+ selected?: boolean;
8
4
  }, never>;
5
+ export declare const Image: import("styled-components").StyledComponent<"img", import("@xstyled/styled-components").Theme, {}, never>;
6
+ export declare const DownloadButtonWrapper: import("styled-components").StyledComponent<"div", import("@xstyled/styled-components").Theme, {}, never>;
@@ -1,22 +1,30 @@
1
- import styled$1 from "@xstyled/styled-components";
2
- import { th as th$1 } from "@xstyled/system";
1
+ import styled$1, { th } from "@xstyled/styled-components";
3
2
  //#region packages/ui/Blocks/ImageList/components/ImageElement/styles.ts
4
- const Container = styled$1.div``;
5
- const Image = styled$1.img`
6
- border-radius: ${th$1.radius("lg")};
7
- border: ${({ selected }) => selected ? `3px solid` : "0"};
8
- border-color: red1;
9
- cursor: pointer;
10
- transition: all 0.2s;
11
- `;
12
3
  const ImageWrapper = styled$1.div`
13
4
  position: relative;
14
- padding-right: ${({ hasImageRemove }) => hasImageRemove ? "15px" : "0"};
15
- padding-top: ${({ hasImageRemove }) => hasImageRemove ? "15px" : "0"};
16
- width: 100px;
17
- height: ${({ hasImageRemove }) => hasImageRemove ? "100px" : "85px"};
5
+ flex-shrink: 0;
6
+ box-sizing: border-box;
7
+ width: 85px;
8
+ height: 85px;
9
+ border: ${({ selected }) => th.border(selected ? "mediumSlim" : "slim")};
10
+ border-color: ${({ selected }) => th.color(selected ? "red1" : "lightGray6")};
11
+ border-radius: ${th.radius("lg")};
12
+ overflow: hidden;
18
13
  display: ${({ visible }) => visible ? "block" : "none"};
19
14
  user-select: none;
15
+ transition: border-color 0.2s;
16
+ `;
17
+ const Image = styled$1.img`
18
+ display: block;
19
+ width: 100%;
20
+ height: 100%;
21
+ object-fit: cover;
22
+ cursor: pointer;
23
+ `;
24
+ const DownloadButtonWrapper = styled$1.div`
25
+ position: absolute;
26
+ right: 2px;
27
+ bottom: 2px;
20
28
  `;
21
29
  //#endregion
22
- export { Container, Image, ImageWrapper };
30
+ export { DownloadButtonWrapper, Image, ImageWrapper };
@@ -2,5 +2,4 @@ export declare const ImageListContainer: import("styled-components").StyledCompo
2
2
  export declare const Control: import("styled-components").StyledComponent<"div", import("@xstyled/styled-components").Theme, {
3
3
  isLeft?: boolean;
4
4
  isDisabled: boolean;
5
- hasRemove?: boolean;
6
5
  }, never>;
@@ -6,6 +6,7 @@ const ImageListContainer = styled$1.div`
6
6
  -ms-overflow-style: none;
7
7
  scrollbar-width: none;
8
8
  position: relative;
9
+ gap: 15px;
9
10
 
10
11
  &::-webkit-scrollbar {
11
12
  display: none;
@@ -14,7 +15,6 @@ const ImageListContainer = styled$1.div`
14
15
  const Control = styled$1.div`
15
16
  width: 24px;
16
17
  margin-right: ${({ isLeft }) => isLeft ? "15px" : 0};
17
- margin-top: ${({ hasRemove }) => hasRemove ? "15px" : 0};
18
18
  cursor: pointer;
19
19
  display: flex;
20
20
  transition: all 0.4s;
@@ -14,4 +14,7 @@ export interface ImageListProps {
14
14
  isDisabled?: boolean;
15
15
  selectable?: boolean;
16
16
  max?: number;
17
+ downloadable?: boolean;
18
+ onImageDownload?: (item: ImageData) => () => void;
19
+ downloadTitle?: string;
17
20
  }
@@ -1,11 +1,21 @@
1
1
  import Button from "../../Elements/Button/Button.js";
2
2
  import "../../Elements/Button/index.js";
3
3
  import Modal_default from "../Modal/index.js";
4
- import { ButtonContainer, Container, Description, Image } from "./styles.js";
4
+ import { DownloadButton } from "./components/DownloadButton/index.js";
5
+ import { useImageDownload } from "./hooks/useImageDownload.js";
6
+ import { ButtonContainer, Container, Description, DownloadButtonWrapper, Image } from "./styles.js";
7
+ import { useCallback } from "react";
5
8
  import { jsx, jsxs } from "react/jsx-runtime";
6
9
  import { Swiper, SwiperSlide } from "swiper/react";
7
10
  //#region packages/ui/Blocks/LightBox/LightBox.tsx
8
- const LightBox = ({ isLightBoxOpen, onCloseLightBox, lightBoxAction, lightBoxActionTitle, images, initialSlide = 0 }) => {
11
+ const LightBox = ({ isLightBoxOpen, onCloseLightBox, lightBoxAction, lightBoxActionTitle, images, initialSlide = 0, downloadable, onImageDownload, downloadTitle }) => {
12
+ const { getDownloadHandler } = useImageDownload({
13
+ downloadable,
14
+ onImageDownload
15
+ });
16
+ const handleLightBoxAction = useCallback((id) => () => {
17
+ lightBoxAction?.(id)();
18
+ }, [lightBoxAction]);
9
19
  if (!images?.length) return null;
10
20
  return /* @__PURE__ */ jsx(Modal_default, {
11
21
  isShown: isLightBoxOpen,
@@ -16,24 +26,32 @@ const LightBox = ({ isLightBoxOpen, onCloseLightBox, lightBoxAction, lightBoxAct
16
26
  initialSlide,
17
27
  slidesPerView: 1,
18
28
  autoHeight: true,
19
- children: images.map((item) => /* @__PURE__ */ jsx(SwiperSlide, { children: /* @__PURE__ */ jsxs(Container, { children: [
20
- /* @__PURE__ */ jsx(Image, {
21
- src: item.originalUrl ?? item.url,
22
- loading: "lazy",
23
- alt: ""
24
- }),
25
- (item.date || item.description) && /* @__PURE__ */ jsxs(Description, { children: [
26
- item.date,
27
- " ",
28
- item.description
29
- ] }),
30
- !!item.withLightBoxAction && lightBoxAction && lightBoxActionTitle && /* @__PURE__ */ jsx(ButtonContainer, { children: /* @__PURE__ */ jsx(Button, {
31
- onClick: lightBoxAction(item.id),
32
- appearance: "primary",
33
- variant: "default",
34
- children: lightBoxActionTitle
35
- }) })
36
- ] }) }, item.id))
29
+ children: images.map((item) => {
30
+ const handleImageDownload = getDownloadHandler(item);
31
+ return /* @__PURE__ */ jsx(SwiperSlide, { children: /* @__PURE__ */ jsxs(Container, { children: [
32
+ /* @__PURE__ */ jsx(Image, {
33
+ src: item.originalUrl ?? item.url,
34
+ loading: "lazy",
35
+ alt: ""
36
+ }),
37
+ handleImageDownload && /* @__PURE__ */ jsx(DownloadButtonWrapper, { children: /* @__PURE__ */ jsx(DownloadButton, {
38
+ onImageDownload: handleImageDownload,
39
+ title: downloadTitle,
40
+ isLarge: true
41
+ }) }),
42
+ (item.date || item.description) && /* @__PURE__ */ jsxs(Description, { children: [
43
+ item.date,
44
+ " ",
45
+ item.description
46
+ ] }),
47
+ !!item.withLightBoxAction && lightBoxAction && lightBoxActionTitle && /* @__PURE__ */ jsx(ButtonContainer, { children: /* @__PURE__ */ jsx(Button, {
48
+ onClick: handleLightBoxAction(item.id),
49
+ appearance: "primary",
50
+ variant: "default",
51
+ children: lightBoxActionTitle
52
+ }) })
53
+ ] }) }, item.id);
54
+ })
37
55
  })
38
56
  });
39
57
  };
@@ -0,0 +1,8 @@
1
+ import { type FC } from 'react';
2
+ type DownloadButtonProps = {
3
+ onImageDownload: () => void;
4
+ title?: string;
5
+ isLarge?: boolean;
6
+ };
7
+ export declare const DownloadButton: FC<DownloadButtonProps>;
8
+ export {};
@@ -0,0 +1,21 @@
1
+ import Icon from "../../../../Elements/Icon/Icon.js";
2
+ import "../../../../Elements/Icon/index.js";
3
+ import { Container } from "./styles.js";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region packages/ui/Blocks/LightBox/components/DownloadButton/index.tsx
6
+ const DownloadButton = ({ onImageDownload, title = "Download", isLarge }) => {
7
+ return /* @__PURE__ */ jsx(Container, {
8
+ type: "button",
9
+ isLarge,
10
+ onClick: onImageDownload,
11
+ title,
12
+ "aria-label": title,
13
+ children: /* @__PURE__ */ jsx(Icon, {
14
+ icon: "download",
15
+ size: isLarge ? "18px" : "14px",
16
+ fill: "gray1"
17
+ })
18
+ });
19
+ };
20
+ //#endregion
21
+ export { DownloadButton };
@@ -0,0 +1,3 @@
1
+ export declare const Container: import("styled-components").StyledComponent<"button", import("@xstyled/styled-components").Theme, {
2
+ isLarge?: boolean;
3
+ }, never>;
@@ -0,0 +1,22 @@
1
+ import styled$1, { th } from "@xstyled/styled-components";
2
+ //#region packages/ui/Blocks/LightBox/components/DownloadButton/styles.ts
3
+ const Container = styled$1.button`
4
+ width: ${({ isLarge }) => isLarge ? "34px" : "24px"};
5
+ height: ${({ isLarge }) => isLarge ? "34px" : "24px"};
6
+ padding: 0;
7
+ border: 0;
8
+ border-radius: 50%;
9
+ background-color: ${({ isLarge }) => th.color(isLarge ? "bgLightGray2" : "bgLightGray1")};
10
+ display: flex;
11
+ align-items: center;
12
+ justify-content: center;
13
+ cursor: pointer;
14
+ opacity: 0.8;
15
+ transition: opacity 0.2s linear;
16
+
17
+ &:hover {
18
+ opacity: 1;
19
+ }
20
+ `;
21
+ //#endregion
22
+ export { Container };
@@ -0,0 +1,10 @@
1
+ import { type ImageData } from '../types';
2
+ type Props = {
3
+ downloadable?: boolean;
4
+ onImageDownload?: (item: ImageData) => () => void;
5
+ };
6
+ type HookType = (props: Props) => {
7
+ getDownloadHandler: (item: ImageData) => (() => void) | undefined;
8
+ };
9
+ export declare const useImageDownload: HookType;
10
+ export {};
@@ -0,0 +1,19 @@
1
+ import { downloadImage } from "../utils/downloadImage.js";
2
+ import { useCallback } from "react";
3
+ //#region packages/ui/Blocks/LightBox/hooks/useImageDownload.ts
4
+ const useImageDownload = ({ downloadable, onImageDownload }) => {
5
+ return { getDownloadHandler: useCallback((item) => {
6
+ if (onImageDownload) return onImageDownload(item);
7
+ if (!downloadable) return void 0;
8
+ const url = item.originalUrl ?? item.url;
9
+ if (!url) return void 0;
10
+ return () => {
11
+ downloadImage({
12
+ url,
13
+ fileName: item.originalName
14
+ });
15
+ };
16
+ }, [downloadable, onImageDownload]) };
17
+ };
18
+ //#endregion
19
+ export { useImageDownload };
@@ -2,3 +2,4 @@ export declare const Container: import("styled-components").StyledComponent<"div
2
2
  export declare const Image: import("styled-components").StyledComponent<"img", import("@xstyled/styled-components").Theme, {}, never>;
3
3
  export declare const ButtonContainer: import("styled-components").StyledComponent<"div", import("@xstyled/styled-components").Theme, {}, never>;
4
4
  export declare const Description: import("styled-components").StyledComponent<"div", import("@xstyled/styled-components").Theme, {}, never>;
5
+ export declare const DownloadButtonWrapper: import("styled-components").StyledComponent<"div", import("@xstyled/styled-components").Theme, {}, never>;
@@ -24,5 +24,10 @@ const Description = styled$1.div`
24
24
  bottom: 0px;
25
25
  background: rgba(255, 255, 255, 0.8);
26
26
  `;
27
+ const DownloadButtonWrapper = styled$1.div`
28
+ position: absolute;
29
+ top: 10px;
30
+ left: 10px;
31
+ `;
27
32
  //#endregion
28
- export { ButtonContainer, Container, Description, Image };
33
+ export { ButtonContainer, Container, Description, DownloadButtonWrapper, Image };
@@ -14,6 +14,7 @@ export interface ImageData {
14
14
  date?: string;
15
15
  smallUrl?: string;
16
16
  originalUrl?: string;
17
+ originalName?: string | null;
17
18
  description?: string | null;
18
19
  withLightBoxAction?: boolean;
19
20
  }
@@ -24,4 +25,7 @@ export interface LightBoxProps {
24
25
  lightBoxAction?: (id?: string) => () => Promise<void>;
25
26
  lightBoxActionTitle?: string;
26
27
  initialSlide?: number;
28
+ downloadable?: boolean;
29
+ onImageDownload?: (item: ImageData) => () => void;
30
+ downloadTitle?: string;
27
31
  }
@@ -0,0 +1,7 @@
1
+ type Props = {
2
+ url: string;
3
+ fileName?: string | null;
4
+ };
5
+ type FuncType = (props: Props) => Promise<void>;
6
+ export declare const downloadImage: FuncType;
7
+ export {};
@@ -0,0 +1,21 @@
1
+ import { getImageFileName } from "./getImageFileName.js";
2
+ //#region packages/ui/Blocks/LightBox/utils/downloadImage.ts
3
+ const downloadImage = async ({ url, fileName }) => {
4
+ try {
5
+ const response = await fetch(url);
6
+ if (!response.ok) throw new Error(`Image download failed with status ${response.status}`);
7
+ const objectUrl = URL.createObjectURL(await response.blob());
8
+ const link = document.createElement("a");
9
+ link.href = objectUrl;
10
+ link.download = getImageFileName({
11
+ url,
12
+ fileName
13
+ });
14
+ link.click();
15
+ URL.revokeObjectURL(objectUrl);
16
+ } catch {
17
+ window.open(url, "_blank", "noopener,noreferrer");
18
+ }
19
+ };
20
+ //#endregion
21
+ export { downloadImage };
@@ -0,0 +1,7 @@
1
+ type Props = {
2
+ url: string;
3
+ fileName?: string | null;
4
+ };
5
+ type FuncType = (props: Props) => string;
6
+ export declare const getImageFileName: FuncType;
7
+ export {};
@@ -0,0 +1,8 @@
1
+ //#region packages/ui/Blocks/LightBox/utils/getImageFileName.ts
2
+ const getImageFileName = ({ url, fileName }) => {
3
+ if (fileName) return fileName;
4
+ const lastSegment = new URL(url, window.location.href).pathname.split("/").pop();
5
+ return lastSegment ? decodeURIComponent(lastSegment) : "image";
6
+ };
7
+ //#endregion
8
+ export { getImageFileName };
@@ -44,18 +44,24 @@ const DateRepeater = ({ onChangeOthers, others, reset }) => {
44
44
  cursor: "pointer",
45
45
  border: "none",
46
46
  children: [
47
- /* @__PURE__ */ jsx("option", {
47
+ /* @__PURE__ */ jsx(x.option, {
48
+ color: "#333",
49
+ backgroundColor: "#fff",
48
50
  value: "",
49
51
  children: i18n._({
50
52
  id: "dataGrid.noRepeat",
51
53
  message: "No repeat"
52
54
  })
53
55
  }),
54
- /* @__PURE__ */ jsx("option", {
56
+ /* @__PURE__ */ jsx(x.option, {
57
+ color: "#333",
58
+ backgroundColor: "#fff",
55
59
  value: "every-today",
56
60
  children: DatePickerRepeatTrans()["every-today"]
57
61
  }),
58
- /* @__PURE__ */ jsx("option", {
62
+ /* @__PURE__ */ jsx(x.option, {
63
+ color: "#333",
64
+ backgroundColor: "#fff",
59
65
  value: "every-yesterday",
60
66
  children: DatePickerRepeatTrans()["every-yesterday"]
61
67
  })
@@ -199,6 +199,10 @@ const DatePickerBase = styled$1(x.div)`
199
199
  background-color: blue10;
200
200
  }
201
201
 
202
+ .rdtPicker .rdtActiveRange:hover {
203
+ border-radius: 0.5rem;
204
+ }
205
+
202
206
  .rdtPicker .rdtCounters > div :first-child {
203
207
  visibility: hidden;
204
208
  transform: rotate(-90deg);