@swan-io/lake 8.5.1 → 8.6.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 +1 -1
- package/src/components/FixedListViewCells.js +3 -2
- package/src/components/LakeCopyButton.js +2 -2
- package/src/components/SegmentedControl.d.ts +2 -1
- package/src/components/SegmentedControl.js +4 -4
- package/src/components/ToastStack.js +3 -2
- package/src/hooks/useBreakpoint.js +5 -9
- package/src/utils/clipboard.d.ts +1 -0
- package/src/utils/clipboard.js +30 -0
- package/src/utils/windowSize.d.ts +8 -0
- package/src/utils/windowSize.js +47 -0
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useState } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { StyleSheet, View } from "react-native";
|
|
4
4
|
import { match } from "ts-pattern";
|
|
5
5
|
import { visuallyHiddenStyle } from "../constants/commonStyles";
|
|
6
6
|
import { colors, spacings } from "../constants/design";
|
|
7
|
+
import { setClipboardText } from "../utils/clipboard";
|
|
7
8
|
import { isNotNullish, isNullish } from "../utils/nullish";
|
|
8
9
|
import { Box } from "./Box";
|
|
9
10
|
import { Icon } from "./Icon";
|
|
@@ -122,7 +123,7 @@ export const CopyableRegularTextCell = ({ variant = "regular", text, textToCopy,
|
|
|
122
123
|
const clipboardText = textToCopy !== null && textToCopy !== void 0 ? textToCopy : text;
|
|
123
124
|
const onPress = useCallback((event) => {
|
|
124
125
|
event.preventDefault();
|
|
125
|
-
|
|
126
|
+
setClipboardText(clipboardText);
|
|
126
127
|
setVisibleState("copied");
|
|
127
128
|
}, [clipboardText]);
|
|
128
129
|
return (_jsxs(View, { style: styles.cell, children: [_jsx(LakeTooltip, { placement: "right", onHide: () => setVisibleState("copy"), togglableOnFocus: true, content: visibleState === "copy" ? copyWording : copiedWording, containerStyle: styles.iconContainer, children: _jsx(Pressable, { role: "button", "aria-label": copyWording, onPress: onPress, style: ({ hovered }) => [styles.icon, hovered && styles.underline], children: ({ hovered }) => (_jsx(Icon, { name: hovered ? "copy-filled" : "copy-regular", color: "currentColor", size: 14 })) }) }), _jsx(Space, { width: 4 }), _jsx(LakeText, { tooltip: tooltip, color: colors.gray[900], style: styles.regularText, variant: variant, children: text })] }));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { setClipboardText } from "../utils/clipboard";
|
|
4
4
|
import { Icon } from "./Icon";
|
|
5
5
|
import { LakeTooltip } from "./LakeTooltip";
|
|
6
6
|
import { Pressable } from "./Pressable";
|
|
@@ -10,7 +10,7 @@ export const LakeCopyButton = ({ color, copiedText, copyText, size = copyButtond
|
|
|
10
10
|
return (_jsx(LakeTooltip, { describedBy: "copy", onHide: () => setVisibleState("copy"), togglableOnFocus: true, content: visibleState === "copy" ? copyText : copiedText, children: _jsx(Pressable, { onPress: event => {
|
|
11
11
|
event.stopPropagation();
|
|
12
12
|
event.preventDefault();
|
|
13
|
-
|
|
13
|
+
setClipboardText(valueToCopy);
|
|
14
14
|
setVisibleState("copied");
|
|
15
15
|
}, children: _jsx(Icon, { color: color, size: size, name: "copy-regular" }) }) }));
|
|
16
16
|
};
|
|
@@ -9,6 +9,7 @@ type Props<T extends string> = {
|
|
|
9
9
|
selected: T;
|
|
10
10
|
items: ReadonlyArray<Item<T>>;
|
|
11
11
|
onValueChange: (value: T) => void;
|
|
12
|
+
minItemWidth?: number;
|
|
12
13
|
};
|
|
13
|
-
export declare const SegmentedControl: <T extends string>({ selected, items, onValueChange, }: Props<T>) => import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export declare const SegmentedControl: <T extends string>({ selected, items, onValueChange, minItemWidth, }: Props<T>) => import("react/jsx-runtime").JSX.Element;
|
|
14
15
|
export {};
|
|
@@ -80,11 +80,11 @@ const styles = StyleSheet.create({
|
|
|
80
80
|
bottom: 0,
|
|
81
81
|
},
|
|
82
82
|
});
|
|
83
|
-
export const SegmentedControl = ({ selected, items, onValueChange, }) => {
|
|
83
|
+
export const SegmentedControl = ({ selected, items, onValueChange, minItemWidth = 250, }) => {
|
|
84
84
|
const selectedItemIndex = items.findIndex(item => item.id === selected);
|
|
85
|
-
const selectedItem = items
|
|
85
|
+
const selectedItem = items[selectedItemIndex];
|
|
86
86
|
const [pressed, setPressed] = useState(false);
|
|
87
|
-
return (_jsx(ResponsiveContainer, { style: styles.container, children: ({ small }) => small ? (_jsxs(Box, { direction: "row", alignItems: "center", justifyContent: "spaceBetween", children: [_jsxs(Pressable, { style: styles.itemMobile, onPress: () => {
|
|
87
|
+
return (_jsx(ResponsiveContainer, { breakpoint: items.length * minItemWidth, style: styles.container, children: ({ small }) => small ? (_jsxs(Box, { direction: "row", alignItems: "center", justifyContent: "spaceBetween", children: [_jsxs(Pressable, { style: styles.itemMobile, onPress: () => {
|
|
88
88
|
setPressed(true);
|
|
89
89
|
}, children: [isNotNullish(selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.icon) &&
|
|
90
90
|
match(selectedItem)
|
|
@@ -101,7 +101,7 @@ export const SegmentedControl = ({ selected, items, onValueChange, }) => {
|
|
|
101
101
|
match(item)
|
|
102
102
|
.with({ icon: P.nonNullable, activeIcon: P.nonNullable }, () => (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.id) === item.id ? selectedItem.activeIcon : item.icon)
|
|
103
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 })] }
|
|
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
105
|
styles.selectedItemIndicator,
|
|
106
106
|
styles.selectedItemDesktop,
|
|
107
107
|
{
|
|
@@ -2,10 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { Array, Option } from "@swan-io/boxed";
|
|
3
3
|
import { t } from "@swan-io/shared-business/src/utils/i18n";
|
|
4
4
|
import { memo, useEffect, useRef, useState } from "react";
|
|
5
|
-
import {
|
|
5
|
+
import { StyleSheet, View } from "react-native";
|
|
6
6
|
import { P, match } from "ts-pattern";
|
|
7
7
|
import { animations, colors, shadows } from "../constants/design";
|
|
8
8
|
import { getErrorToRequestId, hideToast, useToasts, } from "../state/toasts";
|
|
9
|
+
import { setClipboardText } from "../utils/clipboard";
|
|
9
10
|
import { isNotNullishOrEmpty, isNullish } from "../utils/nullish";
|
|
10
11
|
import { Box } from "./Box";
|
|
11
12
|
import { Icon } from "./Icon";
|
|
@@ -115,7 +116,7 @@ const Toast = memo(({ variant, uid, title, description, error, progress, onClose
|
|
|
115
116
|
: t("copyButton.copiedTooltip"), children: _jsxs(Pressable, { style: styles.copyButton, onPress: event => {
|
|
116
117
|
event.stopPropagation();
|
|
117
118
|
event.preventDefault();
|
|
118
|
-
|
|
119
|
+
setClipboardText(requestId !== null && requestId !== void 0 ? requestId : "");
|
|
119
120
|
setVisibleState("copied");
|
|
120
121
|
}, children: [_jsx(Icon, { color: colors.gray[700], size: 14, name: "copy-regular" }), _jsx(Space, { width: 4 }), _jsxs(LakeText, { numberOfLines: 1, variant: "smallRegular", color: colors.gray[700], children: ["ID: ", requestId] })] }) })] })))
|
|
121
122
|
.exhaustive()] }), _jsx(Pressable, { onPress: () => onClose(uid), style: styles.closeButton, children: _jsx(Icon, { name: "lake-close", size: 24, color: colors.gray[500] }) }), progress != null && (_jsxs(_Fragment, { children: [_jsx(Space, { height: 24 }), _jsx(View, { ref: progressBarRef, role: "progressbar", style: [styles.progressBar, { backgroundColor: colors[colorVariation][500] }] })] }))] }) }));
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
// Based on https://github.com/necolas/react-native-web/blob/0.19.
|
|
1
|
+
// Based on https://github.com/necolas/react-native-web/blob/0.19.12/packages/react-native-web/src/exports/useWindowDimensions/index.js
|
|
2
2
|
import { useCallback, useSyncExternalStore } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { windowSize } from "../utils/windowSize";
|
|
4
4
|
export const useBreakpoint = (breakpoint) => useSyncExternalStore(useCallback(onStoreChange => {
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
onStoreChange();
|
|
8
|
-
}
|
|
9
|
-
});
|
|
10
|
-
return subscription.remove;
|
|
5
|
+
const unsubscribe = windowSize.subscribe(onStoreChange);
|
|
6
|
+
return unsubscribe;
|
|
11
7
|
}, []), useCallback(() => {
|
|
12
|
-
return
|
|
8
|
+
return windowSize.get().width >= breakpoint;
|
|
13
9
|
}, [breakpoint]));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const setClipboardText: (text: string) => boolean;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Based on https://github.com/necolas/react-native-web/blob/0.19.12/packages/react-native-web/src/exports/Clipboard/index.js
|
|
2
|
+
export const setClipboardText = (text) => {
|
|
3
|
+
// add the text to a hidden node
|
|
4
|
+
const node = document.createElement("span");
|
|
5
|
+
node.textContent = text;
|
|
6
|
+
node.style.opacity = "0";
|
|
7
|
+
node.style.position = "absolute";
|
|
8
|
+
node.style.userSelect = "auto";
|
|
9
|
+
node.style.whiteSpace = "pre-wrap";
|
|
10
|
+
document.body.appendChild(node);
|
|
11
|
+
// select the text
|
|
12
|
+
const selection = window.getSelection();
|
|
13
|
+
if (selection == null) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
selection.removeAllRanges();
|
|
17
|
+
const range = document.createRange();
|
|
18
|
+
range.selectNodeContents(node);
|
|
19
|
+
selection.addRange(range);
|
|
20
|
+
try {
|
|
21
|
+
document.execCommand("copy");
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
// remove selection and node
|
|
27
|
+
selection.removeAllRanges();
|
|
28
|
+
document.body.removeChild(node);
|
|
29
|
+
return true;
|
|
30
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Based on https://github.com/necolas/react-native-web/blob/0.19.12/packages/react-native-web/src/exports/Dimensions/index.js
|
|
2
|
+
const get = () => {
|
|
3
|
+
const viewport = window.visualViewport;
|
|
4
|
+
/**
|
|
5
|
+
* iOS does not update viewport dimensions on keyboard open/close.
|
|
6
|
+
* window.visualViewport(https://developer.mozilla.org/en-US/docs/Web/API/VisualViewport)
|
|
7
|
+
* is used instead of document.documentElement.clientHeight (which remains as a fallback)
|
|
8
|
+
*/
|
|
9
|
+
if (viewport != null) {
|
|
10
|
+
/**
|
|
11
|
+
* We are multiplying by scale because height and width from visual viewport
|
|
12
|
+
* also react to pinch zoom, and become smaller when zoomed. But it is not desired
|
|
13
|
+
* behaviour, since originally documentElement client height and width were used,
|
|
14
|
+
* and they do not react to pinch zoom.
|
|
15
|
+
*/
|
|
16
|
+
return {
|
|
17
|
+
width: Math.round(viewport.width * viewport.scale),
|
|
18
|
+
height: Math.round(viewport.height * viewport.scale),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const documentElement = window.document.documentElement;
|
|
22
|
+
return {
|
|
23
|
+
width: documentElement.clientWidth,
|
|
24
|
+
height: documentElement.clientHeight,
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
const callbacks = new Set();
|
|
28
|
+
let currentSize = get();
|
|
29
|
+
const onResize = () => {
|
|
30
|
+
currentSize = get();
|
|
31
|
+
callbacks.forEach(callback => callback(currentSize));
|
|
32
|
+
};
|
|
33
|
+
export const windowSize = {
|
|
34
|
+
get: () => currentSize,
|
|
35
|
+
subscribe: (callback) => {
|
|
36
|
+
callbacks.add(callback);
|
|
37
|
+
return () => {
|
|
38
|
+
callbacks.delete(callback);
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
if (window.visualViewport != null) {
|
|
43
|
+
window.visualViewport.addEventListener("resize", onResize, false);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
window.addEventListener("resize", onResize, false);
|
|
47
|
+
}
|