@xaui/native 0.0.3 → 0.0.5

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.
@@ -1,82 +1,166 @@
1
1
  import {
2
2
  useXUITheme
3
- } from "../chunk-DNJWBME5.js";
3
+ } from "../chunk-3ECCBLTG.js";
4
4
 
5
5
  // src/components/checkbox/checkbox.tsx
6
6
  import React2, { useEffect as useEffect2, useRef as useRef2, useState } from "react";
7
- import { Animated as Animated2, Pressable, Text, View } from "react-native";
7
+ import { Animated as Animated3, Pressable, Text, View } from "react-native";
8
8
 
9
9
  // src/components/checkbox/checkbox-icon.tsx
10
10
  import React, { useEffect, useRef } from "react";
11
+ import { Animated as Animated2 } from "react-native";
12
+ import Svg, { Polyline, Line, Path } from "react-native-svg";
13
+
14
+ // src/components/checkbox/checkbox.animation.ts
11
15
  import { Animated } from "react-native";
12
- import Svg, { Polyline, Line } from "react-native-svg";
13
- var AnimatedSvg = Animated.createAnimatedComponent(Svg);
14
- var AnimatedPolyline = Animated.createAnimatedComponent(Polyline);
15
- function CheckIcon({ isChecked, color, size }) {
16
- const opacity = useRef(new Animated.Value(0)).current;
17
- const strokeDashoffset = useRef(new Animated.Value(66)).current;
16
+ var runCheckAnimation = (opacity, strokeDashoffset) => {
17
+ Animated.parallel([
18
+ Animated.timing(opacity, {
19
+ toValue: 1,
20
+ duration: 200,
21
+ useNativeDriver: false
22
+ }),
23
+ Animated.timing(strokeDashoffset, {
24
+ toValue: 44,
25
+ duration: 250,
26
+ useNativeDriver: false
27
+ })
28
+ ]).start();
29
+ };
30
+ var runUncheckAnimation = (opacity, strokeDashoffset) => {
31
+ Animated.parallel([
32
+ Animated.timing(opacity, {
33
+ toValue: 0,
34
+ duration: 200,
35
+ useNativeDriver: false
36
+ }),
37
+ Animated.timing(strokeDashoffset, {
38
+ toValue: 66,
39
+ duration: 250,
40
+ useNativeDriver: false
41
+ })
42
+ ]).start();
43
+ };
44
+ var runBackgroundInAnimation = (backgroundScale, backgroundOpacity) => {
45
+ Animated.parallel([
46
+ Animated.timing(backgroundScale, {
47
+ toValue: 1,
48
+ duration: 200,
49
+ useNativeDriver: true
50
+ }),
51
+ Animated.timing(backgroundOpacity, {
52
+ toValue: 1,
53
+ duration: 200,
54
+ useNativeDriver: true
55
+ })
56
+ ]).start();
57
+ };
58
+ var runBackgroundOutAnimation = (backgroundScale, backgroundOpacity) => {
59
+ Animated.parallel([
60
+ Animated.timing(backgroundScale, {
61
+ toValue: 0.5,
62
+ duration: 200,
63
+ useNativeDriver: true
64
+ }),
65
+ Animated.timing(backgroundOpacity, {
66
+ toValue: 0,
67
+ duration: 200,
68
+ useNativeDriver: true
69
+ })
70
+ ]).start();
71
+ };
72
+ var runPressInAnimation = (scale) => {
73
+ Animated.spring(scale, {
74
+ toValue: 0.95,
75
+ useNativeDriver: true
76
+ }).start();
77
+ };
78
+ var runPressOutAnimation = (scale) => {
79
+ Animated.spring(scale, {
80
+ toValue: 1,
81
+ useNativeDriver: true
82
+ }).start();
83
+ };
84
+
85
+ // src/components/checkbox/checkbox-icon.tsx
86
+ var AnimatedSvg = Animated2.createAnimatedComponent(Svg);
87
+ var AnimatedPolyline = Animated2.createAnimatedComponent(Polyline);
88
+ function CheckIcon({
89
+ isChecked,
90
+ color,
91
+ size
92
+ }) {
93
+ const opacity = useRef(new Animated2.Value(0)).current;
94
+ const strokeDashoffset = useRef(new Animated2.Value(66)).current;
18
95
  useEffect(() => {
19
96
  if (isChecked) {
20
- Animated.parallel([
21
- Animated.timing(opacity, {
22
- toValue: 1,
23
- duration: 200,
24
- useNativeDriver: false
25
- }),
26
- Animated.timing(strokeDashoffset, {
27
- toValue: 44,
28
- duration: 250,
29
- useNativeDriver: false
30
- })
31
- ]).start();
97
+ runCheckAnimation(opacity, strokeDashoffset);
32
98
  } else {
33
- Animated.parallel([
34
- Animated.timing(opacity, {
35
- toValue: 0,
36
- duration: 200,
37
- useNativeDriver: false
38
- }),
39
- Animated.timing(strokeDashoffset, {
40
- toValue: 66,
41
- duration: 250,
42
- useNativeDriver: false
43
- })
44
- ]).start();
99
+ runUncheckAnimation(opacity, strokeDashoffset);
45
100
  }
46
101
  }, [isChecked, opacity, strokeDashoffset]);
47
- return /* @__PURE__ */ React.createElement(AnimatedSvg, { width: size, height: size, viewBox: "0 0 17 18", fill: "none", opacity }, /* @__PURE__ */ React.createElement(
48
- AnimatedPolyline,
102
+ return /* @__PURE__ */ React.createElement(
103
+ AnimatedSvg,
49
104
  {
50
- points: "1 9 7 14 15 4",
105
+ width: size,
106
+ height: size,
107
+ viewBox: "0 0 17 18",
108
+ fill: "none",
109
+ opacity
110
+ },
111
+ /* @__PURE__ */ React.createElement(
112
+ AnimatedPolyline,
113
+ {
114
+ points: "1 9 7 14 15 4",
115
+ stroke: color,
116
+ strokeWidth: 2,
117
+ strokeLinecap: "round",
118
+ strokeLinejoin: "round",
119
+ strokeDasharray: "22",
120
+ strokeDashoffset
121
+ }
122
+ )
123
+ );
124
+ }
125
+ function PlaceholderCheckIcon({ color, size }) {
126
+ return /* @__PURE__ */ React.createElement(Svg, { width: size, height: size, viewBox: "0 0 17 18" }, /* @__PURE__ */ React.createElement(
127
+ Path,
128
+ {
129
+ d: "M 1 9 L 7 14 L 15 4",
51
130
  stroke: color,
52
131
  strokeWidth: 2,
53
132
  strokeLinecap: "round",
54
133
  strokeLinejoin: "round",
55
- strokeDasharray: "22",
56
- strokeDashoffset
134
+ fill: "none"
57
135
  }
58
136
  ));
59
137
  }
60
- function IndeterminateIcon({
138
+ function IndeterminateCheckIcon({
61
139
  color,
62
140
  size
63
141
  }) {
64
142
  return /* @__PURE__ */ React.createElement(Svg, { width: size, height: size, viewBox: "0 0 24 24" }, /* @__PURE__ */ React.createElement(Line, { x1: "21", y1: "12", x2: "3", y2: "12", stroke: color, strokeWidth: 3 }));
65
143
  }
66
- function CheckboxIcon({ isIndeterminate, ...props }) {
67
- const BaseIcon = isIndeterminate ? IndeterminateIcon : CheckIcon;
144
+ function CheckboxIcon({ isIndeterminate, variant, ...props }) {
145
+ const BaseIcon = isIndeterminate ? IndeterminateCheckIcon : CheckIcon;
146
+ if (variant === "light" && !props.isChecked && !isIndeterminate) {
147
+ return /* @__PURE__ */ React.createElement(PlaceholderCheckIcon, { size: props.size, color: props.placeholderColor ?? "" });
148
+ }
68
149
  return /* @__PURE__ */ React.createElement(BaseIcon, { ...props });
69
150
  }
70
151
 
71
152
  // src/components/checkbox/checkbox.hook.ts
72
153
  import { useMemo } from "react";
73
154
  import { getSafeThemeColor } from "@xaui/core";
74
- var useCheckboxStyles = (themeColor, variant, size, radius, labelAlignment, isActive) => {
155
+ function useSizeStyles(size, variant) {
75
156
  const theme = useXUITheme();
76
- const safeThemeColor = getSafeThemeColor(themeColor);
77
- const colorScheme = theme.colors[safeThemeColor];
78
157
  const sizeStyles = useMemo(() => {
79
158
  const sizes = {
159
+ xs: {
160
+ checkboxSize: 14,
161
+ fontSize: theme.fontSizes.xs,
162
+ iconSize: variant === "light" ? 10 : 8
163
+ },
80
164
  sm: {
81
165
  checkboxSize: 18,
82
166
  fontSize: theme.fontSizes.sm,
@@ -94,7 +178,11 @@ var useCheckboxStyles = (themeColor, variant, size, radius, labelAlignment, isAc
94
178
  }
95
179
  };
96
180
  return sizes[size];
97
- }, [size, theme, variant]);
181
+ }, [size, variant, theme]);
182
+ return sizeStyles;
183
+ }
184
+ function useRadiusStyles(radius) {
185
+ const theme = useXUITheme();
98
186
  const radiusStyles = useMemo(() => {
99
187
  const radii = {
100
188
  none: theme.borderRadius.none,
@@ -105,39 +193,59 @@ var useCheckboxStyles = (themeColor, variant, size, radius, labelAlignment, isAc
105
193
  };
106
194
  return { borderRadius: radii[radius] };
107
195
  }, [radius, theme]);
108
- const checkboxStyles = useMemo(() => {
109
- const baseStyle = {
110
- width: sizeStyles.checkboxSize,
111
- height: sizeStyles.checkboxSize,
112
- ...radiusStyles
196
+ return radiusStyles;
197
+ }
198
+ function useCheckmarkColors(themeColor, variant, isActive) {
199
+ const theme = useXUITheme();
200
+ const safeThemeColor = getSafeThemeColor(themeColor);
201
+ const colorScheme = theme.colors[safeThemeColor];
202
+ const checkmarkColors = useMemo(() => {
203
+ if (variant === "filled") {
204
+ return {
205
+ checked: colorScheme.foreground,
206
+ unchecked: void 0
207
+ };
208
+ }
209
+ if (isActive) {
210
+ return {
211
+ checked: colorScheme.main,
212
+ unchecked: void 0
213
+ };
214
+ }
215
+ if (themeColor !== "default") {
216
+ return {
217
+ checked: colorScheme.foreground,
218
+ unchecked: colorScheme.background
219
+ };
220
+ }
221
+ return {
222
+ checked: theme.colors.foreground,
223
+ unchecked: colorScheme.background
113
224
  };
225
+ }, [variant, colorScheme, isActive, themeColor, theme.colors]);
226
+ return checkmarkColors;
227
+ }
228
+ function useVariantStyles(themeColor, variant, isActive) {
229
+ const theme = useXUITheme();
230
+ const safeThemeColor = getSafeThemeColor(themeColor);
231
+ const colorScheme = theme.colors[safeThemeColor];
232
+ const variantStyles = useMemo(() => {
114
233
  if (variant === "filled") {
115
234
  return {
116
- ...baseStyle,
117
235
  backgroundColor: "transparent",
118
236
  borderWidth: isActive ? 0 : theme.borderWidth.md,
119
237
  borderColor: isActive ? "transparent" : colorScheme.main
120
238
  };
121
239
  }
122
240
  return {
123
- ...baseStyle,
124
241
  backgroundColor: "transparent",
125
242
  borderWidth: 0,
126
243
  borderColor: "transparent"
127
244
  };
128
- }, [variant, isActive, colorScheme, sizeStyles, radiusStyles, theme]);
129
- const checkmarkColor = useMemo(() => {
130
- if (variant === "filled") {
131
- return colorScheme.foreground;
132
- }
133
- if (isActive) {
134
- return colorScheme.main;
135
- }
136
- if (themeColor !== "default") {
137
- return colorScheme.background;
138
- }
139
- return theme.colors.foreground;
140
- }, [variant, colorScheme, isActive, themeColor, theme.colors.foreground]);
245
+ }, [variant, isActive, colorScheme, theme]);
246
+ return variantStyles;
247
+ }
248
+ function useContainerStyles(labelAlignment) {
141
249
  const containerStyles = useMemo(() => {
142
250
  const isJustified = labelAlignment === "justify-left" || labelAlignment === "justify-right";
143
251
  return {
@@ -145,15 +253,8 @@ var useCheckboxStyles = (themeColor, variant, size, radius, labelAlignment, isAc
145
253
  justifyContent: isJustified ? "space-between" : "flex-start"
146
254
  };
147
255
  }, [labelAlignment]);
148
- return {
149
- colorScheme,
150
- sizeStyles,
151
- radiusStyles,
152
- checkboxStyles,
153
- checkmarkColor,
154
- containerStyles
155
- };
156
- };
256
+ return containerStyles;
257
+ }
157
258
 
158
259
  // src/components/checkbox/checkbox.style.ts
159
260
  import { StyleSheet } from "react-native";
@@ -194,6 +295,7 @@ var styles = StyleSheet.create({
194
295
  });
195
296
 
196
297
  // src/components/checkbox/checkbox.tsx
298
+ import { getSafeThemeColor as getSafeThemeColor2 } from "@xaui/core";
197
299
  var Checkbox = ({
198
300
  label,
199
301
  labelAlignment = "right",
@@ -210,56 +312,25 @@ var Checkbox = ({
210
312
  onValueChange
211
313
  }) => {
212
314
  const theme = useXUITheme();
315
+ const colorScheme = theme.colors[getSafeThemeColor2(themeColor)];
213
316
  const isControlled = typeof isCheckedProp === "boolean";
214
317
  const [internalChecked, setInternalChecked] = useState(isCheckedProp ?? false);
215
318
  const isChecked = isControlled ? isCheckedProp : internalChecked;
216
- const scale = useRef2(new Animated2.Value(1)).current;
217
- const backgroundScale = useRef2(new Animated2.Value(0.5)).current;
218
- const backgroundOpacity = useRef2(new Animated2.Value(0)).current;
319
+ const scale = useRef2(new Animated3.Value(1)).current;
320
+ const backgroundScale = useRef2(new Animated3.Value(0.5)).current;
321
+ const backgroundOpacity = useRef2(new Animated3.Value(0)).current;
219
322
  const isActive = isChecked || isIndeterminate;
220
- const {
221
- colorScheme,
222
- sizeStyles,
223
- radiusStyles,
224
- checkboxStyles,
225
- checkmarkColor,
226
- containerStyles
227
- } = useCheckboxStyles(
228
- themeColor,
229
- variant,
230
- size,
231
- radius,
232
- labelAlignment,
233
- isActive
234
- );
323
+ const sizeStyles = useSizeStyles(size, variant);
324
+ const radiusStyles = useRadiusStyles(radius);
325
+ const checkmarkColors = useCheckmarkColors(themeColor, variant, isActive);
326
+ const variantStyles = useVariantStyles(themeColor, variant, isActive);
327
+ const containerStyles = useContainerStyles(labelAlignment);
235
328
  useEffect2(() => {
236
329
  if (variant !== "filled") return;
237
330
  if (isActive) {
238
- Animated2.parallel([
239
- Animated2.timing(backgroundScale, {
240
- toValue: 1,
241
- duration: 200,
242
- useNativeDriver: true
243
- }),
244
- Animated2.timing(backgroundOpacity, {
245
- toValue: 1,
246
- duration: 200,
247
- useNativeDriver: true
248
- })
249
- ]).start();
331
+ runBackgroundInAnimation(backgroundScale, backgroundOpacity);
250
332
  } else {
251
- Animated2.parallel([
252
- Animated2.timing(backgroundScale, {
253
- toValue: 0.5,
254
- duration: 200,
255
- useNativeDriver: true
256
- }),
257
- Animated2.timing(backgroundOpacity, {
258
- toValue: 0,
259
- duration: 200,
260
- useNativeDriver: true
261
- })
262
- ]).start();
333
+ runBackgroundOutAnimation(backgroundScale, backgroundOpacity);
263
334
  }
264
335
  }, [isActive, variant, backgroundScale, backgroundOpacity]);
265
336
  const handlePress = () => {
@@ -273,18 +344,12 @@ var Checkbox = ({
273
344
  };
274
345
  const handlePressIn = () => {
275
346
  if (!isDisabled) {
276
- Animated2.spring(scale, {
277
- toValue: 0.95,
278
- useNativeDriver: true
279
- }).start();
347
+ runPressInAnimation(scale);
280
348
  }
281
349
  };
282
350
  const handlePressOut = () => {
283
351
  if (!isDisabled) {
284
- Animated2.spring(scale, {
285
- toValue: 1,
286
- useNativeDriver: true
287
- }).start();
352
+ runPressOutAnimation(scale);
288
353
  }
289
354
  };
290
355
  const accessibilityChecked = isIndeterminate ? "mixed" : isChecked;
@@ -311,18 +376,23 @@ var Checkbox = ({
311
376
  ]
312
377
  },
313
378
  /* @__PURE__ */ React2.createElement(
314
- Animated2.View,
379
+ Animated3.View,
315
380
  {
316
381
  style: [
317
382
  styles.checkbox,
318
- checkboxStyles,
383
+ {
384
+ width: sizeStyles.checkboxSize,
385
+ height: sizeStyles.checkboxSize,
386
+ ...radiusStyles,
387
+ ...variantStyles
388
+ },
319
389
  {
320
390
  transform: [{ scale }]
321
391
  }
322
392
  ]
323
393
  },
324
394
  variant === "filled" && /* @__PURE__ */ React2.createElement(
325
- Animated2.View,
395
+ Animated3.View,
326
396
  {
327
397
  style: [
328
398
  styles.background,
@@ -340,8 +410,10 @@ var Checkbox = ({
340
410
  {
341
411
  isChecked: isActive,
342
412
  isIndeterminate,
343
- color: checkmarkColor,
344
- size: sizeStyles.iconSize
413
+ color: checkmarkColors.checked,
414
+ size: sizeStyles.iconSize,
415
+ placeholderColor: checkmarkColors.unchecked,
416
+ variant
345
417
  }
346
418
  ))
347
419
  ),
@@ -2,6 +2,7 @@
2
2
  import React, { createContext } from "react";
3
3
  import { useColorScheme } from "react-native";
4
4
  import { defaultTheme } from "@xaui/core/theme";
5
+ import { colors } from "@xaui/core/palette";
5
6
  var XUIThemeContext = createContext(null);
6
7
  function XUIProvider({
7
8
  children,
@@ -12,10 +13,12 @@ function XUIProvider({
12
13
  const theme = React.useMemo(() => {
13
14
  if (!darkTheme && !lightTheme) return defaultTheme;
14
15
  const activeTheme = colorScheme === "dark" && darkTheme ? darkTheme : lightTheme;
16
+ const mode = colorScheme === "dark" ? "dark" : "light";
15
17
  if (!activeTheme) return defaultTheme;
16
18
  return {
17
19
  ...defaultTheme,
18
20
  ...activeTheme,
21
+ mode,
19
22
  colors: {
20
23
  ...defaultTheme.colors,
21
24
  ...activeTheme.colors
@@ -27,7 +30,8 @@ function XUIProvider({
27
30
  fontSizes: {
28
31
  ...defaultTheme.fontSizes,
29
32
  ...activeTheme.fontSizes
30
- }
33
+ },
34
+ palette: colors
31
35
  };
32
36
  }, [lightTheme, darkTheme, colorScheme]);
33
37
  return /* @__PURE__ */ React.createElement(XUIThemeContext.Provider, { value: theme }, children);
@@ -51,6 +55,10 @@ function useXUIColors() {
51
55
  const theme = useXUITheme();
52
56
  return theme.colors;
53
57
  }
58
+ function useXUIPalette() {
59
+ const theme = useXUITheme();
60
+ return useMemo(() => theme.palette, [theme]);
61
+ }
54
62
  function useBorderRadiusStyles(radius) {
55
63
  const theme = useXUITheme();
56
64
  const borderRadius = useMemo(() => {
@@ -71,5 +79,6 @@ export {
71
79
  useColorMode,
72
80
  useXUITheme,
73
81
  useXUIColors,
82
+ useXUIPalette,
74
83
  useBorderRadiusStyles
75
84
  };
@@ -0,0 +1,73 @@
1
+ import {
2
+ useXUITheme
3
+ } from "./chunk-3ECCBLTG.js";
4
+
5
+ // src/components/divider/divider.tsx
6
+ import React from "react";
7
+ import { View } from "react-native";
8
+
9
+ // src/components/divider/divider.style.ts
10
+ import { StyleSheet } from "react-native";
11
+ var styles = StyleSheet.create({
12
+ horizontal: {
13
+ height: 1,
14
+ width: "100%"
15
+ },
16
+ vertical: {
17
+ width: 1,
18
+ alignSelf: "stretch"
19
+ }
20
+ });
21
+
22
+ // src/components/divider/divider.hook.ts
23
+ import { useMemo } from "react";
24
+ import { getSafeThemeColor } from "@xaui/core";
25
+ var useDividerColor = (themeColor, customColor) => {
26
+ const theme = useXUITheme();
27
+ const dividerColor = useMemo(() => {
28
+ if (customColor) {
29
+ return customColor;
30
+ }
31
+ const safeThemeColor = getSafeThemeColor(themeColor);
32
+ return theme.colors[safeThemeColor].main;
33
+ }, [customColor, themeColor, theme]);
34
+ return dividerColor;
35
+ };
36
+ var useDividerSize = (size, orientation) => {
37
+ const sizeStyles = useMemo(() => {
38
+ if (orientation === "horizontal") {
39
+ return {
40
+ height: size
41
+ };
42
+ }
43
+ return {
44
+ width: size
45
+ };
46
+ }, [size, orientation]);
47
+ return sizeStyles;
48
+ };
49
+
50
+ // src/components/divider/divider.tsx
51
+ var Divider = ({
52
+ size = 1,
53
+ themeColor = "default",
54
+ color,
55
+ orientation = "horizontal"
56
+ }) => {
57
+ const dividerColor = useDividerColor(themeColor, color);
58
+ const sizeStyles = useDividerSize(size, orientation);
59
+ return /* @__PURE__ */ React.createElement(
60
+ View,
61
+ {
62
+ style: [
63
+ orientation === "horizontal" ? styles.horizontal : styles.vertical,
64
+ sizeStyles,
65
+ { backgroundColor: dividerColor }
66
+ ]
67
+ }
68
+ );
69
+ };
70
+
71
+ export {
72
+ Divider
73
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  useXUITheme
3
- } from "./chunk-DNJWBME5.js";
3
+ } from "./chunk-3ECCBLTG.js";
4
4
 
5
5
  // src/components/indicator/indicator.tsx
6
6
  import React3 from "react";
@@ -41,6 +41,7 @@ module.exports = __toCommonJS(core_exports);
41
41
  var import_react = __toESM(require("react"), 1);
42
42
  var import_react_native = require("react-native");
43
43
  var import_theme = require("@xaui/core/theme");
44
+ var import_palette = require("@xaui/core/palette");
44
45
  var XUIThemeContext = (0, import_react.createContext)(null);
45
46
  function XUIProvider({
46
47
  children,
@@ -51,10 +52,12 @@ function XUIProvider({
51
52
  const theme = import_react.default.useMemo(() => {
52
53
  if (!darkTheme && !lightTheme) return import_theme.defaultTheme;
53
54
  const activeTheme = colorScheme === "dark" && darkTheme ? darkTheme : lightTheme;
55
+ const mode = colorScheme === "dark" ? "dark" : "light";
54
56
  if (!activeTheme) return import_theme.defaultTheme;
55
57
  return {
56
58
  ...import_theme.defaultTheme,
57
59
  ...activeTheme,
60
+ mode,
58
61
  colors: {
59
62
  ...import_theme.defaultTheme.colors,
60
63
  ...activeTheme.colors
@@ -66,7 +69,8 @@ function XUIProvider({
66
69
  fontSizes: {
67
70
  ...import_theme.defaultTheme.fontSizes,
68
71
  ...activeTheme.fontSizes
69
- }
72
+ },
73
+ palette: import_palette.colors
70
74
  };
71
75
  }, [lightTheme, darkTheme, colorScheme]);
72
76
  return /* @__PURE__ */ import_react.default.createElement(XUIThemeContext.Provider, { value: theme }, children);
@@ -3,7 +3,7 @@ import {
3
3
  useColorMode,
4
4
  useXUIColors,
5
5
  useXUITheme
6
- } from "../chunk-DNJWBME5.js";
6
+ } from "../chunk-3ECCBLTG.js";
7
7
  export {
8
8
  XUIProvider,
9
9
  useColorMode,