@expo/ui 1.0.0-canary-20250320-7a205d3 → 1.0.0-canary-20250402-161f57b

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/CHANGELOG.md CHANGED
@@ -19,6 +19,7 @@
19
19
  - Adds `DateTimePicker` component. ([#34883](https://github.com/expo/expo/pull/34883) by [@alanjhughes](https://github.com/alanjhughes))
20
20
  - Add CircularProgress and LinearProgress component. ([#34907](https://github.com/expo/expo/pull/34907) by [@janicduplessis](https://github.com/janicduplessis))
21
21
  - Add Gauge component ([#35032](https://github.com/expo/expo/pull/35032) by [@jakex7](https://github.com/jakex7))
22
+ - Add List and Label component ([#35222](https://github.com/expo/expo/pull/35222) by [@Pflaumenbaum](https://github.com/Pflaumenbaum))
22
23
 
23
24
  ### 🐛 Bug fixes
24
25
 
@@ -53,6 +54,7 @@
53
54
  - Add docs ([#34808](https://github.com/expo/expo/pull/34808) by [@aleqsio](https://github.com/aleqsio))
54
55
  - [apple] Migrate remaining `expo-module.config.json` to unified platform syntax. ([#34445](https://github.com/expo/expo/pull/34445) by [@reichhartd](https://github.com/reichhartd))
55
56
  - Rename the events for the `Switch` component. ([#34577](https://github.com/expo/expo/pull/34577) by [@behenate](https://github.com/behenate))
57
+ - Allow lower case section titles ([#35113](https://github.com/expo/expo/pull/35113) by [@Pflaumenbaum](https://github.com/Pflaumenbaum))
56
58
 
57
59
  ## 0.0.1 — 2025-01-21
58
60
 
@@ -12,13 +12,13 @@ apply plugin: 'expo-module-gradle-plugin'
12
12
  apply plugin: 'org.jetbrains.kotlin.plugin.compose'
13
13
 
14
14
  group = 'expo.modules.ui'
15
- version = '0.0.2'
15
+ version = '1.0.0-canary-20250402-161f57b'
16
16
 
17
17
  android {
18
18
  namespace "expo.modules.ui"
19
19
  defaultConfig {
20
20
  versionCode 1
21
- versionName "0.0.2"
21
+ versionName "1.0.0-canary-20250402-161f57b"
22
22
  }
23
23
  buildFeatures {
24
24
  compose true
@@ -0,0 +1,28 @@
1
+ import { StyleProp, ViewStyle } from 'react-native';
2
+ export type LabelProps = {
3
+ /**
4
+ * The title text to be displayed in the label.
5
+ */
6
+ title?: string;
7
+ /**
8
+ * The name of the SFSymbol to be displayed in the label.
9
+ */
10
+ systemImage?: string;
11
+ /**
12
+ * The color of the label icon.
13
+ */
14
+ color?: string;
15
+ /**
16
+ * Additional styles to apply to the label.
17
+ */
18
+ style?: StyleProp<ViewStyle>;
19
+ };
20
+ /**
21
+ * Renders a native label view, which could be used in a list or section.
22
+ *
23
+ * @param {LabelProps} props - The properties passed to the Label component.
24
+ * @returns {JSX.Element} The rendered native Label component.
25
+ * @platform ios
26
+ */
27
+ export declare function Label(props: LabelProps): import("react").JSX.Element;
28
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../components/Label/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAQ,SAAS,EAAE,MAAM,cAAc,CAAC;AAE1D,MAAM,MAAM,UAAU,GAAG;IACvB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,UAAU,+BAEtC"}
@@ -0,0 +1,10 @@
1
+ import { LabelProps } from '.';
2
+ /**
3
+ * Renders a native label view, which could be used in a list or section.
4
+ *
5
+ * @param {LabelProps} props - The properties passed to the Label component.
6
+ * @returns {JSX.Element} The rendered native Label component.
7
+ * @platform ios
8
+ */
9
+ export declare function Label(props: LabelProps): import("react").JSX.Element;
10
+ //# sourceMappingURL=index.ios.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.ios.d.ts","sourceRoot":"","sources":["../../../components/Label/index.ios.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,CAAC;AAI/B;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,UAAU,+BAEtC"}
@@ -0,0 +1,87 @@
1
+ import { StyleProp, ViewStyle } from 'react-native';
2
+ import { ViewEvent } from '../../src/types';
3
+ export type ListStyle = 'automatic' | 'plain' | 'inset' | 'insetGrouped' | 'grouped' | 'sidebar';
4
+ export interface ListProps {
5
+ /**
6
+ * Custom style for the container wrapping the list.
7
+ */
8
+ style?: StyleProp<ViewStyle>;
9
+ /**
10
+ * One of the predefined ListStyle types in SwiftUI.
11
+ * @default 'automatic'
12
+ */
13
+ listStyle?: ListStyle;
14
+ /**
15
+ * Allows the selection of list items.
16
+ * @default false
17
+ */
18
+ selectEnabled?: boolean;
19
+ /**
20
+ * Enables reordering of list items.
21
+ * @default false
22
+ */
23
+ moveEnabled?: boolean;
24
+ /**
25
+ * Allows the deletion of list items.
26
+ * @default false
27
+ */
28
+ deleteEnabled?: boolean;
29
+ /**
30
+ * Makes the list scrollable.
31
+ * @default true
32
+ * @platform ios 16.0+
33
+ */
34
+ scrollEnabled?: boolean;
35
+ /**
36
+ * Enables SwiftUI edit mode.
37
+ * @default false
38
+ */
39
+ editModeEnabled?: boolean;
40
+ /**
41
+ * The children elements to be rendered inside the list.
42
+ */
43
+ children: React.ReactNode;
44
+ /**
45
+ * Callback triggered when an item is deleted from the list.
46
+ */
47
+ onDeleteItem?: (index: number) => void;
48
+ /**
49
+ * Callback triggered when an item is moved in the list.
50
+ */
51
+ onMoveItem?: (from: number, to: number) => void;
52
+ /**
53
+ * Callback triggered when the selection changes in a list.
54
+ */
55
+ onSelectionChange?: (selection: number[]) => void;
56
+ }
57
+ /**
58
+ * DeleteItemEvent represents an event triggered when an item is deleted from the list.
59
+ */
60
+ type DeleteItemEvent = ViewEvent<'onDeleteItem', {
61
+ index: number;
62
+ }>;
63
+ /**
64
+ * MoveItemEvent represents an event triggered when an item is moved in the list.
65
+ */
66
+ type MoveItemEvent = ViewEvent<'onMoveItem', {
67
+ from: number;
68
+ to: number;
69
+ }>;
70
+ /**
71
+ * SelectItemEvent represents an event triggered when the selection changes in a list.
72
+ */
73
+ type SelectItemEvent = ViewEvent<'onSelectionChange', {
74
+ selection: number[];
75
+ }>;
76
+ export type NativeListProps = Omit<ListProps, 'onDeleteItem' | 'onMoveItem' | 'onSelectionChange'> & DeleteItemEvent & MoveItemEvent & SelectItemEvent & {
77
+ children: React.ReactNode;
78
+ };
79
+ /**
80
+ * A list component that renders its children using a native SwiftUI list.
81
+ * @param {ListProps} props - The properties for the list component.
82
+ * @returns {JSX.Element | null} The rendered list with its children or null if the platform is unsupported.
83
+ * @platform ios
84
+ */
85
+ export declare function List({ children }: ListProps): import("react").ReactNode;
86
+ export {};
87
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../components/List/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,MAAM,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,OAAO,GAAG,cAAc,GAAG,SAAS,GAAG,SAAS,CAAC;AAEjG,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAE7B;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IAEtB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;OAEG;IACH,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAE1B;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEvC;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAEhD;;OAEG;IACH,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACnD;AAED;;GAEG;AACH,KAAK,eAAe,GAAG,SAAS,CAAC,cAAc,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AACpE;;GAEG;AACH,KAAK,aAAa,GAAG,SAAS,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAC3E;;GAEG;AACH,KAAK,eAAe,GAAG,SAAS,CAAC,mBAAmB,EAAE;IAAE,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAAC;AAE/E,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,EAAE,cAAc,GAAG,YAAY,GAAG,mBAAmB,CAAC,GAChG,eAAe,GACf,aAAa,GACb,eAAe,GAAG;IAChB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAEJ;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,SAAS,6BAE3C"}
@@ -0,0 +1,9 @@
1
+ import { ListProps } from '.';
2
+ /**
3
+ * A list component that renders its children using a native SwiftUI list.
4
+ * @param {ListProps} props - The properties for the list component.
5
+ * @returns {JSX.Element | null} The rendered list with its children or null if the platform is unsupported.
6
+ * @platform ios
7
+ */
8
+ export declare function List(props: ListProps): import("react").JSX.Element | null;
9
+ //# sourceMappingURL=index.ios.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.ios.d.ts","sourceRoot":"","sources":["../../../components/List/index.ios.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAmB,MAAM,GAAG,CAAC;AAc/C;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,SAAS,sCAYpC"}
@@ -1,8 +1,11 @@
1
1
  import { StyleProp, ViewStyle } from 'react-native';
2
2
  export type SectionProps = {
3
- style?: StyleProp<ViewStyle>;
3
+ /**
4
+ * @note On iOS, section titles are usually capitalized for consistency with platform conventions.
5
+ */
4
6
  title?: string;
5
7
  children: any;
8
+ style?: StyleProp<ViewStyle>;
6
9
  };
7
10
  /**
8
11
  * Section component uses the native [Section](https://developer.apple.com/documentation/swiftui/section) component.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../components/Section/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEpD,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,GAAG,CAAC;CACf,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,EAAE,QAAQ,EAAE,EAAE,YAAY,OAEjD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../components/Section/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEpD,MAAM,MAAM,YAAY,GAAG;IACzB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,GAAG,CAAC;IACd,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,EAAE,QAAQ,EAAE,EAAE,YAAY,OAEjD"}
@@ -4,6 +4,8 @@ export type * from '../components/Picker';
4
4
  export type * from '../components/Section';
5
5
  export type * from '../components/Slider';
6
6
  export type * from '../components/Switch';
7
+ export type * from '../components/Label';
8
+ export type * from '../components/List';
7
9
  /**
8
10
  * @hidden
9
11
  */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,mBAAmB,sBAAsB,CAAC;AAC1C,mBAAmB,2BAA2B,CAAC;AAC/C,mBAAmB,sBAAsB,CAAC;AAC1C,mBAAmB,uBAAuB,CAAC;AAC3C,mBAAmB,sBAAsB,CAAC;AAC1C,mBAAmB,sBAAsB,CAAC;AAE1C;;GAEG;AACH,MAAM,MAAM,SAAS,CAAC,IAAI,SAAS,MAAM,EAAE,IAAI,IAAI,MAAM,CACvD,IAAI,EACJ,IAAI,SAAS,MAAM,GACf,CAAC,CAAC,KAAK,EAAE;IAAE,WAAW,EAAE,IAAI,CAAA;CAAE,KAAK,IAAI,CAAC,GAAG,SAAS,GACpD,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAC7B,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,mBAAmB,sBAAsB,CAAC;AAC1C,mBAAmB,2BAA2B,CAAC;AAC/C,mBAAmB,sBAAsB,CAAC;AAC1C,mBAAmB,uBAAuB,CAAC;AAC3C,mBAAmB,sBAAsB,CAAC;AAC1C,mBAAmB,sBAAsB,CAAC;AAC1C,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,oBAAoB,CAAC;AAExC;;GAEG;AACH,MAAM,MAAM,SAAS,CAAC,IAAI,SAAS,MAAM,EAAE,IAAI,IAAI,MAAM,CACvD,IAAI,EACJ,IAAI,SAAS,MAAM,GACf,CAAC,CAAC,KAAK,EAAE;IAAE,WAAW,EAAE,IAAI,CAAA;CAAE,KAAK,IAAI,CAAC,GAAG,SAAS,GACpD,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAC7B,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { requireNativeView } from 'expo';
2
+
3
+ import { LabelProps } from '.';
4
+
5
+ const LabelNativeView: React.ComponentType<LabelProps> = requireNativeView('ExpoUI', 'LabelView');
6
+
7
+ /**
8
+ * Renders a native label view, which could be used in a list or section.
9
+ *
10
+ * @param {LabelProps} props - The properties passed to the Label component.
11
+ * @returns {JSX.Element} The rendered native Label component.
12
+ * @platform ios
13
+ */
14
+ export function Label(props: LabelProps) {
15
+ return <LabelNativeView {...props} />;
16
+ }
@@ -0,0 +1,34 @@
1
+ import { StyleProp, Text, ViewStyle } from 'react-native';
2
+
3
+ export type LabelProps = {
4
+ /**
5
+ * The title text to be displayed in the label.
6
+ */
7
+ title?: string;
8
+
9
+ /**
10
+ * The name of the SFSymbol to be displayed in the label.
11
+ */
12
+ systemImage?: string;
13
+
14
+ /**
15
+ * The color of the label icon.
16
+ */
17
+ color?: string;
18
+
19
+ /**
20
+ * Additional styles to apply to the label.
21
+ */
22
+ style?: StyleProp<ViewStyle>;
23
+ };
24
+
25
+ /**
26
+ * Renders a native label view, which could be used in a list or section.
27
+ *
28
+ * @param {LabelProps} props - The properties passed to the Label component.
29
+ * @returns {JSX.Element} The rendered native Label component.
30
+ * @platform ios
31
+ */
32
+ export function Label(props: LabelProps) {
33
+ return <Text>{props.title}</Text>;
34
+ }
@@ -0,0 +1,35 @@
1
+ import { requireNativeView } from 'expo';
2
+
3
+ import { ListProps, NativeListProps } from '.';
4
+
5
+ const ListNativeView: React.ComponentType<NativeListProps> | null =
6
+ requireNativeView<NativeListProps>('ExpoUI', 'ListView');
7
+
8
+ function transformListProps(props: Omit<ListProps, 'children'>): Omit<NativeListProps, 'children'> {
9
+ return {
10
+ ...props,
11
+ onDeleteItem: ({ nativeEvent: { index } }) => props?.onDeleteItem?.(index),
12
+ onMoveItem: ({ nativeEvent: { from, to } }) => props?.onMoveItem?.(from, to),
13
+ onSelectionChange: ({ nativeEvent: { selection } }) => props?.onSelectionChange?.(selection),
14
+ };
15
+ }
16
+
17
+ /**
18
+ * A list component that renders its children using a native SwiftUI list.
19
+ * @param {ListProps} props - The properties for the list component.
20
+ * @returns {JSX.Element | null} The rendered list with its children or null if the platform is unsupported.
21
+ * @platform ios
22
+ */
23
+ export function List(props: ListProps) {
24
+ const { children, ...nativeProps } = props;
25
+
26
+ if (!ListNativeView) {
27
+ return null;
28
+ }
29
+
30
+ return (
31
+ <ListNativeView {...transformListProps(nativeProps)} style={[props.style, { flex: 1 }]}>
32
+ {children}
33
+ </ListNativeView>
34
+ );
35
+ }
@@ -0,0 +1,99 @@
1
+ import { StyleProp, ViewStyle } from 'react-native';
2
+
3
+ import { ViewEvent } from '../../src/types';
4
+
5
+ export type ListStyle = 'automatic' | 'plain' | 'inset' | 'insetGrouped' | 'grouped' | 'sidebar';
6
+
7
+ export interface ListProps {
8
+ /**
9
+ * Custom style for the container wrapping the list.
10
+ */
11
+ style?: StyleProp<ViewStyle>;
12
+
13
+ /**
14
+ * One of the predefined ListStyle types in SwiftUI.
15
+ * @default 'automatic'
16
+ */
17
+ listStyle?: ListStyle;
18
+
19
+ /**
20
+ * Allows the selection of list items.
21
+ * @default false
22
+ */
23
+ selectEnabled?: boolean;
24
+
25
+ /**
26
+ * Enables reordering of list items.
27
+ * @default false
28
+ */
29
+ moveEnabled?: boolean;
30
+
31
+ /**
32
+ * Allows the deletion of list items.
33
+ * @default false
34
+ */
35
+ deleteEnabled?: boolean;
36
+
37
+ /**
38
+ * Makes the list scrollable.
39
+ * @default true
40
+ * @platform ios 16.0+
41
+ */
42
+ scrollEnabled?: boolean;
43
+
44
+ /**
45
+ * Enables SwiftUI edit mode.
46
+ * @default false
47
+ */
48
+ editModeEnabled?: boolean;
49
+
50
+ /**
51
+ * The children elements to be rendered inside the list.
52
+ */
53
+ children: React.ReactNode;
54
+
55
+ /**
56
+ * Callback triggered when an item is deleted from the list.
57
+ */
58
+ onDeleteItem?: (index: number) => void;
59
+
60
+ /**
61
+ * Callback triggered when an item is moved in the list.
62
+ */
63
+ onMoveItem?: (from: number, to: number) => void;
64
+
65
+ /**
66
+ * Callback triggered when the selection changes in a list.
67
+ */
68
+ onSelectionChange?: (selection: number[]) => void;
69
+ }
70
+
71
+ /**
72
+ * DeleteItemEvent represents an event triggered when an item is deleted from the list.
73
+ */
74
+ type DeleteItemEvent = ViewEvent<'onDeleteItem', { index: number }>;
75
+ /**
76
+ * MoveItemEvent represents an event triggered when an item is moved in the list.
77
+ */
78
+ type MoveItemEvent = ViewEvent<'onMoveItem', { from: number; to: number }>;
79
+ /**
80
+ * SelectItemEvent represents an event triggered when the selection changes in a list.
81
+ */
82
+ type SelectItemEvent = ViewEvent<'onSelectionChange', { selection: number[] }>;
83
+
84
+ export type NativeListProps = Omit<ListProps, 'onDeleteItem' | 'onMoveItem' | 'onSelectionChange'> &
85
+ DeleteItemEvent &
86
+ MoveItemEvent &
87
+ SelectItemEvent & {
88
+ children: React.ReactNode;
89
+ };
90
+
91
+ /**
92
+ * A list component that renders its children using a native SwiftUI list.
93
+ * @param {ListProps} props - The properties for the list component.
94
+ * @returns {JSX.Element | null} The rendered list with its children or null if the platform is unsupported.
95
+ * @platform ios
96
+ */
97
+ export function List({ children }: ListProps) {
98
+ return children;
99
+ }
@@ -1,9 +1,12 @@
1
1
  import { StyleProp, ViewStyle } from 'react-native';
2
2
 
3
3
  export type SectionProps = {
4
- style?: StyleProp<ViewStyle>;
4
+ /**
5
+ * @note On iOS, section titles are usually capitalized for consistency with platform conventions.
6
+ */
5
7
  title?: string;
6
8
  children: any;
9
+ style?: StyleProp<ViewStyle>;
7
10
  };
8
11
 
9
12
  /**
@@ -4,6 +4,12 @@
4
4
  "modules": ["ExpoUIModule"]
5
5
  },
6
6
  "android": {
7
- "modules": ["expo.modules.ui.ExpoUIModule"]
7
+ "modules": ["expo.modules.ui.ExpoUIModule"],
8
+ "publication": {
9
+ "groupId": "expo.modules.ui",
10
+ "artifactId": "expo.modules.ui",
11
+ "version": "1.0.0-canary-20250402-161f57b",
12
+ "repository": "https://maven.pkg.github.com/expo/expo"
13
+ }
8
14
  }
9
15
  }
@@ -20,5 +20,7 @@ public class ExpoUIModule: Module {
20
20
  View(TextInputView.self)
21
21
  View(ProgressView.self)
22
22
  View(GaugeView.self)
23
+ View(ListView.self)
24
+ View(LabelView.self)
23
25
  }
24
26
  }
@@ -0,0 +1,24 @@
1
+ // Copyright 2025-present 650 Industries. All rights reserved.
2
+
3
+ import ExpoModulesCore
4
+ import SwiftUI
5
+
6
+ class LabelViewProps: ExpoSwiftUI.ViewProps {
7
+ @Field var title: String?
8
+ @Field var systemImage: String?
9
+ @Field var color: Color?
10
+ }
11
+
12
+ struct LabelView: ExpoSwiftUI.View {
13
+ @EnvironmentObject var props: LabelViewProps
14
+ @EnvironmentObject var shadowNodeProxy: ExpoSwiftUI.ShadowNodeProxy
15
+ var body: some View {
16
+ ExpoSwiftUI.AutoSizingStack(shadowNodeProxy: shadowNodeProxy, axis: .both) {
17
+ Label(
18
+ title: { Text(props.title ?? "") },
19
+ icon: { Image(systemName: props.systemImage ?? "").foregroundStyle(props.color ?? Color.accentColor) }
20
+ )
21
+ .fixedSize()
22
+ }
23
+ }
24
+ }
package/ios/List.swift ADDED
@@ -0,0 +1,122 @@
1
+ // Copyright 2025-present 650 Industries. All rights reserved.
2
+
3
+ import ExpoModulesCore
4
+ import SwiftUI
5
+
6
+ class ListProps: ExpoSwiftUI.ViewProps {
7
+ @Field var listStyle: String = "automatic"
8
+ @Field var moveEnabled: Bool = false
9
+ @Field var deleteEnabled: Bool = false
10
+ @Field var selectEnabled: Bool = true
11
+ @Field var scrollEnabled: Bool = false
12
+ @Field var editModeEnabled: Bool = false
13
+ var onDeleteItem = EventDispatcher()
14
+ var onMoveItem = EventDispatcher()
15
+ var onSelectionChange = EventDispatcher()
16
+ }
17
+
18
+ struct ListView: ExpoSwiftUI.View {
19
+ @EnvironmentObject var props: ListProps
20
+ @State private var selection: Set<Int> = []
21
+ @State var editModeEnabled: EditMode = .inactive
22
+ @State var search: String = ""
23
+ var body: some View {
24
+ let list = List(selection: props.selectEnabled ? $selection : nil) {
25
+ UnwrappedChildren { child, isHostingView in
26
+ child
27
+ .if(!isHostingView) {
28
+ $0.offset(
29
+ x: UIDevice.current.userInterfaceIdiom == .pad
30
+ ? IPAD_OFFSET : IPHONE_OFFSET)
31
+ }
32
+ }
33
+ .onDelete(perform: handleDelete)
34
+ .onMove(perform: handleMove)
35
+ .deleteDisabled(!props.deleteEnabled)
36
+ .moveDisabled(!props.moveEnabled)
37
+ }
38
+ .modifier(ListStyleModifer(style: props.listStyle))
39
+ .onAppear {
40
+ editModeEnabled = props.editModeEnabled ? .active : .inactive
41
+ }
42
+ .onChange(of: props.editModeEnabled) { newValue in
43
+ withAnimation {
44
+ editModeEnabled = newValue ? .active : .inactive
45
+ }
46
+ }
47
+ .onChange(of: selection) { selection in
48
+ print(selection)
49
+ handleSelectionChange(selection: selection)
50
+ }
51
+ .modifier(ScrollDisabledModifier(scrollEnabled: props.selectEnabled))
52
+ .environment(\.editMode, $editModeEnabled)
53
+ if #available(iOS 16.0, tvOS 16.0, *) {
54
+ list.scrollDisabled(!props.scrollEnabled)
55
+ } else {
56
+ list
57
+ }
58
+ }
59
+ func handleDelete(at offsets: IndexSet) {
60
+ for offset in offsets {
61
+ props.onDeleteItem([
62
+ "index": offset
63
+ ])
64
+ selection.remove(offset)
65
+ }
66
+ }
67
+ func handleMove(from sources: IndexSet, to destination: Int) {
68
+ for source in sources {
69
+ props.onMoveItem([
70
+ "from": source,
71
+ "to": destination
72
+ ])
73
+ }
74
+ }
75
+ func handleSelectionChange(selection: Set<Int>) {
76
+ let selectionArray = Array(selection)
77
+ let jsonDict: [String: Any] = [
78
+ "selection": selectionArray
79
+ ]
80
+ props.onSelectionChange(jsonDict)
81
+ }
82
+ }
83
+
84
+ struct ListStyleModifer: ViewModifier {
85
+ var style: String
86
+ @ViewBuilder func body(content: Content) -> some View {
87
+ switch style {
88
+ case "grouped":
89
+ content.listStyle(.grouped)
90
+ case "insetGrouped":
91
+ #if !os(tvOS)
92
+ content.listStyle(.insetGrouped)
93
+ #endif
94
+ case "inset":
95
+ #if !os(tvOS)
96
+ content.listStyle(.inset)
97
+ #endif
98
+ case "plain":
99
+ content.listStyle(.plain)
100
+ case "sidebar":
101
+ #if !os(tvOS)
102
+ content.listStyle(.sidebar)
103
+ #endif
104
+ case "automatic":
105
+ content.listStyle(.automatic)
106
+ default:
107
+ content
108
+ }
109
+ }
110
+ }
111
+
112
+ struct ScrollDisabledModifier: ViewModifier {
113
+ let scrollEnabled: Bool
114
+
115
+ func body(content: Content) -> some View {
116
+ if #available(iOS 16.0, tvOS 16.0, *) {
117
+ content.scrollDisabled(!scrollEnabled)
118
+ } else {
119
+ content
120
+ }
121
+ }
122
+ }
@@ -15,7 +15,7 @@ struct SectionView: ExpoSwiftUI.View {
15
15
 
16
16
  var body: some View {
17
17
  let form = Form {
18
- Section(header: Text(props.title ?? "")) {
18
+ Section(header: Text(props.title ?? "").textCase(nil)) {
19
19
  UnwrappedChildren { child, isHostingView in
20
20
  child
21
21
  .if(!isHostingView) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/ui",
3
- "version": "1.0.0-canary-20250320-7a205d3",
3
+ "version": "1.0.0-canary-20250402-161f57b",
4
4
  "description": "A collection of UI components",
5
5
  "scripts": {
6
6
  "build": "expo-module build",
@@ -27,11 +27,12 @@
27
27
  "dependencies": {},
28
28
  "devDependencies": {
29
29
  "@types/react": "~19.0.10",
30
- "expo-module-scripts": "4.0.5-canary-20250320-7a205d3"
30
+ "expo-module-scripts": "4.0.5-canary-20250402-161f57b"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "expo": "*",
34
34
  "react": "*",
35
35
  "react-native": "*"
36
- }
36
+ },
37
+ "gitHead": "161f57bb5f579c84f8fa0337ec596034e21760f6"
37
38
  }
package/src/types.ts CHANGED
@@ -4,6 +4,8 @@ export type * from '../components/Picker';
4
4
  export type * from '../components/Section';
5
5
  export type * from '../components/Slider';
6
6
  export type * from '../components/Switch';
7
+ export type * from '../components/Label';
8
+ export type * from '../components/List';
7
9
 
8
10
  /**
9
11
  * @hidden