@swan-io/lake 2.7.3 → 2.7.5

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.3",
3
+ "version": "2.7.5",
4
4
  "engines": {
5
5
  "node": ">=18.0.0",
6
6
  "yarn": "^1.22.0"
@@ -65,9 +65,11 @@ export type FixedListViewProps<T, ExtraInfo> = {
65
65
  data: T[];
66
66
  keyExtractor: (item: T, index: number) => string;
67
67
  highlightedRowId?: string;
68
+ headerBackgroundColor?: string;
68
69
  headerHeight: number;
69
70
  rowHeight: number;
70
71
  rowVerticalSpacing: number;
72
+ horizontalPadding?: number;
71
73
  extraInfo: ExtraInfo;
72
74
  stickedToStartColumns?: ColumnConfig<T, ExtraInfo>[];
73
75
  columns: ColumnConfig<T, ExtraInfo>[];
@@ -82,7 +84,8 @@ export type FixedListViewProps<T, ExtraInfo> = {
82
84
  count: number;
83
85
  };
84
86
  };
85
- export declare const FixedListView: <T, ExtraInfo>({ data: originalData, mode, keyExtractor, highlightedRowId, rowHeight, rowVerticalSpacing, headerHeight, renderThreshold, stickedToStartColumns: initialStickedToStartColumns, columns: initialColumns, stickedToEndColumns: initialStickedToEndColumns, extraInfo, onEndReached, onEndReachedThresholdPx, getRowLink, renderEmptyList, loading, }: FixedListViewProps<T, ExtraInfo>) => import("react/jsx-runtime").JSX.Element;
87
+ export declare const SCROLLBAR_RESERVED_SPACE = 20;
88
+ export declare const FixedListView: <T, ExtraInfo>({ data: originalData, mode, keyExtractor, highlightedRowId, rowHeight, rowVerticalSpacing, horizontalPadding, headerBackgroundColor, headerHeight, renderThreshold, stickedToStartColumns: initialStickedToStartColumns, columns: initialColumns, stickedToEndColumns: initialStickedToEndColumns, extraInfo, onEndReached, onEndReachedThresholdPx, getRowLink, renderEmptyList, loading, }: FixedListViewProps<T, ExtraInfo>) => import("react/jsx-runtime").JSX.Element;
86
89
  type PlaceholderProps = {
87
90
  count: number;
88
91
  rowHeight: number;
@@ -50,7 +50,7 @@ import { LakeHeading } from "./LakeHeading";
50
50
  import { LakeText } from "./LakeText";
51
51
  import { Space } from "./Space";
52
52
  const HORIZONTAL_SAFE_AREA = 10;
53
- const SCROLLBAR_RESERVED_SPACE = 20;
53
+ export const SCROLLBAR_RESERVED_SPACE = 20;
54
54
  const styles = StyleSheet.create({
55
55
  root: {
56
56
  height: 1,
@@ -97,16 +97,12 @@ const styles = StyleSheet.create({
97
97
  top: 0,
98
98
  bottom: 0,
99
99
  right: "100%",
100
- width: HORIZONTAL_SAFE_AREA,
101
- backgroundColor: backgroundColor.default,
102
100
  },
103
101
  stickyColumnEndOverflow: {
104
102
  position: "absolute",
105
103
  top: 0,
106
104
  bottom: 0,
107
105
  left: "100%",
108
- width: HORIZONTAL_SAFE_AREA,
109
- backgroundColor: backgroundColor.default,
110
106
  },
111
107
  rowSegment: {
112
108
  position: "absolute",
@@ -128,7 +124,6 @@ const styles = StyleSheet.create({
128
124
  flexDirection: "row",
129
125
  alignItems: "stretch",
130
126
  zIndex: 2,
131
- backgroundColor: backgroundColor.default,
132
127
  },
133
128
  segment: {
134
129
  flexDirection: "row",
@@ -177,9 +172,6 @@ const styles = StyleSheet.create({
177
172
  flexDirection: "row",
178
173
  alignItems: "stretch",
179
174
  },
180
- stickyRow: {
181
- // overflow: "hidden",
182
- },
183
175
  evenRow: {
184
176
  backgroundColor: backgroundColor.accented,
185
177
  },
@@ -226,7 +218,6 @@ const styles = StyleSheet.create({
226
218
  transitionTimingFunction: "ease-in-out",
227
219
  },
228
220
  rowBackgroundContainerPlain: {
229
- backgroundColor: backgroundColor.default,
230
221
  left: -10,
231
222
  right: -10,
232
223
  boxShadow: `inset 0 -1px ${colors.gray[100]}`,
@@ -414,14 +405,15 @@ const findNextFocusableElement = (sortedCellIds, currentCellIndex, direction) =>
414
405
  };
415
406
  const EMPTY_COLUMNS = [];
416
407
  const ZERO = 0;
417
- export const FixedListView = ({ data: originalData, mode = "tile", keyExtractor, highlightedRowId, rowHeight, rowVerticalSpacing, headerHeight, renderThreshold = 1000, stickedToStartColumns: initialStickedToStartColumns = EMPTY_COLUMNS, columns: initialColumns, stickedToEndColumns: initialStickedToEndColumns = EMPTY_COLUMNS, extraInfo, onEndReached, onEndReachedThresholdPx = 200, getRowLink, renderEmptyList, loading, }) => {
408
+ export const FixedListView = ({ data: originalData, mode = "tile", keyExtractor, highlightedRowId, rowHeight, rowVerticalSpacing, horizontalPadding = HORIZONTAL_SAFE_AREA, headerBackgroundColor = backgroundColor.default, headerHeight, renderThreshold = 1000, stickedToStartColumns: initialStickedToStartColumns = EMPTY_COLUMNS, columns: initialColumns, stickedToEndColumns: initialStickedToEndColumns = EMPTY_COLUMNS, extraInfo, onEndReached, onEndReachedThresholdPx = 200, getRowLink, renderEmptyList, loading, }) => {
418
409
  const [viewId] = useState(() => uuid());
419
410
  // Those three refs are used to synchronize the horizontal scroll in the center columns
420
411
  const centerHeadersRef = useRef(null);
421
412
  const centerColumnsRef = useRef(null);
422
413
  const horizontalScrollbarRef = useRef(null);
423
414
  const totalRowHeight = rowHeight + rowVerticalSpacing;
424
- const totalHeight = originalData.length * totalRowHeight + headerHeight;
415
+ const rowsHeight = originalData.length * totalRowHeight;
416
+ const totalHeight = headerHeight + rowsHeight;
425
417
  // It might seem off to use the range in state instead of storing scroll/layout and deriving it,
426
418
  // but it saves a lot of render phases by allowing to bail out from rendering when the range doesn't change
427
419
  const [{ data, range: [renderedRangeStartIndex, renderedRangeEndIndex], }, setDataAndRenderRange,] = useState({ data: originalData, range: [0, 20] });
@@ -560,7 +552,7 @@ export const FixedListView = ({ data: originalData, mode = "tile", keyExtractor,
560
552
  now - lastHorizontalScroll.current.date > SCROLL_THRESHOLD_MS) {
561
553
  const scrollLeft = centerColumns.scrollLeft;
562
554
  setShouldShowStartGradient(scrollLeft > 0);
563
- setShouldShowEndGradient(centerColumns.scrollWidth - HORIZONTAL_SAFE_AREA * 2 >=
555
+ setShouldShowEndGradient(centerColumns.scrollWidth - horizontalPadding * 2 >=
564
556
  scrollLeft + centerColumns.clientWidth);
565
557
  centerHeaders.scrollLeft = scrollLeft;
566
558
  horizontalScrollbar.scrollLeft = scrollLeft;
@@ -573,7 +565,7 @@ export const FixedListView = ({ data: originalData, mode = "tile", keyExtractor,
573
565
  now - lastHorizontalScroll.current.date > SCROLL_THRESHOLD_MS) {
574
566
  const scrollLeft = centerHeaders.scrollLeft;
575
567
  setShouldShowStartGradient(scrollLeft > 0);
576
- setShouldShowEndGradient(centerHeaders.scrollWidth - HORIZONTAL_SAFE_AREA * 2 >=
568
+ setShouldShowEndGradient(centerHeaders.scrollWidth - horizontalPadding * 2 >=
577
569
  scrollLeft + centerHeaders.clientWidth);
578
570
  centerColumns.scrollLeft = scrollLeft;
579
571
  horizontalScrollbar.scrollLeft = scrollLeft;
@@ -586,7 +578,7 @@ export const FixedListView = ({ data: originalData, mode = "tile", keyExtractor,
586
578
  now - lastHorizontalScroll.current.date > SCROLL_THRESHOLD_MS) {
587
579
  const scrollLeft = horizontalScrollbar.scrollLeft;
588
580
  setShouldShowStartGradient(scrollLeft > 0);
589
- setShouldShowEndGradient(horizontalScrollbar.scrollWidth - HORIZONTAL_SAFE_AREA * 2 >=
581
+ setShouldShowEndGradient(horizontalScrollbar.scrollWidth - horizontalPadding * 2 >=
590
582
  scrollLeft + horizontalScrollbar.clientWidth);
591
583
  centerHeaders.scrollLeft = scrollLeft;
592
584
  centerColumns.scrollLeft = scrollLeft;
@@ -602,7 +594,7 @@ export const FixedListView = ({ data: originalData, mode = "tile", keyExtractor,
602
594
  horizontalScrollbar.removeEventListener("scroll", onScrollbarScroll);
603
595
  };
604
596
  }
605
- }, []);
597
+ }, [horizontalPadding]);
606
598
  const onKeyDown = useCallback((event) => {
607
599
  const target = event.nativeEvent.target;
608
600
  const currentTarget = event.nativeEvent.currentTarget;
@@ -743,9 +735,9 @@ export const FixedListView = ({ data: originalData, mode = "tile", keyExtractor,
743
735
  ], children: [_jsx(View, { "aria-busy": isLoading, style: [
744
736
  styles.loadingPlaceholder,
745
737
  {
746
- top: totalHeight,
747
- marginLeft: HORIZONTAL_SAFE_AREA * 2,
748
- marginRight: HORIZONTAL_SAFE_AREA * 2,
738
+ top: rowsHeight,
739
+ marginLeft: horizontalPadding * 2,
740
+ marginRight: horizontalPadding * 2,
749
741
  },
750
742
  ], children: isLoading
751
743
  ? match(mode)
@@ -755,30 +747,39 @@ export const FixedListView = ({ data: originalData, mode = "tile", keyExtractor,
755
747
  : null }), _jsx(View, { style: [styles.backgroundRows, { top: headerHeight }], children: backgroundRows }), _jsxs(View, { style: styles.scrollContentContainer, ref: scrollContentsRef, children: [stickedToStartColumns.length > 0 ? (_jsxs(View, { style: [
756
748
  styles.stickyColumn,
757
749
  {
758
- width: stickedToStartColumnsWidth + HORIZONTAL_SAFE_AREA,
759
- paddingLeft: HORIZONTAL_SAFE_AREA,
750
+ width: stickedToStartColumnsWidth + horizontalPadding,
751
+ paddingLeft: horizontalPadding,
760
752
  },
761
- ], children: [_jsxs(View, { style: [styles.headingSegment, { height: headerHeight }], children: [_jsx(HeaderSegment, { columns: stickedToStartColumns, extraInfo: extraInfo, viewId: viewId, width: stickedToStartColumnsWidth }), _jsx(View, { style: styles.stickyColumnStartOverflow }), _jsx(View, { style: [styles.topGradient, isScrolled && styles.visibleTopGradient] })] }), _jsx(View, { style: [styles.stickyRow, { height: totalHeight }], children: startRows })] })) : null, _jsxs(View, { style: [
753
+ ], children: [_jsxs(View, { style: [
754
+ styles.headingSegment,
755
+ { height: headerHeight, backgroundColor: headerBackgroundColor },
756
+ ], children: [_jsx(HeaderSegment, { columns: stickedToStartColumns, extraInfo: extraInfo, viewId: viewId, width: stickedToStartColumnsWidth }), _jsx(View, { style: [
757
+ styles.stickyColumnStartOverflow,
758
+ { width: horizontalPadding, backgroundColor: headerBackgroundColor },
759
+ ] }), _jsx(View, { style: [styles.topGradient, isScrolled && styles.visibleTopGradient] })] }), _jsx(View, { style: { height: rowsHeight }, children: startRows })] })) : null, _jsxs(View, { style: [
762
760
  styles.centerColumnsContainer,
763
761
  {
764
- paddingLeft: stickedToStartColumns.length === 0 ? HORIZONTAL_SAFE_AREA : ZERO,
765
- paddingRight: stickedToEndColumns.length === 0 ? HORIZONTAL_SAFE_AREA : ZERO,
762
+ paddingLeft: stickedToStartColumns.length === 0 ? horizontalPadding : ZERO,
763
+ paddingRight: stickedToEndColumns.length === 0 ? horizontalPadding : ZERO,
766
764
  },
767
- ], children: [_jsxs(View, { style: [styles.headingSegment, { height: headerHeight }], children: [_jsx(ScrollView, { ref: centerHeadersRef, horizontal: true, onLayout: onCenterTrackLayout, style: styles.centerColumns, contentContainerStyle: {
765
+ ], children: [_jsxs(View, { style: [
766
+ styles.headingSegment,
767
+ { height: headerHeight, backgroundColor: headerBackgroundColor },
768
+ ], children: [_jsx(ScrollView, { ref: centerHeadersRef, horizontal: true, onLayout: onCenterTrackLayout, style: styles.centerColumns, contentContainerStyle: {
768
769
  minWidth: centerColumnsWidth +
769
- (stickedToStartColumns.length === 0 ? HORIZONTAL_SAFE_AREA : 0) +
770
- (stickedToEndColumns.length === 0 ? HORIZONTAL_SAFE_AREA : 0),
770
+ (stickedToStartColumns.length === 0 ? horizontalPadding : 0) +
771
+ (stickedToEndColumns.length === 0 ? horizontalPadding : 0),
771
772
  }, children: _jsx(HeaderSegment, { columns: columns, extraInfo: extraInfo, viewId: viewId, width: centerColumnsWidth }) }), _jsx(View, { style: [styles.topGradient, isScrolled && styles.visibleTopGradient] })] }), _jsx(ScrollView, { horizontal: true, ref: centerColumnsRef, style: styles.centerColumns, contentContainerStyle: [
772
773
  styles.centerColumnsContentContainer,
773
774
  {
774
775
  minWidth: centerColumnsWidth +
775
- (stickedToStartColumns.length === 0 ? HORIZONTAL_SAFE_AREA : 0) +
776
- (stickedToEndColumns.length === 0 ? HORIZONTAL_SAFE_AREA : 0),
776
+ (stickedToStartColumns.length === 0 ? horizontalPadding : 0) +
777
+ (stickedToEndColumns.length === 0 ? horizontalPadding : 0),
777
778
  },
778
779
  ], children: centerRows }), _jsx(ScrollView, { ref: horizontalScrollbarRef, horizontal: true, style: styles.horizontalScrollbar, contentContainerStyle: {
779
780
  minWidth: centerColumnsWidth +
780
- (stickedToStartColumns.length === 0 ? HORIZONTAL_SAFE_AREA : 0) +
781
- (stickedToEndColumns.length === 0 ? HORIZONTAL_SAFE_AREA : 0),
781
+ (stickedToStartColumns.length === 0 ? horizontalPadding : 0) +
782
+ (stickedToEndColumns.length === 0 ? horizontalPadding : 0),
782
783
  } }), stickedToStartColumns.length > 0 && hasHorizontalScroll ? (_jsx(View, { style: [
783
784
  styles.leftToRightGradient,
784
785
  {
@@ -798,10 +799,16 @@ export const FixedListView = ({ data: originalData, mode = "tile", keyExtractor,
798
799
  ] })) : null] }), stickedToEndColumns.length > 0 ? (_jsxs(View, { style: [
799
800
  styles.stickyColumn,
800
801
  {
801
- width: stickedToEndColumnsWidth + HORIZONTAL_SAFE_AREA,
802
- paddingRight: HORIZONTAL_SAFE_AREA,
802
+ width: stickedToEndColumnsWidth + horizontalPadding,
803
+ paddingRight: horizontalPadding,
803
804
  },
804
- ], children: [_jsxs(View, { style: [styles.headingSegment, { height: headerHeight }], children: [_jsx(View, { style: styles.stickyColumnEndOverflow }), _jsx(HeaderSegment, { columns: stickedToEndColumns, extraInfo: extraInfo, viewId: viewId, width: stickedToEndColumnsWidth }), _jsx(View, { style: [styles.topGradient, isScrolled && styles.visibleTopGradient] })] }), _jsx(View, { style: [styles.stickyRow, { height: totalHeight }], children: endRows })] })) : null] })] }), data.length === 0 && isNotNullish(renderEmptyList) && !isLoading ? (_jsx(View, { style: styles.emptyListContainer, children: renderEmptyList() })) : null, _jsx(View, { ref: endFocusAnchorRef, tabIndex: 0 })] }));
805
+ ], children: [_jsxs(View, { style: [
806
+ styles.headingSegment,
807
+ { height: headerHeight, backgroundColor: headerBackgroundColor },
808
+ ], children: [_jsx(View, { style: [
809
+ styles.stickyColumnEndOverflow,
810
+ { width: horizontalPadding, backgroundColor: headerBackgroundColor },
811
+ ] }), _jsx(HeaderSegment, { columns: stickedToEndColumns, extraInfo: extraInfo, viewId: viewId, width: stickedToEndColumnsWidth }), _jsx(View, { style: [styles.topGradient, isScrolled && styles.visibleTopGradient] })] }), _jsx(View, { style: { height: rowsHeight }, children: endRows })] })) : null] })] }), data.length === 0 && isNotNullish(renderEmptyList) && !isLoading ? (_jsx(View, { style: styles.emptyListContainer, children: renderEmptyList() })) : null, _jsx(View, { ref: endFocusAnchorRef, tabIndex: 0 })] }));
805
812
  };
806
813
  export const FixedListViewPlaceholder = ({ count, rowHeight, rowVerticalSpacing, groupHeaderHeight, headerHeight, paddingHorizontal = HORIZONTAL_SAFE_AREA, }) => {
807
814
  const totalRowHeight = rowHeight + rowVerticalSpacing;
@@ -30,7 +30,7 @@ export declare const CopyableRegularTextCell: ({ variant, text, copyWording, cop
30
30
  copyWording: string;
31
31
  copiedWording: string;
32
32
  }) => import("react/jsx-runtime").JSX.Element;
33
- export declare const BalanceCell: ({ value, currency, originalValue, formatCurrency, textAlign, }: {
33
+ export declare const BalanceCell: ({ value, currency, originalValue, formatCurrency, textAlign, variant, }: {
34
34
  value: number;
35
35
  currency: string;
36
36
  originalValue?: {
@@ -39,11 +39,13 @@ export declare const BalanceCell: ({ value, currency, originalValue, formatCurre
39
39
  } | undefined;
40
40
  formatCurrency: (value: number, currency: string) => string;
41
41
  textAlign?: "left" | "right" | "center" | undefined;
42
+ variant?: "light" | "semibold" | "medium" | "regular" | "smallSemibold" | "smallMedium" | "smallRegular" | undefined;
42
43
  }) => import("react/jsx-runtime").JSX.Element;
43
- export declare const LinkCell: ({ children, external, onPress, }: {
44
+ export declare const LinkCell: ({ children, external, onPress, variant, }: {
44
45
  children: ReactNode;
45
46
  onPress: () => void;
46
47
  external?: boolean | undefined;
48
+ variant?: "light" | "semibold" | "medium" | "regular" | "smallSemibold" | "smallMedium" | "smallRegular" | undefined;
47
49
  }) => import("react/jsx-runtime").JSX.Element;
48
50
  export declare const StartAlignedCell: ({ children }: {
49
51
  children: ReactNode;
@@ -123,8 +123,8 @@ export const CopyableRegularTextCell = ({ variant = "regular", text, copyWording
123
123
  return (_jsxs(View, { style: styles.cell, children: [_jsx(LakeTooltip, { placement: "top", onHide: () => setVisibleState("copy"), togglableOnFocus: true, content: visibleState === "copy" ? copyWording : copiedWording, containerStyle: styles.iconContainer, children: _jsx(Pressable, { role: "button", "aria-label": copyWording, onPress: onPress, style: ({ hovered }) => [styles.icon, hovered && styles.underline], children: ({ hovered }) => (_jsx(Icon, { name: hovered ? "copy-filled" : "copy-regular", color: "currentColor", size: 14 })) }) }), _jsx(Space, { width: 4 }), _jsx(LakeText, { color: colors.gray[900], style: styles.regularText, variant: variant, children: text })] }));
124
124
  };
125
125
  // TODO: handle `+` sign properly
126
- export const BalanceCell = ({ value, currency, originalValue, formatCurrency, textAlign = "right", }) => {
127
- return (_jsxs(View, { style: styles.balanceCellContainer, children: [_jsx(View, { style: styles.cell, children: _jsxs(LakeText, { align: textAlign, color: colors.gray[900], variant: "medium", style: [
126
+ export const BalanceCell = ({ value, currency, originalValue, formatCurrency, textAlign = "right", variant = "medium", }) => {
127
+ return (_jsxs(View, { style: styles.balanceCellContainer, children: [_jsx(View, { style: styles.cell, children: _jsxs(LakeText, { align: textAlign, color: colors.gray[900], variant: variant, style: [
128
128
  styles.mediumText,
129
129
  {
130
130
  justifyContent: match(textAlign)
@@ -137,11 +137,11 @@ export const BalanceCell = ({ value, currency, originalValue, formatCurrency, te
137
137
  value < 0 && { color: colors.negative.primary },
138
138
  ], children: [value > 0 && "+", formatCurrency(value, currency)] }) }), isNotNullish(originalValue) && originalValue.currency !== currency && (_jsx(View, { style: styles.cell, children: _jsxs(LakeText, { style: styles.mediumText, align: textAlign, color: colors.gray[500], variant: "smallRegular", children: [originalValue.value > 0 && "+", formatCurrency(originalValue.value, originalValue.currency)] }) }))] }));
139
139
  };
140
- export const LinkCell = ({ children, external = false, onPress, }) => {
140
+ export const LinkCell = ({ children, external = false, onPress, variant = "medium", }) => {
141
141
  return (_jsxs(View, { style: styles.cell, children: [_jsx(Pressable, { style: ({ hovered }) => [styles.icon, hovered && styles.underline], onPress: event => {
142
142
  event.preventDefault();
143
143
  onPress();
144
- }, children: _jsx(Icon, { size: 14, name: external ? "open-regular" : "arrow-right-filled" }) }), _jsx(Space, { width: 8 }), _jsx(LakeText, { color: colors.gray[900], variant: "medium", style: styles.mediumText, children: children })] }));
144
+ }, children: _jsx(Icon, { size: 14, name: external ? "open-regular" : "arrow-right-filled" }) }), _jsx(Space, { width: 8 }), _jsx(LakeText, { color: colors.gray[900], variant: variant, style: styles.mediumText, children: children })] }));
145
145
  };
146
146
  export const StartAlignedCell = ({ children }) => {
147
147
  return _jsx(View, { style: styles.cell, children: children });
@@ -1,6 +1,6 @@
1
1
  import { ReactNode } from "react";
2
2
  import { StyleProp, ViewStyle } from "react-native";
3
- type AlertVariant = "info" | "warning" | "error" | "success";
3
+ type AlertVariant = "info" | "warning" | "error" | "success" | "neutral";
4
4
  type Props = {
5
5
  anchored?: boolean;
6
6
  variant: AlertVariant;
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { StyleSheet, View } from "react-native";
3
3
  import { commonStyles } from "../constants/commonStyles";
4
4
  import { colors, shadows } from "../constants/design";
@@ -38,38 +38,44 @@ const alertIcon = {
38
38
  warning: "warning-regular",
39
39
  error: "dismiss-circle-regular",
40
40
  success: "checkmark-circle-regular",
41
+ neutral: undefined,
41
42
  };
42
43
  const alertColor = {
43
44
  info: colors.shakespear[700],
44
45
  warning: colors.warning[700],
45
46
  error: colors.negative[700],
46
47
  success: colors.positive[700],
48
+ neutral: colors.gray[700],
47
49
  };
48
50
  const alertBackground = {
49
51
  info: colors.shakespear[0],
50
52
  warning: colors.warning[0],
51
53
  error: colors.negative[0],
52
54
  success: colors.positive[0],
55
+ neutral: colors.gray[0],
53
56
  };
54
57
  const alertBorder = {
55
58
  info: colors.shakespear[200],
56
59
  warning: colors.warning[200],
57
60
  error: colors.negative[200],
58
61
  success: colors.positive[200],
62
+ neutral: colors.gray[200],
59
63
  };
60
64
  const alertLeftBorder = {
61
65
  info: colors.shakespear[500],
62
66
  warning: colors.warning[500],
63
67
  error: colors.negative[500],
64
68
  success: colors.positive[500],
69
+ neutral: colors.gray[500],
65
70
  };
66
71
  const isText = (node) => typeof node === "string" || typeof node === "number";
67
72
  export const LakeAlert = ({ anchored = false, variant, title, subtitle, children, style, callToAction, }) => {
68
73
  const color = alertColor[variant];
74
+ const icon = alertIcon[variant];
69
75
  return (_jsxs(View, { style: [
70
76
  styles.base,
71
77
  { backgroundColor: alertBackground[variant], borderColor: alertBorder[variant] },
72
78
  anchored ? styles.anchored : { borderLeftColor: alertLeftBorder[variant] },
73
79
  style,
74
- ], children: [_jsxs(Box, { direction: "row", alignItems: "center", children: [_jsx(Icon, { name: alertIcon[variant], color: color, size: 20 }), _jsx(Space, { width: 20 }), _jsxs(View, { style: commonStyles.fill, children: [_jsx(LakeText, { color: color, children: title }), isNotNullishOrEmpty(subtitle) && _jsx(LakeText, { color: color, children: subtitle })] }), isNotNullish(callToAction) && _jsx(View, { style: styles.callToAction, children: callToAction })] }), isNotNullish(children) && (_jsxs(View, { style: styles.content, children: [_jsx(Space, { height: 12 }), isText(children) ? _jsx(LakeText, { children: children }) : children] }))] }));
80
+ ], children: [_jsxs(Box, { direction: "row", alignItems: "center", children: [icon != null ? (_jsxs(_Fragment, { children: [_jsx(Icon, { name: icon, color: color, size: 20 }), _jsx(Space, { width: 20 })] })) : null, _jsxs(View, { style: commonStyles.fill, children: [_jsx(LakeText, { color: color, variant: icon != null ? "regular" : "medium", children: title }), isNotNullishOrEmpty(subtitle) && _jsx(LakeText, { color: color, children: subtitle })] }), isNotNullish(callToAction) && _jsx(View, { style: styles.callToAction, children: callToAction })] }), isNotNullish(children) && (_jsxs(View, { style: icon != null ? styles.content : null, children: [_jsx(Space, { height: 12 }), isText(children) ? _jsx(LakeText, { children: children }) : children] }))] }));
75
81
  };
@@ -86,8 +86,9 @@ const LakeComboboxWithRef = ({ inputRef, value, items, itemHeight = DEFAULT_ELEM
86
86
  const listRef = useRef(null);
87
87
  const listContainerRef = useRef(null);
88
88
  const blurTimeoutId = useRef(undefined);
89
- const [isFocused, { open, close }] = useDisclosure(false);
89
+ const [isFocused, { open, close }] = useDisclosure(false, () => setHasChanged(false));
90
90
  const [isFetchingAdditionalInfo, setIsFetchingAdditionalInfo] = useState(false);
91
+ const [hasChanged, setHasChanged] = useState(false);
91
92
  useImperativeHandle(externalRef, () => {
92
93
  return {
93
94
  open,
@@ -141,7 +142,10 @@ const LakeComboboxWithRef = ({ inputRef, value, items, itemHeight = DEFAULT_ELEM
141
142
  close();
142
143
  }, 100);
143
144
  }, [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: false, returnFocus: true, visible: isFocused && !items.isNotAsked(), underlay: false, forcedMode: "Dropdown", children: _jsx(View, { style: [styles.list, { maxHeight: itemHeight * nbItemsDisplayed }], children: items.match({
145
+ return (_jsxs(View, { children: [_jsx(LakeTextInput, { containerRef: 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: event => {
146
+ setHasChanged(true);
147
+ onChange?.(event);
148
+ }, 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() && hasChanged, underlay: false, forcedMode: "Dropdown", children: _jsx(View, { style: [styles.list, { maxHeight: itemHeight * nbItemsDisplayed }], children: items.match({
145
149
  NotAsked: () => null,
146
150
  Loading: () => _jsx(LoadingView, { style: styles.loader }),
147
151
  Done: items => items.match({
@@ -1,5 +1,5 @@
1
- import { ChangeEventHandler, ReactNode } from "react";
2
- import { NativeSyntheticEvent, TextInput, TextInputFocusEventData, TextInputProps } from "react-native";
1
+ import { ChangeEventHandler, ReactNode, Ref } from "react";
2
+ import { NativeSyntheticEvent, TextInput, TextInputFocusEventData, TextInputProps, View } from "react-native";
3
3
  import { Except } from "type-fest";
4
4
  import { ColorVariants } from "../constants/design";
5
5
  import { IconName } from "./Icon";
@@ -24,6 +24,7 @@ export type LakeTextInputProps = Except<TextInputProps, "editable" | "keyboardTy
24
24
  maxCharCount?: number;
25
25
  help?: string;
26
26
  renderEnd?: () => ReactNode;
27
+ containerRef?: Ref<View>;
27
28
  };
28
29
  export declare const LakeTextInput: import("react").ForwardRefExoticComponent<{
29
30
  allowFontScaling?: boolean | undefined;
@@ -236,4 +237,5 @@ export declare const LakeTextInput: import("react").ForwardRefExoticComponent<{
236
237
  maxCharCount?: number | undefined;
237
238
  help?: string | undefined;
238
239
  renderEnd?: (() => ReactNode) | undefined;
240
+ containerRef?: Ref<View> | undefined;
239
241
  } & import("react").RefAttributes<TextInput | null>>;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { forwardRef, useCallback, useRef, useState } from "react";
2
+ import { forwardRef, useCallback, useRef, useState, } from "react";
3
3
  import { ActivityIndicator, StyleSheet, TextInput, View, } from "react-native";
4
4
  import { commonStyles } from "../constants/commonStyles";
5
5
  import { backgroundColor, colors, radii, shadows, spacings, texts, } from "../constants/design";
@@ -43,11 +43,11 @@ const styles = StyleSheet.create({
43
43
  placeholderTextColor: colors.gray[400],
44
44
  color: colors.gray[900],
45
45
  paddingHorizontal: spacings[8],
46
- height: 40,
46
+ height: 38,
47
47
  minWidth: 0,
48
48
  },
49
49
  multilineInput: {
50
- height: "auto",
50
+ height: "100%",
51
51
  padding: spacings[8],
52
52
  },
53
53
  inputWithUnit: {
@@ -121,7 +121,7 @@ const styles = StyleSheet.create({
121
121
  paddingTop: spacings[4],
122
122
  },
123
123
  });
124
- export const LakeTextInput = forwardRef(({ ariaExpanded, ariaControls, error, disabled = false, validating = false, valid = false, readOnly = false, icon, children, unit, color = "gray", inputMode = "text", hideErrors = false, onChange, pattern, style: stylesFromProps, onFocus: originalOnFocus, onBlur: originalOnBlur, value, defaultValue, multiline = false,
124
+ export const LakeTextInput = forwardRef(({ ariaExpanded, ariaControls, error, disabled = false, validating = false, valid = false, readOnly = false, icon, children, unit, color = "gray", inputMode = "text", hideErrors = false, onChange, pattern, style: stylesFromProps, onFocus: originalOnFocus, onBlur: originalOnBlur, value, defaultValue, multiline = false, containerRef,
125
125
  //maxCharCount is different from maxLength(props inherited of TextInput)
126
126
  //maxLength truncates the text in the limitation asked,
127
127
  //maxCharCount doesn't have limitation but displays a counter of characters
@@ -158,7 +158,7 @@ maxCharCount, help, renderEnd, ...props }, forwardRef) => {
158
158
  hasError && styles.error,
159
159
  valid && styles.valid,
160
160
  stylesFromProps,
161
- ], children: [isNotNullish(icon) && (_jsx(Icon, { name: icon, size: 20, color: colors.current.primary, style: styles.icon })), _jsx(TextInput, { "aria-expanded": ariaExpanded, "aria-controls": ariaControls, inputMode: inputMode, ref: mergedRef, ...props, defaultValue: defaultValue, value: isNullish(defaultValue) ? value ?? "" : value, onFocus: onFocus, onBlur: onBlur, readOnly: !isInteractive, onChange: onChange, multiline: multiline, style: [
161
+ ], ref: containerRef, children: [isNotNullish(icon) && (_jsx(Icon, { name: icon, size: 20, color: colors.current.primary, style: styles.icon })), _jsx(TextInput, { "aria-expanded": ariaExpanded, "aria-controls": ariaControls, inputMode: inputMode, ...props, defaultValue: defaultValue, value: isNullish(defaultValue) ? value ?? "" : value, onFocus: onFocus, onBlur: onBlur, readOnly: !isInteractive, onChange: onChange, multiline: multiline, ref: mergedRef, style: [
162
162
  styles.input,
163
163
  multiline && styles.multilineInput,
164
164
  readOnly && hasError && styles.readOnlyError,
@@ -1,4 +1,4 @@
1
- export declare const useDisclosure: (initialValue: boolean) => [
1
+ export declare const useDisclosure: (initialValue: boolean, onClose?: () => void) => [
2
2
  visible: boolean,
3
3
  fns: {
4
4
  open: () => void;
@@ -1,11 +1,14 @@
1
1
  import { useMemo, useState } from "react";
2
- export const useDisclosure = (initialValue) => {
2
+ export const useDisclosure = (initialValue, onClose) => {
3
3
  const [value, setValue] = useState(initialValue);
4
4
  return [
5
5
  value,
6
6
  useMemo(() => ({
7
7
  open: () => setValue(true),
8
- close: () => setValue(false),
8
+ close: () => {
9
+ setValue(false);
10
+ onClose?.();
11
+ },
9
12
  toggle: () => setValue(prevValue => !prevValue),
10
13
  }), []),
11
14
  ];