@swan-io/lake 1.1.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 +3 -3
- 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/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"
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"not ie <= 11",
|
|
23
23
|
"safari >= 12"
|
|
24
24
|
],
|
|
25
|
+
"license": "MIT",
|
|
25
26
|
"dependencies": {
|
|
26
27
|
"@popperjs/core": "2.11.6",
|
|
27
28
|
"@swan-io/boxed": "0.12.1",
|
|
@@ -31,7 +32,6 @@
|
|
|
31
32
|
"polished": "4.2.2",
|
|
32
33
|
"prism-react-renderer": "1.3.5",
|
|
33
34
|
"react": "18.2.0",
|
|
34
|
-
"react-atomic-state": "1.2.7",
|
|
35
35
|
"react-dom": "18.2.0",
|
|
36
36
|
"react-dropzone": "14.2.3",
|
|
37
37
|
"react-fast-compare": "3.2.0",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"react-popper": "2.3.0",
|
|
40
40
|
"react-ux-form": "1.3.0",
|
|
41
41
|
"rifm": "0.12.1",
|
|
42
|
+
"ts-dedent": "2.2.0",
|
|
42
43
|
"ts-pattern": "4.2.1",
|
|
43
44
|
"urql": "3.0.3",
|
|
44
45
|
"uuid": "9.0.0"
|
|
@@ -52,7 +53,6 @@
|
|
|
52
53
|
"@types/react-native": "0.70.11",
|
|
53
54
|
"@types/uuid": "9.0.1",
|
|
54
55
|
"jsdom": "21.1.0",
|
|
55
|
-
"ts-dedent": "2.2.0",
|
|
56
56
|
"type-fest": "3.6.1",
|
|
57
57
|
"vitest": "0.29.2"
|
|
58
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 {};
|