@vygruppen/spor-react 3.7.7 → 3.8.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.
@@ -33,6 +33,10 @@ type NumericStepperProps = {
33
33
  isDisabled?: boolean;
34
34
  /** Whether to show input field or not */
35
35
  withInput?: boolean;
36
+ /** The amount to increase/decrease when pressing +/- */
37
+ stepSize?: number;
38
+ /** Whether to show the number input when value is zero */
39
+ showZero?: boolean;
36
40
  } & Omit<BoxProps, "onChange">;
37
41
  /** A simple stepper component for integer values
38
42
  *
@@ -43,10 +47,10 @@ type NumericStepperProps = {
43
47
  * <NumericStepper value={value} onChange={setValue} />
44
48
  * ```
45
49
  *
46
- * You can also set a minimum and/or maximum value:
50
+ * You can also set a minimum and/or maximum value and step size:
47
51
  *
48
52
  * ```tsx
49
- * <NumericStepper value={value} onChange={setValue} minValue={1} maxValue={10} />
53
+ * <NumericStepper value={value} onChange={setValue} minValue={1} maxValue={10} stepSize={3} />
50
54
  * ```
51
55
  *
52
56
  * You can use the NumericStepper inside of a FormControl component to get IDs etc linked up automatically:
@@ -68,6 +72,8 @@ export function NumericStepper({
68
72
  maxValue = 99,
69
73
  isDisabled,
70
74
  withInput = true,
75
+ stepSize = 1,
76
+ showZero = false,
71
77
  ...boxProps
72
78
  }: NumericStepperProps) {
73
79
  const { t } = useTranslation();
@@ -80,15 +86,17 @@ export function NumericStepper({
80
86
  const textColor = useColorModeValue("darkGrey", "white");
81
87
  const backgroundColor = useColorModeValue("white", "darkGrey");
82
88
  const focusColor = useColorModeValue("greenHaze", "azure");
89
+ const clampedStepSize = Math.max(Math.min(stepSize, 10), 1);
83
90
 
84
91
  return (
85
92
  <Flex alignItems="center" {...boxProps}>
86
93
  <VerySmallButton
87
- icon={<SubtractIcon color="white" />}
88
- aria-label={t(texts.decrementButtonAriaLabel)}
89
- onClick={() => onChange(value - 1)}
94
+ icon={<SubtractIcon color="white" stepLabel={clampedStepSize} />}
95
+ aria-label={t(texts.decrementButtonAriaLabel(clampedStepSize))}
96
+ onClick={() => onChange(Math.max(value - clampedStepSize, minValue))}
90
97
  visibility={value <= minValue ? "hidden" : "visible"}
91
98
  isDisabled={formControlProps.disabled}
99
+ id={value <= minValue ? undefined : formControlProps.id}
92
100
  />
93
101
  {withInput ? (
94
102
  <chakra.input
@@ -98,10 +106,10 @@ export function NumericStepper({
98
106
  name={nameProp}
99
107
  value={value}
100
108
  {...formControlProps}
101
- id={value !== 0 ? formControlProps.id : undefined}
109
+ id={!showZero && value === 0 ? undefined : formControlProps.id}
102
110
  fontSize="sm"
103
111
  fontWeight="bold"
104
- width="3ch"
112
+ width={`${Math.max(value.toString().length + 1, 3)}ch`}
105
113
  marginX={1}
106
114
  paddingX={1}
107
115
  borderRadius="xs"
@@ -109,7 +117,7 @@ export function NumericStepper({
109
117
  backgroundColor={backgroundColor}
110
118
  color={textColor}
111
119
  transition="box-shadow .1s ease-out"
112
- visibility={value === 0 ? "hidden" : "visible"}
120
+ visibility={!showZero && value === 0 ? "hidden" : "visible"}
113
121
  aria-live="assertive"
114
122
  aria-label={value.toString()}
115
123
  _hover={{
@@ -136,7 +144,7 @@ export function NumericStepper({
136
144
  if (Number.isNaN(numericInput)) {
137
145
  return;
138
146
  }
139
- onChange(numericInput);
147
+ onChange(Math.max(Math.min(numericInput, maxValue), minValue));
140
148
  }}
141
149
  />
142
150
  ) : (
@@ -149,19 +157,19 @@ export function NumericStepper({
149
157
  textAlign="center"
150
158
  color={textColor}
151
159
  transition="box-shadow .1s ease-out"
152
- visibility={value === 0 ? "hidden" : "visible"}
160
+ visibility={!showZero && value === 0 ? "hidden" : "visible"}
153
161
  aria-label={value.toString()}
154
162
  >
155
163
  {value}
156
164
  </chakra.text>
157
165
  )}
158
166
  <VerySmallButton
159
- icon={<AddIcon color="white" />}
160
- aria-label={t(texts.incrementButtonAriaLabel)}
161
- onClick={() => onChange(value + 1)}
167
+ icon={<AddIcon color="white" stepLabel={clampedStepSize} />}
168
+ aria-label={t(texts.incrementButtonAriaLabel(clampedStepSize))}
169
+ onClick={() => onChange(Math.min(value + clampedStepSize, maxValue))}
162
170
  visibility={value >= maxValue ? "hidden" : "visible"}
163
171
  isDisabled={formControlProps.disabled}
164
- id={value === 0 ? formControlProps.id : undefined}
172
+ id={value >= maxValue ? undefined : formControlProps.id}
165
173
  />
166
174
  </Flex>
167
175
  );
@@ -201,65 +209,80 @@ const VerySmallButton = (props: VerySmallButtonProps) => {
201
209
  );
202
210
  };
203
211
 
204
- const SubtractIcon = (props: BoxProps) => (
205
- <Box
206
- as="svg"
207
- viewBox="0 0 30 30"
208
- width="24"
209
- height="24"
210
- stroke="currentColor"
211
- {...props}
212
- >
213
- <line
214
- x1="9"
215
- y1="15"
216
- x2="21"
217
- y2="15"
218
- strokeWidth="1.5"
219
- strokeLinecap="round"
220
- />
221
- </Box>
212
+ const SubtractIcon = (props: BoxProps & { stepLabel: number }) => (
213
+ <>
214
+ <Box
215
+ as="svg"
216
+ viewBox="0 0 30 30"
217
+ width="24"
218
+ height="24"
219
+ stroke="currentColor"
220
+ {...props}
221
+ >
222
+ <line
223
+ x1="9"
224
+ y1="15"
225
+ x2="21"
226
+ y2="15"
227
+ strokeWidth="1.5"
228
+ strokeLinecap="round"
229
+ />
230
+ </Box>
231
+ {props.stepLabel > 1 && (
232
+ <chakra.span paddingRight="1">{props.stepLabel.toString()}</chakra.span>
233
+ )}
234
+ </>
222
235
  );
223
236
 
224
- const AddIcon = (props: BoxProps) => (
225
- <Box
226
- as="svg"
227
- viewBox="0 0 30 30"
228
- width="24"
229
- height="24"
230
- stroke="currentColor"
231
- {...props}
232
- >
233
- <line
234
- x1="9"
235
- y1="15"
236
- x2="21"
237
- y2="15"
238
- strokeWidth="1.5"
239
- strokeLinecap="round"
240
- />
241
- <line
242
- x1="15"
243
- y1="9"
244
- x2="15"
245
- y2="21"
246
- strokeWidth="1.5"
247
- strokeLinecap="round"
248
- />
249
- </Box>
237
+ const AddIcon = (props: BoxProps & { stepLabel: number }) => (
238
+ <>
239
+ <Box
240
+ as="svg"
241
+ viewBox="0 0 30 30"
242
+ width="24"
243
+ height="24"
244
+ stroke="currentColor"
245
+ {...props}
246
+ >
247
+ <line
248
+ x1="9"
249
+ y1="15"
250
+ x2="21"
251
+ y2="15"
252
+ strokeWidth="1.5"
253
+ strokeLinecap="round"
254
+ />
255
+ <line
256
+ x1="15"
257
+ y1="9"
258
+ x2="15"
259
+ y2="21"
260
+ strokeWidth="1.5"
261
+ strokeLinecap="round"
262
+ />
263
+ </Box>
264
+
265
+ {props.stepLabel > 1 && (
266
+ <chakra.span paddingRight="1">{props.stepLabel.toString()}</chakra.span>
267
+ )}
268
+ </>
250
269
  );
251
270
 
252
271
  const texts = createTexts({
253
- decrementButtonAriaLabel: {
254
- nb: "Trekk fra 1",
255
- en: "Subtract 1",
256
- nn: "Trekk frå 1",
257
- sv: "Subtrahera 1",
272
+ decrementButtonAriaLabel(stepSize) {
273
+ return {
274
+ nb: `Trekk fra ${stepSize}`,
275
+ en: `Subtract ${stepSize}`,
276
+ nn: `Trekk frå ${stepSize}`,
277
+ sv: `Subtrahera ${stepSize}`,
278
+ };
258
279
  },
259
- incrementButtonAriaLabel: {
260
- nb: "Legg til 1",
261
- en: "Add 1",
262
- nn: "Legg til 1",
263
- sv: "Lägg till 1",
280
+ incrementButtonAriaLabel(stepSize) {
281
+ return {
282
+ nb: `Legg til ${stepSize}`,
283
+ en: `Add ${stepSize}`,
284
+ nn: `Legg til ${stepSize}`,
285
+ sv: `Lägg till ${stepSize}`,
286
+ };
264
287
  },
265
288
  });
@@ -1,39 +1,40 @@
1
1
  import { defineStyleConfig } from "@chakra-ui/react";
2
- import { cssVar } from "@chakra-ui/theme-tools";
2
+ import { cssVar, mode } from "@chakra-ui/theme-tools";
3
3
  import { getBoxShadowString } from "../utils/box-shadow-utils";
4
4
  import { focusVisible } from "../utils/focus-utils";
5
5
 
6
6
  const $size = cssVar("close-button-size");
7
7
 
8
8
  const config = defineStyleConfig({
9
- baseStyle: {
9
+ baseStyle: (props) => ({
10
10
  w: [$size.reference],
11
11
  h: [$size.reference],
12
12
  transitionProperty: "common",
13
13
  transitionDuration: "normal",
14
- borderRadius: "xs",
14
+ borderRadius: "md",
15
15
  backgroundColor: "transparent",
16
- color: "darkGrey",
16
+ color: mode("darkGrey", "white")(props),
17
17
  fontWeight: "normal",
18
18
  ...focusVisible({
19
19
  focus: {
20
20
  outline: "none",
21
- boxShadow: getBoxShadowString({ borderColor: "greenHaze" }),
21
+ boxShadow: getBoxShadowString({ borderColor: mode("greenHaze", "azure")(props) }),
22
+ outlineOffset: "2px",
22
23
  },
23
24
  notFocus: {
24
25
  boxShadow: "none",
25
26
  },
26
27
  }),
27
28
  _hover: {
28
- backgroundColor: "seaMist",
29
+ backgroundColor: mode("seaMist", "pine")(props),
29
30
  _disabled: {
30
31
  color: "dimGrey",
31
32
  },
32
33
  },
33
34
  _active: {
34
- backgroundColor: "mint",
35
+ backgroundColor: mode("mint", "whiteAlpha.200")(props),
35
36
  },
36
- },
37
+ }),
37
38
  sizes: {
38
39
  lg: {
39
40
  [$size.variable]: "40px",
@@ -19,7 +19,6 @@ const parts = anatomy("datepicker").parts(
19
19
  const $arrowBackground = cssVar("popper-arrow-bg");
20
20
 
21
21
  const helpers = createMultiStyleConfigHelpers(parts.keys);
22
-
23
22
  const config = helpers.defineMultiStyleConfig({
24
23
  baseStyle: (props) => ({
25
24
  wrapper: {
@@ -29,6 +28,7 @@ const config = helpers.defineMultiStyleConfig({
29
28
  }),
30
29
  transitionProperty: "box-shadow",
31
30
  transitionDuration: "fast",
31
+ borderRadius: "sm",
32
32
  display: "flex",
33
33
  flex: 1,
34
34
  paddingY: 0.5,
@@ -80,27 +80,26 @@ const config = helpers.defineMultiStyleConfig({
80
80
  },
81
81
  calendarTriggerButton: {
82
82
  backgroundColor: mode("white", "night")(props),
83
- boxShadow: `${getBoxShadowString({
84
- borderColor: mode("blackAlpha.400", "whiteAlpha.400")(props),
85
- })}, inset 1px 0 0 1px ${mode("white", colors.night)(props)}`, // to make the shadow colors not multiply
83
+ boxShadow: "none",
86
84
  width: 8,
87
85
  display: "flex",
88
86
  alignItems: "center",
89
87
  justifyContent: "center",
90
- borderRightRadius: "sm",
88
+ borderLeftRadius: "sm",
91
89
  transitionProperty: "box-shadow, background-color",
92
90
  transitionSpeed: "fast",
93
91
  position: "relative",
94
- left: "-1px", // To make the box-shadows overlap
92
+ paddingTop: 1,
93
+ paddingBottom: 1,
94
+ borderRadius: "sm",
95
+ right: "9px",
95
96
 
96
97
  _hover: {
97
- boxShadow: `${getBoxShadowString({
98
- borderColor: mode("darkGrey", "white")(props),
99
- borderWidth: 2,
100
- })}, inset 2px 0 0 2px ${mode("white", colors.night)(props)}`,
98
+ boxShadow: "none",
99
+ backgroundColor: mode("seaMist", "pine")(props),
101
100
  },
102
101
  _active: {
103
- backgroundColor: mode("mint", "azure")(props),
102
+ backgroundColor: mode("mint", "whiteAlpha.200")(props),
104
103
  },
105
104
  ...focusVisible({
106
105
  focus: {
@@ -124,18 +123,22 @@ const config = helpers.defineMultiStyleConfig({
124
123
  }),
125
124
  },
126
125
  },
127
- arrow: {
126
+ arrow: {
128
127
  [$arrowBackground.variable]: mode("white", colors.night)(props),
129
- },
128
+ },
130
129
  calendar: {
131
130
  backgroundColor: mode("white", "night")(props),
132
131
  color: mode("darkGrey", "white")(props),
132
+ boxShadow: getBoxShadowString({
133
+ borderWidth: 2,
134
+ borderColor: mode("blackAlpha.200", "whiteAlpha.200")(props),
135
+ }),
133
136
  },
134
137
  weekdays: {
135
138
  color: mode("darkGrey", "white")(props),
136
139
  },
137
140
  weekend: {
138
- color: mode("greenHaze", "azure")(props),
141
+ color: mode("darkTeal", "seaMist")(props),
139
142
  },
140
143
  dateCell: {
141
144
  backgroundColor: mode("white", "night")(props),
@@ -195,7 +198,7 @@ const config = helpers.defineMultiStyleConfig({
195
198
  "&[data-today]": {
196
199
  boxShadow: getBoxShadowString({
197
200
  borderWidth: 1,
198
- borderColor: mode("osloGrey", "dimGrey")(props),
201
+ borderColor: mode("blackAlpha.400", "whiteAlpha.400")(props),
199
202
  }),
200
203
  _focus: {
201
204
  outline: "none",
@@ -212,16 +215,64 @@ const config = helpers.defineMultiStyleConfig({
212
215
  },
213
216
  }),
214
217
  variants: {
215
- simple: {
216
- wrapper: {
217
- borderRadius: "sm",
218
+ base: (props) => ({
219
+ calendar: {
220
+ backgroundColor: mode("white", "night")(props),
221
+ color: mode("darkGrey", "white")(props),
222
+ boxShadow: getBoxShadowString({
223
+ borderWidth: 2,
224
+ borderColor: mode("blackAlpha.200", "whiteAlpha.200")(props),
225
+ }),
218
226
  },
219
- },
220
- "with-trigger": {
221
- wrapper: {
222
- borderLeftRadius: "sm",
227
+ dateCell: {
228
+ color: mode("darkGrey", "white")(props),
229
+ _hover: {
230
+ backgroundColor: mode("seaMist", "pine")(props),
231
+ },
232
+ "&[data-today]": {
233
+ boxShadow: getBoxShadowString({
234
+ borderWidth: 1,
235
+ borderColor: mode("blackAlpha.400", "whiteAlpha.400")(props),
236
+ }),
237
+ },
223
238
  },
224
- },
239
+ }),
240
+ floating: (props) => ({
241
+ calendar: {
242
+ backgroundColor: mode("white", "night")(props),
243
+ color: mode("darkGrey", "white")(props),
244
+ boxShadow: getBoxShadowString({
245
+ borderColor: mode("grey.200", "whiteAlpha.400")(props),
246
+ baseShadow: "sm",
247
+ }),
248
+ },
249
+ dateCell: {
250
+ color: mode("darkGrey", "white")(props),
251
+ _hover: {
252
+ backgroundColor: mode("", "")(props),
253
+ },
254
+ },
255
+ }),
256
+ ghost: (props) => ({
257
+ calendar: {
258
+ backgroundColor: mode("white", "night")(props),
259
+ color: mode("darkGrey", "white")(props),
260
+ boxShadow: getBoxShadowString({
261
+ borderWidth: 2,
262
+ borderColor: mode("", "")(props),
263
+ }),
264
+ },
265
+ dateCell: {
266
+ color: mode("darkGrey", "white")(props),
267
+ _hover: {
268
+ backgroundColor: mode("seaMist", "pine")(props),
269
+ },
270
+ _selected: {
271
+ backgroundColor: mode("", "primaryGreen")(props),
272
+ color: "darkGrey"
273
+ },
274
+ },
275
+ }),
225
276
  },
226
277
  });
227
278
 
@@ -1,6 +1,6 @@
1
1
  import { modalAnatomy as parts } from "@chakra-ui/anatomy";
2
2
  import { createMultiStyleConfigHelpers } from "@chakra-ui/react";
3
- import type { PartsStyleObject } from "@chakra-ui/theme-tools";
3
+ import { mode, type PartsStyleObject } from "@chakra-ui/theme-tools";
4
4
 
5
5
  const helpers = createMultiStyleConfigHelpers(parts.keys);
6
6
 
@@ -19,8 +19,8 @@ const config = helpers.defineMultiStyleConfig({
19
19
  },
20
20
  dialog: {
21
21
  borderRadius: "md",
22
- background: "white",
23
- color: "inherit",
22
+ background: mode("white", "night")(props),
23
+ color: mode("inherit", "white")(props),
24
24
  my: "3.75rem",
25
25
  zIndex: "modal",
26
26
  maxHeight:
@@ -36,6 +36,7 @@ const config = helpers.defineMultiStyleConfig({
36
36
  },
37
37
  closeButton: {
38
38
  position: "absolute",
39
+ color: "inherit",
39
40
  top: 3,
40
41
  insetEnd: 3,
41
42
  },