@swan-io/lake 2.6.0 → 2.7.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,6 +1,6 @@
1
1
  {
2
2
  "name": "@swan-io/lake",
3
- "version": "2.6.0",
3
+ "version": "2.7.0",
4
4
  "engines": {
5
5
  "node": ">=18.0.0",
6
6
  "yarn": "^1.22.0"
@@ -27,29 +27,29 @@
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
29
  "@popperjs/core": "^2.11.8",
30
- "@react-three/drei": "^9.77.0",
31
- "@react-three/fiber": "^8.13.3",
30
+ "@react-three/drei": "^9.77.10",
31
+ "@react-three/fiber": "^8.13.4",
32
32
  "@swan-io/boxed": "^1.0.2",
33
- "@swan-io/chicane": "^1.4.0",
34
- "dayjs": "^1.11.8",
33
+ "@swan-io/chicane": "^1.4.1",
34
+ "dayjs": "^1.11.9",
35
35
  "polished": "^4.2.2",
36
- "prism-react-renderer": "^2.0.5",
36
+ "prism-react-renderer": "^2.0.6",
37
37
  "react": "^18.2.0",
38
38
  "react-atomic-state": "^1.2.7",
39
39
  "react-dom": "^18.2.0",
40
- "react-native-web": "^0.19.5",
40
+ "react-native-web": "^0.19.6",
41
41
  "react-popper": "^2.3.0",
42
42
  "react-ux-form": "^1.3.0",
43
43
  "rifm": "^0.12.1",
44
- "three": "^0.153.0",
44
+ "three": "^0.154.0",
45
45
  "ts-dedent": "^2.2.0",
46
46
  "ts-pattern": "^5.0.1",
47
47
  "urql": "^4.0.4",
48
48
  "uuid": "^9.0.0"
49
49
  },
50
50
  "devDependencies": {
51
- "@types/react": "^18.2.12",
52
- "@types/react-dom": "^18.2.5",
51
+ "@types/react": "^18.2.14",
52
+ "@types/react-dom": "^18.2.6",
53
53
  "@types/react-native": "^0.72.2",
54
54
  "@types/three": "^0.152.1",
55
55
  "@types/uuid": "^9.0.2",
@@ -50,5 +50,5 @@ export const LakeCheckbox = ({ value, color = "current", disabled = false, isErr
50
50
  ], children: [value === true && (_jsx(Svg, { viewBox: "0 0 16 16", children: _jsx(Path, { d: "m3.5 7.5 2.8 3.4 5.6-6.7", stroke: colors[color].contrast, strokeWidth: 1.5, fill: "none", strokeLinecap: "round", strokeLinejoin: "round", strokeDasharray: "20", strokeDashoffset: shouldAnimate ? "20" : "0", children: shouldAnimate && (_jsx(Animate, { attributeName: "stroke-dashoffset", values: "20;0", dur: "150ms", begin: "150ms", fill: "freeze" })) }) })), value === "mixed" && (_jsx(View, { style: [styles.mixed, { backgroundColor: colors[color].contrast }] }))] }));
51
51
  };
52
52
  export const LakeLabelledCheckbox = ({ value, color, label, onValueChange, disabled = false, isError = false, }) => {
53
- return (_jsxs(Pressable, { "aria-checked": value, style: styles.labelled, onPress: () => onValueChange(value === true ? false : true), disabled: disabled, children: [_jsx(LakeCheckbox, { value: value, color: color, disabled: disabled, isError: isError }), _jsx(Space, { width: 8 }), _jsx(LakeText, { color: colors.gray[900], userSelect: "none", children: label })] }));
53
+ return (_jsxs(Pressable, { role: "checkbox", "aria-checked": value, style: styles.labelled, onPress: () => onValueChange(value === true ? false : true), disabled: disabled, children: [_jsx(LakeCheckbox, { value: value, color: color, disabled: disabled, isError: isError }), _jsx(Space, { width: 8 }), _jsx(LakeText, { color: colors.gray[900], userSelect: "none", children: label })] }));
54
54
  };
@@ -1,9 +1,11 @@
1
+ import { ReactNode } from "react";
1
2
  type Props = {
2
3
  initialValue: string;
3
4
  placeholder: string;
4
5
  onChangeText: (text: string) => void;
5
6
  debounceDuration?: number;
6
7
  maxWidth?: number;
8
+ renderEnd?: () => ReactNode;
7
9
  };
8
- export declare const LakeSearchField: ({ initialValue, placeholder, onChangeText, debounceDuration, maxWidth, }: Props) => import("react/jsx-runtime").JSX.Element;
10
+ export declare const LakeSearchField: ({ initialValue, placeholder, onChangeText, debounceDuration, maxWidth, renderEnd, }: Props) => import("react/jsx-runtime").JSX.Element;
9
11
  export {};
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useCallback, useRef, useState } from "react";
3
3
  import { Pressable, StyleSheet, View } from "react-native";
4
- import { animations, backgroundColor, colors, radii } from "../constants/design";
4
+ import { animations, backgroundColor, colors, radii, spacings } from "../constants/design";
5
5
  import { useBoolean } from "../hooks/useBoolean";
6
6
  import { useDebounce } from "../hooks/useDebounce";
7
7
  import { LakeButton } from "./LakeButton";
@@ -10,44 +10,24 @@ import { ResponsiveContainer } from "./ResponsiveContainer";
10
10
  import { Line, Svg } from "./Svg";
11
11
  import { TransitionView } from "./TransitionView";
12
12
  const styles = StyleSheet.create({
13
- root: {
14
- flexGrow: 1,
15
- flexShrink: 1,
13
+ input: {
14
+ transition: "300ms ease-in-out border-color",
16
15
  // ResponsiveContainer uses a 200 breaking,
17
16
  // we give the opportunity to the component to grow 2px more
18
17
  // to trigger the change
19
18
  maxWidth: 202,
20
19
  minWidth: 38,
21
20
  },
22
- container: {
23
- width: "100%",
24
- flexGrow: 1,
25
- flexShrink: 0,
26
- alignSelf: "flex-end",
27
- },
28
- input: {
29
- paddingRight: 50,
30
- minWidth: 200,
31
- // fixes a responsiveness bug where the default input width is too large
32
- width: 1,
33
- flexGrow: 1,
34
- transition: "300ms ease-in-out border-color",
35
- },
36
21
  focus: {
37
22
  outlineStyle: "none",
38
23
  borderColor: colors.current.primary,
39
24
  },
40
25
  clearButton: {
41
- position: "absolute",
42
- right: 0,
43
- top: "50%",
44
- transform: "translateY(-50%)",
45
- padding: 16,
26
+ marginRight: spacings[8],
46
27
  },
47
28
  clear: {
48
29
  width: 8,
49
30
  height: 8,
50
- display: "flex",
51
31
  },
52
32
  smallButtonContainer: {
53
33
  flexDirection: "row",
@@ -68,30 +48,30 @@ const styles = StyleSheet.create({
68
48
  borderRadius: radii[6],
69
49
  },
70
50
  });
71
- const CollapsibleSeachField = ({ inputRef, placeholder, initialValue, onChange, setFocused, hasFocus, clear, currentValue, }) => {
72
- return (_jsxs(View, { children: [_jsx(LakeButton, { mode: "secondary", size: "small", ariaLabel: placeholder, icon: "search-filled", onPress: () => {
51
+ const CollapsibleSeachField = ({ inputRef, placeholder, initialValue, onChange, setFocused, hasFocus, clear, currentValue, renderEnd, }) => {
52
+ return (_jsxs(View, { style: styles.smallButtonContainer, children: [_jsx(LakeButton, { mode: "secondary", size: "small", ariaLabel: placeholder, icon: "search-filled", onPress: () => {
73
53
  setFocused.on();
74
- }, pill: currentValue !== "" }), _jsx(TransitionView, { style: styles.openSearchFieldContainer, ...animations.fadeAndSlideInFromRight, children: hasFocus ? (_jsx(View, { style: styles.openSearchField, children: _jsx(ExpandedSearchField, { inputRef: inputRef, placeholder: placeholder, initialValue: initialValue, onChange: onChange, setFocused: setFocused, hasFocus: hasFocus, clear: clear, currentValue: currentValue }) })) : null })] }));
54
+ }, pill: currentValue !== "" }), _jsx(TransitionView, { style: styles.openSearchFieldContainer, ...animations.fadeAndSlideInFromRight, children: hasFocus ? (_jsx(View, { style: styles.openSearchField, children: _jsx(ExpandedSearchField, { inputRef: inputRef, placeholder: placeholder, initialValue: initialValue, onChange: onChange, setFocused: setFocused, hasFocus: hasFocus, clear: clear, currentValue: currentValue, renderEnd: renderEnd }) })) : null })] }));
75
55
  };
76
- const ExpandedSearchField = ({ inputRef, placeholder, initialValue, onChange, setFocused, hasFocus, clear, }) => {
56
+ const ExpandedSearchField = ({ inputRef, placeholder, initialValue, onChange, setFocused, hasFocus, clear, renderEnd, }) => {
77
57
  const timeoutRef = useRef(null);
78
- return (_jsxs(View, { style: styles.container, children: [_jsx(LakeTextInput, { ref: inputRef, autoFocus: hasFocus, icon: "search-filled", placeholder: placeholder, defaultValue: initialValue, inputMode: "search", onChangeText: onChange, hideErrors: true, onFocus: () => {
79
- if (timeoutRef.current != null) {
80
- clearTimeout(timeoutRef.current);
81
- }
82
- setFocused.on();
83
- }, onBlur: () => {
84
- timeoutRef.current = window.setTimeout(() => {
85
- setFocused.off();
86
- }, 300);
87
- }, style: [styles.input, hasFocus ? styles.focus : null] }), _jsx(Pressable, { onPress: () => {
88
- if (timeoutRef.current != null) {
89
- clearTimeout(timeoutRef.current);
90
- }
91
- clear();
92
- }, style: styles.clearButton, children: _jsx(Svg, { viewBox: "0 0 16 16", style: styles.clear, children: _jsxs(_Fragment, { children: [_jsx(Line, { x1: "0", x2: "16", y1: "0", y2: "16", strokeLinecap: "round", stroke: colors.gray[500], strokeWidth: 2 }), _jsx(Line, { x1: "0", x2: "16", y1: "16", y2: "0", strokeLinecap: "round", stroke: colors.gray[500], strokeWidth: 2 })] }) }) })] }));
58
+ return (_jsx(LakeTextInput, { ref: inputRef, autoFocus: hasFocus, icon: "search-filled", placeholder: placeholder, defaultValue: initialValue, inputMode: "search", onChangeText: onChange, hideErrors: true, renderEnd: () => (_jsxs(_Fragment, { children: [_jsx(Pressable, { onPress: () => {
59
+ if (timeoutRef.current != null) {
60
+ clearTimeout(timeoutRef.current);
61
+ }
62
+ clear();
63
+ }, style: styles.clearButton, children: _jsx(Svg, { viewBox: "0 0 16 16", style: styles.clear, children: _jsxs(_Fragment, { children: [_jsx(Line, { x1: "0", x2: "16", y1: "0", y2: "16", strokeLinecap: "round", stroke: colors.gray[500], strokeWidth: 2 }), _jsx(Line, { x1: "0", x2: "16", y1: "16", y2: "0", strokeLinecap: "round", stroke: colors.gray[500], strokeWidth: 2 })] }) }) }), renderEnd?.()] })), onFocus: () => {
64
+ if (timeoutRef.current != null) {
65
+ clearTimeout(timeoutRef.current);
66
+ }
67
+ setFocused.on();
68
+ }, onBlur: () => {
69
+ timeoutRef.current = window.setTimeout(() => {
70
+ setFocused.off();
71
+ }, 300);
72
+ }, style: [styles.input, hasFocus ? styles.focus : null] }));
93
73
  };
94
- export const LakeSearchField = ({ initialValue, placeholder, onChangeText, debounceDuration = 500, maxWidth, }) => {
74
+ export const LakeSearchField = ({ initialValue, placeholder, onChangeText, debounceDuration = 500, maxWidth, renderEnd, }) => {
95
75
  const [hasFocus, setFocused] = useBoolean(false);
96
76
  const inputRef = useRef(null);
97
77
  const [currentValue, setCurrentValue] = useState(initialValue);
@@ -107,5 +87,19 @@ export const LakeSearchField = ({ initialValue, placeholder, onChangeText, debou
107
87
  setCurrentValue("");
108
88
  }
109
89
  }, [onChangeText]);
110
- return (_jsx(ResponsiveContainer, { breakpoint: 200, style: [styles.root, maxWidth != null && { maxWidth }], children: ({ large }) => large ? (_jsx(ExpandedSearchField, { inputRef: inputRef, placeholder: placeholder, initialValue: initialValue, onChange: onChange, setFocused: setFocused, hasFocus: hasFocus, clear: clear, currentValue: currentValue })) : (_jsx(View, { style: styles.smallButtonContainer, children: _jsx(CollapsibleSeachField, { inputRef: inputRef, placeholder: placeholder, initialValue: initialValue, onChange: onChange, setFocused: setFocused, hasFocus: hasFocus, clear: clear, currentValue: currentValue }) })) }));
90
+ const props = {
91
+ inputRef,
92
+ placeholder,
93
+ initialValue,
94
+ onChange,
95
+ setFocused,
96
+ hasFocus,
97
+ clear,
98
+ currentValue,
99
+ renderEnd,
100
+ };
101
+ return (_jsx(ResponsiveContainer, { breakpoint: 200, style: maxWidth != null && { maxWidth }, children: ({ large }) => {
102
+ const Component = large ? ExpandedSearchField : CollapsibleSeachField;
103
+ return _jsx(Component, { ...props });
104
+ } }));
111
105
  };
@@ -23,6 +23,7 @@ export type LakeTextInputProps = Except<TextInputProps, "editable" | "keyboardTy
23
23
  onChange?: ChangeEventHandler<HTMLInputElement>;
24
24
  maxCharCount?: number;
25
25
  help?: string;
26
+ renderEnd?: () => ReactNode;
26
27
  };
27
28
  export declare const LakeTextInput: import("react").ForwardRefExoticComponent<{
28
29
  allowFontScaling?: boolean | undefined;
@@ -234,4 +235,5 @@ export declare const LakeTextInput: import("react").ForwardRefExoticComponent<{
234
235
  onChange?: ChangeEventHandler<HTMLInputElement> | undefined;
235
236
  maxCharCount?: number | undefined;
236
237
  help?: string | undefined;
238
+ renderEnd?: (() => ReactNode) | undefined;
237
239
  } & import("react").RefAttributes<TextInput | null>>;
@@ -19,7 +19,6 @@ const styles = StyleSheet.create({
19
19
  },
20
20
  container: {
21
21
  flexGrow: 1,
22
- flexShrink: 1,
23
22
  flexDirection: "row",
24
23
  alignItems: "stretch",
25
24
  },
@@ -27,21 +26,25 @@ const styles = StyleSheet.create({
27
26
  flexGrow: 1,
28
27
  flexShrink: 1,
29
28
  flexDirection: "row",
30
- alignItems: "stretch",
29
+ width: "100%",
30
+ display: "flex",
31
+ alignItems: "center",
32
+ justifyContent: "center",
33
+ borderRadius: radii[6],
34
+ backgroundColor: backgroundColor.accented,
35
+ borderColor: colors.gray[100],
36
+ borderWidth: 1,
37
+ paddingHorizontal: spacings[8],
31
38
  },
32
39
  input: {
33
40
  ...texts.regular,
34
- paddingHorizontal: spacings[16],
41
+ flexGrow: 1,
35
42
  outlineStyle: "none",
36
- height: 40,
37
- borderColor: colors.gray[100],
38
43
  placeholderTextColor: colors.gray[400],
39
- borderWidth: 1,
40
- borderRadius: radii[6],
41
- backgroundColor: backgroundColor.accented,
42
44
  color: colors.gray[900],
43
- width: "100%",
44
- flexShrink: 1,
45
+ paddingHorizontal: spacings[8],
46
+ height: 40,
47
+ minWidth: 0,
45
48
  },
46
49
  multilineInput: {
47
50
  height: "auto",
@@ -65,32 +68,29 @@ const styles = StyleSheet.create({
65
68
  borderColor: colors.gray[50],
66
69
  color: colors.gray[900],
67
70
  },
68
- withIcon: {
69
- paddingLeft: spacings[48],
70
- },
71
71
  error: {
72
72
  borderColor: colors.negative[400],
73
- paddingRight: spacings[48],
74
73
  },
75
74
  valid: {
76
75
  borderColor: colors.positive[500],
77
- paddingRight: spacings[48],
78
76
  },
79
77
  readOnlyError: {
80
78
  borderColor: TRANSPARENT,
81
79
  paddingRight: spacings[32],
82
80
  },
83
81
  endIcon: {
84
- position: "absolute",
85
- right: spacings[16],
86
- top: "50%",
87
- transform: "translateY(-50%)",
82
+ marginHorizontal: spacings[8],
83
+ },
84
+ endComponents: {
85
+ flexDirection: "row",
86
+ display: "flex",
87
+ alignItems: "center",
88
+ justifyContent: "center",
89
+ marginLeft: spacings[8],
88
90
  },
89
91
  icon: {
90
- position: "absolute",
91
- left: spacings[16],
92
- top: "50%",
93
- transform: "translateY(-50%)",
92
+ marginLeft: spacings[8],
93
+ margiRight: spacings[4],
94
94
  },
95
95
  readOnlyEndIcon: {
96
96
  right: 0,
@@ -122,9 +122,10 @@ const styles = StyleSheet.create({
122
122
  },
123
123
  });
124
124
  export const LakeTextInput = forwardRef(({ ariaExpanded, ariaControls, error, disabled = false, validating = false, valid = false, readOnly = false, icon, children, unit, color = "gray", inputMode = "text", hideErrors = false, onChange, pattern, style: stylesFromProps, onFocus: originalOnFocus, onBlur: originalOnBlur, value, defaultValue, multiline = false,
125
- //maxCharCount is different from maxLength(props inherited of TextInput), maxLength truncates the text in the limitation asked,
125
+ //maxCharCount is different from maxLength(props inherited of TextInput)
126
+ //maxLength truncates the text in the limitation asked,
126
127
  //maxCharCount doesn't have limitation but displays a counter of characters
127
- maxCharCount, help, ...props }, forwardRef) => {
128
+ maxCharCount, help, renderEnd, ...props }, forwardRef) => {
128
129
  const inputRef = useRef(null);
129
130
  const [isHovered, setIsHovered] = useState(false);
130
131
  const [isFocused, setIsFocused] = useState(false);
@@ -145,19 +146,23 @@ maxCharCount, help, ...props }, forwardRef) => {
145
146
  const isInteractive = !disabled && !readOnly;
146
147
  const hasError = isNotNullishOrEmpty(error);
147
148
  const charCount = isNullish(value) ? 0 : value.length;
148
- return (_jsxs(View, { style: commonStyles.fill, children: [_jsxs(View, { style: styles.root, "aria-errormessage": error, children: [_jsxs(View, { style: styles.container, children: [_jsxs(View, { style: styles.contents, children: [_jsx(TextInput, { "aria-expanded": ariaExpanded, "aria-controls": ariaControls, inputMode: inputMode, ref: mergedRef, ...props, defaultValue: defaultValue, value: isNullish(defaultValue) ? value ?? "" : value, onFocus: onFocus, onBlur: onBlur, readOnly: !isInteractive, onChange: onChange, multiline: multiline, style: [
149
+ return (_jsxs(View, { style: commonStyles.fill, children: [_jsxs(View, { style: styles.root, "aria-errormessage": error, children: [_jsxs(View, { style: styles.container, children: [_jsxs(View, { style: [
150
+ styles.contents,
151
+ isHovered && isInteractive && styles.hovered,
152
+ isFocused && { borderColor: colors[color][500] },
153
+ readOnly && hasError && styles.readOnlyError,
154
+ disabled && styles.disabled,
155
+ readOnly && styles.readOnly,
156
+ isFocused && styles.focused,
157
+ isNotNullish(unit) && styles.inputWithUnit,
158
+ hasError && styles.error,
159
+ valid && styles.valid,
160
+ stylesFromProps,
161
+ ], children: [isNotNullish(icon) && (_jsx(Icon, { name: icon, size: 20, color: colors.current.primary, style: styles.icon })), _jsx(TextInput, { "aria-expanded": ariaExpanded, "aria-controls": ariaControls, inputMode: inputMode, ref: mergedRef, ...props, defaultValue: defaultValue, value: isNullish(defaultValue) ? value ?? "" : value, onFocus: onFocus, onBlur: onBlur, readOnly: !isInteractive, onChange: onChange, multiline: multiline, style: [
149
162
  styles.input,
150
163
  multiline && styles.multilineInput,
151
- hasError && styles.error,
152
- valid && styles.valid,
153
- isNotNullish(icon) && styles.withIcon,
154
164
  readOnly && hasError && styles.readOnlyError,
155
165
  disabled && styles.disabled,
156
166
  readOnly && styles.readOnly,
157
- isHovered && isInteractive && styles.hovered,
158
- isNotNullish(unit) && styles.inputWithUnit,
159
- isFocused && styles.focused,
160
- isFocused && { borderColor: colors[color][500] },
161
- stylesFromProps,
162
- ] }), validating && (_jsx(ActivityIndicator, { size: "small", style: styles.endIcon, color: colors.current[500] })), !validating && hasError && (_jsx(Icon, { name: "warning-regular", size: 20, color: colors.negative[400], style: [styles.endIcon, readOnly && styles.readOnlyEndIcon] })), !validating && !hasError && valid && (_jsx(Icon, { name: "checkmark-filled", size: 20, color: colors.positive[400], style: [styles.endIcon, readOnly && styles.readOnlyEndIcon] })), isNotNullish(icon) && (_jsx(Icon, { name: icon, size: 20, color: colors.current.primary, style: styles.icon }))] }), isNotNullish(unit) && (_jsx(LakeText, { color: colors.gray[900], style: [styles.unit, (disabled || readOnly) && styles.unitDisabled], children: unit }))] }), children] }), !hideErrors && (_jsxs(Box, { direction: "row", style: styles.errorContainer, children: [isNotNullish(help) ? (_jsx(LakeText, { variant: "smallRegular", color: isNotNullish(error) ? colors.negative[500] : colors.gray[500], children: help })) : (_jsx(LakeText, { variant: "smallRegular", color: colors.negative[500], children: error ?? " " })), isNotNullish(maxCharCount) && (_jsxs(_Fragment, { children: [_jsx(Fill, { minWidth: 4 }), _jsxs(LakeText, { variant: "smallRegular", color: charCount > maxCharCount ? colors.negative[500] : colors.gray[400], style: styles.descriptionLimitation, children: [charCount, " / ", maxCharCount] })] }))] }))] }));
167
+ ] }), isNotNullish(renderEnd) && _jsx(View, { style: styles.endComponents, children: renderEnd() }), validating && (_jsx(ActivityIndicator, { size: "small", style: styles.endIcon, color: colors.current[500] })), !validating && hasError && (_jsx(Icon, { name: "warning-regular", size: 20, color: colors.negative[400], style: [styles.endIcon, readOnly && styles.readOnlyEndIcon] })), !validating && !hasError && valid && (_jsx(Icon, { name: "checkmark-filled", size: 20, color: colors.positive[400], style: [styles.endIcon, readOnly && styles.readOnlyEndIcon] }))] }), isNotNullish(unit) && (_jsx(LakeText, { color: colors.gray[900], style: [styles.unit, (disabled || readOnly) && styles.unitDisabled], children: unit }))] }), children] }), !hideErrors && (_jsxs(Box, { direction: "row", style: styles.errorContainer, children: [isNotNullish(help) ? (_jsx(LakeText, { variant: "smallRegular", color: isNotNullish(error) ? colors.negative[500] : colors.gray[500], children: help })) : (_jsx(LakeText, { variant: "smallRegular", color: colors.negative[500], children: error ?? " " })), isNotNullish(maxCharCount) && (_jsxs(_Fragment, { children: [_jsx(Fill, { minWidth: 4 }), _jsxs(LakeText, { variant: "smallRegular", color: charCount > maxCharCount ? colors.negative[500] : colors.gray[400], style: styles.descriptionLimitation, children: [charCount, " / ", maxCharCount] })] }))] }))] }));
163
168
  });
@@ -82,5 +82,5 @@ export const Switch = memo(forwardRef(({ value, disabled = false, onValueChange
82
82
  useNativeDriver: false,
83
83
  }).start();
84
84
  }, [animation, animatedValue]);
85
- return (_jsx(Pressable, { ref: ref, role: "switch", disabled: disabled, onPress: () => onValueChange?.(!value), children: ({ hovered }) => (_jsxs(_Fragment, { children: [_jsx(View, { style: [styles.shadow, hovered && styles.opaque] }), _jsx(View, { style: [styles.base, value && styles.active, disabled && styles.disabled], children: _jsx(View, { ref: buttonRef, style: styles.button, children: _jsx(Icon, { color: colors.positive[400], name: "checkmark-filled", size: 10, style: [styles.icon, value && styles.opaque] }) }) })] })) }));
85
+ return (_jsx(Pressable, { ref: ref, role: "switch", "aria-checked": value, disabled: disabled, onPress: () => onValueChange?.(!value), children: ({ hovered }) => (_jsxs(_Fragment, { children: [_jsx(View, { style: [styles.shadow, hovered && styles.opaque] }), _jsx(View, { style: [styles.base, value && styles.active, disabled && styles.disabled], children: _jsx(View, { ref: buttonRef, style: styles.button, children: _jsx(Icon, { color: colors.positive[400], name: "checkmark-filled", size: 10, style: [styles.icon, value && styles.opaque] }) }) })] })) }));
86
86
  }));
@@ -1,18 +1,15 @@
1
1
  import { IconName } from "./Icon";
2
2
  import { SpacingValue } from "./Space";
3
3
  export declare const tabsViewHeight: number;
4
- type Tab = {
5
- label: string;
4
+ type Tab = ({
5
+ id: string;
6
+ } | {
6
7
  url: string;
7
- icon?: IconName;
8
- withSeparator?: boolean;
8
+ }) & {
9
9
  count?: number;
10
- } | {
11
- label: string;
12
10
  icon?: IconName;
11
+ label: string;
13
12
  withSeparator?: boolean;
14
- count?: number;
15
- id: string;
16
13
  };
17
14
  type Props = {
18
15
  activeTabId?: string;
@@ -125,8 +125,7 @@ const TabViewLink = forwardRef(({ children, style, tab, onChange, activeTabId, o
125
125
  return match(tab)
126
126
  .with({ url: P.string }, ({ url }) => (_jsx(Link, { ref: ref, to: url, style: style, onFocus: onFocus, onBlur: onBlur, onPress: onPress, children: children })))
127
127
  .with({ id: P.string }, ({ id }) => {
128
- const tabId = getTabId(tab);
129
- const isActive = tabId === activeTabId;
128
+ const isActive = id === activeTabId;
130
129
  return (_jsx(PressableText, { ref: ref, style: state => style({ ...state, active: isActive }), onPress: () => {
131
130
  onChange?.(id);
132
131
  onPress?.();
@@ -265,7 +264,7 @@ const DropdownItems = forwardRef(({ tabs, otherLabel, currentUrl, activeTabId, o
265
264
  onHoverEnd,
266
265
  });
267
266
  const mergedRef = useMergeRefs(containerRef, ref);
268
- const activeTab = tabs.find(tab => isTabActive({ activeTabId, currentLocationURL: currentUrl, tab }));
267
+ const activeTab = useMemo(() => tabs.find(tab => isTabActive({ activeTabId, currentLocationURL: currentUrl, tab })), [activeTabId, currentUrl, tabs]);
269
268
  return (_jsxs(View, { style: styles.dropdownHandleContainer, ref: mergedRef, children: [_jsxs(PressableText, { ref: handleRef, role: "button", "aria-expanded": shouldOpen, "aria-haspopup": "true", onFocus: onHandleFocus, onBlur: onAnyBlur, onPress: onPress, style: ({ hovered }) => [
270
269
  styles.link,
271
270
  isNotNullish(activeTab) ? styles.activeLink : hovered ? styles.hoveredLink : null,