@vygruppen/spor-react 1.3.4 → 2.0.1
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/.turbo/turbo-build.log +12 -10
- package/CHANGELOG.md +31 -0
- package/dist/index.d.ts +6720 -27
- package/dist/index.js +14143 -140
- package/dist/index.mjs +13822 -27
- package/package.json +19 -31
- package/src/accordion/Accordion.test.tsx +20 -0
- package/src/accordion/Accordion.tsx +62 -0
- package/src/accordion/AccordionContext.tsx +27 -0
- package/src/accordion/Expandable.tsx +157 -0
- package/src/accordion/index.tsx +2 -0
- package/src/alert/AlertIcon.tsx +75 -0
- package/src/alert/BaseAlert.test.tsx +37 -0
- package/src/alert/BaseAlert.tsx +21 -0
- package/src/alert/ClosableAlert.test.tsx +37 -0
- package/src/alert/ClosableAlert.tsx +75 -0
- package/src/alert/ExpandableAlert.test.tsx +84 -0
- package/src/alert/ExpandableAlert.tsx +84 -0
- package/src/alert/StaticAlert.tsx +25 -0
- package/src/alert/index.tsx +3 -0
- package/src/button/Button.test.tsx +23 -0
- package/src/button/Button.tsx +162 -0
- package/src/button/ButtonGroup.tsx +43 -0
- package/src/button/CloseButton.tsx +63 -0
- package/src/button/FloatingActionButton.tsx +113 -0
- package/src/button/IconButton.tsx +63 -0
- package/src/button/index.tsx +5 -0
- package/src/card/Card.tsx +59 -0
- package/src/card/index.tsx +1 -0
- package/src/datepicker/Calendar.tsx +32 -0
- package/src/datepicker/CalendarCell.tsx +74 -0
- package/src/datepicker/CalendarGrid.tsx +76 -0
- package/src/datepicker/CalendarHeader.tsx +153 -0
- package/src/datepicker/CalendarNavigationButton.tsx +26 -0
- package/src/datepicker/CalendarTriggerButton.tsx +36 -0
- package/src/datepicker/DateField.tsx +51 -0
- package/src/datepicker/DatePicker.tsx +153 -0
- package/src/datepicker/DateRangePicker.tsx +171 -0
- package/src/datepicker/DateTimeSegment.tsx +56 -0
- package/src/datepicker/RangeCalendar.tsx +35 -0
- package/src/datepicker/StyledField.tsx +31 -0
- package/src/datepicker/TimeField.tsx +46 -0
- package/src/datepicker/TimePicker.test.tsx +74 -0
- package/src/datepicker/TimePicker.tsx +196 -0
- package/src/datepicker/index.tsx +4 -0
- package/src/datepicker/utils.ts +33 -0
- package/src/i18n/index.tsx +38 -0
- package/src/image/index.tsx +2 -0
- package/src/index.tsx +25 -26
- package/src/input/CardSelect.tsx +165 -0
- package/src/input/Checkbox.tsx +24 -0
- package/src/input/CheckboxGroup.tsx +43 -0
- package/src/input/ChoiceChip.tsx +102 -0
- package/src/input/Dialog.tsx +29 -0
- package/src/input/FormControl.tsx +11 -0
- package/src/input/FormErrorMessage.tsx +91 -0
- package/src/input/FormLabel.tsx +11 -0
- package/src/input/InfoSelect.tsx +209 -0
- package/src/input/Input.tsx +59 -0
- package/src/input/InputElement.tsx +45 -0
- package/src/input/ListBox.tsx +123 -0
- package/src/input/NativeSelect.tsx +38 -0
- package/src/input/PasswordInput.tsx +70 -0
- package/src/input/Popover.tsx +70 -0
- package/src/input/Radio.tsx +34 -0
- package/src/input/RadioGroup.tsx +47 -0
- package/src/input/SearchInput.tsx +89 -0
- package/src/input/Switch.tsx +40 -0
- package/src/input/Textarea.tsx +98 -0
- package/src/input/index.tsx +20 -0
- package/src/layout/Divider.tsx +26 -0
- package/src/layout/Stack.tsx +42 -0
- package/src/layout/index.tsx +28 -0
- package/src/linjetag/InfoTag.tsx +54 -0
- package/src/linjetag/LineIcon.tsx +44 -0
- package/src/linjetag/TravelTag.tsx +121 -0
- package/src/linjetag/icons.tsx +80 -0
- package/src/linjetag/index.tsx +3 -0
- package/src/linjetag/types.d.ts +24 -0
- package/src/link/TextLink.tsx +45 -0
- package/src/link/index.tsx +1 -0
- package/src/loader/ClientOnly.tsx +29 -0
- package/src/loader/ColorInlineLoader.tsx +27 -0
- package/src/loader/ColorSpinner.tsx +44 -0
- package/src/loader/ContentLoader.tsx +27 -0
- package/src/loader/DarkFullScreenLoader.tsx +23 -0
- package/src/loader/DarkInlineLoader.tsx +25 -0
- package/src/loader/DarkSpinner.tsx +43 -0
- package/src/loader/LightFullScreenLoader.tsx +23 -0
- package/src/loader/LightInlineLoader.tsx +25 -0
- package/src/loader/LightSpinner.tsx +41 -0
- package/src/loader/Lottie.tsx +10 -0
- package/src/loader/ProgressBar.tsx +128 -0
- package/src/loader/ProgressLoader.tsx +140 -0
- package/src/loader/Skeleton.tsx +16 -0
- package/src/loader/SkeletonCircle.tsx +13 -0
- package/src/loader/SkeletonText.tsx +10 -0
- package/src/loader/index.tsx +14 -0
- package/src/loader/useHydrated.tsx +34 -0
- package/src/loader/useRotatingLabel.tsx +22 -0
- package/src/logo/VyLogo.tsx +101 -0
- package/src/logo/index.tsx +1 -0
- package/src/media-controller/JumpButton.tsx +69 -0
- package/src/media-controller/PlayPauseButton.tsx +67 -0
- package/src/media-controller/SkipButton.tsx +66 -0
- package/src/media-controller/icons.tsx +80 -0
- package/src/media-controller/index.test.tsx +59 -0
- package/src/media-controller/index.tsx +3 -0
- package/src/modal/Drawer.tsx +122 -0
- package/src/modal/Modal.tsx +15 -0
- package/src/modal/ModalHeader.tsx +31 -0
- package/src/modal/SimpleDrawer.tsx +44 -0
- package/src/modal/index.tsx +4 -0
- package/src/popover/PopoverWizardBody.tsx +91 -0
- package/src/popover/SimplePopover.tsx +75 -0
- package/src/popover/WizardPopover.tsx +61 -0
- package/src/popover/index.tsx +23 -0
- package/src/provider/SporProvider.tsx +67 -0
- package/src/provider/index.tsx +1 -0
- package/src/stepper/Stepper.tsx +115 -0
- package/src/stepper/StepperContext.tsx +55 -0
- package/src/stepper/StepperStep.tsx +48 -0
- package/src/stepper/index.tsx +2 -0
- package/src/tab/Tabs.tsx +20 -0
- package/src/tab/index.tsx +9 -0
- package/src/table/Table.tsx +58 -0
- package/src/table/index.tsx +19 -0
- package/src/theme/components/accordion.ts +143 -0
- package/src/theme/components/alert.ts +59 -0
- package/src/theme/components/badge.ts +109 -0
- package/src/theme/components/button.ts +217 -0
- package/src/theme/components/card-select.ts +158 -0
- package/src/theme/components/card.ts +174 -0
- package/src/theme/components/checkbox.ts +90 -0
- package/src/theme/components/choice-chip.ts +79 -0
- package/src/theme/components/close-button.ts +56 -0
- package/src/theme/components/code.ts +17 -0
- package/src/theme/components/datepicker.ts +194 -0
- package/src/theme/components/drawer.ts +92 -0
- package/src/theme/components/fab.ts +111 -0
- package/src/theme/components/form-label.ts +17 -0
- package/src/theme/components/form.ts +27 -0
- package/src/theme/components/index.ts +34 -0
- package/src/theme/components/info-select.ts +91 -0
- package/src/theme/components/info-tag.ts +49 -0
- package/src/theme/components/input.ts +97 -0
- package/src/theme/components/line-icon.ts +121 -0
- package/src/theme/components/link.ts +155 -0
- package/src/theme/components/listbox.ts +52 -0
- package/src/theme/components/media-controller-button.ts +134 -0
- package/src/theme/components/modal.ts +93 -0
- package/src/theme/components/popover.ts +63 -0
- package/src/theme/components/radio.ts +64 -0
- package/src/theme/components/select.ts +52 -0
- package/src/theme/components/skeleton.ts +40 -0
- package/src/theme/components/stepper.ts +230 -0
- package/src/theme/components/switch.ts +227 -0
- package/src/theme/components/table.ts +163 -0
- package/src/theme/components/tabs.ts +282 -0
- package/src/theme/components/textarea.ts +14 -0
- package/src/theme/components/toast.ts +28 -0
- package/src/theme/components/travel-tag.ts +267 -0
- package/src/theme/font-faces.ts +66 -0
- package/src/theme/foundations/borders.ts +11 -0
- package/src/theme/foundations/breakpoints.ts +9 -0
- package/src/theme/foundations/colors.ts +10 -0
- package/src/theme/foundations/config.ts +5 -0
- package/src/theme/foundations/fontSizes.ts +29 -0
- package/src/theme/foundations/fontWeights.ts +5 -0
- package/src/theme/foundations/fonts.ts +7 -0
- package/src/theme/foundations/index.ts +14 -0
- package/src/theme/foundations/lineHeights.ts +5 -0
- package/src/theme/foundations/radii.ts +12 -0
- package/src/theme/foundations/shadows.ts +8 -0
- package/src/theme/foundations/sizes.ts +34 -0
- package/src/theme/foundations/spacing.ts +30 -0
- package/src/theme/foundations/textStyles.ts +60 -0
- package/src/theme/foundations/zIndices.ts +17 -0
- package/src/theme/index.ts +14 -0
- package/src/theme/utils/box-shadow-utils.ts +44 -0
- package/src/theme/utils/focus-utils.ts +16 -0
- package/src/toast/ActionToast.test.tsx +22 -0
- package/src/toast/ActionToast.tsx +28 -0
- package/src/toast/BaseToast.test.tsx +27 -0
- package/src/toast/BaseToast.tsx +75 -0
- package/src/toast/ClosableToast.test.tsx +17 -0
- package/src/toast/ClosableToast.tsx +40 -0
- package/src/toast/index.tsx +1 -0
- package/src/toast/useToast.tsx +99 -0
- package/src/typography/Badge.tsx +68 -0
- package/src/typography/Code.tsx +32 -0
- package/src/typography/Heading.tsx +32 -0
- package/src/typography/Text.tsx +26 -0
- package/src/typography/index.tsx +4 -0
- package/src/util/externals.tsx +23 -0
- package/src/util/index.tsx +1 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
export * from "./ColorInlineLoader";
|
2
|
+
export * from "./ColorSpinner";
|
3
|
+
export * from "./ContentLoader";
|
4
|
+
export * from "./DarkFullScreenLoader";
|
5
|
+
export * from "./DarkInlineLoader";
|
6
|
+
export * from "./DarkSpinner";
|
7
|
+
export * from "./LightFullScreenLoader";
|
8
|
+
export * from "./LightInlineLoader";
|
9
|
+
export * from "./LightSpinner";
|
10
|
+
export * from "./ProgressBar";
|
11
|
+
export * from "./ProgressLoader";
|
12
|
+
export * from "./Skeleton";
|
13
|
+
export * from "./SkeletonCircle";
|
14
|
+
export * from "./SkeletonText";
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import { useEffect, useState } from "react";
|
2
|
+
|
3
|
+
// Lifted from remix-utils
|
4
|
+
// https://github.com/sergiodxa/remix-utils/blob/main/src/react/use-hydrated.ts
|
5
|
+
|
6
|
+
let hydrating = true;
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Return a boolean indicating if the JS has been hydrated already.
|
10
|
+
* When doing Server-Side Rendering, the result will always be false.
|
11
|
+
* When doing Client-Side Rendering, the result will always be false on the
|
12
|
+
* first render and true from then on. Even if a new component renders it will
|
13
|
+
* always start with true.
|
14
|
+
*
|
15
|
+
* Example: Disable a button that needs JS to work.
|
16
|
+
* ```tsx
|
17
|
+
* let hydrated = useHydrated();
|
18
|
+
* return (
|
19
|
+
* <button type="button" disabled={!hydrated} onClick={doSomethingCustom}>
|
20
|
+
* Click me
|
21
|
+
* </button>
|
22
|
+
* );
|
23
|
+
* ```
|
24
|
+
*/
|
25
|
+
export function useHydrated() {
|
26
|
+
let [hydrated, setHydrated] = useState(() => !hydrating);
|
27
|
+
|
28
|
+
useEffect(function hydrate() {
|
29
|
+
hydrating = false;
|
30
|
+
setHydrated(true);
|
31
|
+
}, []);
|
32
|
+
|
33
|
+
return hydrated;
|
34
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import { useInterval } from "@chakra-ui/react";
|
2
|
+
import { useMemo, useState } from "react";
|
3
|
+
|
4
|
+
type UseRotatingLabelArgs = {
|
5
|
+
label?: string | string[];
|
6
|
+
delay: number;
|
7
|
+
};
|
8
|
+
/** Returns a label from a set of labels */
|
9
|
+
export const useRotatingLabel = ({ label, delay }: UseRotatingLabelArgs) => {
|
10
|
+
const loadingTextArray = useMemo(
|
11
|
+
() => (Array.isArray(label) ? label : [label]),
|
12
|
+
[label]
|
13
|
+
);
|
14
|
+
const [currentLoadingTextIndex, setCurrentLoadingTextIndex] = useState(0);
|
15
|
+
|
16
|
+
useInterval(() => {
|
17
|
+
setCurrentLoadingTextIndex(
|
18
|
+
(prevIndex) => (prevIndex + 1) % loadingTextArray.length
|
19
|
+
);
|
20
|
+
}, delay);
|
21
|
+
return loadingTextArray[currentLoadingTextIndex];
|
22
|
+
};
|
@@ -0,0 +1,101 @@
|
|
1
|
+
import { Box, BoxProps } from "@chakra-ui/react";
|
2
|
+
import React, { useId } from "react";
|
3
|
+
|
4
|
+
export type VyLogoProps = {
|
5
|
+
/** The color of the logo
|
6
|
+
*
|
7
|
+
* Use `"light"` when the logo is used on a light background.
|
8
|
+
* Use `"dark"` when the logo is used on a dark background.
|
9
|
+
*/
|
10
|
+
colorScheme: "light" | "dark";
|
11
|
+
} & BoxProps;
|
12
|
+
export const VyLogo = ({ colorScheme, ...boxProps }: VyLogoProps) => {
|
13
|
+
// These colors should not be tokenized, as they are logo specific.
|
14
|
+
const mainColor = colorScheme === "light" ? "#1d211c" : "#ffffff";
|
15
|
+
const accentColor = colorScheme === "light" ? "#138c6e" : "#ffffff";
|
16
|
+
const id = useId();
|
17
|
+
return (
|
18
|
+
<Box as="svg" viewBox="0 0 107 54" {...boxProps}>
|
19
|
+
<title>Vy logo</title>
|
20
|
+
<path
|
21
|
+
fillRule="evenodd"
|
22
|
+
clipRule="evenodd"
|
23
|
+
d="M79.97 33.44a.04.04 0 0 0 0-.08 5.76 5.76 0 0 1-2.32-.85c-1.56-1-2.79-2.9-3.83-6.07L68.14 7.16c-1.18-4.04-3.42-5.85-5.48-6.6a8.36 8.36 0 0 0-2.88-.52h-1.44a.04.04 0 0 0 0 .08c.57.09 1.18.24 1.8.5 1.92.8 3.92 2.63 5.06 6.54l5.61 19.07c1.06 3.3 2.31 5.27 3.92 6.3 1.01.64 2.17.9 3.5.9h1.74Z"
|
24
|
+
fill={mainColor}
|
25
|
+
/>
|
26
|
+
<mask
|
27
|
+
id={`${id}-a`}
|
28
|
+
style={{ maskType: "alpha" }}
|
29
|
+
maskUnits="userSpaceOnUse"
|
30
|
+
x="0"
|
31
|
+
y="0"
|
32
|
+
width="94"
|
33
|
+
height="54"
|
34
|
+
>
|
35
|
+
<path
|
36
|
+
fillRule="evenodd"
|
37
|
+
clipRule="evenodd"
|
38
|
+
d="M0 .03h93.26v53.65H0V.03Z"
|
39
|
+
fill={mainColor}
|
40
|
+
/>
|
41
|
+
</mask>
|
42
|
+
<g
|
43
|
+
mask={`url(#${id}-a)`}
|
44
|
+
fillRule="evenodd"
|
45
|
+
clipRule="evenodd"
|
46
|
+
fill={mainColor}
|
47
|
+
>
|
48
|
+
<path d="M84.57 33.44a.04.04 0 0 0 .01-.08c-2.34-.3-3.85-3.59-4.68-6.38-.88-2.93-4.04-13.63-5.92-19.82C72.08.94 66.2.05 63.54.04a.04.04 0 0 0-.01.08c2.49.34 6.02 1.85 7.55 7.04 1.34 4.55 5.6 19.03 5.76 19.51 1.02 3.03 2.22 4.85 3.73 5.83a6.3 6.3 0 0 0 3.54.94h.46ZM23.28 53.68h-.72c-2.12 0-4.68-1.08-6.09-6.04L3.8 4.37C3.04 1.77 1.93.47.03.15A.04.04 0 0 1 .04.07h1.9c2.54 0 3.92 1.27 4.8 4.3 0 0 11.72 39.78 12.79 43.54.78 2.78 1.7 4.67 3.13 5.43.23.13.42.2.62.26a.04.04 0 0 1 0 .08ZM18.99 5.99C17.77 1.79 15.87.04 12.37.04h-1.71a.04.04 0 0 0 0 .08c2.73.39 4.32 2.19 5.39 5.87 0 0 10.49 35.72 11.85 40.4l1.44-4.87L18.99 6Z" />
|
49
|
+
<path d="M24.26 53.68h1.24c1.57 0 2.69-.41 3.52-1.1 1.37-1.1 1.99-2.93 2.56-4.86.09-.29 11.2-37.95 11.59-39.42 1.32-4.97 4.27-7.13 7.43-7.9a12.2 12.2 0 0 1 1.58-.28.04.04 0 0 0 0-.08h-1.4c-4.15 0-8.8 1.65-10.56 8.26-.63 2.38-11.5 39.13-11.58 39.42-.57 1.93-1.23 3.96-2.59 5.07-.56.45-1.06.7-1.8.81a.04.04 0 0 0 0 .08ZM81.3 27.76l6.53-21.78C88.89 2.3 90.49.5 93.23.11a.04.04 0 0 0-.01-.08H91.5c-3.5 0-5.4 1.76-6.62 5.95l-5.05 16.97s1.33 4.46 1.46 4.8Z" />
|
50
|
+
</g>
|
51
|
+
<path
|
52
|
+
fillRule="evenodd"
|
53
|
+
clipRule="evenodd"
|
54
|
+
d="M98.49.07h-1.82c-2.98 0-4.6 1.49-5.63 5.06l-6.52 21.79a18.22 18.22 0 0 1-1.67 3.96c.57.78 1.17 1.26 1.76 1.38 1.13-.96 2.06-2.75 2.89-5.46l6.49-21.67c.9-3.1 2.23-4.63 4.5-4.98a.04.04 0 0 0 0-.08Z"
|
55
|
+
fill={accentColor}
|
56
|
+
/>
|
57
|
+
<path
|
58
|
+
fillRule="evenodd"
|
59
|
+
clipRule="evenodd"
|
60
|
+
d="M85.25 34.53h-2.93L78.58 46.9c-1.82 6.1 1.05 6.73 2.15 6.73h2.31a.04.04 0 0 0 .01-.09c-1.25-.3-2.96-1.6-1.45-6.64l3.65-12.37ZM102.35.11c.02 0 .03-.02.03-.04a.04.04 0 0 0-.04-.04h-.4c-2.54 0-3.92 1.27-4.8 4.3 0 0-5 16.82-6.57 22.03-1.57 5.2-2.65 6.6-4.78 6.97l-.11.03a.04.04 0 0 0 0 .08h1.45c3.72 0 5.1-2.48 6.41-6.84l7.5-25.07c.19-.6.7-1.23 1.31-1.42Z"
|
61
|
+
fill={mainColor}
|
62
|
+
/>
|
63
|
+
<mask
|
64
|
+
id={`${id}-b`}
|
65
|
+
style={{ maskType: "alpha" }}
|
66
|
+
maskUnits="userSpaceOnUse"
|
67
|
+
x="29"
|
68
|
+
y="0"
|
69
|
+
width="78"
|
70
|
+
height="54"
|
71
|
+
>
|
72
|
+
<path
|
73
|
+
fillRule="evenodd"
|
74
|
+
clipRule="evenodd"
|
75
|
+
d="M29.55.04H106v53.64H29.55V.04Z"
|
76
|
+
fill={mainColor}
|
77
|
+
/>
|
78
|
+
</mask>
|
79
|
+
<g mask={`url(#${id}-b)`} fillRule="evenodd" clipRule="evenodd">
|
80
|
+
<path
|
81
|
+
d="m88.2 34.45-3.96 13.46c-1.54 5.18.9 5.72 1.83 5.72h2.26a.04.04 0 0 0 0-.09c-1.05-.27-2.44-1.4-1.18-5.63l4.43-15.02c-.7.71-1.88 1.37-3.38 1.56ZM93.71 53.63c.02 0 .04-.02.04-.05a.04.04 0 0 0-.03-.04c-.9-.25-2.02-1.24-.96-4.77 0 0 12.4-42.2 13.08-44.6a3.1 3.1 0 0 0-2.47-4.1c-.02 0-.06-.02-.07.01-.01.04.03.06.04.06.3.16.63.52.45 1.14L89.84 48.77c-1.32 4.4.76 4.86 1.55 4.86h2.32ZM74.1 33.44a.04.04 0 0 0 0-.08 5.77 5.77 0 0 1-2.3-.83c-1.64-1.04-2.9-3.06-3.98-6.5-.1-.29-5.37-18.25-5.55-18.87-1.12-3.8-2.91-5.63-4.68-6.46a7.06 7.06 0 0 0-3.04-.66H53a.04.04 0 0 0-.02.08c.3.05 4.32.17 6.35 7.04 2.03 6.86 4.46 15.07 5.28 17.97 1.77 6.26 4.07 8.3 7.75 8.3h1.73Z"
|
82
|
+
fill={mainColor}
|
83
|
+
/>
|
84
|
+
<path
|
85
|
+
d="M55.43 2.4c-1.48 1.27-2.7 3.16-3.44 5.9-.07.29-11.08 37.74-11.32 38.55-.93 3.12-1.7 6.21-5.2 6.75a.04.04 0 0 0 0 .08h.7l.6-.01c3.56-.14 5.33-1.66 6.85-6.82L54.94 8.3c.44-1.44.96-3.08 1.7-4.52-.15-.25-.7-.96-1.2-1.38Z"
|
86
|
+
fill={mainColor}
|
87
|
+
/>
|
88
|
+
<path
|
89
|
+
d="M53.78 1.44a4.64 4.64 0 0 0-4.17.93A10.79 10.79 0 0 0 46.19 8L34.53 47.72c-.58 1.93-1.2 3.75-2.56 4.87-.62.5-1.4.86-2.39 1.01a.04.04 0 0 0 0 .08h1.8c1.57 0 2.69-.41 3.53-1.1 1.36-1.1 1.98-2.93 2.56-4.86L49.05 8.3c.73-2.74 1.95-4.63 3.43-5.9.43-.36.88-.68 1.35-.95l-.05-.01Z"
|
90
|
+
fill={accentColor}
|
91
|
+
/>
|
92
|
+
</g>
|
93
|
+
<path
|
94
|
+
fillRule="evenodd"
|
95
|
+
clipRule="evenodd"
|
96
|
+
d="M26.55 50.33a9.09 9.09 0 0 1-1.24-2.7c-.44-1.54-12.46-42.5-12.46-42.5C11.82 1.56 10.2.07 7.22.07H5.4a.04.04 0 0 0 0 .08C7.67.5 9 2.04 9.9 5.13l12.46 42.5c.65 2.28 1.53 3.74 2.5 4.65.7-.4 1.29-1.05 1.69-1.95Z"
|
97
|
+
fill={mainColor}
|
98
|
+
/>
|
99
|
+
</Box>
|
100
|
+
);
|
101
|
+
};
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from "./VyLogo";
|
@@ -0,0 +1,69 @@
|
|
1
|
+
import { BoxProps, Center, useMultiStyleConfig } from "@chakra-ui/react";
|
2
|
+
import React from "react";
|
3
|
+
import { createTexts, useTranslation } from "..";
|
4
|
+
import { JumpBackwardIcon, JumpForwardIcon } from "./icons";
|
5
|
+
|
6
|
+
type JumpButtonProps = BoxProps & {
|
7
|
+
onClick: () => void;
|
8
|
+
"aria-label"?: string;
|
9
|
+
isDisabled?: boolean;
|
10
|
+
direction: "backward" | "forward";
|
11
|
+
size: "sm" | "lg";
|
12
|
+
};
|
13
|
+
|
14
|
+
/**
|
15
|
+
* A jump button.
|
16
|
+
*
|
17
|
+
* Intended to jump 15 seconds forward or backward in a video, podcast, audiobook or similar.
|
18
|
+
*
|
19
|
+
* Specify what direction you want to skip with the `direction` prop.
|
20
|
+
*
|
21
|
+
* ```tsx
|
22
|
+
* <JumpButton direction="forward" onClick={onGoForward} />
|
23
|
+
* ```
|
24
|
+
*/
|
25
|
+
export const JumpButton = ({
|
26
|
+
direction,
|
27
|
+
isDisabled,
|
28
|
+
size = "sm",
|
29
|
+
...props
|
30
|
+
}: JumpButtonProps) => {
|
31
|
+
const { t } = useTranslation();
|
32
|
+
const styles = useMultiStyleConfig("MediaControllerButton", {
|
33
|
+
variant: "jumpSkip",
|
34
|
+
size,
|
35
|
+
});
|
36
|
+
|
37
|
+
return (
|
38
|
+
<Center
|
39
|
+
as="button"
|
40
|
+
sx={styles.container}
|
41
|
+
aria-label={
|
42
|
+
direction === "forward" ? t(texts.forward) : t(texts.backward)
|
43
|
+
}
|
44
|
+
disabled={isDisabled}
|
45
|
+
{...props}
|
46
|
+
>
|
47
|
+
{direction === "forward" ? (
|
48
|
+
<JumpForwardIcon sx={styles.icon} />
|
49
|
+
) : (
|
50
|
+
<JumpBackwardIcon sx={styles.icon} />
|
51
|
+
)}
|
52
|
+
</Center>
|
53
|
+
);
|
54
|
+
};
|
55
|
+
|
56
|
+
const texts = createTexts({
|
57
|
+
forward: {
|
58
|
+
nb: "15 sekunder frem",
|
59
|
+
nn: "15 sekunder fram",
|
60
|
+
sv: "15 sekunder framåt",
|
61
|
+
en: "15 seconds forward",
|
62
|
+
},
|
63
|
+
backward: {
|
64
|
+
nb: "15 sekunder tilbake",
|
65
|
+
nn: "15 sekunder tilbake",
|
66
|
+
sv: "15 sekunder tillbaka",
|
67
|
+
en: "15 seconds backward",
|
68
|
+
},
|
69
|
+
});
|
@@ -0,0 +1,67 @@
|
|
1
|
+
import { BoxProps, Center, useMultiStyleConfig } from "@chakra-ui/react";
|
2
|
+
import React from "react";
|
3
|
+
import { createTexts, useTranslation } from "..";
|
4
|
+
import { PauseIcon, PlayIcon } from "./icons";
|
5
|
+
|
6
|
+
type PlayPauseButtonProps = BoxProps & {
|
7
|
+
onClick: () => void;
|
8
|
+
"aria-label"?: string;
|
9
|
+
isDisabled?: boolean;
|
10
|
+
isPlaying: boolean;
|
11
|
+
size: "sm" | "lg";
|
12
|
+
};
|
13
|
+
|
14
|
+
/**
|
15
|
+
* A playback button.
|
16
|
+
*
|
17
|
+
* Intended to start or pause playback of a video, podcast, audiobook or similar.
|
18
|
+
*
|
19
|
+
* Specify the current playing state with `isPlaying`.
|
20
|
+
*
|
21
|
+
* ```tsx
|
22
|
+
* <PlayPauseButton isPlaying={isPlaying} onClick={onPlaybackClick} />
|
23
|
+
* ```
|
24
|
+
*/
|
25
|
+
export const PlayPauseButton = ({
|
26
|
+
size = "lg",
|
27
|
+
isPlaying,
|
28
|
+
isDisabled,
|
29
|
+
...props
|
30
|
+
}: PlayPauseButtonProps) => {
|
31
|
+
const { t } = useTranslation();
|
32
|
+
const styles = useMultiStyleConfig("MediaControllerButton", {
|
33
|
+
variant: "play",
|
34
|
+
size,
|
35
|
+
});
|
36
|
+
|
37
|
+
return (
|
38
|
+
<Center
|
39
|
+
as="button"
|
40
|
+
sx={styles.container}
|
41
|
+
aria-label={isPlaying ? t(texts.pause) : t(texts.play)}
|
42
|
+
disabled={isDisabled}
|
43
|
+
{...props}
|
44
|
+
>
|
45
|
+
{isPlaying ? (
|
46
|
+
<PauseIcon sx={styles.icon} />
|
47
|
+
) : (
|
48
|
+
<PlayIcon sx={styles.icon} />
|
49
|
+
)}
|
50
|
+
</Center>
|
51
|
+
);
|
52
|
+
};
|
53
|
+
|
54
|
+
const texts = createTexts({
|
55
|
+
pause: {
|
56
|
+
nb: "Pause",
|
57
|
+
nn: "Pause",
|
58
|
+
sv: "Paus",
|
59
|
+
en: "Pause",
|
60
|
+
},
|
61
|
+
play: {
|
62
|
+
nb: "Spill av",
|
63
|
+
nn: "Spill av",
|
64
|
+
sv: "Spel av",
|
65
|
+
en: "Play",
|
66
|
+
},
|
67
|
+
});
|
@@ -0,0 +1,66 @@
|
|
1
|
+
import { BoxProps, Center, useMultiStyleConfig } from "@chakra-ui/react";
|
2
|
+
import React from "react";
|
3
|
+
import { createTexts, useTranslation } from "..";
|
4
|
+
import { SkipNextIcon, SkipPreviousIcon } from "./icons";
|
5
|
+
|
6
|
+
type SkipButtonProps = BoxProps & {
|
7
|
+
onClick: () => void;
|
8
|
+
"aria-label"?: string;
|
9
|
+
isDisabled?: boolean;
|
10
|
+
direction: "backward" | "forward";
|
11
|
+
size: "sm" | "lg";
|
12
|
+
};
|
13
|
+
/**
|
14
|
+
* A skip button.
|
15
|
+
*
|
16
|
+
* Intended to skip to the next section, chapter og similar.
|
17
|
+
*
|
18
|
+
* Specify what direction you want to skip with the `direction` prop.
|
19
|
+
*
|
20
|
+
* ```tsx
|
21
|
+
* <SkipButton direction="forward" onClick={onNextChapter} />
|
22
|
+
* ```
|
23
|
+
*/
|
24
|
+
export const SkipButton = ({
|
25
|
+
direction,
|
26
|
+
isDisabled,
|
27
|
+
size = "sm",
|
28
|
+
...props
|
29
|
+
}: SkipButtonProps) => {
|
30
|
+
const { t } = useTranslation();
|
31
|
+
const styles = useMultiStyleConfig("MediaControllerButton", {
|
32
|
+
variant: "jumpSkip",
|
33
|
+
size,
|
34
|
+
});
|
35
|
+
|
36
|
+
return (
|
37
|
+
<Center
|
38
|
+
as="button"
|
39
|
+
sx={styles.container}
|
40
|
+
aria-label={direction === "forward" ? t(texts.next) : t(texts.previous)}
|
41
|
+
disabled={isDisabled}
|
42
|
+
{...props}
|
43
|
+
>
|
44
|
+
{direction === "forward" ? (
|
45
|
+
<SkipNextIcon sx={styles.icon} />
|
46
|
+
) : (
|
47
|
+
<SkipPreviousIcon sx={styles.icon} />
|
48
|
+
)}
|
49
|
+
</Center>
|
50
|
+
);
|
51
|
+
};
|
52
|
+
|
53
|
+
const texts = createTexts({
|
54
|
+
next: {
|
55
|
+
nb: "Neste",
|
56
|
+
nn: "Neste",
|
57
|
+
sv: "Nästa",
|
58
|
+
en: "Next",
|
59
|
+
},
|
60
|
+
previous: {
|
61
|
+
nb: "Forrige",
|
62
|
+
nn: "Forrige",
|
63
|
+
sv: "Föregående",
|
64
|
+
en: "Previous",
|
65
|
+
},
|
66
|
+
});
|
@@ -0,0 +1,80 @@
|
|
1
|
+
import { Box, BoxProps } from "@chakra-ui/react";
|
2
|
+
import * as React from "react";
|
3
|
+
|
4
|
+
export const JumpForwardIcon = (props: BoxProps) => (
|
5
|
+
<Box as="svg" {...props} viewBox="0 0 32 30" fill="none">
|
6
|
+
<path
|
7
|
+
fillRule="evenodd"
|
8
|
+
clipRule="evenodd"
|
9
|
+
d="M22.388 7.5C20.567 5.967 18.251 5 15.75 5 9.951 5 5.25 9.701 5.25 15.5S9.951 26 15.75 26s10.5-4.701 10.5-10.5a1 1 0 1 1 2 0c0 6.904-5.596 12.5-12.5 12.5s-12.5-5.596-12.5-12.5S8.846 3 15.75 3c3.206 0 6.11 1.31 8.304 3.3l.206-1.441a1 1 0 0 1 1.98.282L25.617 9.5H21.25a1 1 0 1 1 0-2h1.138Z"
|
10
|
+
fill="currentColor"
|
11
|
+
/>
|
12
|
+
<path
|
13
|
+
fillRule="evenodd"
|
14
|
+
clipRule="evenodd"
|
15
|
+
d="M19.465 14.568c-.4-.232-.863-.348-1.392-.348-.655 0-1.195.172-1.62.516l.18-2.172h2.989c.256 0 .436-.016.54-.048.111-.032.168-.112.168-.24v-1.02h-.012c-.04.04-.117.064-.229.072a7.65 7.65 0 0 1-.515.012H15.42l-.36 4.464 1.273.12c.175-.16.384-.284.623-.372a2.11 2.11 0 0 1 .768-.144c.48 0 .856.136 1.128.408.28.264.42.624.42 1.08 0 .456-.155.832-.468 1.128-.311.296-.703.444-1.175.444a3.04 3.04 0 0 1-.936-.132 3.802 3.802 0 0 1-.756-.348c-.289-.176-.48-.34-.577-.492l-.636.888a.233.233 0 0 0-.047.12c0 .08.043.16.131.24.089.072.225.168.409.288.712.448 1.547.672 2.508.672.576 0 1.091-.124 1.547-.372a2.743 2.743 0 0 0 1.08-1.056 2.97 2.97 0 0 0 .384-1.5c0-.472-.111-.9-.335-1.284a2.314 2.314 0 0 0-.937-.924ZM13.338 19.224a2.954 2.954 0 0 1-.036-.552V11.34h-1.116a2.07 2.07 0 0 1-.576.768c-.248.208-.576.312-.984.312h-.144c-.136 0-.224-.016-.264-.048v.792c0 .128.052.208.156.24.112.032.296.048.552.048h.912v5.364c0 .248.028.424.084.528.056.104.172.156.348.156h1.248v-.012a.478.478 0 0 1-.18-.264Z"
|
16
|
+
fill="currentColor"
|
17
|
+
/>
|
18
|
+
</Box>
|
19
|
+
);
|
20
|
+
|
21
|
+
export const JumpBackwardIcon = (props: BoxProps) => (
|
22
|
+
<Box as="svg" {...props} viewBox="0 0 32 30" fill="none">
|
23
|
+
<path
|
24
|
+
fillRule="evenodd"
|
25
|
+
clipRule="evenodd"
|
26
|
+
d="M9.612 7.5C11.433 5.967 13.749 5 16.25 5c5.799 0 10.5 4.701 10.5 10.5S22.049 26 16.25 26s-10.5-4.701-10.5-10.5a1 1 0 1 0-2 0c0 6.904 5.596 12.5 12.5 12.5s12.5-5.596 12.5-12.5S23.154 3 16.25 3c-3.206 0-6.11 1.31-8.304 3.3L7.74 4.86a1 1 0 0 0-1.98.282L6.383 9.5h4.367a1 1 0 1 0 0-2H9.612Z"
|
27
|
+
fill="currentColor"
|
28
|
+
/>
|
29
|
+
<path
|
30
|
+
fillRule="evenodd"
|
31
|
+
clipRule="evenodd"
|
32
|
+
d="M19.965 14.568c-.4-.232-.863-.348-1.392-.348-.655 0-1.195.172-1.62.516l.18-2.172h2.989c.256 0 .436-.016.54-.048.111-.032.168-.112.168-.24v-1.02h-.012c-.04.04-.117.064-.229.072a7.65 7.65 0 0 1-.515.012H15.92l-.36 4.464 1.273.12c.175-.16.384-.284.623-.372a2.11 2.11 0 0 1 .768-.144c.48 0 .856.136 1.128.408.28.264.42.624.42 1.08 0 .456-.155.832-.468 1.128-.311.296-.703.444-1.175.444a3.04 3.04 0 0 1-.936-.132 3.802 3.802 0 0 1-.756-.348c-.288-.176-.48-.34-.576-.492l-.636.888a.233.233 0 0 0-.049.12c0 .08.045.16.133.24.088.072.223.168.407.288.713.448 1.548.672 2.508.672.576 0 1.092-.124 1.548-.372a2.743 2.743 0 0 0 1.08-1.056 2.97 2.97 0 0 0 .384-1.5c0-.472-.111-.9-.335-1.284a2.314 2.314 0 0 0-.937-.924ZM13.838 19.224a2.954 2.954 0 0 1-.036-.552V11.34h-1.116a2.07 2.07 0 0 1-.576.768c-.248.208-.576.312-.984.312h-.144c-.136 0-.224-.016-.264-.048v.792c0 .128.052.208.156.24.112.032.296.048.552.048h.912v5.364c0 .248.028.424.084.528.056.104.172.156.348.156h1.248v-.012a.478.478 0 0 1-.18-.264Z"
|
33
|
+
fill="currentColor"
|
34
|
+
/>
|
35
|
+
</Box>
|
36
|
+
);
|
37
|
+
|
38
|
+
export const PlayIcon = (props: BoxProps) => (
|
39
|
+
<Box as="svg" {...props} fill="none" viewBox="0 0 60 60">
|
40
|
+
<path
|
41
|
+
fillRule="evenodd"
|
42
|
+
clipRule="evenodd"
|
43
|
+
d="M30 60c16.569 0 30-13.431 30-30C60 13.431 46.569 0 30 0 13.431 0 0 13.431 0 30c0 16.569 13.431 30 30 30Zm-4.25-45.325c-1.97-1.533-4.84-.128-4.84 2.368v25.914c0 2.496 2.87 3.9 4.84 2.368l16.66-12.957a3 3 0 0 0 0-4.736L25.75 14.675Z"
|
44
|
+
fill="currentColor"
|
45
|
+
/>
|
46
|
+
</Box>
|
47
|
+
);
|
48
|
+
|
49
|
+
export const PauseIcon = (props: BoxProps) => (
|
50
|
+
<Box as="svg" {...props} viewBox="0 0 60 60" fill="none">
|
51
|
+
<path
|
52
|
+
fillRule="evenodd"
|
53
|
+
clipRule="evenodd"
|
54
|
+
d="M60 30c0 16.569-13.431 30-30 30C13.431 60 0 46.569 0 30 0 13.431 13.431 0 30 0c16.569 0 30 13.431 30 30Zm-25.5-9.75a2.25 2.25 0 0 1 4.5 0v19.5a2.25 2.25 0 0 1-4.5 0v-19.5ZM23.25 18A2.25 2.25 0 0 0 21 20.25v19.5a2.25 2.25 0 0 0 4.5 0v-19.5A2.25 2.25 0 0 0 23.25 18Z"
|
55
|
+
fill="currentColor"
|
56
|
+
/>
|
57
|
+
</Box>
|
58
|
+
);
|
59
|
+
|
60
|
+
export const SkipNextIcon = (props: BoxProps) => (
|
61
|
+
<Box as="svg" {...props} viewBox="0 0 30 30" fill="none">
|
62
|
+
<path
|
63
|
+
fillRule="evenodd"
|
64
|
+
clipRule="evenodd"
|
65
|
+
d="M6.453 4.18A1.695 1.695 0 0 0 4 5.696v18.608c0 1.26 1.326 2.08 2.453 1.516L24 17.047V25a1 1 0 1 0 2 0V5a1 1 0 1 0-2 0v7.952L6.453 4.18ZM23.623 15 6 23.81V6.19l17.623 8.81Z"
|
66
|
+
fill="currentColor"
|
67
|
+
/>
|
68
|
+
</Box>
|
69
|
+
);
|
70
|
+
|
71
|
+
export const SkipPreviousIcon = (props: BoxProps) => (
|
72
|
+
<Box as="svg" {...props} viewBox="0 0 30 30" fill="none">
|
73
|
+
<path
|
74
|
+
fillRule="evenodd"
|
75
|
+
clipRule="evenodd"
|
76
|
+
d="M23.547 4.18A1.695 1.695 0 0 1 26 5.696v18.608c0 1.26-1.326 2.08-2.453 1.516L6 17.047V25a1 1 0 1 1-2 0V5a1 1 0 1 1 2 0v7.952L23.547 4.18ZM6.377 15 24 23.81V6.19l-17.623 8.81Z"
|
77
|
+
fill="currentColor"
|
78
|
+
/>
|
79
|
+
</Box>
|
80
|
+
);
|
@@ -0,0 +1,59 @@
|
|
1
|
+
import { render } from "@testing-library/react";
|
2
|
+
import React from "react";
|
3
|
+
import { vi } from "vitest";
|
4
|
+
import { axe } from "vitest-axe";
|
5
|
+
import { JumpButton, PlayPauseButton, SkipButton } from ".";
|
6
|
+
|
7
|
+
describe("<PlayPauseButton />", () => {
|
8
|
+
it("works like a button", async () => {
|
9
|
+
const handleClick = vi.fn();
|
10
|
+
const { getByRole } = render(
|
11
|
+
<PlayPauseButton size="sm" isPlaying={true} onClick={handleClick} />
|
12
|
+
);
|
13
|
+
getByRole("button").click();
|
14
|
+
expect(handleClick).toHaveBeenCalled();
|
15
|
+
});
|
16
|
+
|
17
|
+
it("is accessible", async () => {
|
18
|
+
const { container } = render(
|
19
|
+
<PlayPauseButton size="sm" isPlaying={true} onClick={() => {}} />
|
20
|
+
);
|
21
|
+
expect(await axe(container)).toHaveNoViolations();
|
22
|
+
});
|
23
|
+
});
|
24
|
+
|
25
|
+
describe("<SkipButtonButton />", () => {
|
26
|
+
it("works like a button", async () => {
|
27
|
+
const handleClick = vi.fn();
|
28
|
+
const { getByRole } = render(
|
29
|
+
<SkipButton size="sm" direction="forward" onClick={handleClick} />
|
30
|
+
);
|
31
|
+
getByRole("button").click();
|
32
|
+
expect(handleClick).toHaveBeenCalled();
|
33
|
+
});
|
34
|
+
|
35
|
+
it("is accessible", async () => {
|
36
|
+
const { container } = render(
|
37
|
+
<SkipButton size="sm" direction="forward" onClick={() => {}} />
|
38
|
+
);
|
39
|
+
expect(await axe(container)).toHaveNoViolations();
|
40
|
+
});
|
41
|
+
});
|
42
|
+
|
43
|
+
describe("<JumpButtonButton />", () => {
|
44
|
+
it("works like a button", async () => {
|
45
|
+
const handleClick = vi.fn();
|
46
|
+
const { getByRole } = render(
|
47
|
+
<JumpButton size="sm" direction="forward" onClick={handleClick} />
|
48
|
+
);
|
49
|
+
getByRole("button").click();
|
50
|
+
expect(handleClick).toHaveBeenCalled();
|
51
|
+
});
|
52
|
+
|
53
|
+
it("is accessible", async () => {
|
54
|
+
const { container } = render(
|
55
|
+
<JumpButton size="sm" direction="forward" onClick={() => {}} />
|
56
|
+
);
|
57
|
+
expect(await axe(container)).toHaveNoViolations();
|
58
|
+
});
|
59
|
+
});
|
@@ -0,0 +1,122 @@
|
|
1
|
+
import {
|
2
|
+
Box,
|
3
|
+
BoxProps,
|
4
|
+
Center,
|
5
|
+
Drawer as ChakraDrawer,
|
6
|
+
DrawerContent as ChakraDrawerContent,
|
7
|
+
DrawerContentProps as ChakraDrawerContentProps,
|
8
|
+
DrawerProps as ChakraDrawerProps,
|
9
|
+
forwardRef,
|
10
|
+
useModalContext,
|
11
|
+
} from "@chakra-ui/react";
|
12
|
+
import React from "react";
|
13
|
+
import { useSwipeable } from "react-swipeable";
|
14
|
+
export {
|
15
|
+
DrawerBody,
|
16
|
+
DrawerCloseButton,
|
17
|
+
DrawerFooter,
|
18
|
+
DrawerOverlay,
|
19
|
+
} from "@chakra-ui/react";
|
20
|
+
export type { DrawerProps } from "@chakra-ui/react";
|
21
|
+
export { ModalHeader as DrawerHeader } from "./ModalHeader";
|
22
|
+
|
23
|
+
type DrawerProps = ChakraDrawerProps;
|
24
|
+
export const Drawer = (props: DrawerProps) => {
|
25
|
+
return (
|
26
|
+
<DrawerProvider placement={props.placement}>
|
27
|
+
<ChakraDrawer {...props} />
|
28
|
+
</DrawerProvider>
|
29
|
+
);
|
30
|
+
};
|
31
|
+
|
32
|
+
type DrawerContentProps = ChakraDrawerContentProps;
|
33
|
+
export const DrawerContent = forwardRef<DrawerContentProps, any>(
|
34
|
+
({ children, ...props }, ref) => {
|
35
|
+
const placement = useDrawerContext();
|
36
|
+
const { onClose } = useModalContext();
|
37
|
+
const handlers = useSwipeable({
|
38
|
+
onSwiped: (e) => {
|
39
|
+
const shouldClose =
|
40
|
+
(placement === "bottom" && e.dir === "Down") ||
|
41
|
+
(placement === "right" && e.dir === "Right") ||
|
42
|
+
(placement === "left" && e.dir === "Left") ||
|
43
|
+
(placement === "top" && e.dir === "Up") ||
|
44
|
+
(placement === "end" && e.dir === "Right") ||
|
45
|
+
(placement === "start" && e.dir === "Left");
|
46
|
+
if (shouldClose) {
|
47
|
+
onClose();
|
48
|
+
}
|
49
|
+
},
|
50
|
+
swipeDuration: 500,
|
51
|
+
});
|
52
|
+
|
53
|
+
const isTopOrBottom = placement === "top" || placement === "bottom";
|
54
|
+
const widthConstraits = isTopOrBottom
|
55
|
+
? { width: ["100%", "37.5rem"], mx: "auto" }
|
56
|
+
: {};
|
57
|
+
return (
|
58
|
+
<Box {...handlers}>
|
59
|
+
<ChakraDrawerContent
|
60
|
+
{...widthConstraits}
|
61
|
+
borderTopRadius={placement === "bottom" ? "md" : "none"}
|
62
|
+
borderBottomRadius={placement === "top" ? "md" : "none"}
|
63
|
+
{...props}
|
64
|
+
ref={ref}
|
65
|
+
>
|
66
|
+
<Box position="relative">
|
67
|
+
<Box maxHeight="100vh" maxWidth="100vw" overflow="auto">
|
68
|
+
{isTopOrBottom && <Notch />}
|
69
|
+
|
70
|
+
<Box>{children}</Box>
|
71
|
+
</Box>
|
72
|
+
</Box>
|
73
|
+
</ChakraDrawerContent>
|
74
|
+
</Box>
|
75
|
+
);
|
76
|
+
}
|
77
|
+
);
|
78
|
+
|
79
|
+
const Notch = forwardRef<BoxProps, any>((props, ref) => {
|
80
|
+
const placement = useDrawerContext();
|
81
|
+
return (
|
82
|
+
<Box
|
83
|
+
position="absolute"
|
84
|
+
left={0}
|
85
|
+
right={0}
|
86
|
+
top={placement === "bottom" ? 0 : undefined}
|
87
|
+
bottom={placement === "top" ? 0 : undefined}
|
88
|
+
zIndex="modal"
|
89
|
+
{...props}
|
90
|
+
ref={ref}
|
91
|
+
>
|
92
|
+
<Center
|
93
|
+
background={`linear-gradient(to ${
|
94
|
+
placement === "bottom" ? "bottom" : "top"
|
95
|
+
}, white 0%, white 60%, transparent)`}
|
96
|
+
padding={2}
|
97
|
+
borderRadius="md"
|
98
|
+
>
|
99
|
+
<Box
|
100
|
+
width="2.265rem"
|
101
|
+
height={1}
|
102
|
+
backgroundColor="steel"
|
103
|
+
borderRadius="xs"
|
104
|
+
/>
|
105
|
+
</Center>
|
106
|
+
</Box>
|
107
|
+
);
|
108
|
+
});
|
109
|
+
|
110
|
+
const DrawerContext = React.createContext<DrawerProps["placement"]>(undefined);
|
111
|
+
type DrawerProviderProps = {
|
112
|
+
children: React.ReactNode;
|
113
|
+
placement: DrawerProps["placement"];
|
114
|
+
};
|
115
|
+
const DrawerProvider = (props: DrawerProviderProps) => (
|
116
|
+
<DrawerContext.Provider value={props.placement}>
|
117
|
+
{props.children}
|
118
|
+
</DrawerContext.Provider>
|
119
|
+
);
|
120
|
+
const useDrawerContext = () => {
|
121
|
+
return React.useContext(DrawerContext);
|
122
|
+
};
|
@@ -0,0 +1,15 @@
|
|
1
|
+
export {
|
2
|
+
Modal,
|
3
|
+
ModalBody,
|
4
|
+
ModalCloseButton,
|
5
|
+
ModalContent,
|
6
|
+
ModalFooter,
|
7
|
+
ModalOverlay,
|
8
|
+
} from "@chakra-ui/react";
|
9
|
+
export type {
|
10
|
+
ModalBodyProps,
|
11
|
+
ModalContentProps,
|
12
|
+
ModalFooterProps,
|
13
|
+
ModalOverlayProps,
|
14
|
+
ModalProps,
|
15
|
+
} from "@chakra-ui/react";
|