@terreno/ui 0.11.0 → 0.11.2

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/dist/Banner.js CHANGED
@@ -58,9 +58,9 @@ export const Banner = (props) => {
58
58
  bgColor = "warning";
59
59
  }
60
60
  const [show, setShow] = useState(true);
61
- // Load seen from async storage.
61
+ // Load seen from async storage (only when id is provided).
62
62
  useEffect(() => {
63
- if (dismissible) {
63
+ if (dismissible && id) {
64
64
  void Unifier.storage.getItem(getKey(id)).then((isSeen) => {
65
65
  console.debug(`[banner] ${getKey(id)} seen? ${isSeen}`);
66
66
  setShow(!isSeen);
@@ -71,7 +71,9 @@ export const Banner = (props) => {
71
71
  if (!dismissible) {
72
72
  return;
73
73
  }
74
- await hideBanner(id);
74
+ if (id) {
75
+ await hideBanner(id);
76
+ }
75
77
  setShow(false);
76
78
  };
77
79
  if (!show) {
@@ -1 +1 @@
1
- {"version":3,"file":"Banner.js","sourceRoot":"","sources":["../src/Banner.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Banner.js","sourceRoot":"","sources":["../src/Banner.tsx"],"names":[],"mappings":"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"}
package/dist/Common.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { CountryCode } from "libphonenumber-js";
2
2
  import type React from "react";
3
3
  import type { ReactElement, ReactNode } from "react";
4
- import type { ListRenderItemInfo, StyleProp, TextStyle, ViewStyle } from "react-native";
4
+ import type { ImageStyle, ListRenderItemInfo, StyleProp, TextInput, TextStyle, ViewStyle } from "react-native";
5
5
  import type { DimensionValue } from "react-native/Libraries/StyleSheet/StyleSheetTypes";
6
6
  import type { Styles } from "react-native-google-places-autocomplete";
7
7
  import type { SvgProps } from "react-native-svg";
@@ -418,7 +418,7 @@ export interface BoxPropsBase {
418
418
  zIndex?: number | "auto";
419
419
  onClick?: () => void | Promise<void>;
420
420
  className?: string;
421
- style?: any;
421
+ style?: StyleProp<ViewStyle>;
422
422
  onHoverStart?: () => void | Promise<void>;
423
423
  onHoverEnd?: () => void | Promise<void>;
424
424
  scroll?: boolean;
@@ -442,7 +442,7 @@ export type BoxProps = (BoxPropsBase & {
442
442
  } & AccessibilityProps);
443
443
  export type BoxColor = SurfaceColor | "transparent";
444
444
  export interface ErrorBoundaryProps {
445
- onError?: (error: Error, stack: any) => void;
445
+ onError?: (error: Error, stack: string) => void;
446
446
  children?: ReactNode;
447
447
  }
448
448
  export interface IconProps {
@@ -515,7 +515,7 @@ export interface TextFieldProps extends BaseFieldProps, HelperTextProps, ErrorTe
515
515
  grow?: boolean;
516
516
  multiline?: boolean;
517
517
  rows?: number;
518
- inputRef?: any;
518
+ inputRef?: (ref: TextInput | null) => void;
519
519
  trimOnBlur?: boolean;
520
520
  aiSuggestion?: AiSuggestionProps;
521
521
  }
@@ -605,7 +605,7 @@ export interface ImageProps {
605
605
  size?: string;
606
606
  srcSet?: string;
607
607
  fullWidth?: boolean;
608
- style?: any;
608
+ style?: ImageStyle;
609
609
  }
610
610
  export interface BackButtonInterface {
611
611
  onBack: () => void;
@@ -666,7 +666,7 @@ export interface SplitPageProps {
666
666
  renderListViewHeader?: () => ReactElement | null;
667
667
  renderContent?: (index?: number) => ReactElement | ReactElement[] | null;
668
668
  listViewData: any[];
669
- listViewExtraData?: any;
669
+ listViewExtraData?: unknown;
670
670
  listViewWidth?: number;
671
671
  listViewMaxWidth?: number;
672
672
  renderChild?: () => ReactChild;
@@ -686,7 +686,7 @@ export interface AddressInterface {
686
686
  export interface TransformValueOptions {
687
687
  func?: (value: string) => string;
688
688
  options?: {
689
- [key: string]: any;
689
+ [key: string]: unknown;
690
690
  };
691
691
  }
692
692
  export type ReactChild = ReactNode;
@@ -1183,8 +1183,10 @@ export interface BannerButtonProps {
1183
1183
  export interface BannerPropsBase {
1184
1184
  /**
1185
1185
  * Used to identify if banner has been dismissed by the user.
1186
+ * When provided, dismissal state is persisted to AsyncStorage.
1187
+ * When omitted, dismissal is ephemeral (resets on remount).
1186
1188
  */
1187
- id: string;
1189
+ id?: string;
1188
1190
  /**
1189
1191
  * The text to display in the main body of the banner.
1190
1192
  */
@@ -1622,11 +1624,11 @@ export interface PageProps {
1622
1624
  color?: SurfaceColor;
1623
1625
  maxWidth?: number | string;
1624
1626
  keyboardOffset?: number;
1625
- footer?: any;
1627
+ footer?: ReactNode;
1626
1628
  rightButton?: string;
1627
1629
  rightButtonOnClick?: () => void;
1628
- children?: any;
1629
- onError?: (error: Error, stack: any) => void;
1630
+ children?: ReactChildren;
1631
+ onError?: (error: Error, stack: string) => void;
1630
1632
  }
1631
1633
  export interface ProgressBarProps {
1632
1634
  color: SurfaceColor;
@@ -1645,7 +1647,7 @@ export interface RadioFieldProps {
1645
1647
  export interface SignatureFieldProps {
1646
1648
  disabled?: boolean;
1647
1649
  value?: string;
1648
- onChange: (value: any) => void;
1650
+ onChange: (value: string) => void;
1649
1651
  title?: string;
1650
1652
  onStart?: () => void;
1651
1653
  onEnd?: () => void;
@@ -2025,7 +2027,7 @@ export interface APIError {
2025
2027
  pointer?: string;
2026
2028
  parameter?: string;
2027
2029
  meta?: {
2028
- [id: string]: any;
2030
+ [id: string]: unknown;
2029
2031
  };
2030
2032
  };
2031
2033
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Common.js","sourceRoot":"","sources":["../src/Common.ts"],"names":[],"mappings":"AAqXA,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE;CACP,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,OAAqB;IAC9C,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,OAAO,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAmB,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,WAAW,CAAC,OAAyB,CAAC,CAAC;AAChD,CAAC;AAqBD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAe,EAAE,EAAE;IAClD,OAAO;QACL,KAAK,EAAE,EAAE;QACT,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,CAAC;KACN,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAClB,CAAC,CAAC;AAqTF,MAAM,YAAY,GAAG;IACnB,KAAK,EAAE,GAAG;IACV,KAAK,EAAE,GAAG;IACV,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,EAAE;IACR,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,CAAC;IACL,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,GAAG;IACZ,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,EAAE;CACP,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,QAAkB;IAC5C,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC;AAsnED;;GAEG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;CACV,CAAC"}
1
+ {"version":3,"file":"Common.js","sourceRoot":"","sources":["../src/Common.ts"],"names":[],"mappings":"AA4XA,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE;CACP,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,OAAqB;IAC9C,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,OAAO,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAmB,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,WAAW,CAAC,OAAyB,CAAC,CAAC;AAChD,CAAC;AAqBD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAe,EAAE,EAAE;IAClD,OAAO;QACL,KAAK,EAAE,EAAE;QACT,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,CAAC;KACN,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAClB,CAAC,CAAC;AAsTF,MAAM,YAAY,GAAG;IACnB,KAAK,EAAE,GAAG;IACV,KAAK,EAAE,GAAG;IACV,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,EAAE;IACR,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,CAAC;IACL,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,GAAG;IACZ,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,EAAE;CACP,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,QAAkB;IAC5C,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC;AAqoED;;GAEG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;CACV,CAAC"}
package/package.json CHANGED
@@ -137,5 +137,5 @@
137
137
  "test:coverage": "TZ=America/New_York bun run ../scripts/check-coverage.ts",
138
138
  "types": "bun typedoc"
139
139
  },
140
- "version": "0.11.0"
140
+ "version": "0.11.2"
141
141
  }
@@ -1,8 +1,10 @@
1
1
  import {describe, expect, it, mock} from "bun:test";
2
2
  import {act, fireEvent, waitFor} from "@testing-library/react-native";
3
+ import React from "react";
3
4
 
4
5
  import {Banner} from "./Banner";
5
6
  import {renderWithTheme} from "./test-utils";
7
+ import {Unifier} from "./Unifier";
6
8
 
7
9
  describe("Banner", () => {
8
10
  it("renders correctly with default props", () => {
@@ -125,4 +127,45 @@ describe("Banner", () => {
125
127
  expect(handleClick).toHaveBeenCalled();
126
128
  });
127
129
  });
130
+
131
+ // Tests for optional id prop
132
+ it("renders without id prop", () => {
133
+ const {getByText} = renderWithTheme(<Banner text="No id banner" />);
134
+ expect(getByText("No id banner")).toBeTruthy();
135
+ });
136
+
137
+ it("renders without id and without dismissible", () => {
138
+ const {getByText, queryByLabelText} = renderWithTheme(<Banner text="Simple banner no id" />);
139
+ expect(getByText("Simple banner no id")).toBeTruthy();
140
+ expect(queryByLabelText("Dismiss")).toBeNull();
141
+ });
142
+
143
+ it("hides dismissible banner without id when dismissed", async () => {
144
+ const {getByLabelText, queryByText} = renderWithTheme(
145
+ <Banner dismissible text="Ephemeral banner" />
146
+ );
147
+
148
+ await act(async () => {
149
+ fireEvent.press(getByLabelText("Dismiss"));
150
+ });
151
+
152
+ await waitFor(() => {
153
+ expect(queryByText("Ephemeral banner")).toBeNull();
154
+ });
155
+ });
156
+
157
+ it("does not persist dismissal to storage when id is omitted", async () => {
158
+ const setItemMock = Unifier.storage.setItem as ReturnType<typeof mock>;
159
+ setItemMock.mockClear();
160
+
161
+ const {getByLabelText} = renderWithTheme(<Banner dismissible text="No persist banner" />);
162
+
163
+ await act(async () => {
164
+ fireEvent.press(getByLabelText("Dismiss"));
165
+ });
166
+
167
+ await waitFor(() => {
168
+ expect(setItemMock).not.toHaveBeenCalled();
169
+ });
170
+ });
128
171
  });
package/src/Banner.tsx CHANGED
@@ -112,9 +112,9 @@ export const Banner = (props: BannerProps): React.ReactElement | null => {
112
112
 
113
113
  const [show, setShow] = useState(true);
114
114
 
115
- // Load seen from async storage.
115
+ // Load seen from async storage (only when id is provided).
116
116
  useEffect(() => {
117
- if (dismissible) {
117
+ if (dismissible && id) {
118
118
  void Unifier.storage.getItem(getKey(id)).then((isSeen) => {
119
119
  console.debug(`[banner] ${getKey(id)} seen? ${isSeen}`);
120
120
  setShow(!isSeen);
@@ -126,7 +126,9 @@ export const Banner = (props: BannerProps): React.ReactElement | null => {
126
126
  if (!dismissible) {
127
127
  return;
128
128
  }
129
- await hideBanner(id);
129
+ if (id) {
130
+ await hideBanner(id);
131
+ }
130
132
  setShow(false);
131
133
  };
132
134
 
package/src/Common.ts CHANGED
@@ -1,7 +1,14 @@
1
1
  import type {CountryCode} from "libphonenumber-js";
2
2
  import type React from "react";
3
3
  import type {ReactElement, ReactNode} from "react";
4
- import type {ListRenderItemInfo, StyleProp, TextStyle, ViewStyle} from "react-native";
4
+ import type {
5
+ ImageStyle,
6
+ ListRenderItemInfo,
7
+ StyleProp,
8
+ TextInput,
9
+ TextStyle,
10
+ ViewStyle,
11
+ } from "react-native";
5
12
  import type {DimensionValue} from "react-native/Libraries/StyleSheet/StyleSheetTypes";
6
13
  import type {Styles} from "react-native-google-places-autocomplete";
7
14
  import type {SvgProps} from "react-native-svg";
@@ -456,6 +463,7 @@ export interface BoxPropsBase {
456
463
  lgColumn?: UnsignedUpTo12;
457
464
  dangerouslySetInlineStyle?: {
458
465
  __style: {
466
+ // noExplicitAny: escape hatch for arbitrary inline style values
459
467
  [key: string]: any;
460
468
  };
461
469
  };
@@ -528,7 +536,7 @@ export interface BoxPropsBase {
528
536
 
529
537
  onClick?: () => void | Promise<void>;
530
538
  className?: string;
531
- style?: any;
539
+ style?: StyleProp<ViewStyle>;
532
540
  onHoverStart?: () => void | Promise<void>;
533
541
  onHoverEnd?: () => void | Promise<void>;
534
542
  scroll?: boolean;
@@ -554,7 +562,7 @@ export type BoxProps =
554
562
  export type BoxColor = SurfaceColor | "transparent";
555
563
 
556
564
  export interface ErrorBoundaryProps {
557
- onError?: (error: Error, stack: any) => void;
565
+ onError?: (error: Error, stack: string) => void;
558
566
  children?: ReactNode;
559
567
  }
560
568
 
@@ -652,7 +660,7 @@ export interface TextFieldProps extends BaseFieldProps, HelperTextProps, ErrorTe
652
660
  multiline?: boolean;
653
661
  rows?: number;
654
662
 
655
- inputRef?: any;
663
+ inputRef?: (ref: TextInput | null) => void;
656
664
  trimOnBlur?: boolean;
657
665
 
658
666
  aiSuggestion?: AiSuggestionProps;
@@ -782,7 +790,7 @@ export interface ImageProps {
782
790
  size?: string;
783
791
  srcSet?: string;
784
792
  fullWidth?: boolean;
785
- style?: any;
793
+ style?: ImageStyle;
786
794
  }
787
795
 
788
796
  export interface BackButtonInterface {
@@ -850,14 +858,17 @@ export interface SplitPageProps {
850
858
  loading?: boolean;
851
859
  color?: SurfaceColor;
852
860
  keyboardOffset?: number;
861
+ // noExplicitAny: ListRenderItemInfo generic type depends on the consumer's data shape
853
862
  renderListViewItem: (itemInfo: ListRenderItemInfo<any>) => ReactElement | null;
854
863
  renderListViewHeader?: () => ReactElement | null;
855
864
  renderContent?: (index?: number) => ReactElement | ReactElement[] | null;
865
+ // noExplicitAny: list data type varies by consumer's data model
856
866
  listViewData: any[];
857
- listViewExtraData?: any;
867
+ listViewExtraData?: unknown;
858
868
  listViewWidth?: number;
859
869
  listViewMaxWidth?: number;
860
870
  renderChild?: () => ReactChild;
871
+ // noExplicitAny: callback value type varies by consumer's data model
861
872
  onSelectionChange?: (value?: any) => void | Promise<void>;
862
873
  }
863
874
 
@@ -896,7 +907,7 @@ export interface AddressInterface {
896
907
  export interface TransformValueOptions {
897
908
  func?: (value: string) => string;
898
909
  options?: {
899
- [key: string]: any;
910
+ [key: string]: unknown;
900
911
  };
901
912
  }
902
913
 
@@ -1447,8 +1458,10 @@ export interface BannerButtonProps {
1447
1458
  export interface BannerPropsBase {
1448
1459
  /**
1449
1460
  * Used to identify if banner has been dismissed by the user.
1461
+ * When provided, dismissal state is persisted to AsyncStorage.
1462
+ * When omitted, dismissal is ephemeral (resets on remount).
1450
1463
  */
1451
- id: string;
1464
+ id?: string;
1452
1465
  /**
1453
1466
  * The text to display in the main body of the banner.
1454
1467
  */
@@ -1743,6 +1756,7 @@ export interface HeightActionSheetProps {
1743
1756
 
1744
1757
  export interface HyperlinkProps {
1745
1758
  linkDefault?: boolean;
1759
+ // noExplicitAny: type comes from external linkify-it library which lacks an exported type
1746
1760
  linkify?: any;
1747
1761
  linkStyle?: StyleProp<any>;
1748
1762
  linkText?: string | ((url: string) => string);
@@ -1899,10 +1913,12 @@ export interface ModalProps {
1899
1913
  /**
1900
1914
  * The function to call when the primary button is clicked.
1901
1915
  */
1916
+ // noExplicitAny: callback value type varies by consumer context
1902
1917
  primaryButtonOnClick?: (value?: any) => void | Promise<void>;
1903
1918
  /**
1904
1919
  * The function to call when the secondary button is clicked.
1905
1920
  */
1921
+ // noExplicitAny: callback value type varies by consumer context
1906
1922
  secondaryButtonOnClick?: (value?: any) => void | Promise<void>;
1907
1923
  }
1908
1924
 
@@ -1915,6 +1931,7 @@ export interface NumberPickerActionSheetProps {
1915
1931
  }
1916
1932
 
1917
1933
  export interface PageProps {
1934
+ // noExplicitAny: React Navigation type varies by navigation stack configuration
1918
1935
  navigation?: any;
1919
1936
  scroll?: boolean;
1920
1937
  loading?: boolean;
@@ -1928,11 +1945,11 @@ export interface PageProps {
1928
1945
  color?: SurfaceColor;
1929
1946
  maxWidth?: number | string;
1930
1947
  keyboardOffset?: number;
1931
- footer?: any;
1948
+ footer?: ReactNode;
1932
1949
  rightButton?: string;
1933
1950
  rightButtonOnClick?: () => void;
1934
- children?: any;
1935
- onError?: (error: Error, stack: any) => void;
1951
+ children?: ReactChildren;
1952
+ onError?: (error: Error, stack: string) => void;
1936
1953
  }
1937
1954
 
1938
1955
  export interface ProgressBarProps {
@@ -1955,7 +1972,7 @@ export interface RadioFieldProps {
1955
1972
  export interface SignatureFieldProps {
1956
1973
  disabled?: boolean; // default "default"
1957
1974
  value?: string;
1958
- onChange: (value: any) => void;
1975
+ onChange: (value: string) => void;
1959
1976
  title?: string; // default "Signature"
1960
1977
  onStart?: () => void;
1961
1978
  onEnd?: () => void;
@@ -2354,16 +2371,19 @@ export type TapToEditProps =
2354
2371
 
2355
2372
  export interface BaseTapToEditProps extends Omit<FieldProps, "onChange" | "value"> {
2356
2373
  title: string;
2374
+ // noExplicitAny: value type varies across TapToEdit field types (text, number, date, etc.)
2357
2375
  value: any;
2358
2376
 
2359
2377
  /**
2360
2378
  * Not required if not editable.
2361
2379
  */
2380
+ // noExplicitAny: value type varies across TapToEdit field types
2362
2381
  setValue?: (value: any) => void;
2363
2382
 
2364
2383
  /**
2365
2384
  * Not required if not editable.
2366
2385
  */
2386
+ // noExplicitAny: value type varies across TapToEdit field types
2367
2387
  onSave?: (value: any) => void | Promise<void>;
2368
2388
 
2369
2389
  /**
@@ -2376,6 +2396,7 @@ export interface BaseTapToEditProps extends Omit<FieldProps, "onChange" | "value
2376
2396
  * Enable edit mode from outside the component.
2377
2397
  */
2378
2398
  isEditing?: boolean;
2399
+ // noExplicitAny: input value type varies across TapToEdit field types
2379
2400
  transform?: (value: any) => string;
2380
2401
  /**
2381
2402
  * Show a confirmation modal before saving the value.
@@ -2431,7 +2452,7 @@ export interface APIError {
2431
2452
  source?: string;
2432
2453
  pointer?: string;
2433
2454
  parameter?: string;
2434
- meta?: {[id: string]: any};
2455
+ meta?: {[id: string]: unknown};
2435
2456
  };
2436
2457
  }
2437
2458
 
@@ -2464,6 +2485,7 @@ export interface ModelFields {
2464
2485
 
2465
2486
  export interface OpenAPISpec {
2466
2487
  paths: {
2488
+ // noExplicitAny: OpenAPI path items are deeply accessed with chained property lookups
2467
2489
  [key: string]: any;
2468
2490
  };
2469
2491
  }
@@ -2496,7 +2518,8 @@ export interface ModelAdminFieldConfig {
2496
2518
 
2497
2519
  // The props for a custom column component for ModelAdmin.
2498
2520
  export interface ModelAdminCustomComponentProps extends Omit<FieldProps, "name"> {
2499
- doc: any; // The rest of the document.
2521
+ // noExplicitAny: document shape varies by model used with ModelAdmin
2522
+ doc: any;
2500
2523
  fieldKey: string; // Dot notation representation of the field.
2501
2524
  // user: User;
2502
2525
  editing: boolean; // Allow for inline editing of the field.
@@ -1,6 +1,7 @@
1
- import {describe, expect, it, mock} from "bun:test";
1
+ import {afterEach, describe, expect, it, mock} from "bun:test";
2
2
  import {fireEvent} from "@testing-library/react-native";
3
3
 
4
+ import {isMobileDevice} from "./MediaQuery";
4
5
  import {Modal} from "./Modal";
5
6
  import {Text} from "./Text";
6
7
  import {renderWithTheme} from "./test-utils";
@@ -355,3 +356,47 @@ describe("Modal", () => {
355
356
  expect(stopPropagation).not.toHaveBeenCalled();
356
357
  });
357
358
  });
359
+
360
+ describe("Modal mobile branch", () => {
361
+ afterEach(() => {
362
+ (isMobileDevice as ReturnType<typeof mock>).mockImplementation(() => false);
363
+ });
364
+
365
+ it("renders ActionSheet when isMobileDevice is true", () => {
366
+ (isMobileDevice as ReturnType<typeof mock>).mockImplementation(() => true);
367
+ const {toJSON} = renderWithTheme(
368
+ <Modal onDismiss={() => {}} title="Mobile Modal" visible>
369
+ <Text>Mobile Content</Text>
370
+ </Modal>
371
+ );
372
+ expect(toJSON()).toBeTruthy();
373
+ });
374
+
375
+ it("renders ActionSheet with title and buttons on mobile", () => {
376
+ (isMobileDevice as ReturnType<typeof mock>).mockImplementation(() => true);
377
+ const {toJSON} = renderWithTheme(
378
+ <Modal
379
+ onDismiss={() => {}}
380
+ primaryButtonOnClick={() => {}}
381
+ primaryButtonText="Save"
382
+ secondaryButtonOnClick={() => {}}
383
+ secondaryButtonText="Cancel"
384
+ title="Mobile Actions"
385
+ visible
386
+ >
387
+ <Text>Content</Text>
388
+ </Modal>
389
+ );
390
+ expect(toJSON()).toBeTruthy();
391
+ });
392
+
393
+ it("renders ActionSheet with persistOnBackgroundClick enabled", () => {
394
+ (isMobileDevice as ReturnType<typeof mock>).mockImplementation(() => true);
395
+ const {toJSON} = renderWithTheme(
396
+ <Modal onDismiss={() => {}} persistOnBackgroundClick title="Persistent Mobile" visible>
397
+ <Text>Content</Text>
398
+ </Modal>
399
+ );
400
+ expect(toJSON()).toBeTruthy();
401
+ });
402
+ });
@@ -1,32 +1,53 @@
1
1
  import {describe, expect, it, mock} from "bun:test";
2
2
  import {renderHook} from "@testing-library/react-native";
3
3
 
4
+ import type {ConsentFormPublic} from "./useConsentForms";
4
5
  import {detectLocale, useConsentForms} from "./useConsentForms";
5
6
 
7
+ type ConsentFormsApi = Parameters<typeof useConsentForms>[0];
8
+
9
+ interface GlobalThisWithNavigator {
10
+ navigator: {language: string} | undefined;
11
+ }
12
+
13
+ interface MockQueryDef {
14
+ onQueryStarted?: (
15
+ _arg: unknown,
16
+ helpers: {queryFulfilled: Promise<{data: ConsentFormPublic[]}> | Promise<never>}
17
+ ) => Promise<void>;
18
+ query: () => string;
19
+ }
20
+
21
+ interface MockInjectOpts {
22
+ endpoints: (build: {query: (def: MockQueryDef) => string}) => Record<string, unknown>;
23
+ }
24
+
6
25
  mock.module("expo-localization", () => ({
7
26
  getLocales: () => [{languageTag: "es-ES"}],
8
27
  }));
9
28
 
10
29
  describe("detectLocale", () => {
11
30
  it("returns locale from expo-localization in native test env", () => {
12
- const originalNavigator = (globalThis as any).navigator;
13
- (globalThis as any).navigator = undefined;
31
+ const g = globalThis as unknown as GlobalThisWithNavigator;
32
+ const originalNavigator = g.navigator;
33
+ g.navigator = undefined;
14
34
  const locale = detectLocale();
15
- (globalThis as any).navigator = originalNavigator;
35
+ g.navigator = originalNavigator;
16
36
  expect(typeof locale).toBe("string");
17
37
  expect(locale.length).toBeGreaterThan(0);
18
38
  });
19
39
 
20
40
  it("falls back to en when expo-localization throws and no navigator", () => {
21
- const originalNavigator = (globalThis as any).navigator;
22
- (globalThis as any).navigator = undefined;
41
+ const g = globalThis as unknown as GlobalThisWithNavigator;
42
+ const originalNavigator = g.navigator;
43
+ g.navigator = undefined;
23
44
  mock.module("expo-localization", () => ({
24
45
  getLocales: () => {
25
46
  throw new Error("not available");
26
47
  },
27
48
  }));
28
49
  const locale = detectLocale();
29
- (globalThis as any).navigator = originalNavigator;
50
+ g.navigator = originalNavigator;
30
51
  // Reset mock
31
52
  mock.module("expo-localization", () => ({
32
53
  getLocales: () => [{languageTag: "es-ES"}],
@@ -35,10 +56,11 @@ describe("detectLocale", () => {
35
56
  });
36
57
 
37
58
  it("returns navigator.language when available", () => {
38
- const originalNavigator = (globalThis as any).navigator;
39
- (globalThis as any).navigator = {language: "fr-FR"};
59
+ const g = globalThis as unknown as GlobalThisWithNavigator;
60
+ const originalNavigator = g.navigator;
61
+ g.navigator = {language: "fr-FR"};
40
62
  const locale = detectLocale();
41
- (globalThis as any).navigator = originalNavigator;
63
+ g.navigator = originalNavigator;
42
64
  expect(locale).toBe("fr-FR");
43
65
  });
44
66
  });
@@ -54,10 +76,10 @@ describe("useConsentForms", () => {
54
76
  }));
55
77
  const api = {
56
78
  enhanceEndpoints: mock(() => ({
57
- injectEndpoints: mock((opts: any) => {
79
+ injectEndpoints: mock((opts: MockInjectOpts) => {
58
80
  // Call endpoint builder to exercise provides/onQueryStarted
59
81
  const build = {
60
- query: mock((def: any) => {
82
+ query: mock((def: MockQueryDef) => {
61
83
  // Call onQueryStarted with a successful result
62
84
  if (def.onQueryStarted) {
63
85
  void def.onQueryStarted(undefined, {
@@ -78,21 +100,21 @@ describe("useConsentForms", () => {
78
100
  };
79
101
 
80
102
  it("returns an array of forms when response is an array", () => {
81
- const {api} = buildApi({data: [{id: "1", title: "Form 1"} as any]});
82
- const {result} = renderHook(() => useConsentForms(api as any));
103
+ const {api} = buildApi({data: [{id: "1", title: "Form 1"} as unknown as ConsentFormPublic]});
104
+ const {result} = renderHook(() => useConsentForms(api as unknown as ConsentFormsApi));
83
105
  expect(result.current.forms).toBeDefined();
84
106
  expect(Array.isArray(result.current.forms)).toBe(true);
85
107
  });
86
108
 
87
109
  it("unwraps .data property when response is object shape", () => {
88
- const {api} = buildApi({data: {data: [{id: "2"} as any]}});
89
- const {result} = renderHook(() => useConsentForms(api as any, "/api"));
110
+ const {api} = buildApi({data: {data: [{id: "2"} as unknown as ConsentFormPublic]}});
111
+ const {result} = renderHook(() => useConsentForms(api as unknown as ConsentFormsApi, "/api"));
90
112
  expect(Array.isArray(result.current.forms)).toBe(true);
91
113
  });
92
114
 
93
115
  it("returns empty array when no data is present", () => {
94
116
  const {api} = buildApi({data: undefined, isLoading: true});
95
- const {result} = renderHook(() => useConsentForms(api as any));
117
+ const {result} = renderHook(() => useConsentForms(api as unknown as ConsentFormsApi));
96
118
  expect(result.current.forms).toEqual([]);
97
119
  expect(result.current.isLoading).toBe(true);
98
120
  });
@@ -101,9 +123,9 @@ describe("useConsentForms", () => {
101
123
  const refetch = mock(() => {});
102
124
  const api = {
103
125
  enhanceEndpoints: mock(() => ({
104
- injectEndpoints: mock((opts: any) => {
126
+ injectEndpoints: mock((opts: MockInjectOpts) => {
105
127
  const build = {
106
- query: mock((def: any) => {
128
+ query: mock((def: MockQueryDef) => {
107
129
  if (def.onQueryStarted) {
108
130
  void def.onQueryStarted(undefined, {
109
131
  queryFulfilled: Promise.reject(new Error("failed")),
@@ -124,7 +146,7 @@ describe("useConsentForms", () => {
124
146
  }),
125
147
  })),
126
148
  };
127
- const {result} = renderHook(() => useConsentForms(api as any));
149
+ const {result} = renderHook(() => useConsentForms(api as unknown as ConsentFormsApi));
128
150
  expect(result.current.error).toBe("error");
129
151
  });
130
152
  });
@@ -1,8 +1,19 @@
1
1
  import {describe, expect, it, mock} from "bun:test";
2
2
  import {renderHook} from "@testing-library/react-native";
3
3
 
4
+ import type {SubmitConsentBody} from "./useSubmitConsent";
4
5
  import {useSubmitConsent} from "./useSubmitConsent";
5
6
 
7
+ type SubmitConsentApi = Parameters<typeof useSubmitConsent>[0];
8
+
9
+ interface MockMutationDef {
10
+ query: (body: SubmitConsentBody) => {method: string; url: string};
11
+ }
12
+
13
+ interface MockInjectOpts {
14
+ endpoints: (build: {mutation: (def: MockMutationDef) => string}) => Record<string, unknown>;
15
+ }
16
+
6
17
  describe("useSubmitConsent", () => {
7
18
  const buildApi = () => {
8
19
  const unwrap = mock(async () => ({success: true}));
@@ -13,9 +24,9 @@ describe("useSubmitConsent", () => {
13
24
  ]);
14
25
  const api = {
15
26
  enhanceEndpoints: mock(() => ({
16
- injectEndpoints: mock((opts: any) => {
27
+ injectEndpoints: mock((opts: MockInjectOpts) => {
17
28
  const build = {
18
- mutation: mock((def: any) => {
29
+ mutation: mock((def: MockMutationDef) => {
19
30
  // Exercise the query builder
20
31
  const result = def.query({
21
32
  agreed: true,
@@ -37,7 +48,7 @@ describe("useSubmitConsent", () => {
37
48
 
38
49
  it("returns submit function and state", () => {
39
50
  const {api} = buildApi();
40
- const {result} = renderHook(() => useSubmitConsent(api as any));
51
+ const {result} = renderHook(() => useSubmitConsent(api as unknown as SubmitConsentApi));
41
52
  expect(typeof result.current.submit).toBe("function");
42
53
  expect(result.current.isSubmitting).toBe(false);
43
54
  expect(result.current.error).toBeUndefined();
@@ -45,7 +56,7 @@ describe("useSubmitConsent", () => {
45
56
 
46
57
  it("calls submit mutation when submit is invoked", async () => {
47
58
  const {api, submitMutation, unwrap} = buildApi();
48
- const {result} = renderHook(() => useSubmitConsent(api as any, "/api"));
59
+ const {result} = renderHook(() => useSubmitConsent(api as unknown as SubmitConsentApi, "/api"));
49
60
  const response = await result.current.submit({
50
61
  agreed: true,
51
62
  consentFormId: "f1",
@@ -58,7 +69,7 @@ describe("useSubmitConsent", () => {
58
69
 
59
70
  it("uses empty baseUrl when none provided", () => {
60
71
  const {api} = buildApi();
61
- const {result} = renderHook(() => useSubmitConsent(api as any));
72
+ const {result} = renderHook(() => useSubmitConsent(api as unknown as SubmitConsentApi));
62
73
  expect(result.current.submit).toBeDefined();
63
74
  });
64
75
  });