@swan-io/lake 2.7.1 → 2.7.3

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": "2.7.1",
3
+ "version": "2.7.3",
4
4
  "engines": {
5
5
  "node": ">=18.0.0",
6
6
  "yarn": "^1.22.0"
@@ -1,5 +1,20 @@
1
1
  /// <reference types="react" />
2
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
+ };
3
18
  type CardParams = {
4
19
  ownerName: string;
5
20
  cardNumber: string;
@@ -8,6 +23,7 @@ type CardParams = {
8
23
  color: "Silver" | "Black";
9
24
  logo: SVGElement | null;
10
25
  logoScale: number;
26
+ assetsUrls: Card3dAssetsUrls;
11
27
  onSvgError?: (code: string) => void;
12
28
  };
13
29
  type Props = CardParams & {
@@ -4,20 +4,6 @@ import { Canvas, useFrame } from "@react-three/fiber";
4
4
  import { forwardRef, useEffect, useRef, useState } from "react";
5
5
  import * as THREE from "three";
6
6
  import { match } from "ts-pattern";
7
- import envNxUrl from "../assets/3d-card/environment/nx.png?url";
8
- import envNyUrl from "../assets/3d-card/environment/ny.png?url";
9
- import envNzUrl from "../assets/3d-card/environment/nz.png?url";
10
- import envPxUrl from "../assets/3d-card/environment/px.png?url";
11
- import envPyUrl from "../assets/3d-card/environment/py.png?url";
12
- import envPzUrl from "../assets/3d-card/environment/pz.png?url";
13
- import fontMaisonNeueBookUrl from "../assets/3d-card/model/MaisonNeue-Book.woff?url";
14
- import fontMarkProRegularUrl from "../assets/3d-card/model/MarkPro-Regular.ttf?url";
15
- import bandRoughnessUrl from "../assets/3d-card/model/band_roughness.jpg?url";
16
- import cardGltfUrl from "../assets/3d-card/model/card.gltf?url";
17
- import chipUrl from "../assets/3d-card/model/chip.jpg?url";
18
- import colorBlackUrl from "../assets/3d-card/model/color_black.jpg?url";
19
- import colorSilverUrl from "../assets/3d-card/model/color_silver.jpg?url";
20
- import shinyColorFragmentShader from "../assets/3d-card/shaders/shinyColorFragment.glsl?raw";
21
7
  import { isNotNullish, isNullish } from "../utils/nullish";
22
8
  import { createSvgImage, getMonochromeSvg } from "../utils/svg";
23
9
  /*
@@ -40,6 +26,19 @@ And this texture is used as an alpha map on a plane.
40
26
  To reproduce the shiny effect on the back of the card, we inject a custom shader in rainbow_mastercard material.
41
27
  This custom shader chunk change the diffuse color depending on camera position.
42
28
  */
29
+ const shinyColorFragmentShader = `
30
+ float red = cameraPosition.x * cameraPosition.z;
31
+ float green = cameraPosition.y * cameraPosition.z;
32
+ float blue = 0.1;
33
+
34
+ red = sin(red / 5.0) + 1.0 / 2.0;
35
+ green = sin(green / 5.0) + 1.0 / 2.0;
36
+
37
+ vec3 shinyColor = vec3(red, green, blue);
38
+ float shinyFactor = 0.35;
39
+
40
+ diffuseColor.rgb = mix(diffuseColor.rgb, shinyColor, shinyFactor);
41
+ `;
43
42
  const ENV_MAP_INTENSITY = 3;
44
43
  const CARD_WIDTH = 8.56;
45
44
  const CARD_HEIGHT = 5.4;
@@ -72,13 +71,21 @@ export default (props) => {
72
71
  return (_jsxs(Canvas, { camera: { position: [0, 0, 12], fov: 50 }, children: [_jsx(OrbitControls, { enablePan: false, enableZoom: false }), _jsx(CardScene, { ...props })] }));
73
72
  };
74
73
  const CardScene = ({ autoRotationDuration, ...props }) => {
74
+ const { assetsUrls } = props;
75
75
  const card = useRef(null);
76
76
  useFrame(({ clock }) => {
77
77
  if (autoRotationDuration != null && card.current != null) {
78
78
  card.current.rotation.y = (clock.getElapsedTime() / autoRotationDuration) * Math.PI * 2;
79
79
  }
80
80
  });
81
- 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: [envPxUrl, envNxUrl, envPyUrl, envNyUrl, envPzUrl, envNzUrl] }), _jsx(Card, { ref: card, ...props })] }));
81
+ 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: [
82
+ assetsUrls.envPx,
83
+ assetsUrls.envNx,
84
+ assetsUrls.envPy,
85
+ assetsUrls.envNy,
86
+ assetsUrls.envPz,
87
+ assetsUrls.envNz,
88
+ ] }), _jsx(Card, { ref: card, ...props })] }));
82
89
  };
83
90
  // Set color space to sRGB for textures
84
91
  const setTextureColorSpace = (texture) => {
@@ -86,13 +93,13 @@ const setTextureColorSpace = (texture) => {
86
93
  texture.colorSpace = THREE.SRGBColorSpace;
87
94
  }
88
95
  };
89
- export const Card = forwardRef(({ ownerName, cardNumber, expirationDate, cvv, color, logo, logoScale, onSvgError, ...props }, ref) => {
90
- const { nodes, materials } = useGLTF(cardGltfUrl);
96
+ export const Card = forwardRef(({ ownerName, cardNumber, expirationDate, cvv, color, logo, logoScale, assetsUrls, onSvgError, ...props }, ref) => {
97
+ const { nodes, materials } = useGLTF(assetsUrls.cardGltf);
91
98
  const [logoData, setLogoData] = useState(null);
92
- const silverTexture = useTexture(colorSilverUrl, setTextureColorSpace);
93
- const blackTexture = useTexture(colorBlackUrl, setTextureColorSpace);
94
- const chipTexture = useTexture(chipUrl, setTextureColorSpace);
95
- const bandRoughnessTexture = useTexture(bandRoughnessUrl); // keep default color space because it's grayscale
99
+ const silverTexture = useTexture(assetsUrls.colorSilver, setTextureColorSpace);
100
+ const blackTexture = useTexture(assetsUrls.colorBlack, setTextureColorSpace);
101
+ const chipTexture = useTexture(assetsUrls.chipTexture, setTextureColorSpace);
102
+ const bandRoughnessTexture = useTexture(assetsUrls.bandRoughness); // keep default color space because it's grayscale
96
103
  // Set environment map intensity for all materials
97
104
  useEffect(() => {
98
105
  Object.values(materials).forEach(material => {
@@ -155,7 +162,7 @@ export const Card = forwardRef(({ ownerName, cardNumber, expirationDate, cvv, co
155
162
  .with("Black", () => 0xeeeeee)
156
163
  .exhaustive(), metalness: 0.1, roughness: 0.55, envMapIntensity: ENV_MAP_INTENSITY }));
157
164
  const secondaryTextMaterial = (_jsx("meshStandardMaterial", { color: 0x666666, metalness: 0.1, roughness: 0.55, envMapIntensity: ENV_MAP_INTENSITY }));
158
- 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: fontMaisonNeueBookUrl, fontSize: 0.2, anchorX: "left", anchorY: "bottom", position: [-3.4, -1.95, 0], children: [ownerName, mainTextMaterial] }), _jsxs(Text, { font: fontMarkProRegularUrl, 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: fontMarkProRegularUrl, 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: fontMarkProRegularUrl, 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: fontMaisonNeueBookUrl, fontSize: 0.24, anchorX: "left", anchorY: "bottom", rotation: [0, Math.PI, 0], position: [4, 0.68, 0], children: ["Identifier: 0000000000", mainTextMaterial] }), _jsxs(Text, { font: fontMaisonNeueBookUrl, 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: fontMaisonNeueBookUrl, fontSize: 0.2, anchorX: "left", anchorY: "bottom", rotation: [0, Math.PI, 0], position: [4, -0.15, 0], children: ["by Mastercard international.", secondaryTextMaterial] }), _jsxs(Text, { font: fontMaisonNeueBookUrl, fontSize: 0.48, anchorX: "left", anchorY: "bottom", rotation: [0, Math.PI, 0], position: [4, -1.85, 0], children: [cardNumber, mainTextMaterial] }), _jsxs(Text, { font: fontMaisonNeueBookUrl, fontSize: 0.29, anchorX: "left", anchorY: "bottom", rotation: [0, Math.PI, 0], position: [4, -2.3, 0], children: [expirationDate, mainTextMaterial] }), _jsxs(Text, { font: fontMaisonNeueBookUrl, 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: fontMarkProRegularUrl, anchorX: "center", anchorY: "bottom", fontSize: 0.36, rotation: [0, Math.PI, 0], position: [-2.35, -1.15, 0], children: ["debit", mainTextMaterial] })] }), _jsx("group", {
165
+ 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: ["by 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", {
159
166
  // move group to change scale center at top right corner
160
167
  position: [
161
168
  CARD_WIDTH / 2 - LOGO_MARGIN_RIGHT,
@@ -141,7 +141,7 @@ const LakeComboboxWithRef = ({ inputRef, value, items, itemHeight = DEFAULT_ELEM
141
141
  close();
142
142
  }, 100);
143
143
  }, [close]);
144
- return (_jsxs(View, { children: [_jsx(LakeTextInput, { ref: inputTextRef, style: styles.input, ariaExpanded: isFocused, ariaControls: isFocused ? suggestionsId : "", enterKeyHint: "search", icon: icon, role: "combobox", placeholder: placeholder, value: value, disabled: disabled, error: error, hideErrors: hideErrors, onChangeText: onValueChange, onChange: onChange, onFocus: handleFocus, onBlur: handleBlur, onKeyPress: handleKeyPress, id: id, 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, { maxHeight: itemHeight * nbItemsDisplayed }], children: items.match({
144
+ return (_jsxs(View, { children: [_jsx(LakeTextInput, { ref: inputTextRef, style: styles.input, ariaExpanded: isFocused, ariaControls: isFocused ? suggestionsId : "", enterKeyHint: "search", icon: icon, role: "combobox", placeholder: placeholder, value: value, disabled: disabled, error: error, hideErrors: hideErrors, onChangeText: onValueChange, onChange: onChange, onFocus: handleFocus, onBlur: handleBlur, onKeyPress: handleKeyPress, id: id, readOnly: readOnly }), _jsx(Popover, { id: suggestionsId, role: "listbox", matchReferenceWidth: true, onDismiss: close, referenceRef: ref, autoFocus: false, returnFocus: true, visible: isFocused && !items.isNotAsked(), underlay: false, forcedMode: "Dropdown", children: _jsx(View, { style: [styles.list, { maxHeight: itemHeight * nbItemsDisplayed }], children: items.match({
145
145
  NotAsked: () => null,
146
146
  Loading: () => _jsx(LoadingView, { style: styles.loader }),
147
147
  Done: items => items.match({
@@ -49,7 +49,7 @@ export const sortedIndexOf = (array, value) => {
49
49
  if (item === value) {
50
50
  return searchIndex;
51
51
  }
52
- if (typeof item === "number" && typeof value === "number") {
52
+ if (item != null && value != null) {
53
53
  if (item > value) {
54
54
  endIndex = searchIndex;
55
55
  continue;
@@ -1,11 +0,0 @@
1
- float red = cameraPosition.x * cameraPosition.z;
2
- float green = cameraPosition.y * cameraPosition.z;
3
- float blue = 0.1;
4
-
5
- red = sin(red / 5.0) + 1.0 / 2.0;
6
- green = sin(green / 5.0) + 1.0 / 2.0;
7
-
8
- vec3 shinyColor = vec3(red, green, blue);
9
- float shinyFactor = 0.35;
10
-
11
- diffuseColor.rgb = mix(diffuseColor.rgb, shinyColor, shinyFactor);