@vygruppen/spor-react 9.3.0 → 9.4.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/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- export { Accordion, AccordionButton, AccordionIcon, AccordionItem, AccordionPanel, AttachedInputs, Badge, Box, Brand, Breadcrumb, BreadcrumbItem, BreadcrumbLink, Button, ButtonGroup, Card, CardSelect, Center, Checkbox, CheckboxGroup, ChoiceChip, ClosableAlert, CloseButton, Code, Collapse, ColorInlineLoader, ColorSpinner, Combobox, Container, ContentLoader, DarkFullScreenLoader, DarkInlineLoader, DarkMode, DarkSpinner, DatePicker, DateRangePicker, Divider, Drawer, DrawerBody, DrawerCloseButton, DrawerContent, DrawerFooter, ModalHeader as DrawerHeader, DrawerOverlay, Expandable, ExpandableAlert, ExpandableItem, Fade, Flex, FloatingActionButton, FormControl, FormErrorMessage, FormHelperText, FormLabel, Grid, GridItem, HStack, Heading, IconButton, Image, Img, InfoSelect, InfoTag, Input, InputGroup, InputLeftElement, InputRightElement, Item, ItemDescription, ItemLabel, JumpButton, Language, LanguageProvider, LightFullScreenLoader, LightInlineLoader, LightMode, LightSpinner, LineIcon, ListBox, ListItem, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay, NativeSelect, Nudge, NumericStepper, OrderedList, PasswordInput, PhoneNumberInput, PlayPauseButton, Portal, ProgressBar, ProgressIndicator, ProgressLoader, Radio, RadioGroup, ScaleFade, SearchInput, Section, SimpleDrawer, SimpleGrid, Skeleton, SkeletonCircle, SkeletonText, SkipButton, Slide, SlideFade, Spacer, SporProvider, Stack, StaticAlert, Stepper, StepperStep, Switch, Tab, TabList, TabPanel, TabPanels, Table, TableCaption, Tabs, Tbody, Td, Text, TextLink, Textarea, Tfoot, Th, Thead, Time, TimePicker, Tooltip, Tr, TravelTag, UnorderedList, VStack, VyLogo, WizardNudge, Wrap, WrapItem, brandTheme, createTexts, defineStyleConfig, extendTheme, fontFaces, slugify, theme, tokens, useBreakpointValue, useClipboard, useColorMode, useColorModePreference, useColorModeValue, useControllableProp, useDisclosure, useMediaQuery, useMergeRefs, useOutsideClick, usePrefersReducedMotion, useSize, useTheme, useToast, useToken, useTranslation } from './chunk-U3P2P6PX.mjs';
1
+ export { Accordion, AccordionButton, AccordionIcon, AccordionItem, AccordionPanel, AttachedInputs, Badge, Box, Brand, Breadcrumb, BreadcrumbItem, BreadcrumbLink, Button, ButtonGroup, Card, CardSelect, Center, Checkbox, CheckboxGroup, ChoiceChip, ClosableAlert, CloseButton, Code, Collapse, ColorInlineLoader, ColorSpinner, Combobox, Container, ContentLoader, DarkFullScreenLoader, DarkInlineLoader, DarkMode, DarkSpinner, DatePicker, DateRangePicker, Divider, Drawer, DrawerBody, DrawerCloseButton, DrawerContent, DrawerFooter, ModalHeader as DrawerHeader, DrawerOverlay, Expandable, ExpandableAlert, ExpandableItem, Fade, Flex, FloatingActionButton, FormControl, FormErrorMessage, FormHelperText, FormLabel, FullScreenDrawer, Grid, GridItem, HStack, Heading, IconButton, Image, Img, InfoSelect, InfoTag, Input, InputGroup, InputLeftElement, InputRightElement, Item, ItemDescription, ItemLabel, JumpButton, Language, LanguageProvider, LightFullScreenLoader, LightInlineLoader, LightMode, LightSpinner, LineIcon, ListBox, ListItem, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay, NativeSelect, Nudge, NumericStepper, OrderedList, PasswordInput, PhoneNumberInput, PlayPauseButton, Portal, ProgressBar, ProgressIndicator, ProgressLoader, Radio, RadioGroup, ScaleFade, SearchInput, Section, SimpleDrawer, SimpleGrid, Skeleton, SkeletonCircle, SkeletonText, SkipButton, Slide, SlideFade, Spacer, SporProvider, Stack, StaticAlert, StaticCard, Stepper, StepperStep, Switch, Tab, TabList, TabPanel, TabPanels, Table, TableCaption, Tabs, Tbody, Td, Text, TextLink, Textarea, Tfoot, Th, Thead, Time, TimePicker, Tooltip, Tr, TravelTag, UnorderedList, VStack, VyLogo, WizardNudge, Wrap, WrapItem, brandTheme, createTexts, defineStyleConfig, extendTheme, fontFaces, slugify, theme, tokens, useBreakpointValue, useClipboard, useColorMode, useColorModePreference, useColorModeValue, useControllableProp, useDisclosure, useMediaQuery, useMergeRefs, useOutsideClick, usePrefersReducedMotion, useSize, useTheme, useToast, useToken, useTranslation } from './chunk-JRXSGTL2.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vygruppen/spor-react",
3
- "version": "9.3.0",
3
+ "version": "9.4.1",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
@@ -11,7 +11,7 @@ import { BaseAlertProps } from "./BaseAlert";
11
11
 
12
12
  type AlertIconProps = { variant: BaseAlertProps["variant"] };
13
13
  /**
14
- * Internal component that shows the correct icon for the alert.
14
+ * Internal component that shows the correct icon for the alert
15
15
  */
16
16
  export const AlertIcon = ({ variant }: AlertIconProps) => {
17
17
  const Icon = getIcon(variant);
@@ -0,0 +1,25 @@
1
+ import React from "react";
2
+ import { Box, useStyleConfig } from "@chakra-ui/react";
3
+ /**
4
+ * Renders a static card.
5
+ *
6
+ * The most basic version looks like this:
7
+ *
8
+ * ```tsx
9
+ * <StaticCard colorScheme="white">
10
+ * Content
11
+ * </StaticCard>
12
+ * ```
13
+ *
14
+ * Static cards can also be rendered as whatever DOM element you want – like a li (list item) or an article. You do this by specifying the `as` prop:
15
+ *
16
+ * ```tsx
17
+ * <StaticCard colorScheme="green" as="section">
18
+ * This is now a <section /> element
19
+ * </StaticCard>
20
+ * ```
21
+ */
22
+ export const StaticCard = ({ colorScheme, ...props }: any) => {
23
+ const styles = useStyleConfig("StaticCard", { colorScheme });
24
+ return <Box __css={styles} {...props} />;
25
+ };
@@ -1 +1,2 @@
1
1
  export * from "./Card";
2
+ export * from "./StaticCard";
@@ -4,6 +4,29 @@ import { useComboBoxState } from "react-stately";
4
4
  import { ColorSpinner, Input, InputProps, ListBox } from "..";
5
5
  import { Popover } from "./Popover";
6
6
 
7
+ type OverridableInputProps = Pick<
8
+ InputProps,
9
+ | "marginTop"
10
+ | "marginBottom"
11
+ | "marginRight"
12
+ | "marginLeft"
13
+ | "marginY"
14
+ | "marginX"
15
+ | "paddingTop"
16
+ | "paddingBottom"
17
+ | "paddingLeft"
18
+ | "paddingRight"
19
+ | "paddingY"
20
+ | "paddingX"
21
+ | "leftIcon"
22
+ | "rightIcon"
23
+ | "borderTopRightRadius"
24
+ | "borderTopLeftRadius"
25
+ | "borderBottomRightRadius"
26
+ | "borderBottomLeftRadius"
27
+ | "onFocus"
28
+ >;
29
+
7
30
  export type ComboboxProps<T> = AriaComboBoxProps<T> & {
8
31
  /** The label of the combobox */
9
32
  label: string;
@@ -15,28 +38,7 @@ export type ComboboxProps<T> = AriaComboBoxProps<T> & {
15
38
  inputRef?: React.RefObject<HTMLInputElement>;
16
39
  /** If you want to allow an empty collection */
17
40
  allowsEmptyCollection?: boolean;
18
- } & Pick<
19
- InputProps,
20
- | "marginTop"
21
- | "marginBottom"
22
- | "marginRight"
23
- | "marginLeft"
24
- | "marginY"
25
- | "marginX"
26
- | "paddingTop"
27
- | "paddingBottom"
28
- | "paddingLeft"
29
- | "paddingRight"
30
- | "paddingY"
31
- | "paddingX"
32
- | "leftIcon"
33
- | "rightIcon"
34
- | "borderTopRightRadius"
35
- | "borderTopLeftRadius"
36
- | "borderBottomRightRadius"
37
- | "borderBottomLeftRadius"
38
- | "onFocus"
39
- >;
41
+ } & OverridableInputProps;
40
42
  /**
41
43
  * A combobox is a combination of an input and a list of suggestions.
42
44
  *
@@ -60,6 +62,7 @@ export type ComboboxProps<T> = AriaComboBoxProps<T> & {
60
62
  * </Combobox>
61
63
  * ```
62
64
  */
65
+
63
66
  export function Combobox<T extends object>({
64
67
  label,
65
68
  isLoading,
@@ -103,6 +106,24 @@ export function Combobox<T extends object>({
103
106
  ...rest,
104
107
  });
105
108
 
109
+ const comboBoxProps: OverridableInputProps = {
110
+ borderTopLeftRadius,
111
+ borderTopRightRadius,
112
+ marginBottom,
113
+ marginTop,
114
+ marginRight,
115
+ marginLeft,
116
+ marginX,
117
+ marginY,
118
+ paddingBottom,
119
+ paddingRight,
120
+ paddingTop,
121
+ paddingLeft,
122
+ paddingX,
123
+ paddingY,
124
+ leftIcon,
125
+ };
126
+
106
127
  const {
107
128
  inputProps: { size, ...inputProps },
108
129
  listBoxProps,
@@ -119,7 +140,7 @@ export function Combobox<T extends object>({
119
140
  return (
120
141
  <>
121
142
  <Input
122
- {...inputProps}
143
+ {...styleProps(comboBoxProps)}
123
144
  aria-haspopup="listbox"
124
145
  ref={inputRef}
125
146
  label={label}
@@ -129,21 +150,7 @@ export function Combobox<T extends object>({
129
150
  borderBottomRightRadius={
130
151
  state.isOpen && !isLoading ? 0 : borderBottomRightRadius
131
152
  }
132
- borderTopLeftRadius={borderTopLeftRadius}
133
- borderTopRightRadius={borderTopRightRadius}
134
- marginBottom={marginBottom}
135
- marginTop={marginTop}
136
- marginRight={marginRight}
137
- marginLeft={marginLeft}
138
- marginX={marginX}
139
- marginY={marginY}
140
- paddingBottom={paddingBottom}
141
- paddingRight={paddingRight}
142
- paddingTop={paddingTop}
143
- paddingLeft={paddingLeft}
144
- paddingX={paddingX}
145
- paddingY={paddingY}
146
- leftIcon={leftIcon}
153
+ {...inputProps}
147
154
  rightIcon={
148
155
  isLoading ? (
149
156
  <ColorSpinner
@@ -162,6 +169,7 @@ export function Combobox<T extends object>({
162
169
  )
163
170
  }
164
171
  />
172
+
165
173
  {state.isOpen && !isLoading && (
166
174
  <Popover
167
175
  state={state}
@@ -204,6 +212,12 @@ const useInputWidth = (inputRef: React.RefObject<HTMLInputElement>) => {
204
212
  return inputWidth;
205
213
  };
206
214
 
215
+ function styleProps(obj: Record<string, unknown>): Record<string, unknown> {
216
+ return Object.fromEntries(
217
+ Object.entries(obj).filter(([, value]) => value !== undefined),
218
+ );
219
+ }
220
+
207
221
  const debounce = (fn: () => void, ms = 100) => {
208
222
  let timer: any;
209
223
  return () => {
@@ -0,0 +1,179 @@
1
+ import {
2
+ Box,
3
+ DrawerBody,
4
+ DrawerContent,
5
+ DrawerHeader,
6
+ DrawerOverlay,
7
+ Flex,
8
+ useColorModeValue,
9
+ useMediaQuery,
10
+ useModalContext,
11
+ } from "@chakra-ui/react";
12
+ import tokens from "@vygruppen/spor-design-tokens";
13
+ import { CloseFill24Icon, CloseFill30Icon } from "@vygruppen/spor-icon-react";
14
+ import React, { useEffect, useState } from "react";
15
+ import { Button, IconButton } from "../button";
16
+ import { createTexts, useTranslation } from "../i18n";
17
+ import { Drawer } from "./Drawer";
18
+
19
+ type DrawerPlacement = "top" | "right" | "bottom" | "left";
20
+
21
+ type FullScreenDrawerProps = {
22
+ /** The content inside the drawer */
23
+ children: React.ReactNode;
24
+ /** The title in the middle of the top menu */
25
+ title?: String;
26
+ /** Determines which side the drawer slides from */
27
+ placement?: DrawerPlacement;
28
+ /** A React component that will be placed to the left in the modal header */
29
+ leftButton?: React.ReactNode;
30
+ /** A React component that will be placed to the right in the modal header */
31
+ rightButton?: React.ReactNode;
32
+ /** Determines if the drawer is open or closed */
33
+ isOpen: boolean;
34
+ /** Function that will be called when the drawer closes */
35
+ onClose: () => void;
36
+ };
37
+
38
+ export const FullScreenDrawer = ({
39
+ children,
40
+ title,
41
+ placement = "bottom",
42
+ leftButton = null,
43
+ rightButton = <DrawerCloseButton />,
44
+ isOpen,
45
+ onClose,
46
+ }: FullScreenDrawerProps) => {
47
+ const [isContentBoxScrolled, setContentBoxScrolled] = useState(false);
48
+
49
+ const onContentScroll = (e: React.UIEvent<HTMLDivElement, UIEvent>) => {
50
+ const target = e.target as HTMLDivElement;
51
+
52
+ if (target.scrollTop <= 0) {
53
+ setContentBoxScrolled(false);
54
+ return;
55
+ }
56
+ setContentBoxScrolled(true);
57
+ };
58
+
59
+ useEffect(() => {
60
+ setContentBoxScrolled(false);
61
+ }, [isOpen]);
62
+
63
+ return (
64
+ <Drawer isOpen={isOpen} onClose={onClose} placement={placement} size="full">
65
+ <DrawerOverlay />
66
+ <DrawerContent
67
+ height="100vh"
68
+ backgroundSize="100% 285px, 100%"
69
+ backgroundPosition="top"
70
+ backgroundRepeat="no-repeat"
71
+ >
72
+ <DrawerTopMenu
73
+ isScrolled={isContentBoxScrolled}
74
+ title={title}
75
+ leftButton={leftButton}
76
+ rightButton={rightButton}
77
+ />
78
+ <DrawerBody overflow="auto" onScroll={onContentScroll}>
79
+ {children}
80
+ </DrawerBody>
81
+ </DrawerContent>
82
+ </Drawer>
83
+ );
84
+ };
85
+
86
+ type DrawerTopMenuProps = {
87
+ /** Optional title */
88
+ title?: String;
89
+ leftButton?: React.ReactNode;
90
+ rightButton?: React.ReactNode;
91
+ /** Whether or not the context this menu is placed in is scrolled */
92
+ isScrolled: boolean;
93
+ };
94
+
95
+ const DrawerTopMenu = ({
96
+ title,
97
+ leftButton,
98
+ rightButton,
99
+ isScrolled,
100
+ }: DrawerTopMenuProps) => {
101
+ const backgroundColor = useColorModeValue(
102
+ "bg.default.light",
103
+ "bg.default.dark",
104
+ );
105
+
106
+ return (
107
+ <Flex
108
+ width="100%"
109
+ backgroundColor={backgroundColor}
110
+ position="static"
111
+ paddingTop={[1.5, 2.5, 3, 3]}
112
+ paddingBottom={[1.5, 2.5, 3, 3]}
113
+ paddingLeft={[2, 3, 6, 9]}
114
+ paddingRight={[2, 3, 6, 9]}
115
+ transition="box-shadow 0.2s"
116
+ boxShadow={isScrolled ? "md" : undefined}
117
+ >
118
+ <Box flex="1">{leftButton}</Box>
119
+ <DrawerHeader
120
+ as="h2"
121
+ fontSize="md"
122
+ fontWeight="bold"
123
+ textAlign="center"
124
+ flex="1"
125
+ margin={0}
126
+ padding={0}
127
+ >
128
+ {title}
129
+ </DrawerHeader>
130
+ <Box flex="1">
131
+ <Box width="fit-content" marginLeft="auto">
132
+ {rightButton}
133
+ </Box>
134
+ </Box>
135
+ </Flex>
136
+ );
137
+ };
138
+
139
+ const DrawerCloseButton = () => {
140
+ const { onClose } = useModalContext();
141
+ const { t } = useTranslation();
142
+
143
+ const [isScreenSizeMinSm] = useMediaQuery(
144
+ `(min-width: ${tokens.size.breakpoint.sm})`,
145
+ );
146
+
147
+ if (isScreenSizeMinSm) {
148
+ return (
149
+ <Button
150
+ variant="ghost"
151
+ leftIcon={<CloseFill24Icon />}
152
+ onClick={onClose}
153
+ aria-label={t(texts.close)}
154
+ width="fit-content"
155
+ marginLeft="auto"
156
+ >
157
+ {t(texts.close)}
158
+ </Button>
159
+ );
160
+ }
161
+
162
+ return (
163
+ <IconButton
164
+ variant="ghost"
165
+ icon={<CloseFill30Icon />}
166
+ onClick={onClose}
167
+ aria-label={t(texts.close)}
168
+ />
169
+ );
170
+ };
171
+
172
+ const texts = createTexts({
173
+ close: {
174
+ nb: "Lukk",
175
+ nn: "Lukk",
176
+ en: "Close",
177
+ sv: "Stäng",
178
+ },
179
+ });
@@ -1,4 +1,5 @@
1
1
  export * from "./Drawer";
2
+ export * from "./FullScreenDrawer";
2
3
  export * from "./Modal";
3
4
  export * from "./ModalHeader";
4
5
  export * from "./SimpleDrawer";
@@ -38,4 +38,5 @@ export { default as Table } from "./table";
38
38
  export { default as Tabs } from "./tabs";
39
39
  export { default as Textarea } from "./textarea";
40
40
  export { default as Toast } from "./toast";
41
+ export { default as StaticCard } from "./static-card";
41
42
  export { default as TravelTag } from "./travel-tag";
@@ -0,0 +1,66 @@
1
+ import { defineStyleConfig } from "@chakra-ui/react";
2
+ import { mode } from "@chakra-ui/theme-tools";
3
+ import { colors } from "../foundations";
4
+ import { baseBorder } from "../utils/base-utils";
5
+
6
+ const config = defineStyleConfig({
7
+ baseStyle: (props: any) => ({
8
+ appearance: "none",
9
+ border: "none",
10
+ overflow: "hidden",
11
+ fontSize: "inherit",
12
+ display: "block",
13
+ borderRadius: "md",
14
+ // Except for white cards, all cards are light mode always
15
+ color: "text.default.light",
16
+ ...getColorSchemeBaseProps(props),
17
+ }),
18
+ });
19
+
20
+ export default config;
21
+
22
+ type CardThemeProps = {
23
+ colorScheme:
24
+ | "white"
25
+ | "grey"
26
+ | "blue"
27
+ | "green"
28
+ | "teal"
29
+ | "yellow"
30
+ | "orange"
31
+ | "red";
32
+ theme: any;
33
+ colorMode: "light" | "dark";
34
+ };
35
+
36
+ const getColorSchemeBaseProps = (props: CardThemeProps) => {
37
+ switch (props.colorScheme) {
38
+ case "white":
39
+ return {
40
+ ...baseBorder("default", props),
41
+ backgroundColor: mode(
42
+ "white",
43
+ `color-mix(in srgb, white 10%, var(--spor-colors-bg-default-dark))`,
44
+ )(props),
45
+ color: "inherit",
46
+ };
47
+ case "grey":
48
+ return {
49
+ backgroundColor: "lightGrey",
50
+ };
51
+ case "green": {
52
+ return {
53
+ backgroundColor: "seaMist",
54
+ };
55
+ }
56
+ case "red": {
57
+ return {
58
+ backgroundColor: "pink",
59
+ };
60
+ }
61
+ default:
62
+ return {
63
+ backgroundColor: colors[props.colorScheme]?.[100] ?? "platinum",
64
+ };
65
+ }
66
+ };