@swan-io/lake 1.0.0 → 1.2.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 +4 -5
- package/src/components/FilterChooser.d.ts +1 -3
- package/src/components/Filters.d.ts +8 -2
- package/src/components/Filters.js +4 -0
- package/src/components/InputError.js +1 -1
- package/src/components/LakeCombobox.d.ts +2 -1
- package/src/components/LakeCombobox.js +10 -2
- package/src/components/LakeLabel.d.ts +3 -2
- package/src/components/LakeLabel.js +6 -1
- package/src/components/LakeModal.js +1 -1
- package/src/components/LakeStepper.js +4 -1
- package/src/components/LakeTextInput.d.ts +2 -0
- package/src/components/LakeTextInput.js +3 -3
- package/src/components/PlainListView.js +1 -1
- package/src/components/RadioGroup.js +11 -2
- package/src/components/Switch.js +1 -1
- package/src/components/TabView.d.ts +3 -1
- package/src/components/TabView.js +5 -4
- package/src/constants/commonStyles.d.ts +4 -0
- package/src/constants/commonStyles.js +1 -0
- package/src/utils/rifm.d.ts +2 -2
- package/HISTORY.md +0 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swan-io/lake",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=14.0.0",
|
|
6
6
|
"yarn": "^1.20.0"
|
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
"LICENSE",
|
|
10
10
|
"src/**/*.js",
|
|
11
11
|
"src/**/*.d.ts",
|
|
12
|
-
"README.md"
|
|
13
|
-
"HISTORY.md"
|
|
12
|
+
"README.md"
|
|
14
13
|
],
|
|
15
14
|
"publishConfig": {
|
|
16
15
|
"access": "public",
|
|
@@ -23,6 +22,7 @@
|
|
|
23
22
|
"not ie <= 11",
|
|
24
23
|
"safari >= 12"
|
|
25
24
|
],
|
|
25
|
+
"license": "MIT",
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@popperjs/core": "2.11.6",
|
|
28
28
|
"@swan-io/boxed": "0.12.1",
|
|
@@ -32,7 +32,6 @@
|
|
|
32
32
|
"polished": "4.2.2",
|
|
33
33
|
"prism-react-renderer": "1.3.5",
|
|
34
34
|
"react": "18.2.0",
|
|
35
|
-
"react-atomic-state": "1.2.7",
|
|
36
35
|
"react-dom": "18.2.0",
|
|
37
36
|
"react-dropzone": "14.2.3",
|
|
38
37
|
"react-fast-compare": "3.2.0",
|
|
@@ -40,6 +39,7 @@
|
|
|
40
39
|
"react-popper": "2.3.0",
|
|
41
40
|
"react-ux-form": "1.3.0",
|
|
42
41
|
"rifm": "0.12.1",
|
|
42
|
+
"ts-dedent": "2.2.0",
|
|
43
43
|
"ts-pattern": "4.2.1",
|
|
44
44
|
"urql": "3.0.3",
|
|
45
45
|
"uuid": "9.0.0"
|
|
@@ -53,7 +53,6 @@
|
|
|
53
53
|
"@types/react-native": "0.70.11",
|
|
54
54
|
"@types/uuid": "9.0.1",
|
|
55
55
|
"jsdom": "21.1.0",
|
|
56
|
-
"ts-dedent": "2.2.0",
|
|
57
56
|
"type-fest": "3.6.1",
|
|
58
57
|
"vitest": "0.29.2"
|
|
59
58
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
export declare function FilterChooser<FilterName extends string>({ filters, openFilters, label, title, availableFilters, large, onAddFilter, }: {
|
|
3
|
-
filters: Partial<
|
|
4
|
-
[K in FilterName]: string | string[] | undefined;
|
|
5
|
-
}>;
|
|
3
|
+
filters: Partial<Record<FilterName, unknown>>;
|
|
6
4
|
openFilters: FilterName[];
|
|
7
5
|
label: string;
|
|
8
6
|
title: string;
|
|
@@ -36,12 +36,18 @@ export type FilterInputDef = {
|
|
|
36
36
|
placeholder?: string;
|
|
37
37
|
validate?: (value: string) => ValidatorResult;
|
|
38
38
|
};
|
|
39
|
-
type
|
|
39
|
+
export type FilterBooleanDef = {
|
|
40
|
+
type: "boolean";
|
|
41
|
+
label: string;
|
|
42
|
+
};
|
|
43
|
+
type Filter<T> = FilterCheckboxDef<T> | FilterRadioDef<T> | FilterDateDef | FilterInputDef | FilterBooleanDef;
|
|
40
44
|
type ExtractFilterValue<T extends Filter<unknown>> = T extends {
|
|
41
45
|
type: "checkbox";
|
|
42
46
|
} ? T["items"][number]["value"][] | undefined : T extends {
|
|
43
47
|
type: "radio";
|
|
44
|
-
} ? T["items"][number]["value"] | undefined :
|
|
48
|
+
} ? T["items"][number]["value"] | undefined : T extends {
|
|
49
|
+
type: "boolean";
|
|
50
|
+
} ? boolean | undefined : string | undefined;
|
|
45
51
|
type FiltersDefinition = Record<string, Filter<unknown>>;
|
|
46
52
|
export type FiltersState<T extends FiltersDefinition> = Simplify<{
|
|
47
53
|
[K in keyof T]: Simplify<ExtractFilterValue<T[K]>>;
|
|
@@ -224,6 +224,10 @@ export const FiltersStack = ({ filters, openedFilters, definition, onChangeOpene
|
|
|
224
224
|
onChangeFilters({ ...filters, [filterName]: undefined });
|
|
225
225
|
onChangeOpened(openedFilters.filter(f => f !== filterName));
|
|
226
226
|
} })))
|
|
227
|
+
.with({ type: "boolean" }, ({ label }) => (_jsx(Tag, { color: "current", onPressRemove: () => {
|
|
228
|
+
onChangeFilters({ ...filters, [filterName]: undefined });
|
|
229
|
+
onChangeOpened(openedFilters.filter(f => f !== filterName));
|
|
230
|
+
}, children: label })))
|
|
227
231
|
.exhaustive() }, filterName));
|
|
228
232
|
}) }));
|
|
229
233
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { StyleSheet, Text } from "react-native";
|
|
3
|
+
import { Space } from "./Space";
|
|
3
4
|
import { colors } from "../constants/colors";
|
|
4
5
|
import { typography } from "../constants/typography";
|
|
5
|
-
import { Space } from "./Space";
|
|
6
6
|
const styles = StyleSheet.create({
|
|
7
7
|
base: {
|
|
8
8
|
...typography.bodySmall,
|
|
@@ -2,6 +2,7 @@ import { AsyncData, Result } from "@swan-io/boxed";
|
|
|
2
2
|
import { ForwardedRef, ReactNode, RefObject } from "react";
|
|
3
3
|
import { IconName } from "./Icon";
|
|
4
4
|
export type LakeComboboxProps<I> = {
|
|
5
|
+
inputRef?: RefObject<unknown>;
|
|
5
6
|
value: string;
|
|
6
7
|
items: AsyncData<Result<I[], unknown>>;
|
|
7
8
|
ListFooterComponent?: ReactNode;
|
|
@@ -21,7 +22,7 @@ export type LakeComboboxRef = {
|
|
|
21
22
|
close: () => void;
|
|
22
23
|
open: () => void;
|
|
23
24
|
};
|
|
24
|
-
declare const LakeComboboxWithRef: <I>({ value, items, ListFooterComponent, onValueChange, onSelectItem, renderItem, keyExtractor, icon, placeholder, disabled, emptyResultText, readOnly, nativeID, error, }: LakeComboboxProps<I>, externalRef: ForwardedRef<LakeComboboxRef>) => JSX.Element;
|
|
25
|
+
declare const LakeComboboxWithRef: <I>({ inputRef, value, items, ListFooterComponent, onValueChange, onSelectItem, renderItem, keyExtractor, icon, placeholder, disabled, emptyResultText, readOnly, nativeID, error, }: LakeComboboxProps<I>, externalRef: ForwardedRef<LakeComboboxRef>) => JSX.Element;
|
|
25
26
|
export declare const LakeCombobox: <I>(props: LakeComboboxProps<I> & {
|
|
26
27
|
ref?: RefObject<LakeComboboxRef> | undefined;
|
|
27
28
|
}) => ReturnType<typeof LakeComboboxWithRef>;
|
|
@@ -4,6 +4,7 @@ import { FlatList, Pressable, StyleSheet, Text, View, } from "react-native";
|
|
|
4
4
|
import { backgroundColor, colors, spacings } from "../constants/design";
|
|
5
5
|
import { typography } from "../constants/typography";
|
|
6
6
|
import { useDisclosure } from "../hooks/useDisclosure";
|
|
7
|
+
import { useMergeRefs } from "../hooks/useMergeRefs";
|
|
7
8
|
import { getFocusableElements } from "../utils/a11y";
|
|
8
9
|
import { Box } from "./Box";
|
|
9
10
|
import { Icon } from "./Icon";
|
|
@@ -80,8 +81,10 @@ const getItemLayout = (_data, index) => ({
|
|
|
80
81
|
offset: ELEMENT_HEIGHT * index,
|
|
81
82
|
index,
|
|
82
83
|
});
|
|
83
|
-
const LakeComboboxWithRef = ({ value, items, ListFooterComponent, onValueChange, onSelectItem, renderItem, keyExtractor, icon, placeholder, disabled = false, emptyResultText, readOnly, nativeID, error, }, externalRef) => {
|
|
84
|
+
const LakeComboboxWithRef = ({ inputRef, value, items, ListFooterComponent, onValueChange, onSelectItem, renderItem, keyExtractor, icon, placeholder, disabled = false, emptyResultText, readOnly, nativeID, error, }, externalRef) => {
|
|
84
85
|
const ref = useRef(null);
|
|
86
|
+
// @ts-expect-error
|
|
87
|
+
const inputTextRef = useMergeRefs(ref, inputRef);
|
|
85
88
|
const listRef = useRef(null);
|
|
86
89
|
const listContainerRef = useRef(null);
|
|
87
90
|
const blurTimeoutId = useRef(undefined);
|
|
@@ -140,7 +143,11 @@ const LakeComboboxWithRef = ({ value, items, ListFooterComponent, onValueChange,
|
|
|
140
143
|
close();
|
|
141
144
|
}, 100);
|
|
142
145
|
}, [close]);
|
|
143
|
-
return (_jsxs(View, { children: [_jsx(LakeTextInput
|
|
146
|
+
return (_jsxs(View, { children: [_jsx(LakeTextInput
|
|
147
|
+
// @ts-expect-error
|
|
148
|
+
, {
|
|
149
|
+
// @ts-expect-error
|
|
150
|
+
ref: inputTextRef, style: styles.input, accessibilityExpanded: isFocused, accessibilityControls: isFocused ? suggestionsId : "", returnKeyType: "search", icon: icon, accessibilityRole: "combobox", placeholder: placeholder, value: value, disabled: disabled, error: error, onChangeText: onValueChange, onFocus: handleFocus, onBlur: handleBlur, onKeyPress: handleKeyPress, nativeID: nativeID, readOnly: readOnly }), _jsx(Popover, { id: suggestionsId, role: "listbox", matchReferenceWidth: true, onDismiss: close, referenceRef: ref, autoFocus: true, returnFocus: false, visible: isFocused && !items.isNotAsked(), underlay: false, forcedMode: "Dropdown", children: _jsx(View, { style: styles.list, children: items.match({
|
|
144
151
|
NotAsked: () => null,
|
|
145
152
|
Loading: () => _jsx(LoadingView, { style: styles.loader }),
|
|
146
153
|
Done: items => items.match({
|
|
@@ -153,6 +160,7 @@ const LakeComboboxWithRef = ({ value, items, ListFooterComponent, onValueChange,
|
|
|
153
160
|
focused && styles.focusedItem,
|
|
154
161
|
pressed && styles.pressedItem,
|
|
155
162
|
], onPress: () => {
|
|
163
|
+
window.clearTimeout(blurTimeoutId.current);
|
|
156
164
|
setIsFetchingAdditionalInfo(true);
|
|
157
165
|
Promise.resolve(onSelectItem(item)).finally(() => {
|
|
158
166
|
setIsFetchingAdditionalInfo(false);
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
2
|
import { StyleProp, ViewStyle } from "react-native";
|
|
3
3
|
import { ColorVariants } from "../constants/design";
|
|
4
|
+
type LabelType = "form" | "formSmall" | "view" | "viewSmall" | "radioGroup";
|
|
4
5
|
type Props = {
|
|
5
6
|
label: string;
|
|
6
7
|
optionalLabel?: string;
|
|
7
8
|
readOnlyColor?: string;
|
|
8
9
|
color?: ColorVariants;
|
|
9
|
-
type?:
|
|
10
|
+
type?: LabelType;
|
|
10
11
|
extra?: () => ReactNode;
|
|
11
12
|
help?: ReactNode;
|
|
12
13
|
render: (id: string) => ReactNode;
|
|
@@ -14,6 +15,6 @@ type Props = {
|
|
|
14
15
|
readOnly?: boolean;
|
|
15
16
|
style?: StyleProp<ViewStyle>;
|
|
16
17
|
};
|
|
17
|
-
export declare const defaultLabelType:
|
|
18
|
+
export declare const defaultLabelType: LabelType;
|
|
18
19
|
export declare const LakeLabel: ({ label, optionalLabel, extra, readOnly, color, readOnlyColor, type, help, render, actions, style, }: Props) => JSX.Element;
|
|
19
20
|
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useRef, useState } from "react";
|
|
3
3
|
import { StyleSheet, unstable_createElement, View, } from "react-native";
|
|
4
|
+
import { match } from "ts-pattern";
|
|
4
5
|
import { v4 as uuid } from "uuid";
|
|
5
6
|
import { commonStyles } from "../constants/commonStyles";
|
|
6
7
|
import { colors, fonts, spacings, texts } from "../constants/design";
|
|
@@ -39,5 +40,9 @@ export const LakeLabel = ({ label, optionalLabel, extra, readOnly = false, color
|
|
|
39
40
|
target?.focus();
|
|
40
41
|
}
|
|
41
42
|
}, [id]);
|
|
42
|
-
return (_jsxs(Box, { style: [styles.container, style], direction: "row", alignItems: "center", justifyContent: "spaceBetween", children: [_jsxs(View, { style: commonStyles.fill, ref: containerRef, children: [_jsxs(Box, { direction: "row", justifyContent: "spaceBetween", alignItems: "center", children: [_jsxs(Box, { direction: "row", style: styles.shrink, children: [type === "form" || type === "formSmall" ? (_jsxs(Label, { onClick: onClick, htmlFor: id, style: [styles.label, readOnly && { color: readOnlyColor }], children: [label, optionalLabel != null ? (_jsxs(_Fragment, { children: [" - ", _jsx(LakeText, { color: colors.gray[400], style: styles.optionalLabel, children: optionalLabel })] })) : null] })) : (_jsxs(LakeText, { variant: "medium", color: readOnlyColor, nativeID: id, children: [label, optionalLabel != null ? (_jsxs(_Fragment, { children: [" - ", _jsx(LakeText, { color: colors.gray[400], style: styles.optionalLabel, children: optionalLabel })] })) : null] })), isNotNullish(extra) && extra()] }), isNotNullish(help) && (_jsxs(_Fragment, { children: [_jsx(Space, { width: 16 }), help] }))] }), _jsx(Space, { height:
|
|
43
|
+
return (_jsxs(Box, { style: [styles.container, style], direction: "row", alignItems: "center", justifyContent: "spaceBetween", children: [_jsxs(View, { style: commonStyles.fill, ref: containerRef, children: [_jsxs(Box, { direction: "row", justifyContent: "spaceBetween", alignItems: "center", children: [_jsxs(Box, { direction: "row", style: styles.shrink, children: [type === "form" || type === "formSmall" || type === "radioGroup" ? (_jsxs(Label, { onClick: onClick, htmlFor: id, style: [styles.label, readOnly && { color: readOnlyColor }], children: [label, optionalLabel != null ? (_jsxs(_Fragment, { children: [" - ", _jsx(LakeText, { color: colors.gray[400], style: styles.optionalLabel, children: optionalLabel })] })) : null] })) : (_jsxs(LakeText, { variant: "medium", color: readOnlyColor, nativeID: id, children: [label, optionalLabel != null ? (_jsxs(_Fragment, { children: [" - ", _jsx(LakeText, { color: colors.gray[400], style: styles.optionalLabel, children: optionalLabel })] })) : null] })), isNotNullish(extra) && extra()] }), isNotNullish(help) && (_jsxs(_Fragment, { children: [_jsx(Space, { width: 16 }), help] }))] }), _jsx(Space, { height: match(type)
|
|
44
|
+
.with("formSmall", "viewSmall", () => 4)
|
|
45
|
+
.with("form", "view", () => 8)
|
|
46
|
+
.with("radioGroup", () => 12)
|
|
47
|
+
.exhaustive() }), _jsx(View, { accessibilityLabelledBy: type === "view" || type === "viewSmall" ? id : undefined, children: render(id) })] }), isNotNullish(actions) && (_jsxs(_Fragment, { children: [_jsx(Space, { width: 16 }), actions] }))] }));
|
|
43
48
|
};
|
|
@@ -128,5 +128,5 @@ export const LakeModal = ({ visible, icon, title, color = "current", children, m
|
|
|
128
128
|
if (rootElement == null) {
|
|
129
129
|
return null;
|
|
130
130
|
}
|
|
131
|
-
return (_jsx(Portal, { container: rootElement, children: _jsxs(View, { accessibilityModal: true, style: styles.container, pointerEvents: visible ? "auto" : "none", children: [_jsx(TransitionView, { style: styles.fill, enter: styles.overlayEnter, leave: styles.overlayLeave, children: visible ? _jsx(View, { style: styles.overlay }) : null }), _jsx(Suspense, { fallback: _jsx(LoadingView, { color: backgroundColor.accented, delay: 0 }), children: _jsx(TransitionView, { style: styles.fill, enter: styles.modalEnter, leave: styles.modalLeave, children: visible ? (_jsx(ResponsiveContainer, { style: styles.root, breakpoint: breakpoints.tiny, children: ({ large, small }) => (_jsx(FocusTrap, { autoFocus: true, focusLock: true, returnFocus: true, onEscapeKey: onPressClose, style: styles.trap, children: _jsxs(ScrollView, { style: styles.modalContainer, contentContainerStyle: large ? styles.modalContentContainer : styles.modalContentContainerSmall, children: [onPressClose != null ? (_jsx(Pressable, { onPress: onPressClose, style: styles.pressableOverlay })) : null, _jsxs(View, { style: [large ? styles.modal : styles.modalSmall, { maxWidth }], children: [_jsxs(View, { style: styles.modalHeader, children: [_jsxs(View, { style: styles.modalIconTitle, children: [icon != null ? (_jsx(Icon, { name: icon, size: large ? 40 : 32, color: colors[color]
|
|
131
|
+
return (_jsx(Portal, { container: rootElement, children: _jsxs(View, { accessibilityModal: true, style: styles.container, pointerEvents: visible ? "auto" : "none", children: [_jsx(TransitionView, { style: styles.fill, enter: styles.overlayEnter, leave: styles.overlayLeave, children: visible ? _jsx(View, { style: styles.overlay }) : null }), _jsx(Suspense, { fallback: _jsx(LoadingView, { color: backgroundColor.accented, delay: 0 }), children: _jsx(TransitionView, { style: styles.fill, enter: styles.modalEnter, leave: styles.modalLeave, children: visible ? (_jsx(ResponsiveContainer, { style: styles.root, breakpoint: breakpoints.tiny, children: ({ large, small }) => (_jsx(FocusTrap, { autoFocus: true, focusLock: true, returnFocus: true, onEscapeKey: onPressClose, style: styles.trap, children: _jsxs(ScrollView, { style: styles.modalContainer, contentContainerStyle: large ? styles.modalContentContainer : styles.modalContentContainerSmall, children: [onPressClose != null ? (_jsx(Pressable, { onPress: onPressClose, style: styles.pressableOverlay })) : null, _jsxs(View, { style: [large ? styles.modal : styles.modalSmall, { maxWidth }], children: [_jsxs(View, { style: styles.modalHeader, children: [_jsxs(View, { style: styles.modalIconTitle, children: [icon != null ? (_jsx(Icon, { name: icon, size: large ? 40 : 32, color: colors[color][500] })) : null, icon != null && title != null ? _jsx(Space, { height: 12 }) : null, title != null ? (_jsxs(_Fragment, { children: [_jsx(LakeHeading, { level: 2, variant: "h3", children: title }), _jsx(Space, { height: 12 })] })) : null] }), onPressClose != null ? (_jsx(LakeButton, { style: styles.closeButton, mode: "tertiary", onPress: onPressClose, icon: "lake-close" })) : null] }), typeof children == "function" ? children({ large, small }) : children] })] }) })) })) : null }) })] }) }));
|
|
132
132
|
};
|
|
@@ -13,6 +13,9 @@ const linkStyle = {
|
|
|
13
13
|
textDecoration: "none",
|
|
14
14
|
};
|
|
15
15
|
const styles = StyleSheet.create({
|
|
16
|
+
container: {
|
|
17
|
+
alignItems: "flex-end",
|
|
18
|
+
},
|
|
16
19
|
bar: {
|
|
17
20
|
width: "100%",
|
|
18
21
|
height: 4,
|
|
@@ -70,7 +73,7 @@ export const LakeStepper = ({ steps, activeStepId, style }) => {
|
|
|
70
73
|
.exhaustive())
|
|
71
74
|
.flat();
|
|
72
75
|
const activeStepIndex = stepIds.indexOf(activeStepId);
|
|
73
|
-
return (_jsx(Grid, { numColumns: steps.length, horizontalSpace: 12, style: style, children: steps.map((step, index) => {
|
|
76
|
+
return (_jsx(Grid, { numColumns: steps.length, horizontalSpace: 12, style: [styles.container, style], children: steps.map((step, index) => {
|
|
74
77
|
const stepNumber = index + 1;
|
|
75
78
|
const currentId = match(step)
|
|
76
79
|
.with({ id: P.string }, ({ id }) => id)
|
|
@@ -5,6 +5,7 @@ import { IconName } from "./Icon";
|
|
|
5
5
|
export type LakeTextInputProps = Omit<TextInputProps, "editable" | "onChange"> & {
|
|
6
6
|
error?: string;
|
|
7
7
|
readOnly?: boolean;
|
|
8
|
+
validating?: boolean;
|
|
8
9
|
valid?: boolean;
|
|
9
10
|
disabled?: boolean;
|
|
10
11
|
color?: ColorVariants;
|
|
@@ -21,6 +22,7 @@ export type LakeTextInputProps = Omit<TextInputProps, "editable" | "onChange"> &
|
|
|
21
22
|
export declare const LakeTextInput: import("react").ForwardRefExoticComponent<Omit<TextInputProps, "editable" | "onChange"> & {
|
|
22
23
|
error?: string | undefined;
|
|
23
24
|
readOnly?: boolean | undefined;
|
|
25
|
+
validating?: boolean | undefined;
|
|
24
26
|
valid?: boolean | undefined;
|
|
25
27
|
disabled?: boolean | undefined;
|
|
26
28
|
color?: "warning" | "current" | "gray" | "live" | "sandbox" | "positive" | "negative" | "partner" | "swan" | "shakespear" | "darkPink" | "sunglow" | "mediumSladeBlue" | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef, useCallback, useRef, useState } from "react";
|
|
3
|
-
import { StyleSheet, TextInput, View, } from "react-native";
|
|
3
|
+
import { ActivityIndicator, StyleSheet, TextInput, View, } from "react-native";
|
|
4
4
|
import { commonStyles } from "../constants/commonStyles";
|
|
5
5
|
import { backgroundColor, colors, radii, shadows, spacings, texts, } from "../constants/design";
|
|
6
6
|
import { useHover } from "../hooks/useHover";
|
|
@@ -116,7 +116,7 @@ const styles = StyleSheet.create({
|
|
|
116
116
|
boxShadow: shadows.tile,
|
|
117
117
|
},
|
|
118
118
|
});
|
|
119
|
-
export const LakeTextInput = forwardRef(({ error, disabled = false, valid = false, readOnly = false, icon, children, unit, color = "gray", keyboardType = "default", hideErrors = false, onChange, pattern, style: stylesFromProps, onFocus: originalOnFocus, onBlur: originalOnBlur, value, defaultValue, multiline = false, ...props }, forwardRef) => {
|
|
119
|
+
export const LakeTextInput = forwardRef(({ error, disabled = false, validating = false, valid = false, readOnly = false, icon, children, unit, color = "gray", keyboardType = "default", hideErrors = false, onChange, pattern, style: stylesFromProps, onFocus: originalOnFocus, onBlur: originalOnBlur, value, defaultValue, multiline = false, ...props }, forwardRef) => {
|
|
120
120
|
const inputRef = useRef(null);
|
|
121
121
|
const [isHovered, setIsHovered] = useState(false);
|
|
122
122
|
const [isFocused, setIsFocused] = useState(false);
|
|
@@ -150,5 +150,5 @@ export const LakeTextInput = forwardRef(({ error, disabled = false, valid = fals
|
|
|
150
150
|
isFocused && styles.focused,
|
|
151
151
|
isFocused && { borderColor: colors[color][500] },
|
|
152
152
|
stylesFromProps,
|
|
153
|
-
] }), hasError && (_jsx(Icon, { name: "warning-regular", size: 20, color: colors.negative[400], style: [styles.endIcon, readOnly && styles.readOnlyEndIcon] })), !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 && (_jsx(LakeText, { color: colors.negative[400], style: styles.errorText, children: error ?? " " }))] }));
|
|
153
|
+
] }), 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 && (_jsx(LakeText, { color: colors.negative[400], style: styles.errorText, children: error ?? " " }))] }));
|
|
154
154
|
});
|
|
@@ -194,7 +194,7 @@ export const PlainListView = ({ data: originalData, keyExtractor, rowHeight, gro
|
|
|
194
194
|
], children: _jsx(LakeHeading, { level: 3, variant: "h3", children: groupName }) })) : null, items.map((item, index) => {
|
|
195
195
|
const key = keyExtractor(item, index);
|
|
196
196
|
const isActive = activeRowId === key;
|
|
197
|
-
const isHovered = hoveredRow === key;
|
|
197
|
+
const isHovered = isNotNullish(getRowLink) && hoveredRow === key;
|
|
198
198
|
const wrapper = createRowWrapper({ item, absoluteIndex: index, extraInfo });
|
|
199
199
|
return cloneElement(wrapper, {
|
|
200
200
|
style: { ...styles.rowLink, ...wrapper.props.style },
|
|
@@ -16,10 +16,15 @@ const styles = StyleSheet.create({
|
|
|
16
16
|
flexDirection: "row",
|
|
17
17
|
alignItems: "center",
|
|
18
18
|
},
|
|
19
|
-
|
|
19
|
+
withRightSpace: {
|
|
20
20
|
// use margin instead of <Space /> to avoid line starting with <Space /> because of flex-wrap
|
|
21
21
|
marginRight: 24,
|
|
22
22
|
},
|
|
23
|
+
// We need this bottom margin in case there are too much items and some of them are wrapped to next line
|
|
24
|
+
withBottomSpace: {
|
|
25
|
+
// use margin instead of <Space /> to avoid making height bigger than expected
|
|
26
|
+
marginBottom: 12,
|
|
27
|
+
},
|
|
23
28
|
});
|
|
24
29
|
export function RadioGroup({ items, direction = "column", color = "current", disabled = false, value, onValueChange, }) {
|
|
25
30
|
return (_jsx(Box, { direction: direction, style: styles.container, children: items.map((item, index) => {
|
|
@@ -29,6 +34,10 @@ export function RadioGroup({ items, direction = "column", color = "current", dis
|
|
|
29
34
|
if (item.value !== value) {
|
|
30
35
|
onValueChange(item.value);
|
|
31
36
|
}
|
|
32
|
-
}, style: [
|
|
37
|
+
}, style: [
|
|
38
|
+
styles.item,
|
|
39
|
+
direction === "row" && styles.withBottomSpace,
|
|
40
|
+
direction === "row" && !isLast && styles.withRightSpace,
|
|
41
|
+
], children: [_jsx(LakeRadio, { disabled: isDisabled, color: color, value: item.value === value }), _jsx(Space, { width: 12 }), _jsx(LakeText, { color: isDisabled ? colors.gray[300] : colors.gray[900], children: item.name })] }), !isLast && _jsx(Space, { height: direction === "column" ? 12 : undefined })] }, index));
|
|
33
42
|
}) }));
|
|
34
43
|
}
|
package/src/components/Switch.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef, memo, useEffect } from "react";
|
|
3
3
|
import { Animated, Pressable, StyleSheet, View } from "react-native";
|
|
4
|
+
import { Icon } from "./Icon";
|
|
4
5
|
import { backgroundColor, colors, shadows } from "../constants/design";
|
|
5
6
|
import { useAnimatedValue } from "../hooks/useAnimatedValue";
|
|
6
|
-
import { Icon } from "./Icon";
|
|
7
7
|
const WIDTH = 36;
|
|
8
8
|
const BUTTON_SIZE = 16;
|
|
9
9
|
const PADDING = 2;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { IconName } from "@swan-io/lake/src/components/Icon";
|
|
3
|
+
import { SpacingValue } from "@swan-io/lake/src/components/Space";
|
|
3
4
|
type Tab = {
|
|
4
5
|
label: string;
|
|
5
6
|
url: string;
|
|
@@ -11,6 +12,7 @@ type Props = {
|
|
|
11
12
|
tabs: Tab[];
|
|
12
13
|
otherLabel: string;
|
|
13
14
|
hideIfSingleItem?: boolean;
|
|
15
|
+
padding?: SpacingValue;
|
|
14
16
|
};
|
|
15
|
-
export declare const TabView: ({ tabs, otherLabel, hideIfSingleItem }: Props) => JSX.Element | null;
|
|
17
|
+
export declare const TabView: ({ tabs, otherLabel, hideIfSingleItem, padding }: Props) => JSX.Element | null;
|
|
16
18
|
export {};
|
|
@@ -249,7 +249,7 @@ const DropdownItems = forwardRef(({ tabs, otherLabel, currentUrl }, ref) => {
|
|
|
249
249
|
isNotNullish(activeTab) ? styles.activeLink : hovered ? styles.hoveredLink : null,
|
|
250
250
|
], children: [_jsx(Text, { children: otherLabel }), _jsx(Space, { width: 8 }), _jsx(Text, { style: styles.count, children: tabs.length }), _jsx(Space, { width: 4 }), _jsx(Icon, { name: "chevron-down-filled", size: 12 })] }), _jsx(TransitionView, { ...animations.fadeAndSlideInFromBottom, style: styles.dropdownPlacement, children: shouldOpen ? (_jsx(FocusTrap, { autoFocus: shouldAutoFocus, focusLock: shouldLockFocus, returnFocus: shouldLockFocus, onClickOutside: onPressOutside, onEscapeKey: shouldLockFocus ? onEscapeKey : undefined, children: _jsx(Dropdown, { tabs: tabs, onHoverStart: onHoverStart, onHoverEnd: onHoverEnd, onLinkFocus: onLinkFocus, onLinkBlur: onAnyBlur, onLinkPress: onEscapeKey }) })) : null })] }));
|
|
251
251
|
});
|
|
252
|
-
export const TabView = ({ tabs, otherLabel, hideIfSingleItem = true }) => {
|
|
252
|
+
export const TabView = ({ tabs, otherLabel, hideIfSingleItem = true, padding }) => {
|
|
253
253
|
const containerRef = useRef(null);
|
|
254
254
|
const placeholderRef = useRef(null);
|
|
255
255
|
const otherPlaceholderRef = useRef(null);
|
|
@@ -268,14 +268,15 @@ export const TabView = ({ tabs, otherLabel, hideIfSingleItem = true }) => {
|
|
|
268
268
|
for (const [link, node] of values) {
|
|
269
269
|
if ("/" + path.join("/") === link && isNotNullish(node) && isNotNullish(container)) {
|
|
270
270
|
node.measureLayout(container, (left, _, width) => {
|
|
271
|
-
|
|
271
|
+
const leftOffset = padding ?? 0;
|
|
272
|
+
setUnderlinePosition({ left: left - leftOffset, width });
|
|
272
273
|
}, noop);
|
|
273
274
|
return;
|
|
274
275
|
}
|
|
275
276
|
}
|
|
276
277
|
}
|
|
277
278
|
setUnderlinePosition({ left: 0, width: 0 });
|
|
278
|
-
}, [path, kept, collapsed]);
|
|
279
|
+
}, [path, kept, collapsed, padding]);
|
|
279
280
|
useEffect(() => {
|
|
280
281
|
setHasRendered(width > 0);
|
|
281
282
|
}, [width]);
|
|
@@ -370,7 +371,7 @@ export const TabView = ({ tabs, otherLabel, hideIfSingleItem = true }) => {
|
|
|
370
371
|
if (tabs.length <= 1 && hideIfSingleItem) {
|
|
371
372
|
return null;
|
|
372
373
|
}
|
|
373
|
-
return (_jsxs(Box, { alignItems: "center", direction: "row", accessibilityRole: "tablist", ref: containerRef, style: styles.container, children: [_jsxs(View, { style: styles.placeholder, accessibilityHidden: true, ref: placeholderRef, pointerEvents: "none", onLayout: onLayout, children: [tabs.map(({ label, url, icon, count }) => (_jsxs(Fragment, { children: [_jsxs(Link, { ref: ref => {
|
|
374
|
+
return (_jsxs(Box, { alignItems: "center", direction: "row", accessibilityRole: "tablist", ref: containerRef, style: [styles.container, { paddingHorizontal: padding }], children: [_jsxs(View, { style: styles.placeholder, accessibilityHidden: true, ref: placeholderRef, pointerEvents: "none", onLayout: onLayout, children: [tabs.map(({ label, url, icon, count }) => (_jsxs(Fragment, { children: [_jsxs(Link, { ref: ref => {
|
|
374
375
|
if (placeholderLinkRef.current) {
|
|
375
376
|
placeholderLinkRef.current[url] = ref;
|
|
376
377
|
}
|
|
@@ -39,6 +39,7 @@ export const commonStyles = {
|
|
|
39
39
|
center: { alignItems: "center", justifyContent: "center" },
|
|
40
40
|
centerSelf: { marginHorizontal: "auto" },
|
|
41
41
|
fill: { flexGrow: 1, flexShrink: 1 },
|
|
42
|
+
fillNoShrink: { flexGrow: 1, flexShrink: 0 },
|
|
42
43
|
hidden: { visibility: "hidden" },
|
|
43
44
|
view: viewStyle,
|
|
44
45
|
visuallyHidden: visuallyHiddenStyle,
|
package/src/utils/rifm.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ComponentProps } from "react";
|
|
2
2
|
import { Rifm } from "rifm";
|
|
3
|
-
export type
|
|
3
|
+
export type RifmProps = Required<Pick<ComponentProps<typeof Rifm>, "accept" | "append" | "format" | "mask">>;
|
|
4
4
|
declare const accepted: {
|
|
5
5
|
alpha: RegExp;
|
|
6
6
|
numeric: RegExp;
|
|
@@ -10,5 +10,5 @@ export declare const getRifmProps: ({ accept, charMap, maxLength, }: {
|
|
|
10
10
|
accept: keyof typeof accepted;
|
|
11
11
|
maxLength: number;
|
|
12
12
|
charMap: Record<number, string>;
|
|
13
|
-
}) =>
|
|
13
|
+
}) => RifmProps;
|
|
14
14
|
export {};
|
package/HISTORY.md
DELETED