@yourdash/uikit 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/components/box/box.module.scss +1 -1
  2. package/components/box/box.tsx +3 -3
  3. package/components/button/button.module.scss +3 -3
  4. package/components/button/button.tsx +2 -1
  5. package/components/buttonLink/buttonLink.module.scss +5 -1
  6. package/components/buttonLink/buttonLink.tsx +13 -12
  7. package/components/buttonWithIcon/buttonWithIcon.module.scss +56 -0
  8. package/components/buttonWithIcon/buttonWithIcon.tsx +36 -0
  9. package/components/card/card.module.scss +6 -6
  10. package/components/card/card.tsx +23 -20
  11. package/components/container/container.module.scss +20 -0
  12. package/components/container/container.tsx +22 -0
  13. package/components/contextMenu/contextMenu.tsx +1 -1
  14. package/components/contextMenu/contextMenuRoot.module.scss +1 -1
  15. package/components/contextMenu/contextMenuRoot.tsx +83 -83
  16. package/components/flex/flex.module.scss +31 -19
  17. package/components/flex/flex.tsx +23 -2
  18. package/components/heading/heading.module.scss +1 -1
  19. package/components/heading/heading.tsx +1 -1
  20. package/components/icon/icon.tsx +1 -1
  21. package/components/iconButton/iconButton.module.scss +1 -1
  22. package/components/iconButton/iconButton.tsx +3 -3
  23. package/components/image/image.module.scss +72 -1
  24. package/components/image/image.tsx +65 -10
  25. package/components/link/link.module.scss +1 -1
  26. package/components/link/link.tsx +1 -1
  27. package/components/progressBar/progressBar.module.scss +25 -0
  28. package/components/progressBar/progressBar.tsx +21 -0
  29. package/components/redirect/redirect.tsx +1 -1
  30. package/components/separator/separator.module.scss +9 -4
  31. package/components/separator/separator.tsx +3 -3
  32. package/components/spinner/spinner.module.scss +1 -6
  33. package/components/spinner/spinner.tsx +1 -1
  34. package/components/subtext/subtext.module.scss +1 -1
  35. package/components/subtext/subtext.tsx +1 -1
  36. package/components/tag/tag.module.scss +13 -0
  37. package/components/tag/tag.tsx +21 -0
  38. package/components/text/text.module.scss +1 -1
  39. package/components/text/text.tsx +1 -1
  40. package/components/textButton/textButton.module.scss +1 -1
  41. package/components/textButton/textButton.tsx +1 -1
  42. package/components/textInput/textInput.module.scss +1 -1
  43. package/components/textInput/textInput.tsx +40 -10
  44. package/components/toast/toast.module.scss +71 -31
  45. package/components/toast/toast.ts +12 -0
  46. package/components/toast/toastAction.ts +12 -0
  47. package/components/toast/toastContext.ts +5 -3
  48. package/components/toast/toasts.tsx +99 -0
  49. package/core/decrementLevel.tsx +13 -13
  50. package/core/incrementLevel.tsx +1 -1
  51. package/core/level.tsx +1 -1
  52. package/core/remToPx.ts +8 -0
  53. package/core/root.tsx +26 -32
  54. package/core/toast.ts +18 -17
  55. package/imports.d.ts +81 -0
  56. package/package.json +9 -40
  57. package/theme/defaultTheme.module.scss +16 -4
  58. package/theme/themeValues.scss +8 -5
  59. package/tsconfig.json +19 -9
  60. package/utilityComponent/hasBeenShown/hasBeenShown.tsx +47 -0
  61. package/utilityComponent/onInView/onInView.tsx +83 -0
  62. package/views/carousel/carousel.module.scss +77 -0
  63. package/views/carousel/carousel.tsx +138 -0
  64. package/views/header/header.module.scss +16 -0
  65. package/views/header/header.tsx +28 -0
  66. package/views/infiniteScroll/infiniteScroll.module.scss +26 -0
  67. package/views/infiniteScroll/infiniteScroll.tsx +90 -0
  68. package/views/navBar/components/navImage/navImage.module.scss +7 -0
  69. package/views/navBar/components/navImage/navImage.tsx +15 -0
  70. package/views/navBar/components/navTitle/navTitle.tsx +13 -0
  71. package/views/navBar/navBar.module.scss +22 -0
  72. package/views/navBar/navBar.tsx +37 -0
  73. package/views/onBoarding/onBoarding.module.scss +84 -0
  74. package/views/onBoarding/onBoarding.tsx +138 -0
  75. package/views/panAndZoom/panAndZoom.tsx +121 -114
  76. package/views/sidebar/Sidebar.module.scss +49 -0
  77. package/views/sidebar/Sidebar.tsx +30 -0
  78. package/views/sidebar/SidebarContainer.module.scss +22 -0
  79. package/views/sidebar/SidebarContainer.tsx +38 -0
  80. package/views/sidebar/SidebarContext.tsx +15 -0
  81. package/views/sidebar/SidebarToggleButton.tsx +25 -0
  82. package/components/toast/toast.tsx +0 -65
@@ -0,0 +1,77 @@
1
+ @use "@yourdash/uikit/theme/themeValues" as *;
2
+
3
+ .containerComponent {
4
+ display: flex;
5
+ flex-direction: row;
6
+ max-width: 100%;
7
+ height: 24rem;
8
+ position: relative;
9
+ padding: 0;
10
+ overflow: hidden;
11
+ }
12
+
13
+ .component {
14
+ display: flex;
15
+ align-items: center;
16
+ max-width: 100%;
17
+ height: 24rem;
18
+ gap: 0.5rem;
19
+ padding: var(#{$theme+$padding});
20
+ flex-direction: row;
21
+ overflow-x: auto;
22
+ scroll-snap-type: x mandatory;
23
+ scroll-snap-stop: always;
24
+ scrollbar-width: none;
25
+ padding-bottom: 2.5rem;
26
+
27
+ &::-webkit-scrollbar {
28
+ display: none;
29
+ }
30
+ }
31
+
32
+ .page {
33
+ display: flex;
34
+ width: 80%;
35
+ height: 100%;
36
+ flex-shrink: 0;
37
+ scroll-snap-align: center;
38
+
39
+ &:first-of-type {
40
+ margin-left: calc(20% + var(#{$theme+$gap}));
41
+ }
42
+
43
+ &:last-of-type {
44
+ margin-right: calc(20% + var(#{$theme+$gap}));
45
+ }
46
+ }
47
+
48
+ .controls {
49
+ position: absolute;
50
+ bottom: 0;
51
+ left: 50%;
52
+ transform: translateX(-50%);
53
+ display: flex;
54
+ flex-direction: row;
55
+ gap: var(#{$theme+$gap});
56
+ }
57
+
58
+ .indicator {
59
+ display: flex;
60
+ flex-direction: row;
61
+ gap: var(#{$theme+$gap});
62
+ padding: calc(var(#{$theme+$padding}) / 2);
63
+ border-radius: var(#{$theme+$radius});
64
+
65
+ .pageIndicator {
66
+ background-color: var(#{$theme+$color});
67
+ padding: 0.5rem;
68
+ border-radius: var(#{$theme+$radius});
69
+ transition: var(#{$theme+$transition});
70
+ position: relative;
71
+
72
+ &.selected {
73
+ padding-right: 1.5rem;
74
+ padding-left: 1.5rem;
75
+ }
76
+ }
77
+ }
@@ -0,0 +1,138 @@
1
+ import page from "@yourdash/web/src/deprecatedLogin/Page.tsx";
2
+ import React, { useEffect, useRef, useState } from "react";
3
+ import Card from "../../components/card/card.tsx";
4
+ import Container from "../../components/container/container.tsx";
5
+ import { UKIcon } from "../../components/icon/iconDictionary.ts";
6
+ import IconButton from "../../components/iconButton/iconButton.tsx";
7
+ import styles from "./carousel.module.scss";
8
+ import clippy from "@yourdash/shared/web/helpers/clippy.ts";
9
+
10
+ const Carousel: React.FC<{
11
+ items: { element: React.ReactElement; id: string }[];
12
+ className?: string;
13
+ }> = ({ items, className }) => {
14
+ const scrollRef = useRef<HTMLDivElement>(null);
15
+ const [currentPage, setCurrentPage] = useState<number>(0);
16
+
17
+ useEffect(() => {
18
+ const scrollElement = scrollRef.current;
19
+
20
+ if (!scrollElement) return;
21
+
22
+ console.log(Array.from(scrollElement.children));
23
+
24
+ let timer: Timer;
25
+ let listener = () => {
26
+ clearTimeout(timer);
27
+ timer = setTimeout(function () {
28
+ Array.from(scrollElement.children).forEach((ele: Element, index: number) => {
29
+ if (
30
+ Math.abs(
31
+ ele.getBoundingClientRect().left +
32
+ ele.getBoundingClientRect().width / 2 -
33
+ (scrollElement.getBoundingClientRect().left + scrollElement.getBoundingClientRect().width / 2),
34
+ ) <
35
+ ele.getBoundingClientRect().width / 2
36
+ ) {
37
+ setCurrentPage(index);
38
+ return;
39
+ }
40
+ });
41
+ }, 25);
42
+ };
43
+
44
+ scrollElement.addEventListener("scroll", listener);
45
+
46
+ return () => {
47
+ scrollElement.removeEventListener("scroll", listener);
48
+ clearTimeout(timer);
49
+ };
50
+ }, []);
51
+
52
+ return (
53
+ <Container className={clippy(styles.containerComponent, className)}>
54
+ <div
55
+ className={styles.component}
56
+ ref={scrollRef}
57
+ >
58
+ {items.map((child) => {
59
+ return (
60
+ <div
61
+ key={child.id}
62
+ className={styles.page}
63
+ >
64
+ {child.element}
65
+ </div>
66
+ );
67
+ })}
68
+ </div>
69
+ <div className={styles.controls}>
70
+ <IconButton
71
+ accessibleLabel={"previous page"}
72
+ icon={UKIcon.ChevronLeft}
73
+ className={styles.pageControl}
74
+ onClick={() => {
75
+ const scrollElement = scrollRef.current;
76
+
77
+ if (!scrollElement) {
78
+ return;
79
+ }
80
+
81
+ const carouselTargetPage = scrollElement.children[currentPage - 1] as HTMLDivElement;
82
+
83
+ if (!carouselTargetPage) {
84
+ return;
85
+ }
86
+
87
+ carouselTargetPage.scrollIntoView({ behavior: "smooth" });
88
+ }}
89
+ />
90
+ <Card className={styles.indicator}>
91
+ {items.map((page, index) => {
92
+ return (
93
+ <button
94
+ key={page.id}
95
+ className={clippy(styles.pageIndicator, index === currentPage && styles.selected)}
96
+ onClick={() => {
97
+ const scrollElement = scrollRef.current;
98
+
99
+ if (!scrollElement) {
100
+ return;
101
+ }
102
+
103
+ scrollElement.scrollIntoView({ behavior: "smooth" });
104
+
105
+ const carouselTargetPage = scrollElement.children[index] as HTMLDivElement;
106
+
107
+ carouselTargetPage.scrollIntoView({ behavior: "smooth" });
108
+ }}
109
+ />
110
+ );
111
+ })}
112
+ </Card>
113
+ <IconButton
114
+ accessibleLabel={"next page"}
115
+ icon={UKIcon.ChevronRight}
116
+ className={styles.pageControl}
117
+ onClick={() => {
118
+ const scrollElement = scrollRef.current;
119
+
120
+ if (!scrollElement) {
121
+ return;
122
+ }
123
+
124
+ const carouselTargetPage = scrollElement.children[currentPage + 1] as HTMLDivElement;
125
+
126
+ if (!carouselTargetPage) {
127
+ return;
128
+ }
129
+
130
+ carouselTargetPage.scrollIntoView({ behavior: "smooth" });
131
+ }}
132
+ />
133
+ </div>
134
+ </Container>
135
+ );
136
+ };
137
+
138
+ export default Carousel;
@@ -0,0 +1,16 @@
1
+ /*!
2
+ * Copyright ©2024 Ewsgit <https://ewsgit.uk> and YourDash <https://yourdash.ewsgit.uk> contributors.
3
+ * YourDash is licensed under the MIT License. (https://mit.ewsgit.uk)
4
+ */
5
+
6
+ @use "@yourdash/uikit/theme/themeValues" as *;
7
+
8
+ .view {
9
+ width: 100%;
10
+ display: flex;
11
+ align-items: center;
12
+ justify-content: center;
13
+ padding: var(#{$theme+$padding});
14
+ padding-top: calc(var(#{$theme+$padding}) * 4);
15
+ padding-bottom: calc(var(#{$theme+$padding}) * 4);
16
+ }
@@ -0,0 +1,28 @@
1
+ /*
2
+ * Copyright ©2024 Ewsgit <https://ewsgit.uk> and YourDash <https://yourdash.ewsgit.uk> contributors.
3
+ * YourDash is licensed under the MIT License. (https://mit.ewsgit.uk)
4
+ */
5
+
6
+ import React from "react";
7
+ import Heading from "../../components/heading/heading.tsx";
8
+ import styles from "./header.module.scss";
9
+
10
+ const Header: React.FC<{ backgroundImage?: string; heading: string }> = ({ backgroundImage, heading }) => {
11
+ return (
12
+ <>
13
+ <div
14
+ className={styles.view}
15
+ style={
16
+ backgroundImage ? { backgroundImage: backgroundImage } : { backgroundImage: "linear-gradient(-45deg, #ff8093aa, #ffd264aa)" }
17
+ }
18
+ >
19
+ <Heading
20
+ level={1}
21
+ text={heading}
22
+ />
23
+ </div>
24
+ </>
25
+ );
26
+ };
27
+
28
+ export default Header;
@@ -0,0 +1,26 @@
1
+ /*!
2
+ * Copyright ©2024 Ewsgit<https://ewsgit.uk> and YourDash<https://yourdash.ewsgit.uk> contributors.
3
+ * YourDash is licensed under the MIT License. (https://mit.ewsgit.uk)
4
+ */
5
+
6
+ @use "@yourdash/uikit/theme/themeValues" as *;
7
+
8
+ .component {
9
+ display: flex;
10
+ flex-direction: column;
11
+ width: 100%;
12
+ height: 100%;
13
+ gap: 1rem;
14
+ align-items: center;
15
+ }
16
+
17
+ .items {
18
+ height: 100%;
19
+ }
20
+
21
+ .endOfItems {
22
+ text-align: center;
23
+ padding: var(#{$theme+$padding});
24
+ gap: var(#{$theme+$gap});
25
+ width: calc(100% - calc(var(#{$theme+$padding}) * 2));
26
+ }
@@ -0,0 +1,90 @@
1
+ /*
2
+ * Copyright ©2024 Ewsgit<https://ewsgit.uk> and YourDash<https://yourdash.ewsgit.uk> contributors.
3
+ * YourDash is licensed under the MIT License. (https://mit.ewsgit.uk)
4
+ */
5
+
6
+ import clippy from "@yourdash/shared/web/helpers/clippy.ts";
7
+ import React, { useEffect, useState } from "react";
8
+ import Heading from "../../components/heading/heading.tsx";
9
+ import Separator from "../../components/separator/separator.tsx";
10
+ import Text from "../../components/text/text.tsx";
11
+ import styles from "./infiniteScroll.module.scss";
12
+
13
+ const InfiniteScroll: React.FC<{
14
+ children: React.ReactNode | React.ReactNode[];
15
+ fetchNextPage: (nextPageNumber: number) => Promise<{ hasAnotherPage?: boolean }>;
16
+ containerClassName?: string;
17
+ className?: string;
18
+ resetState?: string;
19
+ }> = ({ children, fetchNextPage, containerClassName, className, resetState }) => {
20
+ const endOfItemsRef = React.useRef<HTMLDivElement>(null);
21
+ const lastFetchedPage = React.useRef<number>(-1);
22
+ const [isLoading, setIsLoading] = useState<boolean>(false);
23
+ const [isLastPage, setIsLastPage] = useState<boolean>(false);
24
+
25
+ useEffect(() => {
26
+ lastFetchedPage.current = -1;
27
+ setIsLoading(false);
28
+ setIsLastPage(false);
29
+ fetchNextPageWrapper();
30
+ }, [resetState]);
31
+
32
+ async function fetchNextPageWrapper() {
33
+ if (isLoading) return;
34
+ setIsLoading(true);
35
+ const { hasAnotherPage } = await fetchNextPage(lastFetchedPage.current + 1);
36
+ lastFetchedPage.current++;
37
+ setIsLoading(false);
38
+ setIsLastPage(hasAnotherPage || false);
39
+ }
40
+
41
+ useEffect(() => {
42
+ if (!endOfItemsRef.current) return;
43
+
44
+ const element: HTMLDivElement = endOfItemsRef.current;
45
+
46
+ const observer = new IntersectionObserver((elem) => {
47
+ console.log("observer update");
48
+ const isVisible = elem[0].isIntersecting;
49
+
50
+ if (isVisible) fetchNextPageWrapper();
51
+ });
52
+
53
+ observer.observe(element);
54
+ }, []);
55
+
56
+ // TODO: Use interaction observer to detect when the last item is shown on the screen and fetch the next page
57
+
58
+ return (
59
+ <div className={clippy(containerClassName, styles.component)}>
60
+ {/* @ts-ignore */}
61
+ {children?.length > 0 ? (
62
+ <div className={clippy(className, styles.items)}>{children}</div>
63
+ ) : (
64
+ <div className={"text-center"}>
65
+ <Heading
66
+ level={1}
67
+ text={"Whoops."}
68
+ />
69
+ <Separator direction={"column"} />
70
+ <Text text={"It looks like nothing could be found..."} />
71
+ </div>
72
+ )}
73
+ <div
74
+ ref={endOfItemsRef}
75
+ className={styles.endOfItems}
76
+ >
77
+ {isLoading && <Text text={"Loading more content"} />}
78
+ <Separator direction={"column"} />
79
+ {isLastPage && (
80
+ <Text
81
+ text={"No more items to load"}
82
+ className={styles.endOfItems}
83
+ />
84
+ )}
85
+ </div>
86
+ </div>
87
+ );
88
+ };
89
+
90
+ export default InfiniteScroll;
@@ -0,0 +1,7 @@
1
+ @use "@yourdash/uikit/theme/themeValues" as *;
2
+
3
+ .component {
4
+ height: calc(var(--nav-height) - var(#{$theme+$padding}));
5
+ aspect-ratio: 1 / 1;
6
+ border-radius: 0;
7
+ }
@@ -0,0 +1,15 @@
1
+ import React from "react";
2
+ import Image from "../../../../components/image/image.tsx";
3
+ import styles from "./navImage.module.scss";
4
+
5
+ const NavImage: React.FC<{ src: string }> = ({ src }) => {
6
+ return (
7
+ <Image
8
+ accessibleLabel=""
9
+ src={src}
10
+ className={styles.component}
11
+ />
12
+ );
13
+ };
14
+
15
+ export default NavImage;
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ import Heading from "../../../../components/heading/heading.tsx";
3
+
4
+ const NavTitle: React.FC<{ title: string }> = ({ title }) => {
5
+ return (
6
+ <Heading
7
+ text={title}
8
+ level={2}
9
+ />
10
+ );
11
+ };
12
+
13
+ export default NavTitle;
@@ -0,0 +1,22 @@
1
+ @use "@yourdash/uikit/theme/themeValues" as *;
2
+
3
+ .component {
4
+ --nav-height: calc(2rem + var(#{$theme+$padding}));
5
+
6
+ width: 100%;
7
+ height: calc(var(--nav-height) + calc(var(#{$theme+$padding}) * 2));
8
+ border-top: 0;
9
+ border-left: 0;
10
+ border-right: 0;
11
+ padding: var(#{$theme+$padding});
12
+ display: grid;
13
+ grid-template-columns: auto 1fr auto;
14
+ justify-content: center;
15
+ align-items: center;
16
+ }
17
+
18
+ .segment {
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ }
@@ -0,0 +1,37 @@
1
+ import React from "react";
2
+ import Box from "../../components/box/box.tsx";
3
+ import styles from "./navBar.module.scss";
4
+ import Flex from "../../components/flex/flex.tsx";
5
+ import clippy from "@yourdash/shared/web/helpers/clippy.ts";
6
+
7
+ const NavBar: React.FC<{
8
+ leftSection?: React.ReactElement | React.ReactElement[];
9
+ centerSection?: React.ReactElement | React.ReactElement[];
10
+ rightSection?: React.ReactElement | React.ReactElement[];
11
+ className?: string;
12
+ }> = ({ leftSection, centerSection, rightSection, className }) => {
13
+ return (
14
+ <Box className={clippy(styles.component, className)}>
15
+ <Flex
16
+ className={styles.segment}
17
+ direction="row"
18
+ >
19
+ {leftSection}
20
+ </Flex>
21
+ <Flex
22
+ className={styles.segment}
23
+ direction="row"
24
+ >
25
+ {centerSection}
26
+ </Flex>
27
+ <Flex
28
+ className={styles.segment}
29
+ direction="row"
30
+ >
31
+ {rightSection}
32
+ </Flex>
33
+ </Box>
34
+ );
35
+ };
36
+
37
+ export default NavBar;
@@ -0,0 +1,84 @@
1
+ @use "@yourdash/uikit/theme/themeValues" as *;
2
+
3
+ .page {
4
+ display: flex;
5
+ align-items: center;
6
+ justify-content: center;
7
+ flex-direction: column;
8
+ width: 100%;
9
+ height: 100%;
10
+ position: relative;
11
+ animation: fadeIn 1s 0s cubic-bezier(0.215, 0.610, 0.355, 1);
12
+
13
+ &::before {
14
+ content: "";
15
+ //noinspection CssUnknownTarget
16
+ background-image: url("/assets/productLogos/yourdash.svg");
17
+ background-size: 20rem;
18
+ background-repeat: repeat;
19
+ width: 1000rem;
20
+ height: 1000rem;
21
+ position: absolute;
22
+ filter: blur(0.25rem) grayscale(1);
23
+ opacity: 0.1;
24
+ transform: rotate(-45deg);
25
+ z-index: -1;
26
+ }
27
+
28
+ @keyframes fadeIn {
29
+ from {
30
+ transform: translateY(2.5rem);
31
+ opacity: 0;
32
+ }
33
+ to {
34
+ transform: translateY(0);
35
+ opacity: 1;
36
+ }
37
+ }
38
+ }
39
+
40
+ .card {
41
+ display: flex;
42
+ align-items: center;
43
+ justify-content: center;
44
+ flex-direction: column;
45
+ gap: calc(var(#{$theme+$gap}) * 2);
46
+ padding: 2rem;
47
+ position: relative;
48
+ transition: var(--transition);
49
+ }
50
+
51
+ .cardContainer {
52
+ box-shadow: #00000088 0 0 4rem;
53
+ }
54
+
55
+ .goBackButton {
56
+ position: absolute;
57
+ top: var(#{$theme+$padding});
58
+ left: var(#{$theme+$padding});
59
+ }
60
+
61
+ .headerImage {
62
+ height: 16rem;
63
+ }
64
+
65
+ .header {
66
+ line-height: 1;
67
+ text-align: center;
68
+ }
69
+
70
+ .body {
71
+ text-align: center;
72
+ }
73
+
74
+ .actions {
75
+ }
76
+
77
+ .action {
78
+ }
79
+
80
+ .actionWithoutIcon {
81
+ }
82
+
83
+ .actionWithIcon {
84
+ }
@@ -0,0 +1,138 @@
1
+ import * as React from "react";
2
+ import Card from "../../components/card/card.tsx";
3
+ import { UKIcon } from "../../components/icon/iconDictionary.ts";
4
+ import IconButton from "../../components/iconButton/iconButton.tsx";
5
+ import Image from "../../components/image/image.tsx";
6
+ import Heading from "../../components/heading/heading.tsx";
7
+ import Text from "../../components/text/text.tsx";
8
+ import ButtonWithIcon from "../../components/buttonWithIcon/buttonWithIcon.tsx";
9
+ import Button from "../../components/button/button.tsx";
10
+ import { Outlet } from "react-router";
11
+ import styles from "./onBoarding.module.scss";
12
+ import Flex from "../../components/flex/flex.tsx";
13
+ import clippy from "@yourdash/shared/web/helpers/clippy.ts";
14
+
15
+ const OnBoarding: React.FC<{
16
+ meta: { id: string };
17
+ pages: {
18
+ headerImage: string;
19
+ header: string;
20
+ body: string;
21
+ actions: { label: string; icon?: UKIcon; onClick: () => void; changeTo?: "next" | "previous" | "remain" | "completed" }[];
22
+ allowGoBack?: boolean;
23
+ }[];
24
+ }> = ({ pages, meta }) => {
25
+ const [currentPage, setCurrentPage] = React.useState<number>(0);
26
+ const page = pages[currentPage];
27
+
28
+ if (localStorage.getItem(`yourdash-application-visited-${meta.id}`) || currentPage > pages.length - 1) {
29
+ localStorage.setItem(`yourdash-application-visited-${meta.id}`, "true");
30
+
31
+ return <Outlet />;
32
+ }
33
+
34
+ return (
35
+ <div className={styles.page}>
36
+ <Card
37
+ className={styles.card}
38
+ containerClassName={styles.cardContainer}
39
+ >
40
+ {page.allowGoBack && (
41
+ <IconButton
42
+ className={clippy(styles.goBackButton, "animate__animated animate__fadeInDown")}
43
+ accessibleLabel="Go back to the last page"
44
+ icon={UKIcon.ChevronLeft}
45
+ onClick={() => {
46
+ setCurrentPage(currentPage - 1);
47
+ }}
48
+ />
49
+ )}
50
+ <Image
51
+ className={styles.headerImage}
52
+ src={page.headerImage}
53
+ accessibleLabel=""
54
+ />
55
+ <Heading
56
+ className={styles.header}
57
+ text={page.header}
58
+ />
59
+ <Text
60
+ className={styles.body}
61
+ text={page.body}
62
+ />
63
+ <Flex
64
+ className={styles.actions}
65
+ direction="row"
66
+ >
67
+ {page.actions.map((action) => {
68
+ if (action.icon) {
69
+ return (
70
+ <>
71
+ <ButtonWithIcon
72
+ key={action.label}
73
+ className={clippy(styles.action, styles.actionWithIcon, "animate__animated animate__fadeInUp")}
74
+ text={action.label}
75
+ icon={action.icon}
76
+ onClick={() => {
77
+ action.onClick();
78
+ if (action.changeTo) {
79
+ switch (action.changeTo) {
80
+ case "next":
81
+ setCurrentPage(currentPage + 1);
82
+ break;
83
+ case "previous":
84
+ if (currentPage > 0) setCurrentPage(currentPage - 1);
85
+ break;
86
+ case "remain":
87
+ break;
88
+ case "completed":
89
+ setCurrentPage(pages.length + 1);
90
+ break;
91
+ default:
92
+ break;
93
+ }
94
+ }
95
+ }}
96
+ />
97
+ </>
98
+ );
99
+ }
100
+
101
+ return (
102
+ <>
103
+ <Button
104
+ key={action.icon}
105
+ className={clippy(styles.action, styles.actionWithoutIcon, "animate__animated animate__fadeInUp")}
106
+ text={action.label}
107
+ onClick={() => {
108
+ action.onClick();
109
+
110
+ if (action.changeTo) {
111
+ switch (action.changeTo) {
112
+ case "next":
113
+ setCurrentPage(currentPage + 1);
114
+ break;
115
+ case "previous":
116
+ if (currentPage > 0) setCurrentPage(currentPage - 1);
117
+ break;
118
+ case "remain":
119
+ break;
120
+ case "completed":
121
+ setCurrentPage(pages.length + 1);
122
+ break;
123
+ default:
124
+ break;
125
+ }
126
+ }
127
+ }}
128
+ />
129
+ </>
130
+ );
131
+ })}
132
+ </Flex>
133
+ </Card>
134
+ </div>
135
+ );
136
+ };
137
+
138
+ export default OnBoarding;