@swan-io/lake 12.4.2 → 13.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swan-io/lake",
3
- "version": "12.4.2",
3
+ "version": "13.0.0",
4
4
  "engines": {
5
5
  "node": "^22.12.0"
6
6
  },
@@ -25,28 +25,23 @@
25
25
  ],
26
26
  "license": "MIT",
27
27
  "dependencies": {
28
- "@react-three/drei": "^10.1.2",
29
- "@react-three/fiber": "^9.1.2",
30
28
  "@swan-io/boxed": "^3.2.0",
31
29
  "@swan-io/chicane": "^2.2.0",
32
30
  "@swan-io/use-form": "^3.1.0",
33
31
  "dayjs": "^1.11.13",
34
32
  "polished": "^4.3.1",
35
33
  "prism-react-renderer": "^2.4.1",
36
- "react": "^19.1.0",
37
- "react-dom": "^19.1.0",
38
- "react-native-web": "^0.20.0",
34
+ "react": "^19.1.1",
35
+ "react-dom": "^19.1.1",
36
+ "react-native-web": "^0.21.1",
39
37
  "rifm": "^0.12.1",
40
- "three": "^0.177.0",
41
- "ts-pattern": "^5.7.1",
38
+ "ts-pattern": "^5.8.0",
42
39
  "uuid": "^11.1.0"
43
40
  },
44
41
  "devDependencies": {
45
- "@types/react": "^19.1.6",
46
- "@types/react-dom": "^19.1.5",
42
+ "@types/react": "^19.1.10",
43
+ "@types/react-dom": "^19.1.7",
47
44
  "@types/react-native": "^0.72.8",
48
- "@types/three": "^0.176.0",
49
- "jsdom": "^26.1.0",
50
45
  "type-fest": "^4.41.0"
51
46
  }
52
47
  }
@@ -1,13 +1,9 @@
1
1
  type Props = {
2
+ compact?: boolean;
2
3
  value: boolean;
3
- disabled?: boolean;
4
- onToggle: (next: boolean) => void;
5
- mode?: "desktop" | "mobile";
6
- onLabel: string;
7
- offLabel: string;
4
+ labelOff: string;
5
+ labelOn: string;
6
+ onToggle: (value: boolean) => void;
8
7
  };
9
- /**
10
- * @deprecated
11
- */
12
- export declare const Toggle: ({ onToggle, value, disabled, mode, onLabel, offLabel, }: Props) => import("react/jsx-runtime").JSX.Element;
8
+ export declare const Toggle: ({ compact, value, labelOff, labelOn, onToggle }: Props) => import("react/jsx-runtime").JSX.Element;
13
9
  export {};
@@ -1,76 +1,81 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useRef, useState } from "react";
3
- import { StyleSheet, View } from "react-native";
4
- import { commonStyles } from "../constants/commonStyles";
5
- import { colors } from "../constants/design";
6
- import { Box } from "./Box";
3
+ import { StyleSheet, Text, View } from "react-native";
4
+ import { match, P } from "ts-pattern";
5
+ import { colors, radii, spacings, texts } from "../constants/design";
7
6
  import { Icon } from "./Icon";
8
- import { LakeText } from "./LakeText";
9
7
  import { Pressable } from "./Pressable";
10
- const HEIGHT = 26;
11
8
  const BORDER_WIDTH = 1;
12
9
  const styles = StyleSheet.create({
13
- switch: {
14
- userSelect: "none",
10
+ base: {
15
11
  flexDirection: "row",
16
- borderRadius: HEIGHT / 2,
17
- height: HEIGHT,
18
- transform: "translateZ(0px)",
19
- width: "min-content",
20
- borderColor: colors.gray[100],
12
+ alignItems: "center",
13
+ borderColor: colors.gray[200],
14
+ borderRadius: radii[8],
21
15
  borderWidth: BORDER_WIDTH,
16
+ height: 28,
22
17
  },
23
18
  handle: {
24
19
  position: "absolute",
25
- width: HEIGHT,
26
- height: HEIGHT,
20
+ // Allow handle to bleed on container border
21
+ bottom: -BORDER_WIDTH,
22
+ left: -BORDER_WIDTH,
23
+ right: -BORDER_WIDTH,
27
24
  top: -BORDER_WIDTH,
28
- borderRadius: HEIGHT / 2,
25
+ borderWidth: BORDER_WIDTH,
26
+ borderRadius: radii[8],
29
27
  transitionDuration: "300ms",
28
+ transitionProperty: "transform, width",
30
29
  transitionTimingFunction: "ease-in-out",
31
- borderWidth: BORDER_WIDTH,
32
30
  },
33
- switchItem: {
34
- paddingHorizontal: 8,
35
- height: HEIGHT - BORDER_WIDTH * 2,
36
- display: "flex",
37
- alignItems: "center",
38
- justifyContent: "center",
31
+ item: {
32
+ paddingHorizontal: spacings[8],
33
+ },
34
+ text: {
35
+ ...texts.smallMedium,
36
+ color: colors.gray[700],
37
+ userSelect: "none",
38
+ },
39
+ hidden: {
40
+ visibility: "hidden",
41
+ },
42
+ textOn: {
43
+ color: colors.positive[500],
44
+ },
45
+ textOff: {
46
+ color: colors.negative[500],
39
47
  },
40
48
  });
41
- /**
42
- * @deprecated
43
- */
44
- export const Toggle = ({ onToggle, value, disabled = false, mode = "desktop", onLabel, offLabel, }) => {
45
- const containerRef = useRef(null);
46
- const onItemRef = useRef(null);
47
- const offItemRef = useRef(null);
48
- const [handleStyle, setHandleStyle] = useState();
49
- const isMobileMode = mode === "mobile";
50
- const onColor = value ? colors.positive[500] : colors.gray[500];
51
- const offColor = !value ? colors.negative[500] : colors.gray[500];
52
- const reajustLayout = useCallback(() => {
53
- var _a;
54
- (_a = (value ? onItemRef : offItemRef).current) === null || _a === void 0 ? void 0 : _a.measureLayout(containerRef.current, (left, _, width) => {
55
- setHandleStyle(prev => ({
56
- transitionProperty: prev ? "width, transform" : "none",
57
- width: width + 2 * BORDER_WIDTH,
58
- transform: `translateX(${value ? -BORDER_WIDTH : left - 2 * BORDER_WIDTH}px)`,
59
- }));
60
- }, () => { });
61
- }, [value]);
62
- // biome-ignore lint/correctness/useExhaustiveDependencies(reajustLayout):
63
- // biome-ignore lint/correctness/useExhaustiveDependencies(value):
64
- // biome-ignore lint/correctness/useExhaustiveDependencies(isMobileMode):
65
- // biome-ignore lint/correctness/useExhaustiveDependencies(onLabel):
66
- // biome-ignore lint/correctness/useExhaustiveDependencies(offLabel):
67
- useEffect(reajustLayout, [reajustLayout, value, isMobileMode, onLabel, offLabel]);
68
- return (_jsxs(Pressable, { style: [styles.switch, disabled && commonStyles.disabled], onPress: () => onToggle(!value), "aria-disabled": disabled, "aria-checked": value, disabled: disabled, ref: containerRef, role: "switch", onLayout: reajustLayout, children: [_jsx(View, { style: [
49
+ const getItemWidth = (node) => match(node)
50
+ .returnType()
51
+ .with(P.instanceOf(HTMLElement), element => element.offsetWidth)
52
+ .otherwise(() => 0);
53
+ export const Toggle = ({ compact = false, value, labelOff, labelOn, onToggle }) => {
54
+ const [itemsWidth, setItemsWidth] = useState();
55
+ const onViewRef = useRef(null);
56
+ const offViewRef = useRef(null);
57
+ // biome-ignore lint/correctness/useExhaustiveDependencies(compact):
58
+ useEffect(() => {
59
+ // batch measurements
60
+ setTimeout(() => {
61
+ setItemsWidth({
62
+ on: getItemWidth(onViewRef.current),
63
+ off: getItemWidth(offViewRef.current),
64
+ });
65
+ }, 0);
66
+ }, [compact]);
67
+ const onPress = useCallback(() => {
68
+ onToggle(!value);
69
+ }, [onToggle, value]);
70
+ return (_jsxs(Pressable, { role: "switch", onPress: onPress, "aria-checked": value, style: styles.base, children: [_jsx(View, { role: "presentation", style: [
69
71
  styles.handle,
70
- handleStyle,
71
- {
72
- borderColor: value ? colors.positive[500] : colors.negative[500],
73
- backgroundColor: value ? colors.positive[50] : colors.negative[50],
74
- },
75
- ] }), _jsx(Box, { style: styles.switchItem, ref: onItemRef, children: isMobileMode ? (_jsx(Icon, { size: 16, name: "checkmark-circle-regular", color: onColor })) : (_jsx(LakeText, { variant: "smallMedium", color: onColor, children: onLabel })) }), _jsx(Box, { style: styles.switchItem, ref: offItemRef, children: isMobileMode ? (_jsx(Icon, { size: 16, name: "subtract-circle-regular", color: offColor })) : (_jsx(LakeText, { variant: "smallMedium", color: offColor, children: offLabel })) })] }));
72
+ itemsWidth == null
73
+ ? styles.hidden
74
+ : {
75
+ backgroundColor: value ? colors.positive[50] : colors.negative[50],
76
+ borderColor: value ? colors.positive[500] : colors.negative[500],
77
+ transform: `translateX(${value ? 0 : itemsWidth.on + BORDER_WIDTH}px)`,
78
+ width: (value ? itemsWidth.on : itemsWidth.off) + BORDER_WIDTH,
79
+ },
80
+ ] }), _jsx(View, { ref: onViewRef, style: styles.item, children: compact ? (_jsx(Icon, { color: value ? colors.positive[500] : colors.gray[500], size: 16, name: "checkmark-circle-regular" })) : (_jsx(Text, { style: [styles.text, value && styles.textOn], children: labelOn })) }), _jsx(View, { ref: offViewRef, style: styles.item, children: compact ? (_jsx(Icon, { color: !value ? colors.negative[500] : colors.gray[500], size: 16, name: "subtract-circle-regular" })) : (_jsx(Text, { style: [styles.text, !value && styles.textOff], children: labelOff })) })] }));
76
81
  };
@@ -6,7 +6,7 @@ type Props = {
6
6
  style?: ViewProps["style"];
7
7
  children: ReactNode;
8
8
  };
9
- export declare const CurrentColorContext: import("react").Context<"current" | "gray" | "live" | "sandbox" | "positive" | "warning" | "negative" | "partner" | "swan" | "shakespear" | "darkPink" | "sunglow" | "mediumSladeBlue" | undefined>;
9
+ export declare const CurrentColorContext: import("react").Context<"gray" | "live" | "sandbox" | "positive" | "warning" | "negative" | "current" | "partner" | "swan" | "shakespear" | "darkPink" | "sunglow" | "mediumSladeBlue" | undefined>;
10
10
  export declare const useCurrentColor: (containerRef: RefObject<HTMLElement | null>, variant: ColorVariants | undefined) => void;
11
11
  export declare const WithCurrentColor: ({ variant, style, children }: Props) => import("react/jsx-runtime").JSX.Element;
12
12
  export {};
@@ -67,13 +67,6 @@ export declare const primaryFontStyle: {
67
67
  fontFamily: string;
68
68
  letterSpacing: number;
69
69
  };
70
- /**
71
- * @deprecated use primaryFontStyle instead
72
- */
73
- export declare const interFontStyle: {
74
- fontFamily: string;
75
- letterSpacing: number;
76
- };
77
70
  export declare const texts: {
78
71
  readonly h1: TextStyle;
79
72
  readonly h2: TextStyle;
@@ -258,10 +258,6 @@ export const primaryFontStyle = {
258
258
  fontFamily: fonts.primary,
259
259
  letterSpacing: "var(--letter-spacing-primary)",
260
260
  };
261
- /**
262
- * @deprecated use primaryFontStyle instead
263
- */
264
- export const interFontStyle = primaryFontStyle;
265
261
  const asTextStyle = (x) => {
266
262
  return x;
267
263
  };
@@ -1,36 +0,0 @@
1
- import { JSX, Ref } from "react";
2
- import * as THREE from "three";
3
- export type Card3dAssetsUrls = {
4
- envNx: string;
5
- envNy: string;
6
- envNz: string;
7
- envPx: string;
8
- envPy: string;
9
- envPz: string;
10
- fontMaisonNeueBook: string;
11
- fontMarkProRegular: string;
12
- bandRoughness: string;
13
- cardGltf: string;
14
- chipTexture: string;
15
- colorBlack: string;
16
- colorSilver: string;
17
- };
18
- type CardParams = {
19
- ref?: Ref<THREE.Group>;
20
- ownerName: string;
21
- cardNumber: string;
22
- expirationDate: string;
23
- cvv: string;
24
- color: "Silver" | "Black" | THREE.Texture;
25
- logo: SVGElement | HTMLImageElement | null;
26
- logoScale: number;
27
- assetsUrls: Card3dAssetsUrls;
28
- onSvgError?: (code: string) => void;
29
- };
30
- type Props = CardParams & {
31
- autoRotationDuration?: number;
32
- };
33
- declare const _default: (props: Props) => import("react/jsx-runtime").JSX.Element;
34
- export default _default;
35
- type CardProps = JSX.IntrinsicElements["group"] & CardParams;
36
- export declare const Card: ({ ref, ownerName, cardNumber, expirationDate, cvv, color, logo, logoScale, assetsUrls, onSvgError, ...props }: CardProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,197 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { Environment, OrbitControls, Text, useGLTF, useTexture } from "@react-three/drei";
3
- import { Canvas, useFrame } from "@react-three/fiber";
4
- import { Result } from "@swan-io/boxed";
5
- import { useEffect, useRef, useState } from "react";
6
- import * as THREE from "three";
7
- import { match, P } from "ts-pattern";
8
- import { isNotNullish, isNullish } from "../utils/nullish";
9
- import { createSvgImage, getMonochromeSvg } from "../utils/svg";
10
- /*
11
- This Module exports 2 components:
12
- - default export: A react-three-fiber scene which can be integrated in any react project
13
- (We use default export to be able to use React.lazy to load this component asynchronously without impacting bundle size)
14
- - Card component: which can be use for developers who already have a react-three-fiber scene or want to create there own scene
15
-
16
- Here are some details about choices made for this components:
17
- :one: Textures
18
- Textures aren't integrated in gltf export because it will force all developers to put texture files in their public folder.
19
- By using ?url import and `useTexture` hook, Vite will put textures in dist folder for all developers who use this component.
20
-
21
- :two: Logo integration
22
- There is an SVGLoader for threejs but it doesn't support all svg features.
23
- So to be sure to support all svg features, we transform the SVG into Image element to create a texture.
24
- And this texture is used as an alpha map on a plane.
25
-
26
- :three: Mastercard shiny text on back of card
27
- To reproduce the shiny effect on the back of the card, we inject a custom shader in rainbow_mastercard material.
28
- This custom shader chunk change the diffuse color depending on camera position.
29
- */
30
- // Uses alpha channel instead of green to make pixel transparent on logo plane
31
- const logoAlphaMapFragmentShader = `
32
- diffuseColor.a *= texture2D(alphaMap, vAlphaMapUv).a;
33
- `;
34
- const shinyColorFragmentShader = `
35
- float red = cameraPosition.x * cameraPosition.z;
36
- float green = cameraPosition.y * cameraPosition.z;
37
- float blue = 0.1;
38
-
39
- red = sin(red / 5.0) + 1.0 / 2.0;
40
- green = sin(green / 5.0) + 1.0 / 2.0;
41
-
42
- vec3 shinyColor = vec3(red, green, blue);
43
- float shinyFactor = 0.35;
44
-
45
- diffuseColor.rgb = mix(diffuseColor.rgb, shinyColor, shinyFactor);
46
- `;
47
- const ENV_MAP_INTENSITY = 3;
48
- const CARD_WIDTH = 8.56;
49
- const CARD_HEIGHT = 5.4;
50
- const FRONT_TEXT_POSITION = 0.04;
51
- const BACK_TEXT_POSITION = -FRONT_TEXT_POSITION;
52
- const LOGO_MARGIN_TOP = 0.3;
53
- const LOGO_MARGIN_RIGHT = 0.3;
54
- const LOGO_MAX_WIDTH = 5; // in cm
55
- const LOGO_MAX_HEIGHT = 1; // in cm
56
- const computeCardLogoSize = (logoSize) => {
57
- const logoRatio = logoSize.width / logoSize.height;
58
- const cardSpaceRatio = LOGO_MAX_WIDTH / LOGO_MAX_HEIGHT;
59
- // if logo is wider than available space
60
- // logo will have the same width than available space
61
- if (logoRatio >= cardSpaceRatio) {
62
- const width = LOGO_MAX_WIDTH;
63
- const height = width / logoRatio;
64
- return { width, height };
65
- }
66
- else {
67
- // if logo is higher than available space
68
- // logo will have the same height than available space
69
- const height = LOGO_MAX_HEIGHT;
70
- const width = height * logoRatio;
71
- return { width, height };
72
- }
73
- };
74
- // Use export default for React.lazy
75
- export default (props) => {
76
- return (_jsxs(Canvas, { camera: { position: [0, 0, 12], fov: 50 }, children: [_jsx(OrbitControls, { enablePan: false, enableZoom: false }), _jsx(CardScene, { ...props })] }));
77
- };
78
- const CardScene = ({ autoRotationDuration, ...props }) => {
79
- const { assetsUrls } = props;
80
- const card = useRef(null);
81
- useFrame(({ clock }) => {
82
- if (autoRotationDuration != null && card.current != null) {
83
- card.current.rotation.y = (clock.getElapsedTime() / autoRotationDuration) * Math.PI * 2;
84
- }
85
- });
86
- return (_jsxs(_Fragment, { children: [_jsx("ambientLight", { color: 0xffffff, intensity: 1 }), _jsx("pointLight", { intensity: 0.2, decay: 2, position: [-10, -10, -21] }), _jsx("pointLight", { intensity: 0.2, decay: 2, position: [10, 10, 21] }), _jsx(Environment, { files: [
87
- assetsUrls.envPx,
88
- assetsUrls.envNx,
89
- assetsUrls.envPy,
90
- assetsUrls.envNy,
91
- assetsUrls.envPz,
92
- assetsUrls.envNz,
93
- ] }), _jsx(Card, { ref: card, ...props })] }));
94
- };
95
- // Set color space to sRGB for textures
96
- const setTextureColorSpace = (texture) => {
97
- if (!Array.isArray(texture)) {
98
- texture.colorSpace = THREE.SRGBColorSpace;
99
- }
100
- };
101
- export const Card = ({ ref, ownerName, cardNumber, expirationDate, cvv, color, logo, logoScale, assetsUrls, onSvgError, ...props }) => {
102
- const { nodes, materials } = useGLTF(assetsUrls.cardGltf);
103
- const [logoData, setLogoData] = useState(null);
104
- const silverTexture = useTexture(assetsUrls.colorSilver, setTextureColorSpace);
105
- const blackTexture = useTexture(assetsUrls.colorBlack, setTextureColorSpace);
106
- const chipTexture = useTexture(assetsUrls.chipTexture, setTextureColorSpace);
107
- const bandRoughnessTexture = useTexture(assetsUrls.bandRoughness); // keep default color space because it's grayscale
108
- // Set environment map intensity for all materials
109
- useEffect(() => {
110
- Object.values(materials).forEach(material => {
111
- material.envMapIntensity = ENV_MAP_INTENSITY;
112
- });
113
- }, [materials]);
114
- // Set rainbow mastercard text custom fragment shader
115
- useEffect(() => {
116
- materials.rainbow_mastercard.onBeforeCompile = shader => {
117
- shader.fragmentShader = shader.fragmentShader.replace("#include <color_fragment>", shinyColorFragmentShader);
118
- };
119
- }, [materials.rainbow_mastercard]);
120
- // Set band roughness and chip texture
121
- useEffect(() => {
122
- materials.black_band.roughness = 0.8;
123
- materials.black_band.roughnessMap = bandRoughnessTexture;
124
- materials.chip.map = chipTexture;
125
- }, [materials.black_band, materials.chip, bandRoughnessTexture, chipTexture]);
126
- // Set color texture
127
- useEffect(() => {
128
- match(color)
129
- .with("Silver", () => {
130
- materials.card.map = silverTexture;
131
- })
132
- .with("Black", () => {
133
- materials.card.map = blackTexture;
134
- })
135
- .otherwise(texture => {
136
- materials.card.map = texture;
137
- });
138
- // force threejs to update material
139
- // because sometimes it doesn't apply texture on load randomly
140
- materials.card.needsUpdate = true;
141
- }, [color, materials.card, silverTexture, blackTexture]);
142
- // this avoid to have onSvgError as dependency of the effect below which should run only on logo change
143
- const handleSvgError = useRef(onSvgError);
144
- useEffect(() => {
145
- handleSvgError.current = onSvgError;
146
- }, [onSvgError]);
147
- // Handle logo
148
- useEffect(() => {
149
- var _a;
150
- if (isNullish(logo)) {
151
- setLogoData(null);
152
- return;
153
- }
154
- const image = match(logo)
155
- .with(P.instanceOf(HTMLImageElement), image => Result.Ok(image))
156
- .otherwise(logo => {
157
- // We transform the logo to white to be able to use it as alpha map
158
- const whiteLogo = getMonochromeSvg(logo, "white");
159
- // Convert to Image element to be able to use it as texture
160
- return createSvgImage(whiteLogo);
161
- });
162
- if (image.isError()) {
163
- (_a = handleSvgError.current) === null || _a === void 0 ? void 0 : _a.call(handleSvgError, image.getError());
164
- return;
165
- }
166
- // Compute logo size depending on constraints
167
- const { width: logoWidth, height: logoHeight } = computeCardLogoSize(image.get());
168
- const alphaMap = new THREE.Texture(image.get());
169
- alphaMap.needsUpdate = true;
170
- setLogoData({
171
- size: [logoWidth, logoHeight],
172
- alphaMap,
173
- });
174
- }, [logo]);
175
- const mainTextMaterial = (_jsx("meshStandardMaterial", { color: match(color)
176
- .with("Silver", () => 0x000000)
177
- .with("Black", () => 0xeeeeee)
178
- .otherwise(() => 0xeeeeee), metalness: 0.1, roughness: 0.55, envMapIntensity: ENV_MAP_INTENSITY }));
179
- const secondaryTextMaterial = (_jsx("meshStandardMaterial", { color: 0x666666, metalness: 0.1, roughness: 0.55, envMapIntensity: ENV_MAP_INTENSITY }));
180
- return (_jsx("group", { ref: ref, ...props, dispose: null, children: _jsxs("mesh", { geometry: nodes.card.geometry, material: materials.card, children: [_jsxs("group", { position: [0, 0, FRONT_TEXT_POSITION], children: [_jsxs(Text, { font: assetsUrls.fontMaisonNeueBook, fontSize: 0.2, anchorX: "left", anchorY: "bottom", position: [-3.4, -1.95, 0], children: [ownerName, mainTextMaterial] }), _jsxs(Text, { font: assetsUrls.fontMarkProRegular, fontSize: 0.03, anchorX: "left", anchorY: "bottom", position: [3.85, -2.15, 0], children: ["TM", mainTextMaterial] })] }), _jsxs("group", { position: [0, 0, BACK_TEXT_POSITION], children: [_jsxs(Text, { font: assetsUrls.fontMarkProRegular, anchorX: "left", anchorY: "bottom", fontSize: 0.12, rotation: [0, Math.PI, 0], position: [4, 2.38, 0], children: ["support@swan.io", secondaryTextMaterial] }), _jsxs(Text, { font: assetsUrls.fontMarkProRegular, anchorX: "right", anchorY: "bottom", fontSize: 0.12, rotation: [0, Math.PI, 0], position: [-4, 2.38, 0], children: ["IDEMIA 9 1212121L 09/21", secondaryTextMaterial] }), _jsxs(Text, { font: assetsUrls.fontMaisonNeueBook, fontSize: 0.24, anchorX: "left", anchorY: "bottom", rotation: [0, Math.PI, 0], position: [4, 0.68, 0], children: ["Identifier: 0000000000", mainTextMaterial] }), _jsxs(Text, { font: assetsUrls.fontMaisonNeueBook, fontSize: 0.2, anchorX: "left", anchorY: "bottom", rotation: [0, Math.PI, 0], position: [4, 0.15, 0], children: ["This card is issued by Swan, pursuant to license", secondaryTextMaterial] }), _jsxs(Text, { font: assetsUrls.fontMaisonNeueBook, fontSize: 0.2, anchorX: "left", anchorY: "bottom", rotation: [0, Math.PI, 0], position: [4, -0.15, 0], children: ["from Mastercard International.", secondaryTextMaterial] }), _jsxs(Text, { font: assetsUrls.fontMaisonNeueBook, fontSize: 0.48, anchorX: "left", anchorY: "bottom", rotation: [0, Math.PI, 0], position: [4, -1.85, 0], children: [cardNumber, mainTextMaterial] }), _jsxs(Text, { font: assetsUrls.fontMaisonNeueBook, fontSize: 0.29, anchorX: "left", anchorY: "bottom", rotation: [0, Math.PI, 0], position: [4, -2.3, 0], children: [expirationDate, mainTextMaterial] }), _jsxs(Text, { font: assetsUrls.fontMaisonNeueBook, fontSize: 0.29, anchorX: "left", anchorY: "bottom", rotation: [0, Math.PI, 0], position: [2.55, -2.3, 0], children: ["CVC ", cvv, mainTextMaterial] }), _jsxs(Text, { font: assetsUrls.fontMarkProRegular, anchorX: "center", anchorY: "bottom", fontSize: 0.36, rotation: [0, Math.PI, 0], position: [-2.35, -1.15, 0], children: ["debit", mainTextMaterial] })] }), _jsx("group", {
181
- // move group to change scale center at top right corner
182
- position: [
183
- CARD_WIDTH / 2 - LOGO_MARGIN_RIGHT,
184
- CARD_HEIGHT / 2 - LOGO_MARGIN_TOP,
185
- FRONT_TEXT_POSITION,
186
- ], scale: logoScale, children: isNotNullish(logoData) && (_jsxs("mesh", { position: [-logoData.size[0] / 2, -logoData.size[1] / 2, 0], children: [_jsx("planeGeometry", { args: logoData.size }), _jsx("meshStandardMaterial", { ref: material => {
187
- if (!material) {
188
- return;
189
- }
190
- material.onBeforeCompile = shader => {
191
- shader.fragmentShader = shader.fragmentShader.replace("#include <alphamap_fragment>", logoAlphaMapFragmentShader);
192
- };
193
- }, color: match(color)
194
- .with("Silver", () => 0x000000)
195
- .with("Black", () => 0xffffff)
196
- .otherwise(() => 0xffffff), metalness: 0.1, roughness: 0.35, envMapIntensity: ENV_MAP_INTENSITY, transparent: true, alphaMap: logoData.alphaMap })] })) }), _jsx("mesh", { geometry: nodes.black_band.geometry, material: materials.black_band, position: [0, 1.774, BACK_TEXT_POSITION], rotation: [0, Math.PI / 2, 0] }), _jsx("mesh", { geometry: nodes.chip.geometry, material: materials.chip, position: [-2.78, 0.439, FRONT_TEXT_POSITION], rotation: [0, Math.PI / 2, 0] }), _jsx("mesh", { geometry: nodes.chip_pattern.geometry, material: materials.chip_pattern, position: [-2.778, 0.442, FRONT_TEXT_POSITION + 0.001], rotation: [0, Math.PI / 2, 0] }), _jsx("mesh", { geometry: nodes.mc_center.geometry, material: materials.mastercard_orange, position: [3.052, -1.832, FRONT_TEXT_POSITION], rotation: [Math.PI / 2, 0, 0] }), _jsx("mesh", { geometry: nodes.mc_left.geometry, material: materials.mastercard_red, position: [2.676, -1.773, FRONT_TEXT_POSITION], rotation: [Math.PI / 2, 0, 0] }), _jsx("mesh", { geometry: nodes.mc_right.geometry, material: materials.mastercard_yellow, position: [3.47, -1.773, FRONT_TEXT_POSITION], rotation: [-Math.PI / 2, 0, 0] }), _jsx("mesh", { geometry: nodes.metal_circle.geometry, material: materials.rainbow, position: [-2.33, -1.849, BACK_TEXT_POSITION], rotation: [-Math.PI / 2, Math.PI / 2, 0] }), _jsx("mesh", { geometry: nodes.metal_circle001.geometry, material: materials.rainbow_rough, position: [-2.629, -1.849, BACK_TEXT_POSITION - 0.001], rotation: [-Math.PI / 2, Math.PI / 2, 0], scale: [0.35, 1, 0.35] }), _jsx("mesh", { geometry: nodes.metal_circle002.geometry, material: materials.rainbow_rough, position: [-2.33, -1.849, BACK_TEXT_POSITION - 0.001], rotation: [-Math.PI / 2, Math.PI / 2, 0] }), _jsx("mesh", { geometry: nodes.metal_mastercard.geometry, material: materials.rainbow_mastercard, position: [0.914, -1.298, BACK_TEXT_POSITION - 0.001], rotation: [Math.PI / 2, 0, Math.PI], scale: 0.09 })] }) }));
197
- };
@@ -1,15 +0,0 @@
1
- /**
2
- * @deprecated
3
- */
4
- export declare const FilterChooser: <FilterName extends string>({ filters, openFilters, label, title, availableFilters, large, onAddFilter, }: {
5
- filters: Partial<Record<FilterName, unknown>>;
6
- openFilters: FilterName[];
7
- label: string;
8
- title?: string;
9
- availableFilters: {
10
- label: string;
11
- name: FilterName;
12
- }[];
13
- large?: boolean;
14
- onAddFilter: (filterName: FilterName) => void;
15
- }) => import("react/jsx-runtime").JSX.Element;
@@ -1,51 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useRef } from "react";
3
- import { Pressable, StyleSheet, View } from "react-native";
4
- import { colors } from "../constants/design";
5
- import { useDisclosure } from "../hooks/useDisclosure";
6
- import { isNotNullishOrEmpty } from "../utils/nullish";
7
- import { FlatList } from "./FlatList";
8
- import { Icon } from "./Icon";
9
- import { LakeButton } from "./LakeButton";
10
- import { LakeText } from "./LakeText";
11
- import { Popover } from "./Popover";
12
- import { Space } from "./Space";
13
- const styles = StyleSheet.create({
14
- selected: {
15
- color: colors.gray[500],
16
- },
17
- list: {
18
- paddingVertical: 20,
19
- marginVertical: 4,
20
- minWidth: 250,
21
- overflow: "hidden",
22
- },
23
- item: {
24
- display: "flex",
25
- paddingHorizontal: 24,
26
- flexDirection: "row",
27
- justifyContent: "space-between",
28
- alignItems: "center",
29
- paddingVertical: 8,
30
- },
31
- itemHovered: {
32
- backgroundColor: colors.gray[50],
33
- },
34
- availableFiltersTitle: {
35
- paddingHorizontal: 24,
36
- },
37
- });
38
- /**
39
- * @deprecated
40
- */
41
- export const FilterChooser = ({ filters, openFilters, label, title, availableFilters, large = true, onAddFilter, }) => {
42
- const inputRef = useRef(null);
43
- const [visible, { close, toggle }] = useDisclosure(false);
44
- return (_jsxs(_Fragment, { children: [_jsx(LakeButton, { size: "small", mode: "secondary", color: "gray", onPress: toggle, ref: inputRef, icon: large ? "chevron-down-filled" : "filter-filled", iconPosition: "end", ariaLabel: label, children: large ? label : null }), _jsx(Popover, { role: "listbox", matchReferenceMinWidth: true, onDismiss: close, referenceRef: inputRef, returnFocus: false, visible: visible, children: _jsxs(View, { style: styles.list, children: [isNotNullishOrEmpty(title) ? (_jsxs(_Fragment, { children: [_jsx(LakeText, { style: styles.availableFiltersTitle, children: title }), _jsx(Space, { height: 8 })] })) : null, _jsx(FlatList, { role: "list", data: availableFilters, keyExtractor: (_, index) => `filter-item-${index}`, renderItem: ({ item }) => {
45
- const isSet = Boolean(filters[item.name]) || openFilters.includes(item.name);
46
- return (_jsxs(Pressable, { style: ({ hovered }) => [styles.item, hovered && styles.itemHovered], role: "button", disabled: isSet, onPress: () => {
47
- onAddFilter(item.name);
48
- close();
49
- }, children: [_jsx(LakeText, { variant: "smallRegular", style: isSet && styles.selected, children: item.label }), isSet && _jsx(Icon, { color: colors.positive[500], name: "checkmark-filled", size: 14 })] }));
50
- } })] }) })] }));
51
- };
@@ -1,12 +0,0 @@
1
- import { ReactNode } from "react";
2
- type Props = {
3
- initialValue: string;
4
- placeholder: string;
5
- onChangeText: (text: string) => void;
6
- debounceDuration?: number;
7
- maxWidth?: number;
8
- children?: ReactNode;
9
- renderEnd?: () => ReactNode;
10
- };
11
- export declare const LakeSearchField: ({ initialValue, placeholder, onChangeText, debounceDuration, maxWidth: maxWidthProp, renderEnd, children, }: Props) => import("react/jsx-runtime").JSX.Element;
12
- export {};
@@ -1,102 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useCallback, useRef, useState } from "react";
3
- import { Pressable, StyleSheet, View } from "react-native";
4
- import { animations, backgroundColor, colors, radii, spacings } from "../constants/design";
5
- import { useBoolean } from "../hooks/useBoolean";
6
- import { useDebounce } from "../hooks/useDebounce";
7
- import { isNotNullishOrEmpty } from "../utils/nullish";
8
- import { Icon } from "./Icon";
9
- import { LakeButton } from "./LakeButton";
10
- import { LakeTextInput } from "./LakeTextInput";
11
- import { ResponsiveContainer } from "./ResponsiveContainer";
12
- import { TransitionView } from "./TransitionView";
13
- const BREAKPOINT = 350;
14
- const styles = StyleSheet.create({
15
- container: {
16
- flexDirection: "row",
17
- alignItems: "center",
18
- justifyContent: "flex-end",
19
- flexGrow: 1,
20
- flexShrink: 1,
21
- },
22
- input: {
23
- transition: "300ms ease-in-out border-color",
24
- justifyContent: "flex-end",
25
- },
26
- focus: {
27
- outlineStyle: "none",
28
- borderColor: colors.current.primary,
29
- },
30
- clearButton: {
31
- padding: spacings[8],
32
- borderRadius: radii[4],
33
- },
34
- openSearchFieldContainer: {
35
- position: "absolute",
36
- right: 0,
37
- top: 0,
38
- bottom: 0,
39
- },
40
- openSearchField: {
41
- position: "absolute",
42
- right: 0,
43
- top: 0,
44
- bottom: 0,
45
- boxShadow: `0 0 20px 20px ${backgroundColor.default}`,
46
- borderRadius: radii[6],
47
- },
48
- });
49
- const CollapsibleSearchField = ({ inputRef, placeholder, initialValue, onChange, setFocused, hasFocus, clear, currentValue, renderEnd, }) => {
50
- return (_jsxs(View, { children: [_jsx(LakeButton, { mode: "secondary", size: "small", ariaLabel: placeholder, icon: "search-filled", onPress: setFocused.on, pill: currentValue !== "" }), _jsx(TransitionView, { style: styles.openSearchFieldContainer, ...animations.fadeAndSlideInFromRight, children: hasFocus ? (_jsx(View, { style: styles.openSearchField, children: _jsx(ExpandedSearchField, { inputRef: inputRef, placeholder: placeholder, initialValue: initialValue, onChange: onChange, setFocused: setFocused, hasFocus: hasFocus, clear: clear, currentValue: currentValue, renderEnd: renderEnd }) })) : null })] }));
51
- };
52
- const ExpandedSearchField = ({ inputRef, placeholder, initialValue, onChange, setFocused, hasFocus, clear, renderEnd, currentValue, }) => {
53
- const timeoutRef = useRef(null);
54
- return (_jsx(LakeTextInput, { ref: inputRef, autoFocus: hasFocus, icon: "search-filled", placeholder: placeholder, defaultValue: initialValue, inputMode: "search", onChangeText: onChange, hideErrors: true, renderEnd: () => (_jsxs(_Fragment, { children: [isNotNullishOrEmpty(currentValue) && (_jsx(Pressable, { role: "button", style: styles.clearButton, onPress: () => {
55
- if (timeoutRef.current != null) {
56
- clearTimeout(timeoutRef.current);
57
- }
58
- clear();
59
- }, children: _jsx(Icon, { name: "dismiss-filled", size: 12, color: colors.gray[500] }) })), renderEnd === null || renderEnd === void 0 ? void 0 : renderEnd()] })), onFocus: () => {
60
- if (timeoutRef.current != null) {
61
- clearTimeout(timeoutRef.current);
62
- }
63
- setFocused.on();
64
- }, onBlur: () => {
65
- timeoutRef.current = window.setTimeout(() => {
66
- setFocused.off();
67
- }, 300);
68
- }, style: [styles.input, hasFocus && styles.focus] }));
69
- };
70
- export const LakeSearchField = ({ initialValue, placeholder, onChangeText, debounceDuration = 500, maxWidth: maxWidthProp = 350, renderEnd, children, }) => {
71
- const [hasFocus, setFocused] = useBoolean(false);
72
- const inputRef = useRef(null);
73
- const [currentValue, setCurrentValue] = useState(initialValue);
74
- const onChange = useDebounce((value) => {
75
- onChangeText(value);
76
- setCurrentValue(value.trim());
77
- }, debounceDuration);
78
- const clear = useCallback(() => {
79
- if (inputRef.current != null) {
80
- inputRef.current.clear();
81
- inputRef.current.focus();
82
- onChangeText("");
83
- setCurrentValue("");
84
- }
85
- }, [onChangeText]);
86
- const props = {
87
- inputRef,
88
- placeholder,
89
- initialValue,
90
- onChange,
91
- setFocused,
92
- hasFocus,
93
- clear,
94
- currentValue,
95
- renderEnd,
96
- };
97
- const maxWidth = Math.max(maxWidthProp, BREAKPOINT);
98
- return (_jsx(ResponsiveContainer, { breakpoint: BREAKPOINT, style: [styles.container, { maxWidth }], children: ({ large }) => {
99
- const Component = large ? ExpandedSearchField : CollapsibleSearchField;
100
- return (_jsxs(_Fragment, { children: [children, _jsx(Component, { ...props })] }));
101
- } }));
102
- };