@hzblj/kara-components 0.8.0 → 0.10.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/CHANGELOG.md +60 -26
- package/README.md +8 -8
- package/lib/module/atoms/color-picker/color-picker.android.js +32 -5
- package/lib/module/atoms/color-picker/color-picker.android.js.map +1 -1
- package/lib/module/atoms/icon-button/icon-button.ios.js +17 -4
- package/lib/module/atoms/icon-button/icon-button.ios.js.map +1 -1
- package/lib/module/atoms/pressable/pressable.js +45 -22
- package/lib/module/atoms/pressable/pressable.js.map +1 -1
- package/lib/module/atoms/progress/progress.ios.js +10 -4
- package/lib/module/atoms/progress/progress.ios.js.map +1 -1
- package/lib/module/atoms/surface/surface.ios.js +3 -0
- package/lib/module/atoms/surface/surface.ios.js.map +1 -1
- package/lib/module/atoms/text-field/text-field.android.js +19 -4
- package/lib/module/atoms/text-field/text-field.android.js.map +1 -1
- package/lib/module/atoms/text-field/text-field.ios.js +7 -2
- package/lib/module/atoms/text-field/text-field.ios.js.map +1 -1
- package/lib/typescript/atoms/activity-indicator/activity-indicator.types.d.ts +1 -1
- package/lib/typescript/atoms/avatar/avatar.types.d.ts +2 -2
- package/lib/typescript/atoms/badge/badge.types.d.ts +1 -1
- package/lib/typescript/atoms/blur-view/blur-view.types.d.ts +6 -6
- package/lib/typescript/atoms/button/button.types.d.ts +7 -7
- package/lib/typescript/atoms/card/card.types.d.ts +1 -1
- package/lib/typescript/atoms/checkbox/checkbox.types.d.ts +2 -2
- package/lib/typescript/atoms/chip/chip.types.d.ts +1 -1
- package/lib/typescript/atoms/color-picker/color-picker.types.d.ts +4 -3
- package/lib/typescript/atoms/date-picker/date-picker.types.d.ts +4 -4
- package/lib/typescript/atoms/divider/divider.types.d.ts +2 -2
- package/lib/typescript/atoms/fab/fab.types.d.ts +2 -2
- package/lib/typescript/atoms/glass-view/glass-view.types.d.ts +5 -5
- package/lib/typescript/atoms/h-stack/h-stack.types.d.ts +3 -3
- package/lib/typescript/atoms/icon/icon.types.d.ts +4 -4
- package/lib/typescript/atoms/icon-button/icon-button.types.d.ts +7 -3
- package/lib/typescript/atoms/island/island.types.d.ts +4 -4
- package/lib/typescript/atoms/list/list.types.d.ts +5 -5
- package/lib/typescript/atoms/picker/picker.types.d.ts +1 -1
- package/lib/typescript/atoms/pressable/pressable.types.d.ts +21 -5
- package/lib/typescript/atoms/progress/progress.types.d.ts +2 -2
- package/lib/typescript/atoms/rn-flat-list/rn-flat-list.types.d.ts +2 -2
- package/lib/typescript/atoms/rn-icon/rn-icon.types.d.ts +1 -1
- package/lib/typescript/atoms/rn-scroll-view/rn-scroll-view.types.d.ts +2 -2
- package/lib/typescript/atoms/rn-section-list/rn-section-list.types.d.ts +2 -2
- package/lib/typescript/atoms/rn-text/rn-text.types.d.ts +2 -2
- package/lib/typescript/atoms/rn-view/rn-view.types.d.ts +3 -3
- package/lib/typescript/atoms/scroll-view/scroll-view.types.d.ts +3 -3
- package/lib/typescript/atoms/segmented-control/segmented-control.types.d.ts +3 -3
- package/lib/typescript/atoms/skeleton/skeleton.types.d.ts +2 -2
- package/lib/typescript/atoms/spacer/spacer.types.d.ts +1 -1
- package/lib/typescript/atoms/surface/surface.types.d.ts +2 -2
- package/lib/typescript/atoms/switch/switch.types.d.ts +1 -1
- package/lib/typescript/atoms/text/text.types.d.ts +1 -1
- package/lib/typescript/atoms/text-field/text-field.types.d.ts +8 -4
- package/lib/typescript/atoms/v-stack/v-stack.types.d.ts +1 -1
- package/lib/typescript/atoms/z-stack/z-stack.types.d.ts +1 -1
- package/lib/typescript/glyph/glyph-button.types.d.ts +1 -1
- package/lib/typescript/glyph/glyph.types.d.ts +1 -1
- package/lib/typescript/molecules/collapsible/collapsible.types.d.ts +1 -1
- package/lib/typescript/molecules/empty-state/empty-state.types.d.ts +1 -1
- package/lib/typescript/molecules/label/label.types.d.ts +1 -1
- package/lib/typescript/molecules/labeled-content/labeled-content.types.d.ts +2 -2
- package/lib/typescript/molecules/list-item/list-item.types.d.ts +2 -2
- package/lib/typescript/molecules/navigation-bar/navigation-bar.types.d.ts +8 -8
- package/lib/typescript/molecules/pager/pager.types.d.ts +2 -2
- package/lib/typescript/molecules/radio-group/radio-group.types.d.ts +2 -2
- package/lib/typescript/molecules/rn-list-item/rn-list-item.types.d.ts +1 -1
- package/lib/typescript/molecules/rn-tooltip/rn-tooltip.types.d.ts +7 -7
- package/lib/typescript/molecules/scroll-edge-container/scroll-edge-container.types.d.ts +3 -3
- package/lib/typescript/molecules/search-bar/search-bar.types.d.ts +2 -2
- package/lib/typescript/molecules/stepper/stepper.types.d.ts +2 -2
- package/lib/typescript/molecules/tooltip/tooltip.types.d.ts +6 -6
- package/lib/typescript/organisms/action-sheet/action-sheet.types.d.ts +3 -3
- package/lib/typescript/organisms/alert/alert.types.d.ts +3 -3
- package/lib/typescript/organisms/context-menu/context-menu.types.d.ts +9 -9
- package/lib/typescript/organisms/fab-menu/fab-menu.types.d.ts +5 -5
- package/lib/typescript/organisms/form/form.types.d.ts +1 -1
- package/lib/typescript/organisms/menu/menu.types.d.ts +2 -2
- package/lib/typescript/organisms/sheet/sheet.types.d.ts +12 -12
- package/lib/typescript/organisms/snackbar/snackbar.types.d.ts +1 -1
- package/lib/typescript/organisms/swipe-actions/swipe-actions.types.d.ts +5 -5
- package/lib/typescript/templates/screen/screen.types.d.ts +2 -2
- package/package.json +4 -4
- package/src/atoms/activity-indicator/activity-indicator.types.ts +1 -1
- package/src/atoms/avatar/avatar.types.ts +2 -2
- package/src/atoms/badge/badge.types.ts +1 -1
- package/src/atoms/blur-view/blur-view.types.ts +6 -6
- package/src/atoms/button/button.types.ts +7 -7
- package/src/atoms/card/card.types.ts +1 -1
- package/src/atoms/checkbox/checkbox.types.ts +2 -2
- package/src/atoms/chip/chip.types.ts +1 -1
- package/src/atoms/color-picker/color-picker.android.tsx +26 -6
- package/src/atoms/color-picker/color-picker.types.ts +4 -3
- package/src/atoms/date-picker/date-picker.types.ts +4 -4
- package/src/atoms/divider/divider.types.ts +2 -2
- package/src/atoms/fab/fab.types.ts +2 -2
- package/src/atoms/glass-view/glass-view.types.ts +5 -5
- package/src/atoms/h-stack/h-stack.types.ts +3 -3
- package/src/atoms/icon/icon.types.ts +4 -4
- package/src/atoms/icon-button/icon-button.ios.tsx +12 -2
- package/src/atoms/icon-button/icon-button.types.ts +7 -3
- package/src/atoms/island/island.types.ts +4 -4
- package/src/atoms/list/list.types.ts +5 -5
- package/src/atoms/picker/picker.types.ts +1 -1
- package/src/atoms/pressable/pressable.tsx +39 -18
- package/src/atoms/pressable/pressable.types.ts +22 -5
- package/src/atoms/progress/progress.ios.tsx +14 -5
- package/src/atoms/progress/progress.types.ts +2 -2
- package/src/atoms/rn-flat-list/rn-flat-list.types.ts +2 -2
- package/src/atoms/rn-icon/rn-icon.types.ts +1 -1
- package/src/atoms/rn-scroll-view/rn-scroll-view.types.ts +2 -2
- package/src/atoms/rn-section-list/rn-section-list.types.ts +2 -2
- package/src/atoms/rn-text/rn-text.types.ts +2 -2
- package/src/atoms/rn-view/rn-view.types.ts +3 -3
- package/src/atoms/scroll-view/scroll-view.types.ts +3 -3
- package/src/atoms/segmented-control/segmented-control.types.ts +3 -3
- package/src/atoms/skeleton/skeleton.types.ts +2 -2
- package/src/atoms/spacer/spacer.types.ts +1 -1
- package/src/atoms/surface/surface.ios.tsx +2 -1
- package/src/atoms/surface/surface.types.ts +2 -2
- package/src/atoms/switch/switch.types.ts +1 -1
- package/src/atoms/text/text.types.ts +1 -1
- package/src/atoms/text-field/text-field.android.tsx +19 -3
- package/src/atoms/text-field/text-field.ios.tsx +7 -1
- package/src/atoms/text-field/text-field.types.ts +8 -4
- package/src/atoms/v-stack/v-stack.types.ts +1 -1
- package/src/atoms/z-stack/z-stack.types.ts +1 -1
- package/src/glyph/glyph-button.types.ts +1 -1
- package/src/glyph/glyph.types.ts +1 -1
- package/src/molecules/collapsible/collapsible.types.ts +1 -1
- package/src/molecules/empty-state/empty-state.types.ts +1 -1
- package/src/molecules/label/label.types.ts +1 -1
- package/src/molecules/labeled-content/labeled-content.types.ts +2 -2
- package/src/molecules/list-item/list-item.types.ts +2 -2
- package/src/molecules/navigation-bar/navigation-bar.types.ts +8 -8
- package/src/molecules/pager/pager.types.ts +2 -2
- package/src/molecules/radio-group/radio-group.types.ts +2 -2
- package/src/molecules/rn-list-item/rn-list-item.types.ts +1 -1
- package/src/molecules/rn-tooltip/rn-tooltip.types.ts +7 -7
- package/src/molecules/scroll-edge-container/scroll-edge-container.types.ts +3 -3
- package/src/molecules/search-bar/search-bar.types.ts +2 -2
- package/src/molecules/stepper/stepper.types.ts +2 -2
- package/src/molecules/tooltip/tooltip.types.ts +6 -6
- package/src/organisms/action-sheet/action-sheet.types.ts +3 -3
- package/src/organisms/alert/alert.types.ts +3 -3
- package/src/organisms/context-menu/context-menu.types.ts +9 -9
- package/src/organisms/fab-menu/fab-menu.types.ts +5 -5
- package/src/organisms/form/form.types.ts +1 -1
- package/src/organisms/menu/menu.types.ts +2 -2
- package/src/organisms/sheet/sheet.types.ts +12 -12
- package/src/organisms/snackbar/snackbar.types.ts +1 -1
- package/src/organisms/swipe-actions/swipe-actions.types.ts +5 -5
- package/src/templates/screen/screen.types.ts +2 -2
- package/lib/module/platform-support.js +0 -19
- package/lib/module/platform-support.js.map +0 -1
- package/lib/typescript/platform-support.d.ts +0 -8
- package/src/platform-support.ts +0 -20
|
@@ -7,12 +7,12 @@ import type { NavigationBarItem, NavigationBarSearch } from '../../molecules/nav
|
|
|
7
7
|
export type SheetDetent = 'auto' | number;
|
|
8
8
|
/**
|
|
9
9
|
* `center` is iOS's own, `leading` Material's. `large` puts the title above the content in a large face, and once
|
|
10
|
-
* that scrolls under the bar the bar's own title fades in
|
|
10
|
+
* that scrolls under the bar the bar's own title fades in (centred on iOS, leading on Android).
|
|
11
11
|
*/
|
|
12
12
|
export type SheetTitleStyle = 'center' | 'large' | 'leading';
|
|
13
13
|
/**
|
|
14
14
|
* The sheet's header: a `NavigationBar` with the title and items, and anything else that should stay put above the
|
|
15
|
-
* content (`children
|
|
15
|
+
* content (`children`: a segmented control, a search hint). On iOS 26 a scrollable sheet's content scrolls under it
|
|
16
16
|
* with the system's scroll edge effect; elsewhere it sits above the content.
|
|
17
17
|
*/
|
|
18
18
|
export type SheetHeaderProps = {
|
|
@@ -24,24 +24,24 @@ export type SheetHeaderProps = {
|
|
|
24
24
|
leadingItems?: NavigationBarItem[];
|
|
25
25
|
/** A search field in place of the title (iOS). */
|
|
26
26
|
search?: NavigationBarSearch;
|
|
27
|
-
/** The title
|
|
27
|
+
/** The title: in the bar, or above the content with a `large` `titleStyle`. */
|
|
28
28
|
title?: string;
|
|
29
29
|
/** `center` by default. */
|
|
30
30
|
titleStyle?: SheetTitleStyle;
|
|
31
|
-
/** In screen order, toward the trailing edge
|
|
31
|
+
/** In screen order, toward the trailing edge: the close item, by convention. */
|
|
32
32
|
trailingItems?: NavigationBarItem[];
|
|
33
33
|
};
|
|
34
34
|
/** Imperative control of a `Sheet`, through its `ref`. */
|
|
35
35
|
export type SheetRef = {
|
|
36
36
|
/** Dismisses it without calling `onDismiss`, which reports the user's dismissals only. */
|
|
37
37
|
dismiss: () => Promise<void>;
|
|
38
|
-
/** Presents at a detent
|
|
38
|
+
/** Presents at a detent, the first by default. */
|
|
39
39
|
present: (detentIndex?: number) => Promise<void>;
|
|
40
40
|
/** Moves to another detent. */
|
|
41
41
|
resize: (detentIndex: number) => Promise<void>;
|
|
42
42
|
};
|
|
43
43
|
/**
|
|
44
|
-
* A native sheet
|
|
44
|
+
* A native sheet (`UISheetPresentationController` on iOS, Material's bottom sheet on Android) with an optional
|
|
45
45
|
* native header (`<Sheet.Header>` as a direct child). The React Native tier: it needs no host, and must not sit inside
|
|
46
46
|
* one; native atoms in its content go in an `Island`.
|
|
47
47
|
*/
|
|
@@ -50,7 +50,7 @@ export type SheetProps = {
|
|
|
50
50
|
bg?: ColorToken;
|
|
51
51
|
/** The content. A `<Sheet.Header>` among the direct children becomes the native header instead. */
|
|
52
52
|
children: ReactNode;
|
|
53
|
-
/** Where the sheet can rest, smallest first. `['auto']`
|
|
53
|
+
/** Where the sheet can rest, smallest first. `['auto']` (fit the content) by default. */
|
|
54
54
|
detents?: SheetDetent[];
|
|
55
55
|
/** Dims what is behind. On by default. */
|
|
56
56
|
dimmed?: boolean;
|
|
@@ -62,9 +62,9 @@ export type SheetProps = {
|
|
|
62
62
|
footer?: ReactElement;
|
|
63
63
|
/** The drag handle. On by default. */
|
|
64
64
|
grabber?: boolean;
|
|
65
|
-
/** The user dismissed it
|
|
65
|
+
/** The user dismissed it; `visible` going false does not call this. */
|
|
66
66
|
onDismiss: () => void;
|
|
67
|
-
/** The sheet moved to another detent
|
|
67
|
+
/** The sheet moved to another detent: its index in `detents`. */
|
|
68
68
|
onDetentChange?: (detentIndex: number) => void;
|
|
69
69
|
/** The sheet finished presenting. */
|
|
70
70
|
onPresent?: () => void;
|
|
@@ -72,7 +72,7 @@ export type SheetProps = {
|
|
|
72
72
|
ref?: Ref<SheetRef>;
|
|
73
73
|
/**
|
|
74
74
|
* The content is a scroll view (`<Sheet.ScrollView>`) the sheet drives: dragging past its top resizes the sheet,
|
|
75
|
-
* and a header scrolls with the iOS 26 edge effect. Off by default
|
|
75
|
+
* and a header scrolls with the iOS 26 edge effect. Off by default; set it with a scrolling body.
|
|
76
76
|
*/
|
|
77
77
|
scrollable?: boolean;
|
|
78
78
|
/** Test identifier, forwarded to the native sheet. */
|
|
@@ -85,7 +85,7 @@ export type SheetScrollHandler = (event: NativeSyntheticEvent<NativeScrollEvent>
|
|
|
85
85
|
export type SheetScrollContextValue = {
|
|
86
86
|
/** Render it first in the content. `null` unless the header's `titleStyle` is `large`. */
|
|
87
87
|
largeTitle: ReactNode;
|
|
88
|
-
/** Forward the scroll view's scroll events to it
|
|
88
|
+
/** Forward the scroll view's scroll events to it; it tracks the large title. Unset when there is none. */
|
|
89
89
|
onScroll?: SheetScrollHandler;
|
|
90
90
|
/** The room an overlaid header takes, to add to the content's top padding. `0` where the header sits above it. */
|
|
91
91
|
topInset: number;
|
|
@@ -97,7 +97,7 @@ export type SheetScrollContextValue = {
|
|
|
97
97
|
export type SheetScrollViewProps = Pick<ScrollViewProps, 'keyboardShouldPersistTaps'> & {
|
|
98
98
|
/** The scrolling content, after the large title if there is one. */
|
|
99
99
|
children: ReactNode;
|
|
100
|
-
/** Styles the scrolling content
|
|
100
|
+
/** Styles the scrolling content: padding and gap belong here, as with `RnScrollView`. */
|
|
101
101
|
content?: ResponsiveViewSx;
|
|
102
102
|
/** Called on every scroll event, after the sheet's own listener. */
|
|
103
103
|
onScroll?: SheetScrollHandler;
|
|
@@ -8,7 +8,7 @@ export type SnackbarProps = {
|
|
|
8
8
|
actionLabel?: string;
|
|
9
9
|
/** The message. */
|
|
10
10
|
message: string;
|
|
11
|
-
/** The action was pressed. The snackbar stays up
|
|
11
|
+
/** The action was pressed. The snackbar stays up; turn `visible` off to hide it. */
|
|
12
12
|
onAction?: () => void;
|
|
13
13
|
/** Shows the snackbar while true, fading it in and out. It sets no timer of its own. */
|
|
14
14
|
visible: boolean;
|
|
@@ -5,25 +5,25 @@ import type { IconName } from '../../atoms/icon';
|
|
|
5
5
|
export type SwipeAction = {
|
|
6
6
|
/** Fills the button with `fill.destructive.primary` unless `tint` says otherwise. */
|
|
7
7
|
destructive?: boolean;
|
|
8
|
-
/** One of the app's icons, on the button
|
|
8
|
+
/** One of the app's icons, on the button: a round one on iOS 26, as in Mail, a filled stadium on Android. */
|
|
9
9
|
icon: IconName;
|
|
10
10
|
/**
|
|
11
|
-
* The action's name, written under the button
|
|
11
|
+
* The action's name, written under the button; before iOS 26 a row of the usual height shows the icon alone and
|
|
12
12
|
* keeps the label for VoiceOver. Actions are keyed by it, so keep labels unique within one row.
|
|
13
13
|
*/
|
|
14
14
|
label: string;
|
|
15
15
|
/** Called when the button is pressed. The row closes by itself. */
|
|
16
16
|
onPress: () => void;
|
|
17
17
|
/**
|
|
18
|
-
* The button's fill
|
|
18
|
+
* The button's fill: `fill.destructive.primary` for a destructive action, `fill.accent.primary` otherwise. The icon
|
|
19
19
|
* on it is white, so pick a fill that holds white in both appearances.
|
|
20
20
|
*/
|
|
21
21
|
tint?: ColorToken;
|
|
22
22
|
};
|
|
23
23
|
/**
|
|
24
|
-
* A list row with buttons behind it, uncovered by a swipe
|
|
24
|
+
* A list row with buttons behind it, uncovered by a swipe. SwiftUI's `swipeActions` on iOS, and on Android, where
|
|
25
25
|
* Compose has none, kara's own: the row slides on an anchored drag and the buttons show in the strip it leaves. One
|
|
26
|
-
* row is open at a time on both; a tap on an open row closes it. A native organism
|
|
26
|
+
* row is open at a time on both; a tap on an open row closes it. A native organism: it belongs inside a `List`.
|
|
27
27
|
*/
|
|
28
28
|
export type SwipeActionsProps = {
|
|
29
29
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Sx } from '@hzblj/kara-sx';
|
|
2
2
|
import type { ReactNode } from 'react';
|
|
3
3
|
/**
|
|
4
|
-
* The full-bleed native host a screen starts with
|
|
4
|
+
* The full-bleed native host a screen starts with: a SwiftUI or Compose `Host` filling its parent, so native atoms
|
|
5
5
|
* render anywhere inside it. The background runs to the edges; the content keeps clear of the status bar where the
|
|
6
6
|
* screen covers it (no navigation bar above), on Android as SwiftUI's safe area does on iOS.
|
|
7
7
|
*/
|
|
@@ -12,7 +12,7 @@ export type ScreenProps = {
|
|
|
12
12
|
children?: ReactNode;
|
|
13
13
|
/** Keeps the content where it is when the keyboard opens, instead of avoiding it. Android reads it once, on mount. */
|
|
14
14
|
ignoreKeyboardInset?: boolean;
|
|
15
|
-
/** Test identifier
|
|
15
|
+
/** Test identifier, on the host view on iOS and on the view around it on Android. */
|
|
16
16
|
testID?: string;
|
|
17
17
|
};
|
|
18
18
|
export type ScreenComponent = (props: ScreenProps) => ReactNode;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hzblj/kara-components",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "The atoms, molecules, organisms and templates of @hzblj/kara-ui — real SwiftUI and Jetpack Compose views through @expo/ui.",
|
|
5
5
|
"author": "Jan Blazej",
|
|
6
6
|
"license": "MIT",
|
|
@@ -59,9 +59,9 @@
|
|
|
59
59
|
]
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@hzblj/kara-native": "^0.
|
|
63
|
-
"@hzblj/kara-sx": "^0.
|
|
64
|
-
"@hzblj/kara-theme": "^0.
|
|
62
|
+
"@hzblj/kara-native": "^0.10.0",
|
|
63
|
+
"@hzblj/kara-sx": "^0.10.0",
|
|
64
|
+
"@hzblj/kara-theme": "^0.10.0",
|
|
65
65
|
"sf-symbols-typescript": "^2.2.0"
|
|
66
66
|
},
|
|
67
67
|
"peerDependencies": {
|
|
@@ -4,7 +4,7 @@ import type {ReactNode} from 'react'
|
|
|
4
4
|
export type ActivityIndicatorSize = 'large' | 'small'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* That something is loading, for as long as it takes
|
|
7
|
+
* That something is loading, for as long as it takes: UIKit's spinner on iOS, Material 3's expressive
|
|
8
8
|
* `LoadingIndicator` on Android, its shapes morphing as it turns. A React Native view on iOS and a host of its own on
|
|
9
9
|
* Android, so it renders anywhere. For how far along something is, use `Progress`.
|
|
10
10
|
*/
|
|
@@ -3,11 +3,11 @@ import type {ImageSourcePropType} from 'react-native'
|
|
|
3
3
|
|
|
4
4
|
export type AvatarSize = 'lg' | 'md' | 'sm'
|
|
5
5
|
|
|
6
|
-
/** A round avatar: the image in `source`, or `initials` without one. The React Native tier
|
|
6
|
+
/** A round avatar: the image in `source`, or `initials` without one. The React Native tier: it needs no host. */
|
|
7
7
|
export type AvatarProps = {
|
|
8
8
|
/** Shown in place of the image when there is no `source`. */
|
|
9
9
|
initials?: string
|
|
10
|
-
/** The diameter
|
|
10
|
+
/** The diameter: `sm` is `s24`, `md` `s40`, `lg` `s64`. `md` by default. */
|
|
11
11
|
size?: AvatarSize
|
|
12
12
|
/** The image, cropped to the circle. */
|
|
13
13
|
source?: ImageSourcePropType
|
|
@@ -2,7 +2,7 @@ import type {ReactNode} from 'react'
|
|
|
2
2
|
|
|
3
3
|
export type BadgeTone = 'accent' | 'destructive' | 'neutral' | 'success'
|
|
4
4
|
|
|
5
|
-
/** A small status label in a capsule
|
|
5
|
+
/** A small status label in a capsule: a SwiftUI `HStack` in the tone's fill on iOS, Material's `Badge` on Android. */
|
|
6
6
|
export type BadgeProps = {
|
|
7
7
|
/** The text inside. */
|
|
8
8
|
label: string
|
|
@@ -5,16 +5,16 @@ import type {ReactNode} from 'react'
|
|
|
5
5
|
export type {BlurMaterial, BlurVibrancy} from '@hzblj/kara-native/swift-ui'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* One of the system's materials
|
|
8
|
+
* One of the system's materials (what sheets, bars, menus and HUDs are made of) behind React Native content, in
|
|
9
9
|
* SwiftUI's five thicknesses. iOS: UIKit's `system*Material` blur, with optional vibrancy for the content. Android:
|
|
10
|
-
* what lies behind, blurred and saturated (Android 12+), under a Material tonal surface as thick as the material
|
|
11
|
-
* `surface` at `ultraThin` up to `surfaceContainerHighest` at `ultraThick
|
|
10
|
+
* what lies behind, blurred and saturated (Android 12+), under a Material tonal surface as thick as the material
|
|
11
|
+
* (`surface` at `ultraThin` up to `surfaceContainerHighest` at `ultraThick`); below Android 12 the surface alone. The
|
|
12
12
|
* React Native tier: it needs no host, so it suits a list cell. Shape it with `borderRadius`; it clips its children.
|
|
13
13
|
*/
|
|
14
14
|
export type BlurViewProps = ResponsiveViewSx & {
|
|
15
15
|
/**
|
|
16
|
-
* Pins the material to light or dark whatever the app's appearance
|
|
17
|
-
* the app theme. Android draws the opposite appearance with Material's inverse surface.
|
|
16
|
+
* Pins the material to light or dark whatever the app's appearance (a dark HUD over a light screen). Unset, it
|
|
17
|
+
* follows the app theme. Android draws the opposite appearance with Material's inverse surface.
|
|
18
18
|
*/
|
|
19
19
|
appearance?: 'dark' | 'light'
|
|
20
20
|
/** React Native content, over the material. */
|
|
@@ -24,7 +24,7 @@ export type BlurViewProps = ResponsiveViewSx & {
|
|
|
24
24
|
/** Test identifier, forwarded to the view. */
|
|
25
25
|
testID?: string
|
|
26
26
|
/**
|
|
27
|
-
* iOS: draws the children vibrant at this level, the way iOS draws its own labels and fills on a material
|
|
27
|
+
* iOS: draws the children vibrant at this level, the way iOS draws its own labels and fills on a material. Their
|
|
28
28
|
* colour becomes the material's vibrant one and their alpha the mask. Android has no vibrancy: the children keep
|
|
29
29
|
* their colours there.
|
|
30
30
|
*/
|
|
@@ -4,7 +4,7 @@ import type {ReactNode} from 'react'
|
|
|
4
4
|
export type ButtonVariant = 'accent' | 'destructive' | 'glass' | 'secondary'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* SwiftUI `ButtonStyle`. iOS only
|
|
7
|
+
* SwiftUI `ButtonStyle`. iOS only: Compose has no equivalent, so Android ignores it and keeps
|
|
8
8
|
* rendering the variant's tokens.
|
|
9
9
|
*/
|
|
10
10
|
export type ButtonStyleName =
|
|
@@ -17,19 +17,19 @@ export type ButtonStyleName =
|
|
|
17
17
|
| 'plain'
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* SwiftUI `ControlSize`. iOS only, and it has no `automatic` member
|
|
20
|
+
* SwiftUI `ControlSize`. iOS only, and it has no `automatic` member: leave it unset to inherit
|
|
21
21
|
* whatever the surrounding SwiftUI environment provides.
|
|
22
22
|
*/
|
|
23
23
|
export type ButtonControlSize = 'extraLarge' | 'large' | 'mini' | 'regular' | 'small'
|
|
24
24
|
|
|
25
|
-
/** A text button
|
|
25
|
+
/** A text button: SwiftUI `Button` on iOS, Material's filled button (outlined for `glass`) on Android. */
|
|
26
26
|
export type ButtonProps = {
|
|
27
27
|
/**
|
|
28
|
-
* Replaces the style the variant picks
|
|
29
|
-
* `secondary`, `glass` for `glass`. iOS only
|
|
28
|
+
* Replaces the style the variant picks: `borderedProminent` for `accent` and `destructive`, `bordered` for
|
|
29
|
+
* `secondary`, `glass` for `glass`. iOS only. Android ignores it.
|
|
30
30
|
*/
|
|
31
31
|
buttonStyle?: ButtonStyleName
|
|
32
|
-
/** SwiftUI's control size. `large` by default. iOS only
|
|
32
|
+
/** SwiftUI's control size. `large` by default. iOS only. Android ignores it. */
|
|
33
33
|
controlSize?: ButtonControlSize
|
|
34
34
|
/** Draws the button in its disabled colours and stops it responding to presses. */
|
|
35
35
|
disabled?: boolean
|
|
@@ -42,7 +42,7 @@ export type ButtonProps = {
|
|
|
42
42
|
/**
|
|
43
43
|
* Overrides the variant's own tint. A prominent style takes it as the fill and picks a contrasting
|
|
44
44
|
* label. `glass` has to reach the material through `glassEffect` instead, so tinting one costs it
|
|
45
|
-
* the stock `.glass` style
|
|
45
|
+
* the stock `.glass` style (see the iOS implementation).
|
|
46
46
|
*/
|
|
47
47
|
tint?: ColorToken
|
|
48
48
|
/** The look. `accent` by default. Material has no glass, so on Android `glass` is an outlined button. */
|
|
@@ -2,7 +2,7 @@ import type {ResponsiveSx} from '@hzblj/kara-sx'
|
|
|
2
2
|
import type {ReactNode} from 'react'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* A raised container
|
|
5
|
+
* A raised container: SwiftUI `VStack` / Compose `Column` on `surface.primary`, with a large radius, `s16` padding and
|
|
6
6
|
* the `card` shadow. Any `sx` prop overrides its default.
|
|
7
7
|
*/
|
|
8
8
|
export type CardProps = ResponsiveSx & {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type {ReactNode} from 'react'
|
|
2
2
|
|
|
3
|
-
/** Material's `Checkbox` on Android. iOS has none, so there it is a SwiftUI `Toggle
|
|
3
|
+
/** Material's `Checkbox` on Android. iOS has none, so there it is a SwiftUI `Toggle`, the same switch as `Switch`. */
|
|
4
4
|
export type CheckboxProps = {
|
|
5
5
|
/** Dims the control and ignores taps. */
|
|
6
6
|
disabled?: boolean
|
|
@@ -8,7 +8,7 @@ export type CheckboxProps = {
|
|
|
8
8
|
label?: string
|
|
9
9
|
/** Called with the new value when the user toggles it. */
|
|
10
10
|
onValueChange?: (value: boolean) => void
|
|
11
|
-
/** Whether it is checked. Controlled
|
|
11
|
+
/** Whether it is checked. Controlled: update it from `onValueChange`. */
|
|
12
12
|
value: boolean
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type {ReactNode} from 'react'
|
|
2
2
|
|
|
3
|
-
/** A filter pill on a `Pressable`, not a native control
|
|
3
|
+
/** A filter pill on a `Pressable`, not a native control. It belongs to the React Native tier, so it needs no host. */
|
|
4
4
|
export type ChipProps = {
|
|
5
5
|
/** The text in the pill. */
|
|
6
6
|
label: string
|
|
@@ -1,9 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {ColorPickerComponent} from './color-picker.types'
|
|
1
|
+
import {ColorWell} from '@hzblj/kara-native/jetpack-compose'
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
import {useHostGuard} from '../../host-context'
|
|
4
|
+
import {HStack} from '../h-stack'
|
|
5
|
+
import {Spacer} from '../spacer'
|
|
6
|
+
import {Text} from '../text'
|
|
7
|
+
import type {ColorPickerComponent, ColorPickerProps} from './color-picker.types'
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
/**
|
|
10
|
+
* The row SwiftUI's `ColorPicker` lays out on iOS, the label leading and the well trailing, around kara's own Compose
|
|
11
|
+
* well: Compose ships no colour picker, so the sheet behind it draws the iOS picker's grid, spectrum and sliders.
|
|
12
|
+
*/
|
|
13
|
+
export const ColorPicker: ColorPickerComponent = ({
|
|
14
|
+
label,
|
|
15
|
+
onValueChange,
|
|
16
|
+
supportsOpacity = false,
|
|
17
|
+
testID,
|
|
18
|
+
value,
|
|
19
|
+
}: ColorPickerProps) => {
|
|
20
|
+
useHostGuard('ColorPicker')
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<HStack align="center" spacing="s12" testID={testID} wide>
|
|
24
|
+
{label ? <Text>{label}</Text> : null}
|
|
25
|
+
<Spacer />
|
|
26
|
+
<ColorWell onValueChange={onValueChange} supportsOpacity={supportsOpacity} title={label} value={value} />
|
|
27
|
+
</HStack>
|
|
28
|
+
)
|
|
9
29
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type {ReactNode} from 'react'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* A row with a label and a colour well that opens a picker: SwiftUI's `ColorPicker` on iOS. Compose ships none, so on
|
|
5
|
+
* Android it is kara's own, in the same shape: a well with a rainbow ring, and a sheet with a grid of swatches, a
|
|
6
|
+
* spectrum and RGB sliders.
|
|
6
7
|
*/
|
|
7
8
|
export type ColorPickerProps = {
|
|
8
|
-
/** Text beside the colour well. */
|
|
9
|
+
/** Text beside the colour well, and the Android sheet's title. */
|
|
9
10
|
label?: string
|
|
10
11
|
/** Called with the colour the user picks. */
|
|
11
12
|
onValueChange?: (color: string) => void
|
|
@@ -3,7 +3,7 @@ import type {ReactNode} from 'react'
|
|
|
3
3
|
export type DatePickerMode = 'date' | 'datetime' | 'time'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* A date or time picker
|
|
6
|
+
* A date or time picker: SwiftUI's compact `DatePicker` on iOS, a field that opens Material's picker dialog on a tap
|
|
7
7
|
* on Android. The React Native tier: it brings its own host and sizes itself to the value, so it sits in a row beside
|
|
8
8
|
* its label like a `Text`.
|
|
9
9
|
*/
|
|
@@ -17,11 +17,11 @@ export type DatePickerProps = {
|
|
|
17
17
|
* `value`'s time of day.
|
|
18
18
|
*/
|
|
19
19
|
mode?: DatePickerMode
|
|
20
|
-
/** Called with the new date
|
|
20
|
+
/** Called with the new date: on iOS as it changes, on Android when the dialog is confirmed. */
|
|
21
21
|
onValueChange?: (date: Date) => void
|
|
22
|
-
/** Test identifier
|
|
22
|
+
/** Test identifier, on the native picker on iOS and on the tappable field on Android. */
|
|
23
23
|
testID?: string
|
|
24
|
-
/** The selected date. Controlled
|
|
24
|
+
/** The selected date. Controlled: update it from `onValueChange`. */
|
|
25
25
|
value: Date
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type {ColorToken} from '@hzblj/kara-theme'
|
|
2
2
|
import type {ReactNode} from 'react'
|
|
3
3
|
|
|
4
|
-
/** A horizontal hairline
|
|
4
|
+
/** A horizontal hairline: SwiftUI `Divider` / Compose `HorizontalDivider`. */
|
|
5
5
|
export type DividerProps = {
|
|
6
6
|
/** The line's colour. `border.tertiary` by default. */
|
|
7
7
|
color?: ColorToken
|
|
8
|
-
/** Test identifier, forwarded to the native view on iOS
|
|
8
|
+
/** Test identifier, forwarded to the native view on iOS. Android ignores it. */
|
|
9
9
|
testID?: string
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -3,7 +3,7 @@ import type {ReactNode} from 'react'
|
|
|
3
3
|
import type {IconName} from '../icon'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* A floating action button
|
|
6
|
+
* A floating action button: Material's `FloatingActionButton` on Android, a 56pt accent circle (a plain SwiftUI
|
|
7
7
|
* `Button`) on iOS. It renders inline; pinning it to a corner is up to the screen.
|
|
8
8
|
*/
|
|
9
9
|
export type FabProps = {
|
|
@@ -11,7 +11,7 @@ export type FabProps = {
|
|
|
11
11
|
name: IconName
|
|
12
12
|
/** Called when the button is pressed. */
|
|
13
13
|
onPress?: () => void
|
|
14
|
-
/** Test identifier, forwarded to the native view on iOS
|
|
14
|
+
/** Test identifier, forwarded to the native view on iOS. Android ignores it. */
|
|
15
15
|
testID?: string
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -3,13 +3,13 @@ import type {ColorToken} from '@hzblj/kara-theme'
|
|
|
3
3
|
import type {ReactNode} from 'react'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Glass around a React Native subtree, shaped as a capsule
|
|
7
|
-
* Liquid Glass. Android: frosted glass
|
|
8
|
-
* (or `tint`) and a hairline. iOS before 26 has no Liquid Glass and draws a capsule of `tint` instead, or
|
|
9
|
-
* buttons' translucent fill (`btn.bg.glass.base`) when there is none.
|
|
6
|
+
* Glass around a React Native subtree, shaped as a capsule. It belongs to the React Native tier, so it needs no host.
|
|
7
|
+
* iOS 26: Liquid Glass. Android: frosted glass, made of what lies behind, blurred on Android 12+, under a translucent
|
|
8
|
+
* tonal surface (or `tint`) and a hairline. iOS before 26 has no Liquid Glass and draws a capsule of `tint` instead, or
|
|
9
|
+
* of the glass buttons' translucent fill (`btn.bg.glass.base`) when there is none.
|
|
10
10
|
*
|
|
11
11
|
* On Android each glass re-records what lies behind it before every frame: a few buttons cost nothing, but keep it out
|
|
12
|
-
* of the cells of a long list
|
|
12
|
+
* of the cells of a long list. A plain `tint` reads as well there.
|
|
13
13
|
*/
|
|
14
14
|
export type GlassViewProps = ResponsiveViewSx & {
|
|
15
15
|
/** React Native views. Give them `pointerEvents="none"` when `interactive`, so the press reaches the `Pressable`. */
|
|
@@ -4,13 +4,13 @@ import type {ReactNode} from 'react'
|
|
|
4
4
|
|
|
5
5
|
export type HStackAlign = 'center' | 'end' | 'start'
|
|
6
6
|
|
|
7
|
-
/** A horizontal stack
|
|
7
|
+
/** A horizontal stack: SwiftUI `HStack` / Compose `Row`. */
|
|
8
8
|
export type HStackProps = ResponsiveSx & {
|
|
9
|
-
/** How the children line up vertically
|
|
9
|
+
/** How the children line up vertically: `start` is the top, `end` the bottom. `start` by default. */
|
|
10
10
|
align?: HStackAlign
|
|
11
11
|
/** Native views, laid out from the leading edge. */
|
|
12
12
|
children?: ReactNode
|
|
13
|
-
/** Makes the stack pressable
|
|
13
|
+
/** Makes the stack pressable: a tap gesture on iOS, a `clickable` with Material's ripple on Android. */
|
|
14
14
|
onPress?: () => void
|
|
15
15
|
/** The gap between children. Unset, SwiftUI puts its default spacing between them and Compose none. */
|
|
16
16
|
spacing?: SpaceSize
|
|
@@ -13,13 +13,13 @@ declare global {
|
|
|
13
13
|
type DeclaredIconName = keyof KaraIcons & string
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* One of the app's icons. Once the plugin has written `kara-icons.d.ts` only those names type-check
|
|
16
|
+
* One of the app's icons. Once the plugin has written `kara-icons.d.ts` only those names type-check: an icon removed
|
|
17
17
|
* from the folder fails at every call site. Before that, any string, so a project can adopt icons gradually.
|
|
18
18
|
*/
|
|
19
19
|
export type IconName = [DeclaredIconName] extends [never] ? string : DeclaredIconName
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* One of the app's icons, in a host
|
|
22
|
+
* One of the app's icons, in a host: SwiftUI `Image` from the asset catalog on iOS, Material's `Icon` with the vector
|
|
23
23
|
* drawable on Android. `RnIcon` draws the same asset outside one.
|
|
24
24
|
*/
|
|
25
25
|
export type IconProps = {
|
|
@@ -27,11 +27,11 @@ export type IconProps = {
|
|
|
27
27
|
accessibilityLabel?: string
|
|
28
28
|
/** The icon's tint. `content.primary` by default. */
|
|
29
29
|
color?: ColorToken
|
|
30
|
-
/** Which of the app's icons
|
|
30
|
+
/** Which of the app's icons, a key of `KaraIcons`. */
|
|
31
31
|
name: IconName
|
|
32
32
|
/** Its width and height, a spacing token. `s24` by default. */
|
|
33
33
|
size?: SpaceSize
|
|
34
|
-
/** Test identifier, forwarded to the native view on iOS
|
|
34
|
+
/** Test identifier, forwarded to the native view on iOS. Android ignores it. */
|
|
35
35
|
testID?: string
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import {Button} from '@expo/ui/swift-ui'
|
|
2
|
-
import {buttonStyle, disabled as disabledModifier} from '@expo/ui/swift-ui/modifiers'
|
|
2
|
+
import {buttonStyle, contentShape, disabled as disabledModifier, shapes} from '@expo/ui/swift-ui/modifiers'
|
|
3
3
|
import {useMemo} from 'react'
|
|
4
4
|
|
|
5
5
|
import {useHostGuard} from '../../host-context'
|
|
6
6
|
import {Icon} from '../icon'
|
|
7
|
+
import {ZStack} from '../z-stack'
|
|
7
8
|
import type {IconButtonComponent, IconButtonProps} from './icon-button.types'
|
|
8
9
|
|
|
10
|
+
/** Apple's least tap target. Android's `IconButton` is Material's 48dp; this is the same idea in points. */
|
|
11
|
+
const TARGET = 44
|
|
12
|
+
|
|
13
|
+
/** The whole square takes the tap, not only the glyph's own pixels. */
|
|
14
|
+
const WHOLE_TARGET = {modifiers: [contentShape(shapes.circle())]}
|
|
15
|
+
|
|
9
16
|
export const IconButton: IconButtonComponent = ({disabled = false, name, onPress, testID}: IconButtonProps) => {
|
|
10
17
|
useHostGuard('IconButton')
|
|
11
18
|
|
|
@@ -21,7 +28,10 @@ export const IconButton: IconButtonComponent = ({disabled = false, name, onPress
|
|
|
21
28
|
|
|
22
29
|
return (
|
|
23
30
|
<Button modifiers={modifiers} onPress={onPress} testID={testID}>
|
|
24
|
-
<
|
|
31
|
+
<ZStack h={TARGET} ios={WHOLE_TARGET} w={TARGET}>
|
|
32
|
+
{/* SwiftUI dims a disabled button's label itself; a disabled colour on top of that dimmed it twice. */}
|
|
33
|
+
<Icon color="content.primary" name={name} />
|
|
34
|
+
</ZStack>
|
|
25
35
|
</Button>
|
|
26
36
|
)
|
|
27
37
|
}
|
|
@@ -2,15 +2,19 @@ import type {ReactNode} from 'react'
|
|
|
2
2
|
|
|
3
3
|
import type {IconName} from '../icon'
|
|
4
4
|
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* A button that is just an icon: a plain SwiftUI `Button` on iOS, Material's `IconButton` on Android. The icon sits
|
|
7
|
+
* centred in a tap target the size each platform asks for, 44pt on iOS and 48dp on Android, so a row of them spaces
|
|
8
|
+
* itself the same way on both.
|
|
9
|
+
*/
|
|
6
10
|
export type IconButtonProps = {
|
|
7
|
-
/**
|
|
11
|
+
/** Dims the icon (iOS's own disabled look, `btn.content.disabled` on Android) and stops the button responding. */
|
|
8
12
|
disabled?: boolean
|
|
9
13
|
/** The icon, one of the app's. */
|
|
10
14
|
name: IconName
|
|
11
15
|
/** Called when the button is pressed. */
|
|
12
16
|
onPress?: () => void
|
|
13
|
-
/** Test identifier, forwarded to the native view on iOS
|
|
17
|
+
/** Test identifier, forwarded to the native view on iOS. Android ignores it. */
|
|
14
18
|
testID?: string
|
|
15
19
|
}
|
|
16
20
|
|
|
@@ -3,7 +3,7 @@ import type {ReactNode} from 'react'
|
|
|
3
3
|
import type {StyleProp, ViewStyle} from 'react-native'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* A host for native atoms in a React Native layout
|
|
6
|
+
* A host for native atoms in a React Native layout: the SwiftUI / Compose `Host` an `@expo/ui` tree mounts into. It
|
|
7
7
|
* sits in that layout like a `Box`, and takes `Box`'s `sx` props for it: `h`, `flex`, margins.
|
|
8
8
|
*/
|
|
9
9
|
export type IslandProps = ResponsiveViewSx & {
|
|
@@ -15,15 +15,15 @@ export type IslandProps = ResponsiveViewSx & {
|
|
|
15
15
|
* width maps to `fixedSize(horizontal: true)`, so the native side ignores the proposed width and
|
|
16
16
|
* resolves a `wide` stack's ideal width as unbounded.
|
|
17
17
|
*
|
|
18
|
-
* Turn it off
|
|
18
|
+
* Turn it off (and give the island an explicit height, `h`) when the subtree contains an
|
|
19
19
|
* `RnView`: that host drives its SwiftUI frame from the child's Yoga-laid-out bounds while this one
|
|
20
20
|
* writes its measured size back into the Yoga style, and the two together spin a layout loop that
|
|
21
21
|
* hangs the main thread as soon as the views lay out on screen.
|
|
22
22
|
*/
|
|
23
23
|
matchContents?: boolean
|
|
24
|
-
/** A React Native style for the host view, merged over the `sx` props
|
|
24
|
+
/** A React Native style for the host view, merged over the `sx` props, for what they cannot say. */
|
|
25
25
|
style?: StyleProp<ViewStyle>
|
|
26
|
-
/** Test identifier, forwarded to the host view on iOS
|
|
26
|
+
/** Test identifier, forwarded to the host view on iOS. Android ignores it. */
|
|
27
27
|
testID?: string
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import type {ReactNode} from 'react'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* A scrolling list
|
|
4
|
+
* A scrolling list: SwiftUI `List`, Compose `LazyColumn`. It has no height of its own, so it needs one from outside:
|
|
5
5
|
* a `Screen`, or an `Island` with `matchContents={false}` and a height. In an island that sizes itself to its content
|
|
6
6
|
* Compose measures it against an infinite height and throws ("Vertically scrollable component was measured with an
|
|
7
7
|
* infinity maximum height"); SwiftUI shows nothing. For a handful of rows that should not scroll, use a `VStack`.
|
|
8
8
|
*
|
|
9
|
-
* Rows are separated for you
|
|
9
|
+
* Rows are separated for you (SwiftUI's own separators, a `Divider` between rows on Android), so a `Divider` among
|
|
10
10
|
* the children is one too many: on iOS it becomes an empty row of its own.
|
|
11
11
|
*/
|
|
12
12
|
export type ListProps = {
|
|
13
|
-
/** The rows
|
|
13
|
+
/** The rows: native views, one row each. */
|
|
14
14
|
children: ReactNode
|
|
15
15
|
/**
|
|
16
|
-
* Enables pull-to-refresh. Async on purpose
|
|
16
|
+
* Enables pull-to-refresh. Async on purpose (see `ScrollViewProps.onRefresh`): the spinner runs
|
|
17
17
|
* until the promise settles, so neither platform needs a `refreshing` flag kept in sync by hand.
|
|
18
18
|
*/
|
|
19
19
|
onRefresh?: () => Promise<void>
|
|
20
|
-
/** Test identifier, forwarded to the native view on iOS
|
|
20
|
+
/** Test identifier, forwarded to the native view on iOS. Android ignores it. */
|
|
21
21
|
testID?: string
|
|
22
22
|
}
|
|
23
23
|
|
|
@@ -9,7 +9,7 @@ export type PickerOption = {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* A single choice from a list
|
|
12
|
+
* A single choice from a list: a SwiftUI wheel picker on iOS, Material's exposed dropdown on Android. It brings its
|
|
13
13
|
* own host, so it renders outside `Screen` and `Island` as well.
|
|
14
14
|
*/
|
|
15
15
|
export type PickerProps = {
|