@swan-io/lake 13.10.2 → 13.11.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/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
|
|
3
|
-
import { StyleSheet, TextInput, View, } from "react-native";
|
|
3
|
+
import { StyleSheet, Text, TextInput, View, } from "react-native";
|
|
4
|
+
import { t } from "../../../shared-business/src/utils/i18n";
|
|
4
5
|
import { commonStyles } from "../constants/commonStyles";
|
|
5
6
|
import { backgroundColor, colors, invariantColors, radii, shadows, spacings, texts, } from "../constants/design";
|
|
6
7
|
import { useBoolean } from "../hooks/useBoolean";
|
|
@@ -145,6 +146,12 @@ const styles = StyleSheet.create({
|
|
|
145
146
|
list: {
|
|
146
147
|
maxHeight: ITEM_ELEMENT_HEIGHT * NB_SUGGESTION_DISPLAYED,
|
|
147
148
|
},
|
|
149
|
+
emptyList: {
|
|
150
|
+
height: 136,
|
|
151
|
+
},
|
|
152
|
+
emptyListText: {
|
|
153
|
+
color: colors.gray.primary,
|
|
154
|
+
},
|
|
148
155
|
});
|
|
149
156
|
export const LakeSelect = ({ ref, title, items, valueStyle, size, color = "current", disabled = false, mode = "normal", placeholder, readOnly = false, id, matchReferenceMinWidth = true, matchReferenceWidth = false, value, error, hideErrors = false, icon, onValueChange, disabledItems = [], renderItem, PopoverFooter, style, hasSearch = false, searchPlaceholder, }) => {
|
|
150
157
|
var _a;
|
|
@@ -212,6 +219,7 @@ export const LakeSelect = ({ ref, title, items, valueStyle, size, color = "curre
|
|
|
212
219
|
setHighlightApi(filter, (_a = listRef.current) === null || _a === void 0 ? void 0 : _a.element);
|
|
213
220
|
}, [filter, hasSearch]);
|
|
214
221
|
const ListHeaderComponent = useMemo(() => (_jsxs(Box, { direction: "row", alignItems: "center", style: styles.filterContainer, children: [_jsx(TextInput, { autoComplete: "off", inputMode: "search", multiline: false, rows: 1, onChangeText: filterValue => setFilter(filterValue), placeholder: searchPlaceholder, value: filter, onFocus: setFilterFocused.on, onBlur: setFilterFocused.off, style: [styles.filterInput, filterFocused && styles.filterFocused] }), _jsx(Icon, { name: "search-filled", color: colors[color].primary, size: 20, style: styles.searchIcon })] })), [filter, filterFocused, setFilterFocused, searchPlaceholder, color]);
|
|
222
|
+
const ListEmptyComponent = (_jsxs(Box, { justifyContent: "center", alignItems: "center", style: styles.emptyList, children: [_jsx(Icon, { name: "clipboard-search-regular", size: 24, color: colors.gray.primary }), _jsx(Space, { height: 8 }), _jsx(Text, { style: styles.emptyListText, children: t("common.noResult") })] }));
|
|
215
223
|
return (_jsxs(View, { style: commonStyles.fill, children: [_jsx(Pressable, { id: id, ref: mergedRef, "aria-haspopup": "listbox", role: "button", "aria-expanded": visible, disabled: readOnly || disabled, style: ({ focused, hovered, pressed }) => [
|
|
216
224
|
mode === "normal" ? styles.normal : styles.borderless,
|
|
217
225
|
size === "small" && styles.small,
|
|
@@ -234,7 +242,7 @@ export const LakeSelect = ({ ref, title, items, valueStyle, size, color = "curre
|
|
|
234
242
|
styles.itemText,
|
|
235
243
|
styles.selectPlaceholder,
|
|
236
244
|
isSmall && styles.selectSmallPlaceholder,
|
|
237
|
-
], children: placeholder !== null && placeholder !== void 0 ? placeholder : " " }))] }), _jsx(Fill, { minWidth: 8 }), !disabled && (_jsx(Icon, { color: colors.gray[900], name: visible ? "chevron-up-filled" : "chevron-down-filled", size: 16 }))] })] })) }), !hideErrors && (_jsx(LakeText, { variant: "smallRegular", color: colors.negative[500], style: styles.errorText, children: error !== null && error !== void 0 ? error : " " })), _jsxs(Popover, { role: "listbox", matchReferenceWidth: matchReferenceWidth, matchReferenceMinWidth: matchReferenceMinWidth, onDismiss: close, referenceRef: inputRef, returnFocus: true, visible: visible, children: [hasSearch ? ListHeaderComponent : undefined, _jsxs(View, { style: styles.list, children: [isNotNullish(title) && (_jsxs(_Fragment, { children: [_jsx(LakeText, { variant: "semibold", color: colors.gray[900], style: styles.selectListTitle, children: title }), _jsx(Separator, {})] })), _jsx(FlatList, { role: "list", data: filteredItems, ref: listRef, contentContainerStyle: styles.listContent, onKeyDown: (event) => {
|
|
245
|
+
], children: placeholder !== null && placeholder !== void 0 ? placeholder : " " }))] }), _jsx(Fill, { minWidth: 8 }), !disabled && (_jsx(Icon, { color: colors.gray[900], name: visible ? "chevron-up-filled" : "chevron-down-filled", size: 16 }))] })] })) }), !hideErrors && (_jsx(LakeText, { variant: "smallRegular", color: colors.negative[500], style: styles.errorText, children: error !== null && error !== void 0 ? error : " " })), _jsxs(Popover, { role: "listbox", matchReferenceWidth: matchReferenceWidth, matchReferenceMinWidth: matchReferenceMinWidth, onDismiss: close, referenceRef: inputRef, returnFocus: true, visible: visible, children: [hasSearch ? ListHeaderComponent : undefined, _jsxs(View, { style: styles.list, children: [isNotNullish(title) && (_jsxs(_Fragment, { children: [_jsx(LakeText, { variant: "semibold", color: colors.gray[900], style: styles.selectListTitle, children: title }), _jsx(Separator, {})] })), _jsx(FlatList, { role: "list", data: filteredItems, ref: listRef, contentContainerStyle: styles.listContent, ListEmptyComponent: ListEmptyComponent, onKeyDown: (event) => {
|
|
238
246
|
var _a;
|
|
239
247
|
const { key } = event.nativeEvent;
|
|
240
248
|
if (key === "ArrowDown" || key === "ArrowUp") {
|
|
@@ -8,8 +8,9 @@ export type Item<T extends string> = {
|
|
|
8
8
|
type Props<T extends string> = {
|
|
9
9
|
selected: T;
|
|
10
10
|
items: ReadonlyArray<Item<T>>;
|
|
11
|
+
fullWidth?: boolean;
|
|
12
|
+
mobileBreakpoint?: number;
|
|
11
13
|
onValueChange: (value: T) => void;
|
|
12
|
-
minItemWidth?: number;
|
|
13
14
|
};
|
|
14
|
-
export declare const SegmentedControl: <T extends string>(
|
|
15
|
+
export declare const SegmentedControl: <T extends string>(props: Props<T>) => import("react/jsx-runtime").JSX.Element;
|
|
15
16
|
export {};
|
|
@@ -1,45 +1,56 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
import { StyleSheet, View } from "react-native";
|
|
4
|
-
import {
|
|
5
|
-
import { backgroundColor, colors, radii, spacings, texts } from "../constants/design";
|
|
6
|
-
import { isNotNullish } from "../utils/nullish";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { Pressable, StyleSheet, View } from "react-native";
|
|
4
|
+
import { backgroundColor, breakpoints, colors, invariantColors, radii, spacings, } from "../constants/design";
|
|
7
5
|
import { BottomPanel } from "./BottomPanel";
|
|
8
6
|
import { Box } from "./Box";
|
|
9
7
|
import { Icon } from "./Icon";
|
|
10
8
|
import { LakeButton } from "./LakeButton";
|
|
11
9
|
import { LakeText } from "./LakeText";
|
|
12
|
-
import { Pressable } from "./Pressable";
|
|
13
10
|
import { ResponsiveContainer } from "./ResponsiveContainer";
|
|
14
11
|
import { Space } from "./Space";
|
|
12
|
+
const HORIZONTAL_PADDING = 4;
|
|
15
13
|
const styles = StyleSheet.create({
|
|
14
|
+
responsiveContainer: {
|
|
15
|
+
flexDirection: "row",
|
|
16
|
+
justifyContent: "center",
|
|
17
|
+
},
|
|
16
18
|
container: {
|
|
17
|
-
|
|
19
|
+
flexDirection: "row",
|
|
20
|
+
alignItems: "center",
|
|
18
21
|
backgroundColor: colors.gray[50],
|
|
19
|
-
borderRadius:
|
|
22
|
+
borderRadius: 30,
|
|
23
|
+
paddingVertical: 4,
|
|
24
|
+
paddingHorizontal: HORIZONTAL_PADDING,
|
|
20
25
|
},
|
|
21
|
-
|
|
26
|
+
containerFullWidth: {
|
|
27
|
+
width: "100%",
|
|
28
|
+
},
|
|
29
|
+
selectedIndicator: {
|
|
22
30
|
position: "absolute",
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
transitionProperty: "transform",
|
|
28
|
-
transitionDuration: "250ms",
|
|
31
|
+
top: 4,
|
|
32
|
+
bottom: 4,
|
|
33
|
+
backgroundColor: invariantColors.white,
|
|
34
|
+
borderRadius: 30,
|
|
35
|
+
transitionProperty: "transform, width",
|
|
29
36
|
transitionTimingFunction: "ease",
|
|
30
|
-
padding: spacings[4],
|
|
31
|
-
borderRadius: radii[4],
|
|
32
|
-
backgroundColor: backgroundColor.accented,
|
|
33
37
|
},
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
fill: {
|
|
39
|
+
flex: 1,
|
|
40
|
+
},
|
|
41
|
+
item: {
|
|
38
42
|
flexDirection: "row",
|
|
39
|
-
height: 60,
|
|
40
|
-
alignItems: "center",
|
|
41
43
|
justifyContent: "center",
|
|
42
|
-
|
|
44
|
+
alignItems: "center",
|
|
45
|
+
paddingVertical: 12,
|
|
46
|
+
paddingHorizontal: 12,
|
|
47
|
+
borderRadius: 30,
|
|
48
|
+
},
|
|
49
|
+
itemSelected: {
|
|
50
|
+
backgroundColor: invariantColors.white,
|
|
51
|
+
},
|
|
52
|
+
button: {
|
|
53
|
+
borderRadius: 30,
|
|
43
54
|
},
|
|
44
55
|
dropdownItem: {
|
|
45
56
|
backgroundColor: backgroundColor.accented,
|
|
@@ -48,71 +59,70 @@ const styles = StyleSheet.create({
|
|
|
48
59
|
flexDirection: "row",
|
|
49
60
|
height: 60,
|
|
50
61
|
alignItems: "center",
|
|
51
|
-
|
|
62
|
+
flex: 1,
|
|
52
63
|
},
|
|
53
64
|
dropdownItemSelected: {
|
|
54
65
|
backgroundColor: colors.gray[50],
|
|
55
|
-
borderRadius: radii[4],
|
|
56
|
-
padding: spacings[16],
|
|
57
|
-
flexDirection: "row",
|
|
58
|
-
height: 60,
|
|
59
|
-
alignItems: "center",
|
|
60
|
-
flexGrow: 1,
|
|
61
|
-
},
|
|
62
|
-
button: {
|
|
63
|
-
width: 60,
|
|
64
|
-
height: 60,
|
|
65
66
|
},
|
|
66
|
-
|
|
67
|
-
flexBasis: "0%",
|
|
68
|
-
flexGrow: 1,
|
|
69
|
-
flexShrink: 1,
|
|
67
|
+
dropdownCheckIconContainer: {
|
|
70
68
|
alignItems: "center",
|
|
71
|
-
padding: spacings[16],
|
|
72
|
-
flexDirection: "row",
|
|
73
69
|
justifyContent: "center",
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
userSelect: "none",
|
|
77
|
-
lineHeight: texts.regular.fontSize,
|
|
78
|
-
},
|
|
79
|
-
selectedItemDesktop: {
|
|
80
|
-
bottom: 0,
|
|
70
|
+
paddingHorizontal: spacings[24],
|
|
71
|
+
backgroundColor: colors.gray[50],
|
|
81
72
|
},
|
|
82
73
|
});
|
|
83
|
-
export const SegmentedControl = (
|
|
74
|
+
export const SegmentedControl = (props) => {
|
|
75
|
+
const { mobileBreakpoint = breakpoints.small } = props;
|
|
76
|
+
return (_jsx(ResponsiveContainer, { breakpoint: mobileBreakpoint, style: styles.responsiveContainer, children: ({ small }) => small ? _jsx(SegmentedControlMobile, { ...props }) : _jsx(SegmentedControlDesktop, { ...props }) }));
|
|
77
|
+
};
|
|
78
|
+
const SegmentedControlDesktop = ({ selected, items, fullWidth = false, onValueChange, }) => {
|
|
79
|
+
var _a;
|
|
84
80
|
const selectedItemIndex = items.findIndex(item => item.id === selected);
|
|
85
|
-
const
|
|
86
|
-
const [
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
81
|
+
const [itemSizes, setItemSizes] = useState([]);
|
|
82
|
+
const indicatorPosition = (_a = itemSizes[selectedItemIndex]) !== null && _a !== void 0 ? _a : { left: 0, width: 0 };
|
|
83
|
+
const [indicatorRendered, setIndicatorRendered] = useState(false); // use to prevent animation on first render
|
|
84
|
+
const updateItemSize = (event) => {
|
|
85
|
+
// @ts-expect-error target exists in react-native-web
|
|
86
|
+
const target = event.nativeEvent.target;
|
|
87
|
+
const sizes = Array.from(target.children)
|
|
88
|
+
.slice(1) // first child is the selected indicator
|
|
89
|
+
.map(child => ({
|
|
90
|
+
left: child.offsetLeft - HORIZONTAL_PADDING,
|
|
91
|
+
width: child.offsetWidth,
|
|
92
|
+
}));
|
|
93
|
+
setItemSizes(sizes);
|
|
94
|
+
};
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
if (indicatorPosition.width > 0) {
|
|
97
|
+
setIndicatorRendered(true);
|
|
98
|
+
}
|
|
99
|
+
}, [indicatorPosition]);
|
|
100
|
+
return (_jsxs(View, { style: [styles.container, fullWidth && styles.containerFullWidth], onLayout: updateItemSize, children: [_jsx(View, { role: "none", style: [
|
|
101
|
+
styles.selectedIndicator,
|
|
102
|
+
indicatorPosition
|
|
103
|
+
? {
|
|
104
|
+
transitionDuration: indicatorRendered ? "250ms" : "0ms",
|
|
105
|
+
transform: `translateX(${indicatorPosition.left}px)`,
|
|
106
|
+
width: indicatorPosition.width,
|
|
107
|
+
}
|
|
108
|
+
: null,
|
|
109
|
+
] }), items.map(item => {
|
|
110
|
+
const isSelected = item.id === selected;
|
|
111
|
+
return (_jsxs(Pressable, { style: [styles.item, fullWidth && styles.fill], onPress: () => onValueChange(item.id), children: [item.icon != null && (_jsxs(_Fragment, { children: [isSelected && item.activeIcon != null ? item.activeIcon : item.icon, _jsx(Space, { width: 12 })] })), _jsx(LakeText, { color: isSelected ? colors.current[500] : colors.gray[500], children: item.name })] }, item.id));
|
|
112
|
+
})] }));
|
|
113
|
+
};
|
|
114
|
+
const SegmentedControlMobile = ({ selected, items, onValueChange }) => {
|
|
115
|
+
var _a;
|
|
116
|
+
// biome-ignore lint/style/noNonNullAssertion: we're sure to have at least 2 items
|
|
117
|
+
const selectedItem = (_a = items.find(item => item.id === selected)) !== null && _a !== void 0 ? _a : items[0];
|
|
118
|
+
const [menuOpen, setMenuOpen] = useState(false);
|
|
119
|
+
return (_jsxs(View, { style: [styles.container, styles.containerFullWidth], children: [_jsxs(Pressable, { style: [styles.item, styles.itemSelected, styles.fill], onPress: () => setMenuOpen(true), children: [selectedItem.icon != null && (_jsxs(_Fragment, { children: [selectedItem.activeIcon != null ? selectedItem.activeIcon : selectedItem.icon, _jsx(Space, { width: 12 })] })), _jsx(LakeText, { color: colors.current[500], children: selectedItem.name })] }), _jsx(Space, { width: 4 }), _jsx(LakeButton, { mode: "tertiary", size: "small", icon: "more-horizontal-filled", style: styles.button, onPress: () => setMenuOpen(true), ariaLabel: "Open options" }), _jsx(BottomPanel, { visible: menuOpen === true, onPressClose: () => {
|
|
120
|
+
setMenuOpen(false);
|
|
121
|
+
}, children: items.map(item => {
|
|
122
|
+
const isSelected = item.id === selected;
|
|
123
|
+
return (_jsxs(Box, { direction: "row", children: [_jsxs(Pressable, { style: [styles.dropdownItem, isSelected && styles.dropdownItemSelected], onPress: () => {
|
|
98
124
|
onValueChange(item.id);
|
|
99
|
-
|
|
100
|
-
}, children: [
|
|
101
|
-
|
|
102
|
-
.with({ icon: P.nonNullable, activeIcon: P.nonNullable }, () => (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.id) === item.id ? selectedItem.activeIcon : item.icon)
|
|
103
|
-
.with({ icon: P.nonNullable }, () => item.icon)
|
|
104
|
-
.otherwise(() => null), _jsx(Space, { height: 8, width: 12 }), _jsx(LakeText, { color: colors.gray[900], numberOfLines: 1, variant: "regular", style: styles.itemText, children: item.name })] }), (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.id) === item.id && (_jsx(Box, { justifyContent: "center", style: { paddingHorizontal: spacings[24], backgroundColor: colors.gray[50] }, children: _jsx(Icon, { size: 16, name: "lake-check", color: colors.positive[500] }) }))] }, item.id))) }), _jsx(Space, { width: 4 }), _jsx(LakeButton, { mode: "tertiary", style: styles.button, size: "small", icon: "more-horizontal-filled", onPress: () => setPressed(true), ariaLabel: "Previous" })] })) : (_jsxs(Box, { direction: "row", children: [_jsx(View, { role: "none", style: [
|
|
105
|
-
styles.selectedItemIndicator,
|
|
106
|
-
styles.selectedItemDesktop,
|
|
107
|
-
{
|
|
108
|
-
width: `${(1 / items.length) * 100}%`,
|
|
109
|
-
transform: `translateX(${selectedItemIndex * 100}%)`,
|
|
110
|
-
},
|
|
111
|
-
] }), items.map(item => (_jsxs(Pressable, { style: styles.itemDesktop, onPress: () => {
|
|
112
|
-
onValueChange(item.id);
|
|
113
|
-
}, children: [_jsxs(_Fragment, { children: [isNotNullish(item.icon) &&
|
|
114
|
-
match(item)
|
|
115
|
-
.with({ icon: P.nonNullable, activeIcon: P.nonNullable }, () => (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.id) === item.id ? selectedItem.activeIcon : item.icon)
|
|
116
|
-
.with({ icon: P.nonNullable }, () => item.icon)
|
|
117
|
-
.otherwise(() => null), _jsx(Space, { height: 8, width: 12 })] }), _jsx(LakeText, { color: colors.gray[900], numberOfLines: 1, variant: "regular", style: styles.itemText, children: item.name })] }, item.id)))] })) }));
|
|
125
|
+
setMenuOpen(false);
|
|
126
|
+
}, children: [item.icon != null && (_jsxs(_Fragment, { children: [isSelected && item.activeIcon != null ? item.activeIcon : item.icon, _jsx(Space, { width: 12 })] })), _jsx(Space, { height: 8, width: 12 }), _jsx(LakeText, { color: colors.gray[900], numberOfLines: 1, variant: "regular", children: item.name })] }), isSelected && (_jsx(View, { style: styles.dropdownCheckIconContainer, children: _jsx(Icon, { size: 16, name: "lake-check", color: colors.positive[500] }) }))] }, item.id));
|
|
127
|
+
}) })] }));
|
|
118
128
|
};
|