@hzblj/kara-components 0.9.0 → 0.11.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 +72 -28
- package/README.md +8 -8
- package/lib/module/atoms/activity-indicator/activity-indicator.android.js +6 -1
- package/lib/module/atoms/activity-indicator/activity-indicator.android.js.map +1 -1
- package/lib/module/atoms/activity-indicator/activity-indicator.ios.js +2 -0
- package/lib/module/atoms/activity-indicator/activity-indicator.ios.js.map +1 -1
- package/lib/module/atoms/avatar/avatar.js +5 -0
- package/lib/module/atoms/avatar/avatar.js.map +1 -1
- package/lib/module/atoms/button/button-tokens.js +2 -2
- package/lib/module/atoms/button/button-tokens.js.map +1 -1
- package/lib/module/atoms/button/button.android.js +6 -2
- package/lib/module/atoms/button/button.android.js.map +1 -1
- package/lib/module/atoms/button/button.ios.js +7 -2
- package/lib/module/atoms/button/button.ios.js.map +1 -1
- package/lib/module/atoms/card/card.android.js +5 -3
- package/lib/module/atoms/card/card.android.js.map +1 -1
- package/lib/module/atoms/card/card.ios.js +7 -3
- package/lib/module/atoms/card/card.ios.js.map +1 -1
- package/lib/module/atoms/checkbox/checkbox.android.js +1 -1
- package/lib/module/atoms/checkbox/checkbox.android.js.map +1 -1
- 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/fab/fab.android.js +9 -1
- package/lib/module/atoms/fab/fab.android.js.map +1 -1
- package/lib/module/atoms/fab/fab.ios.js +9 -3
- package/lib/module/atoms/fab/fab.ios.js.map +1 -1
- package/lib/module/atoms/glass-view/glass-view.android.js +1 -1
- package/lib/module/atoms/glass-view/glass-view.android.js.map +1 -1
- package/lib/module/atoms/h-stack/h-stack.ios.js +5 -3
- package/lib/module/atoms/h-stack/h-stack.ios.js.map +1 -1
- package/lib/module/atoms/icon-button/icon-button.android.js +9 -0
- package/lib/module/atoms/icon-button/icon-button.android.js.map +1 -1
- package/lib/module/atoms/icon-button/icon-button.ios.js +26 -6
- package/lib/module/atoms/icon-button/icon-button.ios.js.map +1 -1
- package/lib/module/atoms/image/image.js +4 -4
- package/lib/module/atoms/image/image.js.map +1 -1
- package/lib/module/atoms/pressable/pressable.js +52 -28
- package/lib/module/atoms/pressable/pressable.js.map +1 -1
- package/lib/module/atoms/progress/progress.android.js +7 -0
- package/lib/module/atoms/progress/progress.android.js.map +1 -1
- package/lib/module/atoms/progress/progress.ios.js +6 -1
- package/lib/module/atoms/progress/progress.ios.js.map +1 -1
- package/lib/module/atoms/segmented-control/segmented-control.android.js +1 -1
- package/lib/module/atoms/segmented-control/segmented-control.android.js.map +1 -1
- package/lib/module/atoms/segmented-control/segmented-control.ios.js +1 -1
- package/lib/module/atoms/segmented-control/segmented-control.ios.js.map +1 -1
- package/lib/module/atoms/skeleton/skeleton.js +20 -6
- package/lib/module/atoms/skeleton/skeleton.js.map +1 -1
- package/lib/module/atoms/surface/surface.android.js +5 -3
- package/lib/module/atoms/surface/surface.android.js.map +1 -1
- package/lib/module/atoms/surface/surface.ios.js +7 -3
- package/lib/module/atoms/surface/surface.ios.js.map +1 -1
- package/lib/module/atoms/switch/switch.android.js +1 -1
- package/lib/module/atoms/switch/switch.android.js.map +1 -1
- package/lib/module/atoms/text/text.android.js +5 -3
- package/lib/module/atoms/text/text.android.js.map +1 -1
- package/lib/module/atoms/text/text.ios.js +6 -4
- package/lib/module/atoms/text/text.ios.js.map +1 -1
- package/lib/module/atoms/v-stack/v-stack.ios.js +5 -3
- package/lib/module/atoms/v-stack/v-stack.ios.js.map +1 -1
- package/lib/module/atoms/z-stack/z-stack.ios.js +5 -3
- package/lib/module/atoms/z-stack/z-stack.ios.js.map +1 -1
- package/lib/module/glyph/glyph.android.js +2 -0
- package/lib/module/glyph/glyph.android.js.map +1 -1
- package/lib/module/glyph/glyph.ios.js +5 -2
- package/lib/module/glyph/glyph.ios.js.map +1 -1
- package/lib/module/molecules/collapsible/collapsible.android.js +18 -8
- package/lib/module/molecules/collapsible/collapsible.android.js.map +1 -1
- package/lib/module/molecules/labeled-content/labeled-content.js +4 -1
- package/lib/module/molecules/labeled-content/labeled-content.js.map +1 -1
- package/lib/module/molecules/link/link.js +4 -1
- package/lib/module/molecules/link/link.js.map +1 -1
- package/lib/module/molecules/list-item/list-item.js +4 -1
- package/lib/module/molecules/list-item/list-item.js.map +1 -1
- package/lib/module/molecules/navigation-bar/navigation-bar.android.js +1 -1
- package/lib/module/molecules/navigation-bar/navigation-bar.android.js.map +1 -1
- package/lib/module/molecules/navigation-bar/navigation-bar.ios.js +1 -1
- package/lib/module/molecules/navigation-bar/navigation-bar.ios.js.map +1 -1
- package/lib/module/molecules/rn-list-item/rn-list-item.js +10 -2
- package/lib/module/molecules/rn-list-item/rn-list-item.js.map +1 -1
- package/lib/module/molecules/scroll-edge-container/scroll-edge-container.android.js +3 -4
- package/lib/module/molecules/scroll-edge-container/scroll-edge-container.android.js.map +1 -1
- package/lib/module/molecules/stepper/stepper.ios.js +6 -2
- package/lib/module/molecules/stepper/stepper.ios.js.map +1 -1
- package/lib/module/motion.js +19 -0
- package/lib/module/motion.js.map +1 -0
- package/lib/module/organisms/fab-menu/fab-menu.android.js +8 -5
- package/lib/module/organisms/fab-menu/fab-menu.android.js.map +1 -1
- package/lib/module/organisms/fab-menu/fab-menu.ios.js +5 -2
- package/lib/module/organisms/fab-menu/fab-menu.ios.js.map +1 -1
- package/lib/module/organisms/snackbar/snackbar.js +142 -17
- package/lib/module/organisms/snackbar/snackbar.js.map +1 -1
- package/lib/module/organisms/swipe-actions/swipe-actions.android.js +1 -1
- package/lib/module/organisms/swipe-actions/swipe-actions.android.js.map +1 -1
- package/lib/module/use-stack-modifiers.js +10 -8
- package/lib/module/use-stack-modifiers.js.map +1 -1
- package/lib/typescript/atoms/activity-indicator/activity-indicator.types.d.ts +3 -1
- package/lib/typescript/atoms/avatar/avatar.types.d.ts +7 -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-tokens.d.ts +1 -1
- package/lib/typescript/atoms/button/button.types.d.ts +9 -7
- package/lib/typescript/atoms/card/card.types.d.ts +3 -3
- 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 +10 -3
- package/lib/typescript/atoms/glass-view/glass-view.types.d.ts +5 -5
- package/lib/typescript/atoms/h-stack/h-stack.types.d.ts +8 -5
- package/lib/typescript/atoms/icon/icon.types.d.ts +4 -4
- package/lib/typescript/atoms/icon-button/icon-button.types.d.ts +14 -3
- package/lib/typescript/atoms/image/image.d.ts +2 -2
- 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 +23 -7
- package/lib/typescript/atoms/progress/progress.types.d.ts +3 -1
- 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 -1
- package/lib/typescript/atoms/spacer/spacer.types.d.ts +1 -1
- package/lib/typescript/atoms/surface/surface.types.d.ts +3 -3
- package/lib/typescript/atoms/switch/switch.types.d.ts +1 -1
- package/lib/typescript/atoms/text/text.types.d.ts +3 -3
- package/lib/typescript/atoms/text-field/text-field.types.d.ts +4 -4
- package/lib/typescript/atoms/v-stack/v-stack.types.d.ts +4 -4
- package/lib/typescript/atoms/z-stack/z-stack.types.d.ts +4 -4
- package/lib/typescript/glyph/glyph-button.types.d.ts +1 -1
- package/lib/typescript/glyph/glyph.types.d.ts +3 -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 +6 -4
- package/lib/typescript/molecules/link/link.types.d.ts +2 -1
- package/lib/typescript/molecules/list-item/list-item.types.d.ts +6 -4
- 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.ios.d.ts +1 -1
- 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/motion.d.ts +8 -0
- 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 +10 -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 +39 -6
- 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/lib/typescript/use-stack-modifiers.d.ts +6 -5
- package/package.json +4 -4
- package/src/atoms/activity-indicator/activity-indicator.android.tsx +7 -1
- package/src/atoms/activity-indicator/activity-indicator.ios.tsx +9 -1
- package/src/atoms/activity-indicator/activity-indicator.types.ts +3 -1
- package/src/atoms/avatar/avatar.tsx +5 -1
- package/src/atoms/avatar/avatar.types.ts +7 -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-tokens.ts +2 -2
- package/src/atoms/button/button.android.tsx +5 -3
- package/src/atoms/button/button.ios.tsx +10 -2
- package/src/atoms/button/button.types.ts +9 -7
- package/src/atoms/card/card.android.tsx +6 -4
- package/src/atoms/card/card.ios.tsx +7 -3
- package/src/atoms/card/card.types.ts +9 -8
- package/src/atoms/checkbox/checkbox.android.tsx +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.android.tsx +5 -3
- package/src/atoms/fab/fab.ios.tsx +8 -4
- package/src/atoms/fab/fab.types.ts +10 -3
- package/src/atoms/glass-view/glass-view.android.tsx +1 -1
- package/src/atoms/glass-view/glass-view.types.ts +5 -5
- package/src/atoms/h-stack/h-stack.ios.tsx +6 -4
- package/src/atoms/h-stack/h-stack.types.ts +18 -14
- package/src/atoms/icon/icon.types.ts +4 -4
- package/src/atoms/icon-button/icon-button.android.tsx +16 -3
- package/src/atoms/icon-button/icon-button.ios.tsx +24 -5
- package/src/atoms/icon-button/icon-button.types.ts +14 -3
- package/src/atoms/image/image.tsx +3 -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 +50 -21
- package/src/atoms/pressable/pressable.types.ts +35 -17
- package/src/atoms/progress/progress.android.tsx +5 -3
- package/src/atoms/progress/progress.ios.tsx +5 -2
- package/src/atoms/progress/progress.types.ts +3 -1
- 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.android.tsx +1 -1
- package/src/atoms/segmented-control/segmented-control.ios.tsx +1 -1
- package/src/atoms/segmented-control/segmented-control.types.ts +3 -3
- package/src/atoms/skeleton/skeleton.tsx +18 -4
- package/src/atoms/skeleton/skeleton.types.ts +2 -1
- package/src/atoms/spacer/spacer.types.ts +1 -1
- package/src/atoms/surface/surface.android.tsx +6 -4
- package/src/atoms/surface/surface.ios.tsx +7 -3
- package/src/atoms/surface/surface.types.ts +11 -10
- package/src/atoms/switch/switch.android.tsx +1 -1
- package/src/atoms/switch/switch.types.ts +1 -1
- package/src/atoms/text/text.android.tsx +6 -4
- package/src/atoms/text/text.ios.tsx +6 -4
- package/src/atoms/text/text.types.ts +24 -23
- package/src/atoms/text-field/text-field.types.ts +4 -4
- package/src/atoms/v-stack/v-stack.ios.tsx +6 -4
- package/src/atoms/v-stack/v-stack.types.ts +18 -17
- package/src/atoms/z-stack/z-stack.ios.tsx +6 -4
- package/src/atoms/z-stack/z-stack.types.ts +16 -15
- package/src/glyph/glyph-button.types.ts +1 -1
- package/src/glyph/glyph.android.tsx +14 -2
- package/src/glyph/glyph.ios.tsx +13 -3
- package/src/glyph/glyph.types.ts +3 -1
- package/src/molecules/collapsible/collapsible.android.tsx +27 -7
- 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.tsx +12 -1
- package/src/molecules/labeled-content/labeled-content.types.ts +6 -4
- package/src/molecules/link/link.tsx +2 -1
- package/src/molecules/link/link.types.ts +2 -1
- package/src/molecules/list-item/list-item.tsx +20 -2
- package/src/molecules/list-item/list-item.types.ts +6 -4
- package/src/molecules/navigation-bar/navigation-bar.android.tsx +1 -1
- package/src/molecules/navigation-bar/navigation-bar.ios.tsx +1 -1
- 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.tsx +18 -3
- 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.android.tsx +3 -2
- 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.ios.tsx +8 -2
- package/src/molecules/stepper/stepper.types.ts +2 -2
- package/src/molecules/tooltip/tooltip.types.ts +6 -6
- package/src/motion.ts +13 -0
- 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.android.tsx +9 -5
- package/src/organisms/fab-menu/fab-menu.ios.tsx +6 -2
- package/src/organisms/fab-menu/fab-menu.types.ts +10 -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.tsx +143 -19
- package/src/organisms/snackbar/snackbar.types.ts +42 -6
- package/src/organisms/swipe-actions/swipe-actions.android.tsx +1 -1
- package/src/organisms/swipe-actions/swipe-actions.types.ts +5 -5
- package/src/templates/screen/screen.types.ts +2 -2
- package/src/use-stack-modifiers.ts +20 -7
- 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
|
@@ -15,8 +15,8 @@ type NavigationBarItemBase = {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* One item of the bar. `back` and `close` are the platform's own
|
|
19
|
-
* Material arrow and cross on Android
|
|
18
|
+
* One item of the bar. `back` and `close` are the platform's own (a chevron and the system close item on iOS, the
|
|
19
|
+
* Material arrow and cross on Android), with `Back` / `Close` as their labels unless given others. `icon` is one of the
|
|
20
20
|
* app's icons and names itself for VoiceOver and TalkBack.
|
|
21
21
|
*/
|
|
22
22
|
export type NavigationBarItem =
|
|
@@ -28,7 +28,7 @@ export type NavigationBarSearchRef = {
|
|
|
28
28
|
clear: () => void
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
/** A search field in place of the title
|
|
31
|
+
/** A search field in place of the title. iOS only for now; Android keeps the title. */
|
|
32
32
|
export type NavigationBarSearch = {
|
|
33
33
|
/** Every edit of the field's text. */
|
|
34
34
|
onChangeText: (text: string) => void
|
|
@@ -45,10 +45,10 @@ export type NavigationBarSearch = {
|
|
|
45
45
|
export type NavigationBarTitleAlignment = 'center' | 'leading'
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
|
-
* A title with items on either side, for a header that is not a navigation screen's
|
|
48
|
+
* A title with items on either side, for a header that is not a navigation screen's. `Sheet.Header` is built on it.
|
|
49
49
|
* On iOS a standalone `UINavigationBar`, so the items press and render exactly like a native-stack header's: on iOS 26
|
|
50
50
|
* neighbours share a glass capsule instead of swelling as standalone glass buttons do. On Android Material's top app
|
|
51
|
-
* bar. Where an item goes is the caller's choice
|
|
51
|
+
* bar. Where an item goes is the caller's choice: the bar places nothing by itself, so a close can sit on either side.
|
|
52
52
|
* The React Native tier: it needs no host.
|
|
53
53
|
*/
|
|
54
54
|
export type NavigationBarProps = {
|
|
@@ -58,13 +58,13 @@ export type NavigationBarProps = {
|
|
|
58
58
|
leadingItems?: NavigationBarItem[]
|
|
59
59
|
/** Replaces the title with a search field (iOS). */
|
|
60
60
|
search?: NavigationBarSearch
|
|
61
|
-
/** Test identifier, forwarded to the native bar. iOS only
|
|
61
|
+
/** Test identifier, forwarded to the native bar. iOS only; Android ignores it. */
|
|
62
62
|
testID?: string
|
|
63
63
|
/** The bar's title. */
|
|
64
64
|
title?: string
|
|
65
|
-
/** `center`
|
|
65
|
+
/** `center` (iOS's own) by default; `leading` is Material's top app bar. */
|
|
66
66
|
titleAlignment?: NavigationBarTitleAlignment
|
|
67
|
-
/** Fades the title out and in without moving the items
|
|
67
|
+
/** Fades the title out and in without moving the items, for a large title that scrolls under the bar. */
|
|
68
68
|
titleVisible?: boolean
|
|
69
69
|
/** In screen order, toward the trailing edge. */
|
|
70
70
|
trailingItems?: NavigationBarItem[]
|
|
@@ -5,7 +5,7 @@ import type {ReactNode} from 'react'
|
|
|
5
5
|
* A swipeable, snapping pager: SwiftUI's `TabView` in its page style, Compose's `HorizontalPager`.
|
|
6
6
|
*
|
|
7
7
|
* Pages are addressed by their index rather than by a name, because Compose's pager is index-native
|
|
8
|
-
* and SwiftUI's tab values are strings
|
|
8
|
+
* and SwiftUI's tab values are strings; synthesising the string from the child's position is
|
|
9
9
|
* lossless, whereas inventing indices for named tabs on Compose would not be. Children are therefore
|
|
10
10
|
* plain nodes with no `Pager.Page` part to wrap them in: a page carries no props of its own, so the
|
|
11
11
|
* ceremony would buy nothing.
|
|
@@ -22,7 +22,7 @@ export type PagerProps = {
|
|
|
22
22
|
onPageChange?: (page: number) => void
|
|
23
23
|
/** Zero-based. Controlled when passed; otherwise the pager just starts at 0 and owns its position. */
|
|
24
24
|
page?: number
|
|
25
|
-
/** Android only
|
|
25
|
+
/** Android only: a SwiftUI page-style `TabView` has no gap between pages. */
|
|
26
26
|
pageSpacing?: SpaceSize
|
|
27
27
|
/**
|
|
28
28
|
* Android only. SwiftUI can only disable a `TabView` as a whole, which would take the pages'
|
|
@@ -4,13 +4,13 @@ import type {ReactNode} from 'react'
|
|
|
4
4
|
export type RadioOption = {
|
|
5
5
|
/** The option's text. */
|
|
6
6
|
label: string
|
|
7
|
-
/** Identifies the option to `value` and `onValueChange`, and keys its row
|
|
7
|
+
/** Identifies the option to `value` and `onValueChange`, and keys its row. Keep it unique. */
|
|
8
8
|
value: string
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* A single choice from a list: rows with a checkmark on the selected one on iOS, Material radio buttons on Android. A
|
|
13
|
-
* native atom
|
|
13
|
+
* native atom: it renders inside `<Screen>` or `<Island>`.
|
|
14
14
|
*/
|
|
15
15
|
export type RadioGroupProps = {
|
|
16
16
|
/** The user pressed an option; it passes that option's `value`. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {accessibilityProps} from '@hzblj/kara-sx'
|
|
1
2
|
import {useAppTheme} from '@hzblj/kara-theme'
|
|
2
3
|
import {useMemo} from 'react'
|
|
3
4
|
import {Platform, Pressable, type PressableStateCallbackType} from 'react-native'
|
|
@@ -8,8 +9,18 @@ import {RnText} from '../../atoms/rn-text'
|
|
|
8
9
|
import {RnGlyph} from '../../glyph'
|
|
9
10
|
import type {RnListItemComponent, RnListItemProps} from './rn-list-item.types'
|
|
10
11
|
|
|
11
|
-
export const RnListItem: RnListItemComponent = ({
|
|
12
|
+
export const RnListItem: RnListItemComponent = ({
|
|
13
|
+
icon,
|
|
14
|
+
onPress,
|
|
15
|
+
px,
|
|
16
|
+
subtitle,
|
|
17
|
+
testID,
|
|
18
|
+
title,
|
|
19
|
+
...accessibility
|
|
20
|
+
}: RnListItemProps) => {
|
|
12
21
|
const theme = useAppTheme()
|
|
22
|
+
// One element for a screen reader, as `ListItem` is: a button when it can be pressed.
|
|
23
|
+
const a11y = accessibilityProps({accessible: true, ...accessibility}, onPress ? 'button' : undefined)
|
|
13
24
|
const pressedColor = theme.color('fill.tertiary')
|
|
14
25
|
|
|
15
26
|
const ripple = useMemo(() => ({color: pressedColor}), [pressedColor])
|
|
@@ -37,11 +48,15 @@ export const RnListItem: RnListItemComponent = ({icon, onPress, px, subtitle, te
|
|
|
37
48
|
)
|
|
38
49
|
|
|
39
50
|
if (!onPress) {
|
|
40
|
-
return
|
|
51
|
+
return (
|
|
52
|
+
<Box {...a11y} testID={testID}>
|
|
53
|
+
{row}
|
|
54
|
+
</Box>
|
|
55
|
+
)
|
|
41
56
|
}
|
|
42
57
|
|
|
43
58
|
return (
|
|
44
|
-
<Pressable
|
|
59
|
+
<Pressable {...a11y} android_ripple={ripple} onPress={onPress} style={highlight} testID={testID}>
|
|
45
60
|
{row}
|
|
46
61
|
</Pressable>
|
|
47
62
|
)
|
|
@@ -3,7 +3,7 @@ import type {ReactNode} from 'react'
|
|
|
3
3
|
import type {ListItemProps} from '../list-item'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* `ListItem`'s row in the React Native tier
|
|
6
|
+
* `ListItem`'s row in the React Native tier: plain views, no host. For lists long enough that a native host per row
|
|
7
7
|
* would cost too much to mount (a navigation list, an `RnFlatList` of rows), with the platform's own press feedback: a
|
|
8
8
|
* ripple across the whole row on Android, a highlight on iOS. In a rounded card, give the card `overflow="hidden"`:
|
|
9
9
|
* Android draws the ripple as the row's foreground, which only a parent's clip keeps inside rounded corners.
|
|
@@ -6,9 +6,9 @@ export type RnTooltipActionVariant = 'link' | 'primary' | 'secondary'
|
|
|
6
6
|
export type RnTooltipAction = {
|
|
7
7
|
/** The button's text. */
|
|
8
8
|
label: string
|
|
9
|
-
/** Called on press. The tooltip stays up
|
|
9
|
+
/** Called on press. The tooltip stays up; turn `visible` off here if the action should close it. */
|
|
10
10
|
onPress: () => void
|
|
11
|
-
/** `link` by default
|
|
11
|
+
/** `link` by default, an underlined text. `primary`/`secondary` are small filled/outlined buttons. */
|
|
12
12
|
variant?: RnTooltipActionVariant
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -16,7 +16,7 @@ export type RnTooltipAction = {
|
|
|
16
16
|
export type RnTooltipDismissReason = 'anchorHidden' | 'outside'
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* A rich tooltip
|
|
19
|
+
* A rich tooltip (title, message, actions) anchored below a React Native view, and drawn above every sibling.
|
|
20
20
|
* Controlled: it never hides itself. `onDismiss` reports why it should, and the caller turns `visible` off. The React
|
|
21
21
|
* Native tier, unlike `Tooltip`, whose anchor is a native view inside a host.
|
|
22
22
|
*/
|
|
@@ -26,16 +26,16 @@ export type RnTooltipProps = {
|
|
|
26
26
|
/** Which end of the bubble the actions sit at. `end` by default. */
|
|
27
27
|
actionsAlignment?: 'end' | 'start'
|
|
28
28
|
/**
|
|
29
|
-
* Insets from the window's top and bottom that the anchor's centre must stay inside
|
|
30
|
-
* content. Past them the tooltip asks to be dismissed with `anchorHidden`.
|
|
29
|
+
* Insets from the window's top and bottom that the anchor's centre must stay inside (a header or a tab bar over the
|
|
30
|
+
* content). Past them the tooltip asks to be dismissed with `anchorHidden`.
|
|
31
31
|
*/
|
|
32
32
|
boundaryInsets?: {bottom?: number; top?: number}
|
|
33
|
-
/** The anchor
|
|
33
|
+
/** The anchor: a single React Native view. */
|
|
34
34
|
children: ReactElement
|
|
35
35
|
/** The body text, under the title. */
|
|
36
36
|
message?: string
|
|
37
37
|
/**
|
|
38
|
-
* Asks for the tooltip to close, with the reason
|
|
38
|
+
* Asks for the tooltip to close, with the reason; turn `visible` off. On Android any touch outside asks, the start
|
|
39
39
|
* of a scroll included; iOS keeps the tooltip through a scroll.
|
|
40
40
|
*/
|
|
41
41
|
onDismiss: (reason: RnTooltipDismissReason) => void
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {opacity} from '@hzblj/kara-theme'
|
|
2
2
|
import {cloneElement, type ReactNode, useCallback, useRef} from 'react'
|
|
3
3
|
import type {LayoutChangeEvent, NativeScrollEvent, NativeSyntheticEvent} from 'react-native'
|
|
4
4
|
import {type SharedValue, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'
|
|
5
5
|
|
|
6
6
|
import {ABox, Box} from '../../atoms/box'
|
|
7
|
+
import {timing} from '../../motion'
|
|
7
8
|
import type {ScrollEdgeContainerComponent, ScrollEdgeContainerProps} from './scroll-edge-container.types'
|
|
8
9
|
|
|
9
10
|
/** Less than a pixel scrolled is not scrolled — a fling settles a fraction away from the edge. */
|
|
10
11
|
const EDGE_SLOP = 0.5
|
|
11
12
|
|
|
12
|
-
const FILL =
|
|
13
|
+
const FILL = timing('quick', 'out')
|
|
13
14
|
|
|
14
15
|
type Bar = {children: ReactNode; filled: SharedValue<number>}
|
|
15
16
|
|
|
@@ -5,13 +5,13 @@ import type {ReactElement, ReactNode} from 'react'
|
|
|
5
5
|
export type {ScrollEdgeEffect, ScrollEdgeScrollableProps} from '@hzblj/kara-native/swift-ui'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* Bars over one React Native scroll view, with each platform's scroll edge under them
|
|
8
|
+
* Bars over one React Native scroll view, with each platform's scroll edge under them: on iOS 26 the system's
|
|
9
9
|
* progressive blur where content scrolls past a bar; on Android a Material top app bar's behaviour, the bars stacked
|
|
10
10
|
* around the scroll view and filling with `surface.secondary` once content scrolls under them. The React Native tier:
|
|
11
11
|
* it needs no host.
|
|
12
12
|
*
|
|
13
13
|
* A screen-level container: wrap the screen's scroll view with it. Mounted inside a cell of a virtualized list on iOS
|
|
14
|
-
* it draws only its bottom bar
|
|
14
|
+
* it draws only its bottom bar; the hosted scroll view and the top bar stay blank.
|
|
15
15
|
*/
|
|
16
16
|
export type ScrollEdgeContainerProps = ResponsiveViewSx & {
|
|
17
17
|
/**
|
|
@@ -21,7 +21,7 @@ export type ScrollEdgeContainerProps = ResponsiveViewSx & {
|
|
|
21
21
|
automaticInsets?: boolean
|
|
22
22
|
/** Laid over the scroll view's bottom edge on iOS; stacked below it on Android, filled while content continues below. */
|
|
23
23
|
bottomBar?: ReactNode
|
|
24
|
-
/** Exactly one React Native scroll view
|
|
24
|
+
/** Exactly one React Native scroll view: `RnScrollView`, `RnFlatList`, `RnSectionList`. */
|
|
25
25
|
children: ReactElement<ScrollEdgeScrollableProps>
|
|
26
26
|
/** iOS 26: how hard the edge cuts. `soft` by default. */
|
|
27
27
|
effect?: ScrollEdgeEffect
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type {ReactNode} from 'react'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* A search field drawn the same on both platforms
|
|
4
|
+
* A search field drawn the same on both platforms: a rounded box with a magnifier, a `TextInput` and a clear button
|
|
5
5
|
* while there is text. The React Native tier: it needs no host.
|
|
6
6
|
*/
|
|
7
7
|
export type SearchBarProps = {
|
|
@@ -11,7 +11,7 @@ export type SearchBarProps = {
|
|
|
11
11
|
placeholder?: string
|
|
12
12
|
/** Test identifier, put on the field's container view rather than on the `TextInput`. */
|
|
13
13
|
testID?: string
|
|
14
|
-
/** The field's text. Controlled
|
|
14
|
+
/** The field's text. Controlled: pass back what `onChangeText` reports. */
|
|
15
15
|
value: string
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {Stepper as SwiftUIStepper} from '@expo/ui/swift-ui'
|
|
2
2
|
import {labelsHidden} from '@expo/ui/swift-ui/modifiers'
|
|
3
|
+
import {useReducedMotion} from '@hzblj/kara-theme'
|
|
3
4
|
import {useRef} from 'react'
|
|
4
5
|
|
|
5
6
|
import {HStack} from '../../atoms/h-stack'
|
|
@@ -14,10 +15,11 @@ const LABEL_HIDDEN = [labelsHidden()]
|
|
|
14
15
|
/**
|
|
15
16
|
* SwiftUI's `Stepper` at the end of a row, the label leading and the value just before the control — the way iOS's own
|
|
16
17
|
* settings show a stepped value. The value rolls to the next one (`numericText`), up or down with the change, in
|
|
17
|
-
* monospaced digits so the row does not jump.
|
|
18
|
+
* monospaced digits so the row does not jump. With motion reduced it cross-fades instead.
|
|
18
19
|
*/
|
|
19
20
|
export const Stepper: StepperComponent = ({label, max, min, onValueChange, step = 1, value}: StepperProps) => {
|
|
20
21
|
useHostGuard('Stepper')
|
|
22
|
+
const reduced = useReducedMotion()
|
|
21
23
|
const previous = useRef(value)
|
|
22
24
|
const countsDown = value < previous.current
|
|
23
25
|
previous.current = value
|
|
@@ -28,7 +30,11 @@ export const Stepper: StepperComponent = ({label, max, min, onValueChange, step
|
|
|
28
30
|
<Spacer />
|
|
29
31
|
<Text
|
|
30
32
|
color="content.secondary"
|
|
31
|
-
ios={{
|
|
33
|
+
ios={{
|
|
34
|
+
animation: {value},
|
|
35
|
+
contentTransition: reduced ? {type: 'opacity'} : {countsDown, type: 'numericText'},
|
|
36
|
+
monospacedDigit: true,
|
|
37
|
+
}}
|
|
32
38
|
>
|
|
33
39
|
{String(value)}
|
|
34
40
|
</Text>
|
|
@@ -2,10 +2,10 @@ import type {ReactNode} from 'react'
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* A number with minus and plus buttons beside a label: SwiftUI's `Stepper` on iOS; on Android the label, the value and
|
|
5
|
-
* two icon buttons in a row. A native atom
|
|
5
|
+
* two icon buttons in a row. A native atom: it renders inside `<Screen>` or `<Island>`.
|
|
6
6
|
*/
|
|
7
7
|
export type StepperProps = {
|
|
8
|
-
/** The leading text. The value is shown too
|
|
8
|
+
/** The leading text. The value is shown too: before the control on iOS, between the buttons on Android. */
|
|
9
9
|
label: string
|
|
10
10
|
/** The highest value. When unset, Android has no upper limit and iOS stops at `100`. */
|
|
11
11
|
max?: number
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import type {ReactNode} from 'react'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* A short text tip on a native view, shown while `visible
|
|
5
|
-
* tooltip centred above them on Android. A native atom
|
|
4
|
+
* A short text tip on a native view, shown while `visible`: a SwiftUI popover from `children` on iOS, Material's plain
|
|
5
|
+
* tooltip centred above them on Android. A native atom: it renders inside `<Screen>` or `<Island>`; `RnTooltip`
|
|
6
6
|
* anchors to a React Native view.
|
|
7
7
|
*/
|
|
8
8
|
export type TooltipProps = {
|
|
9
|
-
/** The anchor
|
|
9
|
+
/** The anchor: a native view. */
|
|
10
10
|
children: ReactNode
|
|
11
11
|
/** The tip. */
|
|
12
12
|
text: string
|
|
13
|
-
/** Shows the tip while true. Controlled: nothing opens it but this
|
|
13
|
+
/** Shows the tip while true. Controlled: nothing opens it but this. Wire a long press to it if you want one. */
|
|
14
14
|
visible: boolean
|
|
15
15
|
/**
|
|
16
|
-
* The user dismissed the tip
|
|
17
|
-
* start of a scroll included, or the anchor scrolling out of the window.
|
|
16
|
+
* The user dismissed the tip, so turn `visible` off. iOS: a tap outside the popover. Android: any touch outside it,
|
|
17
|
+
* the start of a scroll included, or the anchor scrolling out of the window.
|
|
18
18
|
*/
|
|
19
19
|
onDismiss: () => void
|
|
20
20
|
}
|
package/src/motion.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {type DurationSize, duration, type EasingName, easing} from '@hzblj/kara-theme'
|
|
2
|
+
import {Easing, ReduceMotion, type WithTimingConfig} from 'react-native-reanimated'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A Reanimated timing from the motion tokens, `smoothOut` unless told otherwise. `ReduceMotion.Never`, because a
|
|
6
|
+
* component has applied `useReducedMotion` before it animates: what is left (a fade, a dim) is meant to run, and
|
|
7
|
+
* Reanimated's own check reads the setting once at launch and never hears of `KaraProvider reduceMotion`.
|
|
8
|
+
*/
|
|
9
|
+
export const timing = (size: DurationSize, curve: EasingName = 'smoothOut'): WithTimingConfig => {
|
|
10
|
+
const [x1, y1, x2, y2] = easing[curve]
|
|
11
|
+
|
|
12
|
+
return {duration: duration[size], easing: Easing.bezier(x1, y1, x2, y2), reduceMotion: ReduceMotion.Never}
|
|
13
|
+
}
|
|
@@ -3,13 +3,13 @@ import type {ReactNode} from 'react'
|
|
|
3
3
|
import type {MenuAction} from '../menu'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* A list of actions to pick one from: SwiftUI's confirmation dialog on iOS, a `Sheet` of Material rows
|
|
7
|
-
*
|
|
6
|
+
* A list of actions to pick one from: SwiftUI's confirmation dialog on iOS, a `Sheet` of Material rows (icon and label)
|
|
7
|
+
* under the title on Android. A native atom: it renders inside `<Screen>` or `<Island>`.
|
|
8
8
|
*/
|
|
9
9
|
export type ActionSheetProps = {
|
|
10
10
|
/** The choices, top to bottom. Picking one closes the sheet. */
|
|
11
11
|
actions: MenuAction[]
|
|
12
|
-
/** The sheet closed
|
|
12
|
+
/** The sheet closed (after a pick too), so turn `visible` off. */
|
|
13
13
|
onDismiss: () => void
|
|
14
14
|
/** The heading above the actions. Android always shows it; on iOS the system decides, and may hide it. */
|
|
15
15
|
title: string
|
|
@@ -2,18 +2,18 @@ import type {ReactNode} from 'react'
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* A modal alert with a confirm button and Cancel: SwiftUI's alert on iOS, Material's `AlertDialog` on Android. A native
|
|
5
|
-
* atom
|
|
5
|
+
* atom: it renders inside `<Screen>` or `<Island>`.
|
|
6
6
|
*/
|
|
7
7
|
export type AlertProps = {
|
|
8
8
|
/** The confirm button's label. `OK` by default. */
|
|
9
9
|
confirmLabel?: string
|
|
10
|
-
/** Marks the confirm button destructive
|
|
10
|
+
/** Marks the confirm button destructive: the system's destructive role on iOS, the destructive colour on Android. */
|
|
11
11
|
destructive?: boolean
|
|
12
12
|
/** The body text, under the title. */
|
|
13
13
|
message?: string
|
|
14
14
|
/** The confirm button was pressed. `onDismiss` follows, as it does for every way the alert closes. */
|
|
15
15
|
onConfirm?: () => void
|
|
16
|
-
/** The alert closed
|
|
16
|
+
/** The alert closed (either button, or on Android a tap outside or back), so turn `visible` off. */
|
|
17
17
|
onDismiss: () => void
|
|
18
18
|
/** The alert's heading. */
|
|
19
19
|
title: string
|
|
@@ -3,7 +3,7 @@ import type {ReactNode} from 'react'
|
|
|
3
3
|
import type {MenuAction} from '../menu'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* A context menu on a React Native subtree
|
|
6
|
+
* A context menu on a React Native subtree (a card in a list, say), opened by a long press. iOS: a
|
|
7
7
|
* `UIContextMenuInteraction`, with an optional React Native `preview` lifted while the menu is open and a callback for
|
|
8
8
|
* a tap on it. Android, where Material has no lifted preview: a ripple and the long-press haptic, then a Material
|
|
9
9
|
* dropdown where the finger is, with the trigger highlighted while it is open. The trigger is ordinary React Native layout, so it
|
|
@@ -14,35 +14,35 @@ export type ContextMenuProps = ResponsiveViewSx & {
|
|
|
14
14
|
actions: MenuAction[]
|
|
15
15
|
/** The trigger, laid out as usual. */
|
|
16
16
|
children: ReactNode
|
|
17
|
-
/** iOS: the user tapped the lifted preview, committing to it
|
|
17
|
+
/** iOS: the user tapped the lifted preview, committing to it. Open the detail the card stands for. */
|
|
18
18
|
onPreviewPress?: () => void
|
|
19
19
|
/**
|
|
20
|
-
* iOS: lifted in place of the trigger while the menu is open
|
|
20
|
+
* iOS: lifted in place of the trigger while the menu is open (a larger version of the card, say). A snapshot of the
|
|
21
21
|
* trigger when unset. Mounted only once a finger has rested on the trigger, so a list of cards does not pay for
|
|
22
22
|
* every preview up front.
|
|
23
23
|
*/
|
|
24
24
|
preview?: ReactNode
|
|
25
25
|
/**
|
|
26
26
|
* iOS: how the preview leaves once tapped, before `onPreviewPress`. `zoom`: its photo grows straight into the pushed
|
|
27
|
-
* screen, the way the App Store expands a preview
|
|
28
|
-
* trigger, a `preview` and iOS 18, and shrinks back like `dismiss` otherwise. `pop`: UIKit's default, the preview
|
|
27
|
+
* screen, the way the App Store expands a preview. It needs a `ZoomTransition.Source` (`@hzblj/kara-ui/router`) in
|
|
28
|
+
* the trigger, a `preview` and iOS 18, and shrinks back like `dismiss` otherwise. `pop`: UIKit's default, the preview
|
|
29
29
|
* flies out. `dismiss`: it shrinks back onto the trigger first. Default: `zoom` when the trigger holds a
|
|
30
30
|
* `ZoomTransition.Source`, `pop` otherwise.
|
|
31
31
|
*/
|
|
32
32
|
previewTransition?: 'dismiss' | 'pop' | 'zoom'
|
|
33
|
-
/** Test identifier
|
|
33
|
+
/** Test identifier: on the native view around the trigger on iOS, on the trigger's `Pressable` on Android. */
|
|
34
34
|
testID?: string
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
/** A region of a `ContextMenu`'s trigger that keeps its own long press
|
|
37
|
+
/** A region of a `ContextMenu`'s trigger that keeps its own long press (see `ContextMenu.Exclusion`). */
|
|
38
38
|
export type ContextMenuExclusionProps = {
|
|
39
|
-
/** The region
|
|
39
|
+
/** The region: a button inside the card, say. */
|
|
40
40
|
children: ReactNode
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
export type ContextMenuComponent = ((props: ContextMenuProps) => ReactNode) & {
|
|
44
44
|
/**
|
|
45
|
-
* A region of the trigger that must not open the menu
|
|
45
|
+
* A region of the trigger that must not open the menu: a button inside the card. On iOS the interaction covers the
|
|
46
46
|
* whole trigger, so a long press on that button would otherwise open the card's menu.
|
|
47
47
|
*/
|
|
48
48
|
Exclusion: (props: ContextMenuExclusionProps) => ReactNode
|
|
@@ -25,16 +25,16 @@ const FabMenuRow = ({action, onSelect}: FabMenuRowProps) => {
|
|
|
25
25
|
return (
|
|
26
26
|
<FloatingActionButtonMenuItem
|
|
27
27
|
containerColor={theme.color('fill.accent.primary')}
|
|
28
|
-
contentColor={theme.color('content.on.
|
|
28
|
+
contentColor={theme.color('content.on.accent')}
|
|
29
29
|
onClick={onClick}
|
|
30
30
|
>
|
|
31
31
|
{action.icon ? (
|
|
32
32
|
<FloatingActionButtonMenuItem.Icon>
|
|
33
|
-
<Icon color="content.on.
|
|
33
|
+
<Icon color="content.on.accent" name={action.icon} />
|
|
34
34
|
</FloatingActionButtonMenuItem.Icon>
|
|
35
35
|
) : null}
|
|
36
36
|
<FloatingActionButtonMenuItem.Text>
|
|
37
|
-
<ComposeText color={theme.colorString('content.on.
|
|
37
|
+
<ComposeText color={theme.colorString('content.on.accent')} style={theme.typography.labelMedium}>
|
|
38
38
|
{action.label}
|
|
39
39
|
</ComposeText>
|
|
40
40
|
</FloatingActionButtonMenuItem.Text>
|
|
@@ -47,7 +47,7 @@ const FabMenuRow = ({action, onSelect}: FabMenuRowProps) => {
|
|
|
47
47
|
* content — rather than a row of its own. The pills take the button's colours, so the menu reads as the button
|
|
48
48
|
* unfolding rather than a second surface.
|
|
49
49
|
*/
|
|
50
|
-
export const FabMenu: FabMenuComponent = ({actions, icon}: FabMenuProps) => {
|
|
50
|
+
export const FabMenu: FabMenuComponent = ({accessibilityLabel, actions, icon}: FabMenuProps) => {
|
|
51
51
|
useHostGuard('FabMenu')
|
|
52
52
|
|
|
53
53
|
const theme = useAppTheme()
|
|
@@ -67,7 +67,11 @@ export const FabMenu: FabMenuComponent = ({actions, icon}: FabMenuProps) => {
|
|
|
67
67
|
onCheckedChange={setExpanded}
|
|
68
68
|
>
|
|
69
69
|
<ToggleFloatingActionButton.Icon>
|
|
70
|
-
{icon ?
|
|
70
|
+
{icon ? (
|
|
71
|
+
<Icon accessibilityLabel={accessibilityLabel} color="content.on.accent" name={icon} />
|
|
72
|
+
) : (
|
|
73
|
+
<Glyph accessibilityLabel={accessibilityLabel} color="content.on.accent" name="plus" />
|
|
74
|
+
)}
|
|
71
75
|
</ToggleFloatingActionButton.Icon>
|
|
72
76
|
</ToggleFloatingActionButton>
|
|
73
77
|
</FloatingActionButtonMenu.Button>
|
|
@@ -10,7 +10,7 @@ import type {FabMenuComponent, FabMenuProps} from './fab-menu.types'
|
|
|
10
10
|
/** Matches `Fab`, so a screen can switch between the two without the button changing shape. */
|
|
11
11
|
const FAB_SIZE = 56
|
|
12
12
|
|
|
13
|
-
export const FabMenu: FabMenuComponent = ({actions, icon, testID}: FabMenuProps) => {
|
|
13
|
+
export const FabMenu: FabMenuComponent = ({accessibilityLabel, actions, icon, testID}: FabMenuProps) => {
|
|
14
14
|
useHostGuard('FabMenu')
|
|
15
15
|
|
|
16
16
|
return (
|
|
@@ -25,7 +25,11 @@ export const FabMenu: FabMenuComponent = ({actions, icon, testID}: FabMenuProps)
|
|
|
25
25
|
shadow="btn.accent"
|
|
26
26
|
w={FAB_SIZE}
|
|
27
27
|
>
|
|
28
|
-
{icon ?
|
|
28
|
+
{icon ? (
|
|
29
|
+
<Icon accessibilityLabel={accessibilityLabel} color="content.on.accent" name={icon} />
|
|
30
|
+
) : (
|
|
31
|
+
<Glyph accessibilityLabel={accessibilityLabel} color="content.on.accent" name="plus" />
|
|
32
|
+
)}
|
|
29
33
|
</VStack>
|
|
30
34
|
}
|
|
31
35
|
testID={testID}
|
|
@@ -4,16 +4,21 @@ import type {IconName} from '../../atoms/icon'
|
|
|
4
4
|
import type {MenuAction} from '../menu'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* A floating action button that unfolds into its actions. Android: Material 3 Expressive's `FloatingActionButtonMenu
|
|
8
|
-
*
|
|
9
|
-
* of a SwiftUI `Menu`. A native atom
|
|
7
|
+
* A floating action button that unfolds into its actions. Android: Material 3 Expressive's `FloatingActionButtonMenu`,
|
|
8
|
+
* where the button turns into a close and the actions rise above it as labelled pills. iOS: the same button as the
|
|
9
|
+
* label of a SwiftUI `Menu`. A native atom: it renders inside `<Screen>` or `<Island>`.
|
|
10
10
|
*/
|
|
11
11
|
export type FabMenuProps = {
|
|
12
|
+
/**
|
|
13
|
+
* What VoiceOver and TalkBack say for the button, since an icon has no words of its own: "Create". Required for that
|
|
14
|
+
* reason.
|
|
15
|
+
*/
|
|
16
|
+
accessibilityLabel: string
|
|
12
17
|
/** The actions the button unfolds into. */
|
|
13
18
|
actions: MenuAction[]
|
|
14
|
-
/** The closed button's icon
|
|
19
|
+
/** The closed button's icon, one of the app's. A plus by default. */
|
|
15
20
|
icon?: IconName
|
|
16
|
-
/** Test identifier, forwarded to the SwiftUI `Menu`. iOS only
|
|
21
|
+
/** Test identifier, forwarded to the SwiftUI `Menu`. iOS only; Android ignores it. */
|
|
17
22
|
testID?: string
|
|
18
23
|
}
|
|
19
24
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type {ReactNode} from 'react'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* A settings form
|
|
4
|
+
* A settings form: SwiftUI `Form` with its grouped sections, Material cards on Android. On iOS it scrolls like a
|
|
5
5
|
* `List`, so it needs a height from outside: a `Screen`, or an `Island` with `matchContents={false}` and a height. In
|
|
6
6
|
* an island that sizes itself to its content it has no height and shows nothing.
|
|
7
7
|
*/
|
|
@@ -5,7 +5,7 @@ import type {IconName} from '../../atoms/icon'
|
|
|
5
5
|
/** One action of a `Menu`, an `ActionSheet`, a `ContextMenu` or a `FabMenu`. */
|
|
6
6
|
export type MenuAction = {
|
|
7
7
|
/**
|
|
8
|
-
* Draws the action in the destructive colour
|
|
8
|
+
* Draws the action in the destructive colour (the system's destructive role on iOS). `FabMenu` ignores it on
|
|
9
9
|
* Android.
|
|
10
10
|
*/
|
|
11
11
|
destructive?: boolean
|
|
@@ -22,7 +22,7 @@ export type MenuAction = {
|
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* A text button that opens a list of actions: a SwiftUI `Menu` on iOS, a Material dropdown anchored to it on Android.
|
|
25
|
-
* A native atom
|
|
25
|
+
* A native atom: it renders inside `<Screen>` or `<Island>`.
|
|
26
26
|
*/
|
|
27
27
|
export type MenuProps = {
|
|
28
28
|
/** The menu's actions, top to bottom. */
|