@vygruppen/spor-react 12.14.1 → 12.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vygruppen/spor-react",
3
3
  "type": "module",
4
- "version": "12.14.1",
4
+ "version": "12.15.0",
5
5
  "exports": {
6
6
  ".": {
7
7
  "types": "./dist/index.d.ts",
@@ -47,8 +47,8 @@
47
47
  "react-swipeable": "^7.0.1",
48
48
  "usehooks-ts": "^3.1.0",
49
49
  "@vygruppen/spor-design-tokens": "4.2.0",
50
- "@vygruppen/spor-loader": "0.7.0",
51
- "@vygruppen/spor-icon-react": "4.2.1"
50
+ "@vygruppen/spor-icon-react": "4.2.1",
51
+ "@vygruppen/spor-loader": "0.7.0"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@react-types/datepicker": "^3.10.0",
@@ -26,49 +26,64 @@ type AlertIconProps = {
26
26
  * Internal component that shows the correct icon for the alert
27
27
  */
28
28
  export const AlertIcon = forwardRef<SVGSVGElement, AlertIconProps>(
29
- ({ variant, customIcon }, ref) => {
29
+ ({ variant, customIcon: CustomAlertIcon }, ref) => {
30
30
  const { t } = useTranslation();
31
31
 
32
- const Icon = customIcon ?? getIcon(variant);
33
-
34
32
  return (
35
33
  <Box
36
- as={Icon}
34
+ asChild
37
35
  ref={ref}
38
36
  aria-label={t(texts[variant as keyof typeof texts])}
39
- color={customIcon ? `alert.${variant}.icon` : undefined}
40
- />
37
+ >
38
+ {CustomAlertIcon ? (
39
+ <CustomAlertIcon color={`alert.${variant}.icon`} />
40
+ ) : (
41
+ <BaseAlertIcon variant={variant} />
42
+ )}
43
+ </Box>
41
44
  );
42
45
  },
43
46
  );
44
47
 
45
48
  AlertIcon.displayName = "AlertIcon";
46
49
 
47
- const getIcon = (variant: AlertProps["variant"]) => {
50
+ const BaseAlertIcon = ({ variant }: { variant: AlertProps["variant"] }) => {
51
+ const css = {
52
+ "& path:first-of-type": {
53
+ fill: `alert.${variant}.icon`,
54
+ },
55
+ "& path:not(:first-of-type)": {
56
+ fill: `alert.${variant}.surface`,
57
+ },
58
+ };
59
+
48
60
  switch (variant) {
49
61
  case "info": {
50
- return InformationFill24Icon;
62
+ return <InformationFill24Icon css={css} />;
51
63
  }
52
64
  case "success": {
53
- return SuccessFill24Icon;
65
+ return <SuccessFill24Icon css={css} />;
54
66
  }
55
67
  case "important": {
56
- return WarningFill24Icon;
68
+ return <WarningFill24Icon />;
57
69
  }
58
70
  case "alt": {
59
- return AltTransportFill24Icon;
71
+ return <AltTransportFill24Icon css={css} />;
60
72
  }
61
73
  case "error": {
62
- return ErrorFill24Icon;
74
+ return <ErrorFill24Icon css={css} />;
63
75
  }
64
76
  case "error-secondary": {
65
- return ErrorOutline24Icon;
77
+ return <ErrorOutline24Icon css={css} />;
66
78
  }
67
79
  case "neutral": {
68
- return QuestionFill24Icon;
80
+ return <QuestionFill24Icon css={css} />;
69
81
  }
70
82
  case "service": {
71
- return ServiceFill24Icon;
83
+ return <ServiceFill24Icon />;
84
+ }
85
+ default: {
86
+ return <InformationFill24Icon css={css} />;
72
87
  }
73
88
  }
74
89
  };
@@ -0,0 +1,27 @@
1
+ import { Button, ButtonProps } from "./Button";
2
+ import { IconButton, IconButtonProps } from "./IconButton";
3
+
4
+ /**
5
+ * For internal use
6
+ */
7
+
8
+ type Props = IconButtonProps &
9
+ Omit<ButtonProps, "leftIcon" | "rightIcon"> & {
10
+ label: string;
11
+ };
12
+
13
+ export const ResponsiveButton = ({ label, icon, ...props }: Props) => {
14
+ return (
15
+ <>
16
+ <Button display={["none", "flex"]} leftIcon={icon} {...props}>
17
+ {label}
18
+ </Button>
19
+ <IconButton
20
+ display={["flex", "none"]}
21
+ aria-label={label}
22
+ icon={icon}
23
+ {...props}
24
+ />
25
+ </>
26
+ );
27
+ };
@@ -11,6 +11,8 @@ import { PropsWithChildren, useEffect, useRef } from "react";
11
11
  import { useCalendarCell } from "react-aria";
12
12
  import { CalendarState, RangeCalendarState } from "react-stately";
13
13
 
14
+ import { spor } from "@/util";
15
+
14
16
  import { DatePickerVariantProps } from "./DatePicker";
15
17
  import { CalendarVariants } from "./types";
16
18
 
@@ -74,8 +76,8 @@ export function CalendarCell({
74
76
 
75
77
  return (
76
78
  <Box as="td" {...cellProps} textAlign="center" css={styles.cell}>
77
- <Box
78
- as="button"
79
+ <spor.button
80
+ type="button" // Prevents form submission
79
81
  {...buttonProps}
80
82
  {...stateProps}
81
83
  ref={ref}
@@ -83,7 +85,7 @@ export function CalendarCell({
83
85
  hidden={isOutsideVisibleRange}
84
86
  >
85
87
  {date.day}
86
- </Box>
88
+ </spor.button>
87
89
  </Box>
88
90
  );
89
91
  }
@@ -4,8 +4,6 @@ import {
4
4
  Box,
5
5
  createContext,
6
6
  Drawer as ChakraDrawer,
7
- Grid,
8
- GridItem,
9
7
  Portal,
10
8
  useDialogContext,
11
9
  } from "@chakra-ui/react";
@@ -16,9 +14,12 @@ import {
16
14
  import { forwardRef } from "react";
17
15
  import { useSwipeable } from "react-swipeable";
18
16
 
19
- import { Button, CloseButton } from "../button";
17
+ import { ResponsiveButton } from "@/button/ResponsiveButton";
18
+
19
+ import { CloseButton } from "../button";
20
20
  import { createTexts, useTranslation } from "../i18n";
21
21
  import {
22
+ DrawerCloseTriggerProps,
22
23
  DrawerContentProps,
23
24
  DrawerFullScreenHeaderProps,
24
25
  DrawerProps,
@@ -56,7 +57,13 @@ const [RootDrawerProvider, useRootDrawerProps] =
56
57
 
57
58
  export const DrawerContent = forwardRef<HTMLDivElement, DrawerContentProps>(
58
59
  (props, ref) => {
59
- const { children, portalled = true, portalRef, ...rest } = props;
60
+ const {
61
+ children,
62
+ portalled = true,
63
+ portalRef,
64
+ hideHandle = false,
65
+ ...rest
66
+ } = props;
60
67
  const { size, placement } = useRootDrawerProps();
61
68
  const { setOpen } = useDialogContext();
62
69
  const handlers = useSwipeable({
@@ -73,14 +80,20 @@ export const DrawerContent = forwardRef<HTMLDivElement, DrawerContentProps>(
73
80
  swipeDuration: 250,
74
81
  });
75
82
  const sizeNotFull = size !== "full";
83
+ const showHandle = !hideHandle;
84
+
76
85
  return (
77
86
  <Portal disabled={!portalled} container={portalRef}>
78
87
  <ChakraDrawer.Positioner asChild>
79
88
  <Box {...handlers} width="100%">
80
89
  <ChakraDrawer.Content ref={ref} {...rest}>
81
- {sizeNotFull && placement === "bottom" && <CloseDrawerLine />}
90
+ {showHandle && sizeNotFull && placement === "bottom" && (
91
+ <CloseDrawerLine />
92
+ )}
82
93
  {children}
83
- {sizeNotFull && placement === "top" && <CloseDrawerLine />}
94
+ {showHandle && sizeNotFull && placement === "top" && (
95
+ <CloseDrawerLine />
96
+ )}
84
97
  </ChakraDrawer.Content>
85
98
  </Box>
86
99
  </ChakraDrawer.Positioner>
@@ -109,16 +122,19 @@ CloseDrawerLine.displayName = "CloseDrawerLine";
109
122
 
110
123
  export const DrawerCloseTrigger = forwardRef<
111
124
  HTMLButtonElement,
112
- ChakraDrawer.CloseTriggerProps
125
+ DrawerCloseTriggerProps
113
126
  >(function DrawerCloseTrigger(props, ref) {
127
+ const { showText = false, ...rest } = props;
114
128
  const { size } = useRootDrawerProps();
115
129
  const { t } = useTranslation();
116
130
  return (
117
- <ChakraDrawer.CloseTrigger ref={ref} {...props} asChild>
118
- {size === "full" ? (
119
- <Button variant="ghost" leftIcon={<CloseFill24Icon />}>
120
- {t(texts.close)}
121
- </Button>
131
+ <ChakraDrawer.CloseTrigger ref={ref} {...rest} asChild>
132
+ {showText || size === "full" ? (
133
+ <ResponsiveButton
134
+ variant="ghost"
135
+ icon={<CloseFill24Icon />}
136
+ label={t(texts.close)}
137
+ />
122
138
  ) : (
123
139
  <CloseButton size="md" />
124
140
  )}
@@ -132,10 +148,12 @@ export const DrawerBackTrigger = forwardRef<
132
148
  >((props, ref) => {
133
149
  const { t } = useTranslation();
134
150
  return (
135
- <ChakraDrawer.CloseTrigger asChild {...props} ref={ref} top="0">
136
- <Button variant="ghost" leftIcon={<ArrowLeftFill24Icon />}>
137
- {t(texts.back)}
138
- </Button>
151
+ <ChakraDrawer.CloseTrigger asChild {...props} ref={ref}>
152
+ <ResponsiveButton
153
+ variant="ghost"
154
+ icon={<ArrowLeftFill24Icon />}
155
+ label={t(texts.back)}
156
+ />
139
157
  </ChakraDrawer.CloseTrigger>
140
158
  );
141
159
  });
@@ -147,20 +165,10 @@ export const DrawerFullScreenHeader = forwardRef<
147
165
  >((props, ref) => {
148
166
  const { backTrigger = true, closeTrigger = true, children } = props;
149
167
  return (
150
- <ChakraDrawer.Header {...props} ref={ref} asChild>
151
- <Grid templateColumns="1fr auto 1fr" height="auto" paddingX="8">
152
- <GridItem width="full" alignSelf="center">
153
- {backTrigger && <DrawerBackTrigger />}
154
- </GridItem>
155
- <GridItem width="full" alignSelf="end" asChild>
156
- {children && <DrawerTitle>{children}</DrawerTitle>}
157
- </GridItem>
158
- {closeTrigger && (
159
- <GridItem width="full" alignSelf="end">
160
- <DrawerCloseTrigger justifySelf="end" top="0" />
161
- </GridItem>
162
- )}
163
- </Grid>
168
+ <ChakraDrawer.Header {...props} ref={ref}>
169
+ <Box>{backTrigger && <DrawerBackTrigger />}</Box>
170
+ {<DrawerTitle>{children}</DrawerTitle>}
171
+ <Box> {closeTrigger && <DrawerCloseTrigger />}</Box>
164
172
  </ChakraDrawer.Header>
165
173
  );
166
174
  });
@@ -10,6 +10,7 @@ export type DrawerContentProps = ChakraDrawer.ContentProps &
10
10
  children: React.ReactNode;
11
11
  portalled?: boolean;
12
12
  portalRef?: React.RefObject<HTMLElement>;
13
+ hideHandle?: boolean;
13
14
  };
14
15
 
15
16
  export type DrawerProps = Omit<
@@ -28,3 +29,7 @@ export type DrawerFullScreenHeaderProps = Omit<
28
29
  backTrigger?: boolean;
29
30
  closeTrigger?: boolean;
30
31
  };
32
+
33
+ export type DrawerCloseTriggerProps = ChakraDrawer.CloseTriggerProps & {
34
+ showText?: boolean;
35
+ };
@@ -78,7 +78,7 @@ export const Switch = forwardRef<HTMLInputElement, SwitchProps>(
78
78
  <ChakraSwitch.Control css={styles.control}>
79
79
  <ChakraSwitch.Thumb />
80
80
  </ChakraSwitch.Control>
81
- <ChakraSwitch.Label>{label}</ChakraSwitch.Label>
81
+ {label && <ChakraSwitch.Label>{label}</ChakraSwitch.Label>}
82
82
  </ChakraSwitch.Root>
83
83
  </Field>
84
84
  );
@@ -59,7 +59,8 @@ export const drawerSlotRecipe = defineSlotRecipe({
59
59
  display: "flex",
60
60
  alignItems: "center",
61
61
  justifyContent: "space-between",
62
- paddingX: ["3", null, null, "5"],
62
+ paddingX: ["2", null, null, "5"],
63
+ gap: "1",
63
64
  paddingBottom: "1",
64
65
  },
65
66
  body: {