@swan-io/lake 2.7.38 → 3.1.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": "2.7.38",
3
+ "version": "3.1.0",
4
4
  "engines": {
5
5
  "node": ">=18.0.0",
6
6
  "yarn": "^1.22.0"
@@ -20,7 +20,7 @@ type CardParams = {
20
20
  cardNumber: string;
21
21
  expirationDate: string;
22
22
  cvv: string;
23
- color: "Silver" | "Black";
23
+ color: "Silver" | "Black" | THREE.Texture;
24
24
  logo: SVGElement | HTMLImageElement | null;
25
25
  logoScale: number;
26
26
  assetsUrls: Card3dAssetsUrls;
@@ -132,7 +132,9 @@ export const Card = forwardRef(({ ownerName, cardNumber, expirationDate, cvv, co
132
132
  .with("Black", () => {
133
133
  materials.card.map = blackTexture;
134
134
  })
135
- .exhaustive();
135
+ .otherwise(texture => {
136
+ materials.card.map = texture;
137
+ });
136
138
  // force threejs to update material
137
139
  // because sometimes it doesn't apply texture on load randomly
138
140
  materials.card.needsUpdate = true;
@@ -172,9 +174,9 @@ export const Card = forwardRef(({ ownerName, cardNumber, expirationDate, cvv, co
172
174
  const mainTextMaterial = (_jsx("meshStandardMaterial", { color: match(color)
173
175
  .with("Silver", () => 0x000000)
174
176
  .with("Black", () => 0xeeeeee)
175
- .exhaustive(), metalness: 0.1, roughness: 0.55, envMapIntensity: ENV_MAP_INTENSITY }));
177
+ .otherwise(() => 0xeeeeee), metalness: 0.1, roughness: 0.55, envMapIntensity: ENV_MAP_INTENSITY }));
176
178
  const secondaryTextMaterial = (_jsx("meshStandardMaterial", { color: 0x666666, metalness: 0.1, roughness: 0.55, envMapIntensity: ENV_MAP_INTENSITY }));
177
- 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", {
179
+ 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", {
178
180
  // move group to change scale center at top right corner
179
181
  position: [
180
182
  CARD_WIDTH / 2 - LOGO_MARGIN_RIGHT,
@@ -190,5 +192,5 @@ export const Card = forwardRef(({ ownerName, cardNumber, expirationDate, cvv, co
190
192
  }, color: match(color)
191
193
  .with("Silver", () => 0x000000)
192
194
  .with("Black", () => 0xffffff)
193
- .exhaustive(), 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 })] }) }));
195
+ .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 })] }) }));
194
196
  });
@@ -1,6 +1,6 @@
1
+ import { DateFormat, DatePickerDate } from "@swan-io/shared-business/src/components/DatePicker";
1
2
  import { ValidatorResult } from "react-ux-form";
2
3
  import { Simplify } from "type-fest";
3
- import { DateFormat, DatePickerDate, MonthNames, WeekDayNames } from "./DatePicker";
4
4
  type Item<T> = {
5
5
  label: string;
6
6
  value: T;
@@ -22,8 +22,6 @@ export type FilterRadioDef<T> = {
22
22
  export type FilterDateDef<Values = unknown> = {
23
23
  type: "date";
24
24
  label: string;
25
- monthNames: MonthNames;
26
- dayNames: WeekDayNames;
27
25
  cancelText: string;
28
26
  submitText: string;
29
27
  noValueText: string;
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { DatePickerModal, } from "@swan-io/shared-business/src/components/DatePicker";
2
3
  import dayjs from "dayjs";
3
4
  import { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from "react";
4
5
  import { FlatList, Pressable, StyleSheet, Text, View } from "react-native";
@@ -10,7 +11,6 @@ import { useMergeRefs } from "../hooks/useMergeRefs";
10
11
  import { usePreviousValue } from "../hooks/usePreviousValue";
11
12
  import { isNotNullish } from "../utils/nullish";
12
13
  import { Box } from "./Box";
13
- import { DatePickerModal, } from "./DatePicker";
14
14
  import { Icon } from "./Icon";
15
15
  import { LakeButton } from "./LakeButton";
16
16
  import { LakeCheckbox } from "./LakeCheckbox";
@@ -154,11 +154,11 @@ function FilterCheckbox({ label, items, width, checkAllLabel, value, onValueChan
154
154
  return (_jsxs(Pressable, { role: "radio", "aria-checked": isSelected, style: ({ hovered }) => [styles.radio, hovered && styles.itemHovered], onPress: onPress, children: [_jsx(LakeCheckbox, { value: isSelected }), _jsx(Space, { width: 12 }), _jsx(Text, { style: styles.itemLabel, children: item.label })] }));
155
155
  } }), _jsx(Space, { height: 8 }), _jsx(View, { style: styles.buttonContainer, children: _jsx(LakeButton, { color: "current", onPress: save, children: applyButtonLabel }) }), _jsx(Space, { height: 24 })] }) })] }));
156
156
  }
157
- function FilterDate({ label, monthNames, dayNames, initialValue, noValueText, cancelText, submitText, dateFormat, isSelectable, validate, onSave, onPressRemove, autoOpen = false, }) {
157
+ function FilterDate({ label, initialValue, noValueText, cancelText, submitText, dateFormat, isSelectable, validate, onSave, onPressRemove, autoOpen = false, }) {
158
158
  const inputRef = useRef(null);
159
159
  const [visible, { close, toggle }] = useDisclosure(autoOpen);
160
160
  const value = useMemo(() => (isNotNullish(initialValue) ? dayjs(initialValue).format(dateFormat) : ""), [initialValue, dateFormat]);
161
- return (_jsxs(View, { style: styles.container, children: [_jsx(FilterTag, { label: label, onPress: toggle, ref: inputRef, onPressRemove: onPressRemove, isActive: visible, value: isNotNullish(initialValue) ? dayjs(initialValue).format(dateFormat) : noValueText }), _jsx(DatePickerModal, { visible: visible, monthNames: monthNames, weekDayNames: dayNames, format: dateFormat, firstWeekDay: "monday", label: label, cancelLabel: cancelText, confirmLabel: submitText, value: value, isSelectable: isSelectable, validate: validate, onChange: value => {
161
+ return (_jsxs(View, { style: styles.container, children: [_jsx(FilterTag, { label: label, onPress: toggle, ref: inputRef, onPressRemove: onPressRemove, isActive: visible, value: isNotNullish(initialValue) ? dayjs(initialValue).format(dateFormat) : noValueText }), _jsx(DatePickerModal, { visible: visible, format: dateFormat, firstWeekDay: "monday", label: label, cancelLabel: cancelText, confirmLabel: submitText, value: value, isSelectable: isSelectable, validate: validate, onChange: value => {
162
162
  const formattedValue = dayjs(value, dateFormat, true).toJSON();
163
163
  onSave(formattedValue);
164
164
  }, onDissmiss: close })] }));
@@ -211,7 +211,7 @@ export const FiltersStack = ({ filters, openedFilters, definition, onChangeOpene
211
211
  onChangeFilters({ ...filters, [filterName]: undefined });
212
212
  onChangeOpened(openedFilters.filter(f => f !== filterName));
213
213
  } })))
214
- .with({ type: "date" }, ({ type, label, monthNames, dayNames, noValueText, cancelText, submitText, dateFormat, isSelectable, validate, }) => (_jsx(FilterDate, { label: label, monthNames: monthNames, dayNames: dayNames, noValueText: noValueText, cancelText: cancelText, submitText: submitText, dateFormat: dateFormat, autoOpen: lastOpenedFilter === filterName, isSelectable: isSelectable ? date => isSelectable(date, filters) : undefined, validate: validate ? value => validate(value, filters) : undefined, initialValue: getFilterValue(type, filters, filterName), onSave: value => onChangeFilters({ ...filters, [filterName]: value }), onPressRemove: () => {
214
+ .with({ type: "date" }, ({ type, label, noValueText, cancelText, submitText, dateFormat, isSelectable, validate, }) => (_jsx(FilterDate, { label: label, noValueText: noValueText, cancelText: cancelText, submitText: submitText, dateFormat: dateFormat, autoOpen: lastOpenedFilter === filterName, isSelectable: isSelectable ? date => isSelectable(date, filters) : undefined, validate: validate ? value => validate(value, filters) : undefined, initialValue: getFilterValue(type, filters, filterName), onSave: value => onChangeFilters({ ...filters, [filterName]: value }), onPressRemove: () => {
215
215
  onChangeFilters({ ...filters, [filterName]: undefined });
216
216
  onChangeOpened(openedFilters.filter(f => f !== filterName));
217
217
  } })))
@@ -5,8 +5,6 @@ import { IconName } from "./Icon";
5
5
  export type ButtonProps = {
6
6
  ariaControls?: string;
7
7
  ariaExpanded?: boolean;
8
- ariaLabel?: string;
9
- children?: ReactNode;
10
8
  color?: ColorVariants;
11
9
  disabled?: boolean;
12
10
  loading?: boolean;
@@ -25,7 +23,13 @@ export type ButtonProps = {
25
23
  target?: string;
26
24
  };
27
25
  pill?: boolean;
28
- };
26
+ } & ({
27
+ ariaLabel: string;
28
+ children?: never;
29
+ } | {
30
+ ariaLabel?: string;
31
+ children: ReactNode;
32
+ });
29
33
  export declare const LakeButton: import("react").MemoExoticComponent<import("react").ForwardRefExoticComponent<ButtonProps & import("react").RefAttributes<View>>>;
30
34
  type GroupProps = {
31
35
  children: ReactNode;
@@ -1,12 +0,0 @@
1
- import { ReactNode } from "react";
2
- type Props<T> = {
3
- items: T[];
4
- large?: boolean;
5
- renderItem: (value: T) => ReactNode;
6
- value?: T;
7
- getId?: (item: T) => unknown;
8
- onChange: (value: T) => void;
9
- disabled?: boolean;
10
- };
11
- export declare const ChoicePicker: <T>({ items, getId, large, renderItem, value, disabled, onChange, }: Props<T>) => import("react/jsx-runtime").JSX.Element;
12
- export {};
@@ -1,192 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useRef, useState } from "react";
3
- import { ScrollView, StyleSheet, View } from "react-native";
4
- import { match } from "ts-pattern";
5
- import { commonStyles } from "../constants/commonStyles";
6
- import { breakpoints, negativeSpacings, spacings } from "../constants/design";
7
- import { useResponsive } from "../hooks/useResponsive";
8
- import { clampValue } from "../utils/math";
9
- import { detectScrollAnimationEnd } from "../utils/viewport";
10
- import { LakeButton } from "./LakeButton";
11
- import { LakeRadio } from "./LakeRadio";
12
- import { Pressable } from "./Pressable";
13
- import { Space } from "./Space";
14
- import { Tile } from "./Tile";
15
- const styles = StyleSheet.create({
16
- root: {
17
- alignSelf: "stretch",
18
- alignItems: "stretch",
19
- flexGrow: 1,
20
- overflow: "hidden",
21
- marginHorizontal: negativeSpacings[12],
22
- },
23
- scrollSnap: {
24
- scrollSnapType: "x mandatory",
25
- },
26
- container: {
27
- alignSelf: "stretch",
28
- flexDirection: "row",
29
- flexWrap: "wrap",
30
- alignItems: "stretch",
31
- justifyContent: "center",
32
- },
33
- mobileContainer: {
34
- flexWrap: "nowrap",
35
- justifyContent: "flex-start",
36
- transitionProperty: "transform",
37
- transitionDuration: "300ms",
38
- transitionTimingFunction: "ease-in-out",
39
- },
40
- item: {
41
- flexGrow: 0,
42
- flexBasis: "33.333%",
43
- maxWidth: 300,
44
- padding: spacings[12],
45
- },
46
- itemAnimation: {
47
- transform: "translateZ(0px)",
48
- animationKeyframes: {
49
- from: {
50
- opacity: 0,
51
- transform: "translateZ(0px) translateX(50px)",
52
- },
53
- to: {
54
- opacity: 1,
55
- transform: "translateZ(0px) translateX(0px)",
56
- },
57
- },
58
- animationDuration: "200ms",
59
- animationFillMode: "backwards",
60
- animationTimingFunction: "ease-in-out",
61
- },
62
- itemLarge: {
63
- flexBasis: "50%",
64
- maxWidth: "none",
65
- },
66
- itemSmallViewport: {
67
- width: "100%",
68
- flexBasis: "auto",
69
- maxWidth: "none",
70
- scrollSnapAlign: "center",
71
- },
72
- tileContents: {
73
- alignItems: "center",
74
- alignSelf: "stretch",
75
- flexGrow: 1,
76
- },
77
- tileRenderedContents: {
78
- alignItems: "center",
79
- alignSelf: "stretch",
80
- flexGrow: 1,
81
- },
82
- leftButton: {
83
- position: "absolute",
84
- top: "50%",
85
- left: negativeSpacings[24],
86
- transform: "translateY(-50%)",
87
- borderTopLeftRadius: 0,
88
- borderBottomLeftRadius: 0,
89
- borderWidth: 1,
90
- borderLeftWidth: 0,
91
- },
92
- rightButton: {
93
- position: "absolute",
94
- top: "50%",
95
- right: negativeSpacings[24],
96
- transform: "translateY(-50%)",
97
- borderTopRightRadius: 0,
98
- borderBottomRightRadius: 0,
99
- borderWidth: 1,
100
- borderRightWidth: 0,
101
- },
102
- });
103
- const identity = (x) => x;
104
- export const ChoicePicker = ({ items, getId = identity, large = false, renderItem, value, disabled = false, onChange, }) => {
105
- const containerRef = useRef(null);
106
- const { desktop } = useResponsive(breakpoints.medium);
107
- const [mobilePosition, setMobilePosition] = useState("start");
108
- useEffect(() => {
109
- if (desktop) {
110
- return;
111
- }
112
- // auto scroll to selected value on mobile
113
- const scrollContainer = containerRef.current;
114
- const index = items.findIndex(item => value === item);
115
- if (index !== -1 && scrollContainer instanceof HTMLDivElement) {
116
- const width = scrollContainer.offsetWidth;
117
- scrollContainer.scrollTo({ x: index * width, animated: false });
118
- }
119
- // if no value is selected, select first item
120
- if (value == null && items[0] != null) {
121
- onChange(items[0]);
122
- }
123
- // disable exhaustive-deps because we only want to run this effect only when screen size go from desktop to mobile
124
- }, [desktop]); // eslint-disable-line react-hooks/exhaustive-deps
125
- const onScroll = () => {
126
- // prevent scroll event when we change screen size from mobile to desktop
127
- if (desktop) {
128
- return;
129
- }
130
- const scrollContainer = containerRef.current;
131
- if (scrollContainer instanceof HTMLDivElement) {
132
- const scrollLeft = scrollContainer.scrollLeft;
133
- const width = scrollContainer.offsetWidth;
134
- const index = clampValue(0, items.length - 1)(Math.round(scrollLeft / width));
135
- const item = items[index];
136
- if (item != null) {
137
- onChange(item);
138
- }
139
- match(index)
140
- .with(0, () => setMobilePosition("start"))
141
- .with(items.length - 1, () => setMobilePosition("end"))
142
- .otherwise(() => setMobilePosition("middle"));
143
- }
144
- };
145
- const onPressPrevious = () => {
146
- const scrollContainer = containerRef.current;
147
- if (scrollContainer instanceof HTMLDivElement) {
148
- const scrollLeft = scrollContainer.scrollLeft;
149
- const width = scrollContainer.offsetWidth;
150
- const index = Math.round(scrollLeft / width);
151
- const previousIndex = Math.max(0, index - 1);
152
- // remove scroll snap during scroll animation to avoid weird behavior on older browsers
153
- scrollContainer.style.scrollSnapType = "none";
154
- containerRef.current?.scrollTo({ x: previousIndex * width, animated: true });
155
- detectScrollAnimationEnd(scrollContainer).onResolve(() => {
156
- // set back scroll snap
157
- // @ts-expect-error
158
- scrollContainer.style.scrollSnapType = null;
159
- });
160
- }
161
- };
162
- const onPressNext = () => {
163
- const scrollContainer = containerRef.current;
164
- if (scrollContainer instanceof HTMLDivElement) {
165
- const scrollLeft = scrollContainer.scrollLeft;
166
- const width = scrollContainer.offsetWidth;
167
- const index = Math.round(scrollLeft / width);
168
- const nextIndex = Math.min(items.length - 1, index + 1);
169
- // remove scroll snap during scroll animation to avoid weird behavior on older browsers
170
- scrollContainer.style.scrollSnapType = "none";
171
- containerRef.current?.scrollTo({ x: nextIndex * width, animated: true });
172
- detectScrollAnimationEnd(scrollContainer).onResolve(() => {
173
- // set back scroll snap
174
- // @ts-expect-error
175
- scrollContainer.style.scrollSnapType = null;
176
- });
177
- }
178
- };
179
- return (_jsxs(View, { children: [_jsx(View, { style: styles.root, children: _jsx(ScrollView, { ref: containerRef, horizontal: !desktop, onScroll: onScroll, scrollEventThrottle: 200, style: styles.scrollSnap, contentContainerStyle: [
180
- styles.container,
181
- !desktop && styles.mobileContainer,
182
- !desktop && { width: `${items.length * 100}%` },
183
- ], children: items.map((item, index) => (_jsx(Pressable, { disabled: disabled, style: [
184
- styles.item,
185
- disabled && commonStyles.disabled,
186
- desktop && styles.itemAnimation,
187
- desktop && { animationDelay: `${200 + 100 * index}ms` },
188
- large && styles.itemLarge,
189
- !desktop && styles.itemSmallViewport,
190
- !desktop && { width: `${100 / items.length}%` },
191
- ], onPress: () => onChange(item), children: ({ hovered }) => (_jsx(Tile, { hovered: hovered, selected: value != null && getId(item) === getId(value), flexGrow: 1, children: _jsxs(View, { style: styles.tileContents, children: [_jsx(View, { style: styles.tileRenderedContents, children: renderItem(item) }), desktop && (_jsxs(_Fragment, { children: [_jsx(Space, { height: 24 }), _jsx(LakeRadio, { value: value != null && getId(item) === getId(value) })] }))] }) })) }, String(index)))) }) }), !desktop && (_jsx(LakeButton, { icon: "chevron-left-filled", mode: "secondary", forceBackground: true, onPress: onPressPrevious, disabled: mobilePosition === "start" || disabled, style: styles.leftButton })), !desktop && (_jsx(LakeButton, { icon: "chevron-right-filled", mode: "secondary", forceBackground: true, onPress: onPressNext, disabled: mobilePosition === "end" || disabled, style: styles.rightButton }))] }));
192
- };
@@ -1,90 +0,0 @@
1
- import { Option } from "@swan-io/boxed";
2
- import { ValidatorResult } from "react-ux-form";
3
- import { Except } from "type-fest";
4
- export type MonthNames = readonly [
5
- string,
6
- string,
7
- string,
8
- string,
9
- string,
10
- string,
11
- string,
12
- string,
13
- string,
14
- string,
15
- string,
16
- string
17
- ];
18
- export type WeekDayNames = readonly [string, string, string, string, string, string, string];
19
- declare const weekDayIndex: {
20
- sunday: number;
21
- monday: number;
22
- tuesday: number;
23
- wednesday: number;
24
- thursday: number;
25
- friday: number;
26
- saturday: number;
27
- };
28
- export type DatePickerDate = {
29
- day: number;
30
- month: number;
31
- year: number;
32
- };
33
- export type DatePickerRange = {
34
- start: Option<DatePickerDate>;
35
- end: Option<DatePickerDate>;
36
- };
37
- export type DateFormat = "DD/MM/YYYY" | "MM/DD/YYYY";
38
- export declare const validateDateRangeOrder: (value: {
39
- start: string;
40
- end: string;
41
- }, format: DateFormat) => boolean;
42
- export declare const isTodayOrFutureDate: (date: DatePickerDate) => boolean;
43
- export declare const isDateInRange: (minDate: Date, maxDate: Date) => (date: DatePickerDate) => boolean;
44
- export type DatePickerProps = {
45
- label: string;
46
- value?: string;
47
- error?: string;
48
- format: DateFormat;
49
- firstWeekDay: keyof typeof weekDayIndex;
50
- monthNames: MonthNames;
51
- weekDayNames: WeekDayNames;
52
- isSelectable?: (date: DatePickerDate) => boolean;
53
- onChange: (date: string) => void;
54
- };
55
- export declare const DatePicker: ({ label, value, error, format, firstWeekDay, monthNames, weekDayNames, isSelectable, onChange, }: DatePickerProps) => import("react/jsx-runtime").JSX.Element;
56
- type DatePickerModalProps = Except<DatePickerProps, "error"> & {
57
- visible: boolean;
58
- cancelLabel: string;
59
- confirmLabel: string;
60
- validate?: (value: string) => ValidatorResult;
61
- onDissmiss: () => void;
62
- };
63
- export declare const DatePickerModal: ({ value, format, firstWeekDay, monthNames, weekDayNames, isSelectable, onChange, visible, label, cancelLabel, confirmLabel, validate, onDissmiss, }: DatePickerModalProps) => import("react/jsx-runtime").JSX.Element;
64
- export type DateRangePickerProps = {
65
- value: {
66
- start: string;
67
- end: string;
68
- };
69
- error?: string;
70
- format: DateFormat;
71
- startLabel: string;
72
- endLabel: string;
73
- firstWeekDay: keyof typeof weekDayIndex;
74
- monthNames: MonthNames;
75
- weekDayNames: WeekDayNames;
76
- isSelectable?: (date: DatePickerDate) => boolean;
77
- onChange: (date: {
78
- start: string;
79
- end: string;
80
- }) => void;
81
- };
82
- export declare const DateRangePicker: ({ value, error, format, startLabel, endLabel, firstWeekDay, monthNames, weekDayNames, isSelectable, onChange, }: DateRangePickerProps) => import("react/jsx-runtime").JSX.Element;
83
- type DateRangePickerModalProps = DateRangePickerProps & {
84
- visible: boolean;
85
- cancelLabel: string;
86
- confirmLabel: string;
87
- onDissmiss: () => void;
88
- };
89
- export declare const DateRangePickerModal: ({ value, error, format, firstWeekDay, monthNames, weekDayNames, isSelectable, onChange, visible, startLabel, endLabel, cancelLabel, confirmLabel, onDissmiss, }: DateRangePickerModalProps) => import("react/jsx-runtime").JSX.Element;
90
- export {};
@@ -1,619 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Option } from "@swan-io/boxed";
3
- import dayjs from "dayjs";
4
- import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
5
- import { StyleSheet, View } from "react-native";
6
- import { useForm } from "react-ux-form";
7
- import { Rifm } from "rifm";
8
- import { P, match } from "ts-pattern";
9
- import { colors, spacings } from "../constants/design";
10
- import { useDisclosure } from "../hooks/useDisclosure";
11
- import { useFirstMountState } from "../hooks/useFirstMountState";
12
- import { useResponsive } from "../hooks/useResponsive";
13
- import { noop } from "../utils/function";
14
- import { isNotNullish, isNotNullishOrEmpty, isNullishOrEmpty } from "../utils/nullish";
15
- import { getRifmProps } from "../utils/rifm";
16
- import { BottomPanel } from "./BottomPanel";
17
- import { Box } from "./Box";
18
- import { Fill } from "./Fill";
19
- import { Icon } from "./Icon";
20
- import { LakeButton } from "./LakeButton";
21
- import { LakeLabel } from "./LakeLabel";
22
- import { LakeModal } from "./LakeModal";
23
- import { LakeSelect } from "./LakeSelect";
24
- import { LakeText } from "./LakeText";
25
- import { LakeTextInput } from "./LakeTextInput";
26
- import { Popover } from "./Popover";
27
- import { Pressable } from "./Pressable";
28
- import { Separator } from "./Separator";
29
- import { Space } from "./Space";
30
- const styles = StyleSheet.create({
31
- label: {
32
- flex: 1,
33
- },
34
- arrowContainer: {
35
- height: 40, // input height
36
- },
37
- popover: {
38
- padding: spacings[12],
39
- },
40
- popoverDesktop: {
41
- padding: spacings[24],
42
- },
43
- rangeCalendarSide: {
44
- flex: 1,
45
- },
46
- button: {
47
- flex: 1,
48
- },
49
- monthSelect: {
50
- width: 130,
51
- },
52
- yearSelect: {
53
- width: 100,
54
- },
55
- weekRow: {
56
- paddingVertical: spacings[4],
57
- },
58
- dayName: {
59
- flex: 1,
60
- height: 32,
61
- alignItems: "center",
62
- justifyContent: "center",
63
- },
64
- dayContainer: {
65
- flex: 1,
66
- alignItems: "center",
67
- },
68
- dayRangeIndicator: {
69
- position: "absolute",
70
- top: 0,
71
- right: 0,
72
- bottom: 0,
73
- left: 0,
74
- backgroundColor: colors.current[100],
75
- },
76
- dayStartRangeIndicator: {
77
- left: "50%",
78
- },
79
- dayEndRangeIndicator: {
80
- right: "50%",
81
- },
82
- dayNumber: {
83
- width: 32,
84
- height: 32,
85
- alignItems: "center",
86
- justifyContent: "center",
87
- borderRadius: 16,
88
- },
89
- dayNumberFocused: {},
90
- dayNumberHover: {
91
- backgroundColor: colors.current[100],
92
- },
93
- dayNumberPressed: {},
94
- dayNumberSelected: {
95
- backgroundColor: colors.current[500],
96
- },
97
- todayIndicator: {
98
- position: "absolute",
99
- left: 0,
100
- right: 0,
101
- bottom: 0,
102
- width: 4,
103
- height: 4,
104
- marginHorizontal: "auto",
105
- borderRadius: 2,
106
- backgroundColor: colors.current[500],
107
- },
108
- });
109
- const MODALE_MOBILE_THRESHOLD = 600;
110
- const DATE_PICKER_MOBILE_THRESHOLD = 400;
111
- const DATE_RANGE_PICKER_THRESHOLD = 800;
112
- const NB_DAYS_IN_WEEK = 7;
113
- const weekDayIndex = {
114
- sunday: 0,
115
- monday: 1,
116
- tuesday: 2,
117
- wednesday: 3,
118
- thursday: 4,
119
- friday: 5,
120
- saturday: 6,
121
- };
122
- const rifmDateProps = getRifmProps({
123
- accept: "numeric",
124
- charMap: { 2: "/", 4: "/" },
125
- maxLength: 8,
126
- });
127
- const parseDate = (value, format) => {
128
- const date = dayjs.utc(value, format);
129
- return date.isValid()
130
- ? Option.Some({ day: date.date(), month: date.month(), year: date.year() })
131
- : Option.None();
132
- };
133
- const parseRange = (value, format) => {
134
- return {
135
- start: parseDate(value.start, format),
136
- end: parseDate(value.end, format),
137
- };
138
- };
139
- const stringifyDate = (value, format) => {
140
- const date = dayjs.utc().year(value.year).month(value.month).date(value.day);
141
- return date.format(format);
142
- };
143
- export const validateDateRangeOrder = (value, format) => {
144
- const range = parseRange(value, format);
145
- if (range.start.isNone() || range.end.isNone()) {
146
- return true;
147
- }
148
- if (isDateAfter(range.start.value, range.end.value)) {
149
- return false;
150
- }
151
- return true;
152
- };
153
- const range = (start, end) => {
154
- const result = [];
155
- for (let i = start; i <= end; i++) {
156
- result.push(i);
157
- }
158
- return result;
159
- };
160
- const groupEvery = (input, groupSize) => {
161
- const result = [];
162
- const nbGroups = Math.ceil(input.length / groupSize);
163
- for (let i = 0; i < nbGroups; i++) {
164
- result.push(input.slice(i * groupSize, (i + 1) * groupSize));
165
- }
166
- return result;
167
- };
168
- const padEnd = (input, length, value) => {
169
- const itemsToAppend = new Array(length - input.length).fill(value);
170
- return [...input, ...itemsToAppend];
171
- };
172
- export const isTodayOrFutureDate = (date) => {
173
- const yesterday = new Date();
174
- yesterday.setDate(yesterday.getDate() - 1);
175
- const yesterdayDate = {
176
- day: yesterday.getDate(),
177
- month: yesterday.getMonth(),
178
- year: yesterday.getFullYear(),
179
- };
180
- return isDateAfter(date, yesterdayDate);
181
- };
182
- export const isDateInRange = (minDate, maxDate) => (date) => {
183
- const min = {
184
- day: minDate.getDate(),
185
- month: minDate.getMonth(),
186
- year: minDate.getFullYear(),
187
- };
188
- const max = {
189
- day: maxDate.getDate(),
190
- month: maxDate.getMonth(),
191
- year: maxDate.getFullYear(),
192
- };
193
- return isDateAfter(date, min) && isDateBefore(date, max);
194
- };
195
- const isDateToday = (date) => {
196
- const today = new Date();
197
- return (date.day === today.getDate() &&
198
- date.month === today.getMonth() &&
199
- date.year === today.getFullYear());
200
- };
201
- const getMonthDates = (month, year) => {
202
- const aggregate = (acc, date) => {
203
- const dateDay = date.getDate();
204
- const dateMonth = date.getMonth();
205
- const dateYear = date.getFullYear();
206
- if (date.getMonth() !== month) {
207
- return acc;
208
- }
209
- return aggregate([...acc, { day: dateDay, month: dateMonth, year: dateYear }], new Date(year, month, dateDay + 1));
210
- };
211
- return aggregate([], new Date(year, month, 1));
212
- };
213
- const getMonthWeeks = (month, year, firstWeekDay) => {
214
- const firstWeekDayIndex = weekDayIndex[firstWeekDay];
215
- const monthFirstWeekDay = new Date(year, month, 1).getDay();
216
- const monthDates = getMonthDates(month, year).map(date => Option.Some(date));
217
- const nbDaysToPrepend = monthFirstWeekDay >= firstWeekDayIndex
218
- ? monthFirstWeekDay - firstWeekDayIndex
219
- : NB_DAYS_IN_WEEK - firstWeekDayIndex + monthFirstWeekDay;
220
- for (let i = 0; i < nbDaysToPrepend; i++) {
221
- monthDates.unshift(Option.None());
222
- }
223
- const weeks = groupEvery(monthDates, NB_DAYS_IN_WEEK);
224
- const lastWeek = weeks[weeks.length - 1];
225
- if (!lastWeek) {
226
- return weeks;
227
- }
228
- weeks[weeks.length - 1] = padEnd(lastWeek, NB_DAYS_IN_WEEK, Option.None());
229
- return weeks;
230
- };
231
- const getWeekDayNames = (dayNames, firstWeekDay = "sunday") => {
232
- const firstWeekDayIndex = weekDayIndex[firstWeekDay];
233
- const firstWeekDayNames = dayNames.slice(firstWeekDayIndex);
234
- const lastWeekDayNames = dayNames.slice(0, firstWeekDayIndex);
235
- // @ts-expect-error
236
- return [...firstWeekDayNames, ...lastWeekDayNames];
237
- };
238
- const isDateEquals = (date1, date2) => {
239
- return date1.day === date2.day && date1.month === date2.month && date1.year === date2.year;
240
- };
241
- const isDateBefore = (date1, date2) => {
242
- return (date1.year < date2.year ||
243
- (date1.year === date2.year && date1.month < date2.month) ||
244
- (date1.year === date2.year && date1.month === date2.month && date1.day < date2.day));
245
- };
246
- const isDateAfter = (date1, date2) => {
247
- return (date1.year > date2.year ||
248
- (date1.year === date2.year && date1.month > date2.month) ||
249
- (date1.year === date2.year && date1.month === date2.month && date1.day > date2.day));
250
- };
251
- const isDateRange = (value) => {
252
- return match(value)
253
- .with({ start: P._, end: P._ }, () => true)
254
- .otherwise(() => false);
255
- };
256
- const isSelectedDate = (date, value) => {
257
- return match(value)
258
- .with(Option.pattern.Some(P.select()), value => isDateEquals(value, date))
259
- .with(Option.pattern.None, () => false)
260
- .with(P.when(isDateRange), ({ start, end }) => {
261
- // if range is invalid, we don't display any selection
262
- if (start.isSome() && end.isSome() && isDateAfter(start.value, end.value)) {
263
- return false;
264
- }
265
- return (start.match({
266
- Some: start => isDateEquals(start, date),
267
- None: () => false,
268
- }) ||
269
- end.match({
270
- Some: end => isDateEquals(end, date),
271
- None: () => false,
272
- }));
273
- })
274
- .exhaustive();
275
- };
276
- const getRangeIndicatorType = (date, value) => {
277
- if (!isDateRange(value)) {
278
- return "none";
279
- }
280
- const { start, end } = value;
281
- if (start.isNone() || end.isNone()) {
282
- return "none";
283
- }
284
- const startDate = start.value;
285
- const endDate = end.value;
286
- // no interval indicator if range is invalid
287
- if (isDateAfter(startDate, endDate)) {
288
- return "none";
289
- }
290
- if (isDateEquals(startDate, endDate)) {
291
- return "none";
292
- }
293
- if (isDateEquals(date, startDate)) {
294
- return "start";
295
- }
296
- if (isDateEquals(date, endDate)) {
297
- return "end";
298
- }
299
- if (isDateAfter(date, startDate) && isDateBefore(date, endDate)) {
300
- return "between";
301
- }
302
- return "none";
303
- };
304
- const computeDateDistanceInDays = (date1, date2) => {
305
- const date1Date = new Date(date1.year, date1.month, date1.day);
306
- const date2Date = new Date(date2.year, date2.month, date2.day);
307
- const diffInMs = Math.abs(date2Date.getTime() - date1Date.getTime());
308
- return Math.round(diffInMs / (1000 * 3600 * 24));
309
- };
310
- const getNewDateRange = (currentRange, selectedDate) => {
311
- const { start, end } = currentRange;
312
- // Handle initial selection
313
- if (start.isNone()) {
314
- return { start: Option.Some(selectedDate), end: Option.None() };
315
- }
316
- if (end.isNone()) {
317
- if (isDateAfter(selectedDate, start.value)) {
318
- return { start, end: Option.Some(selectedDate) };
319
- }
320
- return { start: Option.Some(selectedDate), end: currentRange.start };
321
- }
322
- // Handle selection outside of the current range
323
- if (isDateBefore(selectedDate, start.value)) {
324
- return { start: Option.Some(selectedDate), end: currentRange.end };
325
- }
326
- if (isDateAfter(selectedDate, end.value)) {
327
- return { start: currentRange.start, end: Option.Some(selectedDate) };
328
- }
329
- // We change the closest date to the new date
330
- const startDistance = computeDateDistanceInDays(start.value, selectedDate);
331
- const endDistance = computeDateDistanceInDays(end.value, selectedDate);
332
- if (startDistance < endDistance) {
333
- return { start: Option.Some(selectedDate), end: currentRange.end };
334
- }
335
- return { start: currentRange.start, end: Option.Some(selectedDate) };
336
- };
337
- const getTodayYearMonth = () => ({
338
- month: new Date().getMonth(),
339
- year: new Date().getFullYear(),
340
- });
341
- const getYearMonth = (value, format) => {
342
- if (isNullishOrEmpty(value)) {
343
- return Option.None();
344
- }
345
- return parseDate(value, format);
346
- };
347
- const isYearMonthBefore = (date1, date2) => {
348
- return date1.year < date2.year || (date1.year === date2.year && date1.month < date2.month);
349
- };
350
- const isYearMonthEquals = (date1, date2) => {
351
- return date1.year === date2.year && date1.month === date2.month;
352
- };
353
- const minYearMonth = (date1, date2) => {
354
- return isYearMonthBefore(date1, date2) ? date1 : date2;
355
- };
356
- const maxYearMonth = (date1, date2) => {
357
- return isYearMonthBefore(date1, date2) ? date2 : date1;
358
- };
359
- const incrementYearMonth = ({ month, year }) => {
360
- if (month === 11) {
361
- return { month: 0, year: year + 1 };
362
- }
363
- return { month: month + 1, year };
364
- };
365
- const decrementYearMonth = ({ month, year }) => {
366
- if (month === 0) {
367
- return { month: 11, year: year - 1 };
368
- }
369
- return { month: month - 1, year };
370
- };
371
- const YearMonthSelect = ({ monthNames, value, arrowsPosition = "right", hideArrows, minValue, maxValue, onChange, }) => {
372
- const monthItems = useMemo(() => monthNames.map((name, index) => ({ name, value: index })), [monthNames]);
373
- const yearItems = useMemo(() => range(value.year - 5, value.year + 5).map(year => ({
374
- name: year.toString(),
375
- value: year,
376
- })), [value.year]);
377
- const selectMonth = (month) => {
378
- onChange({ year: value.year, month });
379
- };
380
- const selectYear = (year) => {
381
- onChange({ year, month: value.month });
382
- };
383
- const setPreviousMonth = () => {
384
- onChange(decrementYearMonth(value));
385
- };
386
- const setNextMonth = () => {
387
- onChange(incrementYearMonth(value));
388
- };
389
- const isPreviousDisabled = !minValue
390
- ? false
391
- : value.year <= minValue.year && value.month <= minValue.month;
392
- const isNextDisabled = !maxValue
393
- ? false
394
- : value.year >= maxValue.year && value.month >= maxValue.month;
395
- return (_jsxs(Box, { direction: "row", alignItems: "center", children: [arrowsPosition === "around" && hideArrows !== true && (_jsxs(_Fragment, { children: [_jsx(LakeButton, { size: "small", mode: "tertiary", icon: "arrow-left-filled", disabled: isPreviousDisabled, onPress: setPreviousMonth }), _jsx(Fill, { minWidth: 12 })] })), _jsx(LakeSelect, { items: monthItems, value: value.month, onValueChange: selectMonth, mode: "borderless", size: "small", hideErrors: true, style: styles.monthSelect }), _jsx(LakeSelect, { items: yearItems, value: value.year, onValueChange: selectYear, mode: "borderless", size: "small", hideErrors: true, style: styles.yearSelect }), hideArrows !== true && (_jsxs(_Fragment, { children: [_jsx(Fill, { minWidth: 12 }), arrowsPosition === "right" && (_jsxs(_Fragment, { children: [_jsx(LakeButton, { size: "small", mode: "tertiary", icon: "arrow-left-filled", disabled: isPreviousDisabled, onPress: setPreviousMonth }), _jsx(Space, { width: 12 })] })), _jsx(LakeButton, { size: "small", mode: "tertiary", icon: "arrow-right-filled", disabled: isNextDisabled, onPress: setNextMonth })] }))] }));
396
- };
397
- const MonthCalendar = ({ month, year, value, firstWeekDay, weekDayNames, isSelectable, onChange, }) => {
398
- const dayNames = useMemo(() => getWeekDayNames(weekDayNames, firstWeekDay), [weekDayNames, firstWeekDay]);
399
- const weeks = useMemo(() => getMonthWeeks(month, year, firstWeekDay), [month, year, firstWeekDay]);
400
- return (_jsxs(View, { children: [_jsx(Box, { direction: "row", alignItems: "center", style: styles.weekRow, children: dayNames.map(dayName => (_jsx(View, { style: styles.dayName, children: _jsx(LakeText, { variant: "medium", color: colors.gray[600], children: dayName.substring(0, 1) }) }, dayName))) }), weeks.map((week, weekIndex) => (_jsx(Box, { direction: "row", alignItems: "center", style: styles.weekRow, children: week.map((date, dateIndex) => {
401
- const isDisabled = date.match({
402
- Some: date => isNotNullish(isSelectable) && !isSelectable(date),
403
- None: () => true,
404
- });
405
- const isSelected = date.match({
406
- Some: date => isSelectedDate(date, value),
407
- None: () => false,
408
- });
409
- const isToday = date.match({
410
- Some: date => isDateToday(date),
411
- None: () => false,
412
- });
413
- const rangeIndicator = date.match({
414
- Some: date => getRangeIndicatorType(date, value),
415
- None: () => "none",
416
- });
417
- return (_jsxs(View, { style: styles.dayContainer, children: [rangeIndicator !== "none" && (_jsx(View, { style: [
418
- styles.dayRangeIndicator,
419
- rangeIndicator === "start" && styles.dayStartRangeIndicator,
420
- rangeIndicator === "end" && styles.dayEndRangeIndicator,
421
- ] })), _jsxs(Pressable, { disabled: isDisabled, onPress: () => date.match({ Some: onChange, None: noop }), style: ({ focused, hovered, pressed }) => [
422
- styles.dayNumber,
423
- focused && styles.dayNumberFocused,
424
- hovered && styles.dayNumberHover,
425
- pressed && styles.dayNumberPressed,
426
- isSelected && styles.dayNumberSelected,
427
- ], children: [_jsx(LakeText, { variant: "smallRegular", color: isSelected
428
- ? colors.current.contrast
429
- : isDisabled
430
- ? colors.gray[300]
431
- : isToday
432
- ? colors.current[500]
433
- : colors.gray[900], children: date.match({ Some: ({ day }) => day.toString(), None: () => " " }) }), isToday && _jsx(View, { style: styles.todayIndicator })] })] }, dateIndex));
434
- }) }, weekIndex)))] }));
435
- };
436
- const DatePickerPopoverContent = ({ value, format, firstWeekDay, monthNames, weekDayNames, desktop, isSelectable, onChange, }) => {
437
- const [monthYear, setMonthYear] = useState(() => getYearMonth(value, format).getWithDefault(getTodayYearMonth()));
438
- // Automatically change displayed year and month when user change the value with text input
439
- useEffect(() => {
440
- const yearMonth = getYearMonth(value, format);
441
- if (yearMonth.isSome()) {
442
- setMonthYear(yearMonth.value);
443
- }
444
- }, [value, format]);
445
- const handleChange = useCallback((date) => {
446
- const formatted = stringifyDate(date, format);
447
- onChange(formatted);
448
- }, [format, onChange]);
449
- return (_jsxs(_Fragment, { children: [_jsx(YearMonthSelect, { monthNames: monthNames, value: monthYear, hideArrows: !desktop, onChange: setMonthYear }), _jsx(Space, { height: 24 }), _jsx(MonthCalendar, { month: monthYear.month, year: monthYear.year, value: isNotNullishOrEmpty(value) ? parseDate(value, format) : Option.None(), firstWeekDay: firstWeekDay, weekDayNames: weekDayNames, isSelectable: isSelectable, onChange: handleChange })] }));
450
- };
451
- export const DatePicker = ({ label, value, error, format, firstWeekDay, monthNames, weekDayNames, isSelectable, onChange, }) => {
452
- const { desktop } = useResponsive(DATE_PICKER_MOBILE_THRESHOLD);
453
- const ref = useRef(null);
454
- const [isOpened, { open, close }] = useDisclosure(false);
455
- const popoverId = useId();
456
- return (_jsxs(_Fragment, { children: [_jsx(Box, { direction: "row", alignItems: "end", children: _jsx(LakeLabel, { label: label, style: styles.label, actions: _jsx(LakeButton, { mode: "secondary", icon: "calendar-ltr-regular", size: "small", onPress: open }), render: id => (_jsx(Rifm, { value: value ?? "", onChange: onChange, ...rifmDateProps, children: ({ value, onChange }) => (_jsx(LakeTextInput, { ref: ref, id: id, placeholder: format, value: value, error: error, onChange: onChange, ariaExpanded: isOpened })) })) }) }), _jsx(Popover, { id: popoverId, role: "dialog", onDismiss: close, referenceRef: ref, visible: isOpened, children: _jsx(View, { style: desktop ? styles.popoverDesktop : styles.popover, children: _jsx(DatePickerPopoverContent, { value: value, format: format, firstWeekDay: firstWeekDay, monthNames: monthNames, weekDayNames: weekDayNames, desktop: desktop, isSelectable: isSelectable, onChange: onChange }) }) })] }));
457
- };
458
- export const DatePickerModal = ({ value, format, firstWeekDay, monthNames, weekDayNames, isSelectable, onChange, visible, label, cancelLabel, confirmLabel, validate, onDissmiss, }) => {
459
- const { desktop } = useResponsive(DATE_PICKER_MOBILE_THRESHOLD);
460
- const { Field, submitForm, setFieldValue, resetField } = useForm({
461
- date: {
462
- initialValue: value ?? "",
463
- validate,
464
- },
465
- });
466
- const handleCancel = () => {
467
- setFieldValue("date", value ?? "");
468
- onDissmiss();
469
- };
470
- const handleConfirm = () => {
471
- submitForm(({ date }) => {
472
- if (isNotNullishOrEmpty(date)) {
473
- onChange(date);
474
- }
475
- onDissmiss();
476
- });
477
- };
478
- useEffect(() => {
479
- if (!visible) {
480
- resetField("date");
481
- }
482
- }, [visible, resetField]);
483
- return (_jsxs(DateModal, { visible: visible, maxWidth: 500, onPressClose: handleCancel, children: [_jsx(Field, { name: "date", children: ({ ref, value, error, onBlur, onChange }) => (_jsxs(_Fragment, { children: [_jsx(LakeLabel, { label: label, render: id => (_jsx(Rifm, { value: value, onChange: onChange, ...rifmDateProps, children: ({ value, onChange }) => (_jsx(LakeTextInput, { ref: ref, id: id, placeholder: format, value: value, error: error, onBlur: onBlur, onChange: onChange })) })) }), _jsx(DatePickerPopoverContent, { value: value, format: format, firstWeekDay: firstWeekDay, monthNames: monthNames, weekDayNames: weekDayNames, desktop: desktop, isSelectable: isSelectable, onChange: onChange })] })) }), _jsx(Space, { height: 24 }), _jsxs(Box, { direction: "row", alignItems: "center", children: [_jsx(LakeButton, { mode: "secondary", size: "small", onPress: handleCancel, style: styles.button, children: cancelLabel }), _jsx(Space, { width: 24 }), _jsx(LakeButton, { color: "current", size: "small", onPress: handleConfirm, style: styles.button, children: confirmLabel })] })] }));
484
- };
485
- const DateModal = ({ children, visible, maxWidth, withCloseButton, onPressClose, }) => {
486
- const { desktop } = useResponsive(MODALE_MOBILE_THRESHOLD);
487
- if (desktop) {
488
- return (_jsx(LakeModal, { visible: visible, maxWidth: maxWidth, onPressClose: withCloseButton === true ? onPressClose : undefined, children: children }));
489
- }
490
- return (_jsx(BottomPanel, { visible: visible, onPressClose: onPressClose, children: _jsx(View, { style: styles.popover, children: children }) }));
491
- };
492
- const DateRangePickerModalContent = ({ value, format, firstWeekDay, monthNames, weekDayNames, desktop, displayTwoCalendar, isSelectable, onChange, }) => {
493
- const isFirstMount = useFirstMountState();
494
- const [periods, setPeriods] = useState(() => {
495
- const startYearMonth = getYearMonth(value.start, format).getWithDefault(getTodayYearMonth());
496
- const endYearMonth = getYearMonth(value.end, format).getWithDefault(incrementYearMonth(startYearMonth));
497
- return {
498
- start: startYearMonth,
499
- end: isYearMonthEquals(startYearMonth, endYearMonth)
500
- ? incrementYearMonth(startYearMonth)
501
- : endYearMonth,
502
- };
503
- });
504
- // Automatically change displayed year and month when start date changes
505
- useEffect(() => {
506
- if (isFirstMount) {
507
- return;
508
- }
509
- const startYearMonth = getYearMonth(value.start, format);
510
- if (startYearMonth.isSome()) {
511
- setPeriods(periods => {
512
- const isStartAndEndSameMonth = isYearMonthEquals(startYearMonth.value, periods.end);
513
- if (isStartAndEndSameMonth) {
514
- return {
515
- start: decrementYearMonth(periods.end),
516
- end: periods.end,
517
- };
518
- }
519
- // change end period if it becomes before start period
520
- const endPeriod = maxYearMonth(periods.end, incrementYearMonth(startYearMonth.value));
521
- return {
522
- start: startYearMonth.value,
523
- end: endPeriod,
524
- };
525
- });
526
- }
527
- }, [isFirstMount, value.start, format]);
528
- // Automatically change displayed year and month when end date changes
529
- useEffect(() => {
530
- if (isFirstMount) {
531
- return;
532
- }
533
- const endYearMonth = getYearMonth(value.end, format);
534
- if (endYearMonth.isSome()) {
535
- setPeriods(periods => {
536
- const isStartAndEndSameMonth = isYearMonthEquals(periods.start, endYearMonth.value);
537
- if (isStartAndEndSameMonth) {
538
- return {
539
- start: periods.start,
540
- end: incrementYearMonth(periods.start),
541
- };
542
- }
543
- // change start period if it becomes after end period
544
- const startPeriod = minYearMonth(periods.start, decrementYearMonth(endYearMonth.value));
545
- return {
546
- start: startPeriod,
547
- end: endYearMonth.value,
548
- };
549
- });
550
- }
551
- }, [isFirstMount, value.end, format]);
552
- const setStartPeriod = useCallback((yearMonth) => {
553
- setPeriods(periods => ({
554
- start: yearMonth,
555
- end: maxYearMonth(periods.end, incrementYearMonth(yearMonth)),
556
- }));
557
- }, []);
558
- const setEndPeriod = useCallback((yearMonth) => {
559
- setPeriods(periods => ({
560
- start: minYearMonth(periods.start, decrementYearMonth(yearMonth)),
561
- end: yearMonth,
562
- }));
563
- }, []);
564
- const dateRange = useMemo(() => parseRange(value, format), [value, format]);
565
- const handleSelectDate = (date) => {
566
- const newRange = getNewDateRange(dateRange, date);
567
- const newValue = {
568
- start: newRange.start.match({
569
- Some: date => stringifyDate(date, format),
570
- None: () => value.start,
571
- }),
572
- end: newRange.end.match({
573
- Some: date => stringifyDate(date, format),
574
- None: () => value.end,
575
- }),
576
- };
577
- onChange(newValue);
578
- };
579
- if (!displayTwoCalendar) {
580
- return (_jsxs(_Fragment, { children: [_jsx(YearMonthSelect, { monthNames: monthNames, value: periods.start, hideArrows: !desktop, onChange: setStartPeriod }), _jsx(Space, { height: 24 }), _jsx(MonthCalendar, { month: periods.start.month, year: periods.start.year, value: dateRange, firstWeekDay: firstWeekDay, weekDayNames: weekDayNames, isSelectable: isSelectable, onChange: handleSelectDate })] }));
581
- }
582
- return (_jsx(View, { children: _jsxs(Box, { direction: "row", alignItems: "start", children: [_jsxs(View, { style: styles.rangeCalendarSide, children: [_jsx(YearMonthSelect, { monthNames: monthNames, value: periods.start, maxValue: decrementYearMonth(periods.end), arrowsPosition: "around", onChange: setStartPeriod }), _jsx(Space, { height: 24 }), _jsx(MonthCalendar, { month: periods.start.month, year: periods.start.year, value: dateRange, firstWeekDay: firstWeekDay, weekDayNames: weekDayNames, isSelectable: isSelectable, onChange: handleSelectDate })] }), _jsx(Separator, { space: 24, horizontal: true }), _jsxs(View, { style: styles.rangeCalendarSide, children: [_jsx(YearMonthSelect, { monthNames: monthNames, value: periods.end, minValue: incrementYearMonth(periods.start), arrowsPosition: "around", onChange: setEndPeriod }), _jsx(Space, { height: 24 }), _jsx(MonthCalendar, { month: periods.end.month, year: periods.end.year, value: dateRange, firstWeekDay: firstWeekDay, weekDayNames: weekDayNames, isSelectable: isSelectable, onChange: handleSelectDate })] })] }) }));
583
- };
584
- export const DateRangePicker = ({ value, error, format, startLabel, endLabel, firstWeekDay, monthNames, weekDayNames, isSelectable, onChange, }) => {
585
- const { desktop } = useResponsive(DATE_PICKER_MOBILE_THRESHOLD);
586
- const { desktop: displayTwoCalendar } = useResponsive(DATE_RANGE_PICKER_THRESHOLD);
587
- const ref = useRef(null);
588
- const [isOpened, { open, close }] = useDisclosure(false);
589
- const handleStartChange = useCallback((start) => {
590
- onChange({ start, end: value.end });
591
- }, [value, onChange]);
592
- const handleEndChange = useCallback((end) => {
593
- onChange({ start: value.start, end });
594
- }, [value, onChange]);
595
- return (_jsxs(View, { children: [_jsxs(Box, { direction: "row", alignItems: "end", children: [_jsx(LakeLabel, { label: startLabel, style: styles.label, render: id => (_jsx(Rifm, { value: value.start, onChange: handleStartChange, ...rifmDateProps, children: ({ value, onChange }) => (_jsx(LakeTextInput, { ref: ref, id: id, placeholder: format, value: value, onChange: onChange, error: error, hideErrors: true, ariaExpanded: isOpened })) })) }), _jsx(Space, { width: 12 }), _jsx(Box, { style: styles.arrowContainer, justifyContent: "center", children: _jsx(Icon, { name: "arrow-right-filled", size: 20 }) }), _jsx(Space, { width: 12 }), _jsx(LakeLabel, { label: endLabel, style: styles.label, render: id => (_jsx(Rifm, { value: value.end, onChange: handleEndChange, ...rifmDateProps, children: ({ value, onChange }) => (_jsx(LakeTextInput, { id: id, placeholder: format, value: value, onChange: onChange, error: error, hideErrors: true, ariaExpanded: isOpened })) })) }), _jsx(Space, { width: 12 }), _jsx(LakeButton, { mode: "secondary", icon: "calendar-ltr-regular", size: "small", onPress: open })] }), _jsx(Space, { height: 4 }), _jsx(LakeText, { variant: "smallRegular", color: colors.negative[500], children: error ?? " " }), _jsx(DateModal, { visible: isOpened, maxWidth: 900, withCloseButton: true, onPressClose: close, children: _jsx(DateRangePickerModalContent, { value: value, format: format, firstWeekDay: firstWeekDay, monthNames: monthNames, weekDayNames: weekDayNames, desktop: desktop, displayTwoCalendar: displayTwoCalendar, isSelectable: isSelectable, onChange: onChange }) })] }));
596
- };
597
- export const DateRangePickerModal = ({ value, error, format, firstWeekDay, monthNames, weekDayNames, isSelectable, onChange, visible, startLabel, endLabel, cancelLabel, confirmLabel, onDissmiss, }) => {
598
- const { desktop } = useResponsive(MODALE_MOBILE_THRESHOLD);
599
- const { desktop: displayTwoCalendar } = useResponsive(DATE_RANGE_PICKER_THRESHOLD);
600
- const [localeValue, setLocaleValue] = useState(value);
601
- useEffect(() => {
602
- setLocaleValue(value);
603
- }, [value]);
604
- const handleStartChange = (start) => {
605
- setLocaleValue({ start, end: localeValue.end });
606
- };
607
- const handleEndChange = (end) => {
608
- setLocaleValue({ start: localeValue.start, end });
609
- };
610
- const handleCancel = () => {
611
- setLocaleValue(value);
612
- onDissmiss();
613
- };
614
- const handleConfirm = () => {
615
- onChange(localeValue);
616
- onDissmiss();
617
- };
618
- return (_jsxs(DateModal, { visible: visible, maxWidth: 900, onPressClose: handleCancel, children: [_jsxs(View, { children: [_jsxs(Box, { direction: "row", alignItems: "end", children: [_jsx(LakeLabel, { label: startLabel, style: styles.label, render: id => (_jsx(Rifm, { value: localeValue.start, onChange: handleStartChange, ...rifmDateProps, children: ({ value, onChange }) => (_jsx(LakeTextInput, { id: id, placeholder: format, value: value, onChange: onChange, error: error, hideErrors: true })) })) }), _jsx(Space, { width: 12 }), _jsx(Box, { style: styles.arrowContainer, justifyContent: "center", children: _jsx(Icon, { name: "arrow-right-filled", size: 20 }) }), _jsx(Space, { width: 12 }), _jsx(LakeLabel, { label: endLabel, style: styles.label, render: id => (_jsx(Rifm, { value: localeValue.end, onChange: handleEndChange, ...rifmDateProps, children: ({ value, onChange }) => (_jsx(LakeTextInput, { id: id, placeholder: format, value: value, onChange: onChange, error: error, hideErrors: true })) })) })] }), _jsx(Space, { height: 4 }), _jsx(LakeText, { variant: "smallRegular", color: colors.negative[500], children: error ?? " " })] }), _jsx(DateRangePickerModalContent, { value: localeValue, format: format, firstWeekDay: firstWeekDay, monthNames: monthNames, weekDayNames: weekDayNames, desktop: desktop, displayTwoCalendar: displayTwoCalendar, isSelectable: isSelectable, onChange: setLocaleValue }), _jsx(Space, { height: 24 }), _jsxs(Box, { direction: "row", alignItems: "center", children: [_jsx(LakeButton, { mode: "secondary", size: "small", onPress: handleCancel, style: styles.button, children: cancelLabel }), _jsx(Space, { width: 24 }), _jsx(LakeButton, { color: "current", size: "small", onPress: handleConfirm, style: styles.button, children: confirmLabel })] })] }));
619
- };
@@ -1,10 +0,0 @@
1
- type Props = {
2
- variant?: "none" | "pending" | "verified" | "refused";
3
- name: string;
4
- url?: string;
5
- onRemove?: () => void;
6
- title?: string;
7
- description?: string;
8
- };
9
- export declare const FileTile: ({ variant, name, url, onRemove, title, description }: Props) => import("react/jsx-runtime").JSX.Element;
10
- export {};
@@ -1,37 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { StyleSheet } from "react-native";
3
- import { match } from "ts-pattern";
4
- import { commonStyles } from "../constants/commonStyles";
5
- import { backgroundColor, colors, shadows, spacings } from "../constants/design";
6
- import { getIconNameFromFilename } from "../utils/file";
7
- import { isNotNullish, isNotNullishOrEmpty } from "../utils/nullish";
8
- import { Box } from "./Box";
9
- import { LakeAlert } from "./LakeAlert";
10
- import { LakeButton } from "./LakeButton";
11
- import { LakeText } from "./LakeText";
12
- import { Space } from "./Space";
13
- import { Tag } from "./Tag";
14
- const styles = StyleSheet.create({
15
- base: {
16
- backgroundColor: backgroundColor.accented,
17
- borderRadius: 8,
18
- boxShadow: shadows.tile,
19
- overflow: "hidden",
20
- },
21
- content: {
22
- height: 56,
23
- paddingLeft: spacings[20],
24
- paddingRight: spacings[8],
25
- },
26
- });
27
- export const FileTile = ({ variant = "none", name, url, onRemove, title, description }) => (_jsxs(Box, { style: styles.base, children: [_jsxs(Box, { alignItems: "center", direction: "row", style: styles.content, children: [_jsx(Tag, { icon: getIconNameFromFilename(name), iconSize: 20, color: match(variant)
28
- .with("none", "pending", () => "shakespear")
29
- .with("verified", () => "positive")
30
- .with("refused", () => "negative")
31
- .exhaustive() }), _jsx(Space, { width: 16 }), _jsx(LakeText, { numberOfLines: 1, color: colors.gray[700], style: commonStyles.fill, children: name }), _jsx(Space, { width: 12 }), isNotNullishOrEmpty(url) && (_jsx(LakeButton, { mode: "tertiary", size: "small", icon: "open-filled", onPress: () => {
32
- window.open(url, "_blank");
33
- } })), isNotNullish(onRemove) && (_jsx(LakeButton, { mode: "tertiary", size: "small", icon: "delete-regular", color: "negative", onPress: onRemove }))] }), variant !== "none" && (_jsx(LakeAlert, { anchored: true, title: title, variant: match(variant)
34
- .with("pending", () => "info")
35
- .with("verified", () => "success")
36
- .with("refused", () => "error")
37
- .exhaustive(), children: description }))] }));
@@ -1,14 +0,0 @@
1
- import { ReactNode } from "react";
2
- import { ColorVariants } from "../constants/design";
3
- import { IconName } from "./Icon";
4
- import { Context } from "./ResponsiveContainer";
5
- export type LakeModalProps = {
6
- visible: boolean;
7
- title?: string;
8
- icon?: IconName;
9
- color?: ColorVariants;
10
- children: ReactNode | ((context: Context) => ReactNode);
11
- maxWidth?: number;
12
- onPressClose?: () => void;
13
- };
14
- export declare const LakeModal: ({ visible, icon, title, color, children, maxWidth, onPressClose, }: LakeModalProps) => import("react/jsx-runtime").JSX.Element | null;
@@ -1,135 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Suspense, useEffect, useState } from "react";
3
- import { ScrollView, StyleSheet, View } from "react-native";
4
- import { commonStyles } from "../constants/commonStyles";
5
- import { backgroundColor, breakpoints, colors, negativeSpacings, shadows, spacings, } from "../constants/design";
6
- import { useBodyClassName } from "../hooks/useBodyClassName";
7
- import { FocusTrap } from "./FocusTrap";
8
- import { Icon } from "./Icon";
9
- import { LakeButton } from "./LakeButton";
10
- import { LakeHeading } from "./LakeHeading";
11
- import { LoadingView } from "./LoadingView";
12
- import { Portal } from "./Portal";
13
- import { Pressable } from "./Pressable";
14
- import { ResponsiveContainer } from "./ResponsiveContainer";
15
- import { Space } from "./Space";
16
- import { TransitionView } from "./TransitionView";
17
- const BACKGROUND_COLOR = "rgba(0, 0, 0, 0.6)";
18
- const styles = StyleSheet.create({
19
- root: {
20
- ...StyleSheet.absoluteFillObject,
21
- },
22
- container: {
23
- ...StyleSheet.absoluteFillObject,
24
- },
25
- inert: {
26
- pointerEvents: "none",
27
- },
28
- fill: {
29
- ...StyleSheet.absoluteFillObject,
30
- animationFillMode: "forwards",
31
- },
32
- overlay: {
33
- ...StyleSheet.absoluteFillObject,
34
- backgroundColor: BACKGROUND_COLOR,
35
- },
36
- overlayEnter: {
37
- animationKeyframes: {
38
- "0%": { opacity: 0 },
39
- },
40
- animationDuration: "200ms",
41
- animationTimingFunction: "ease-in-out",
42
- },
43
- overlayLeave: {
44
- animationKeyframes: {
45
- "100%": { opacity: 0 },
46
- },
47
- animationDuration: "200ms",
48
- animationTimingFunction: "ease-in-out",
49
- },
50
- modalEnter: {
51
- animationKeyframes: {
52
- "0%": {
53
- opacity: 0,
54
- transform: "translateY(-20px)",
55
- },
56
- },
57
- animationDuration: "300ms",
58
- animationTimingFunction: "ease-in-out",
59
- },
60
- modalLeave: {
61
- animationKeyframes: {
62
- "100%": {
63
- opacity: 0,
64
- transform: "translateY(-20px)",
65
- },
66
- },
67
- animationDuration: "300ms",
68
- animationTimingFunction: "ease-in-out",
69
- },
70
- modalContainer: {
71
- ...StyleSheet.absoluteFillObject,
72
- },
73
- modalContentContainer: {
74
- padding: spacings[24],
75
- justifyContent: "center",
76
- flexGrow: 1,
77
- },
78
- modalContentContainerSmall: {
79
- padding: spacings[8],
80
- flexGrow: 1,
81
- justifyContent: "center",
82
- },
83
- modal: {
84
- backgroundColor: backgroundColor.default,
85
- borderRadius: 24,
86
- padding: spacings[48],
87
- boxShadow: shadows.modal,
88
- alignSelf: "stretch",
89
- width: "100%",
90
- marginHorizontal: "auto",
91
- },
92
- modalSmall: {
93
- borderRadius: 16,
94
- backgroundColor: backgroundColor.default,
95
- width: "100%",
96
- padding: spacings[24],
97
- alignSelf: "stretch",
98
- marginHorizontal: "auto",
99
- },
100
- modalHeader: {
101
- display: "flex",
102
- flexDirection: "row",
103
- justifyContent: "space-between",
104
- },
105
- modalIconTitle: {
106
- ...commonStyles.fill,
107
- },
108
- trap: {
109
- ...commonStyles.fill,
110
- },
111
- pressableOverlay: {
112
- ...StyleSheet.absoluteFillObject,
113
- },
114
- closeButton: {
115
- top: negativeSpacings[16],
116
- right: negativeSpacings[16],
117
- },
118
- });
119
- export const LakeModal = ({ visible, icon, title, color = "current", children, maxWidth = 570, onPressClose, }) => {
120
- const [rootElement, setRootElement] = useState(() => undefined);
121
- useEffect(() => {
122
- const rootElement = document.createElement("div");
123
- document.body.append(rootElement);
124
- setRootElement(rootElement);
125
- return () => {
126
- rootElement.remove();
127
- setRootElement(undefined);
128
- };
129
- }, []);
130
- useBodyClassName("ModalOpen", { enabled: visible });
131
- if (rootElement == null) {
132
- return null;
133
- }
134
- return (_jsx(Portal, { container: rootElement, children: _jsxs(View, { "aria-modal": true, style: [styles.container, !visible && styles.inert], 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, { role: "dialog", 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 }) })] }) }));
135
- };