@hzblj/kara-components 0.10.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 +27 -0
- 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/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 +9 -2
- 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 +26 -25
- 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 +2 -0
- package/lib/typescript/atoms/avatar/avatar.types.d.ts +5 -0
- package/lib/typescript/atoms/button/button-tokens.d.ts +1 -1
- package/lib/typescript/atoms/button/button.types.d.ts +2 -0
- package/lib/typescript/atoms/card/card.types.d.ts +2 -2
- package/lib/typescript/atoms/fab/fab.types.d.ts +8 -1
- package/lib/typescript/atoms/h-stack/h-stack.types.d.ts +6 -3
- package/lib/typescript/atoms/icon-button/icon-button.types.d.ts +7 -0
- package/lib/typescript/atoms/image/image.d.ts +2 -2
- package/lib/typescript/atoms/pressable/pressable.types.d.ts +9 -9
- package/lib/typescript/atoms/progress/progress.types.d.ts +2 -0
- package/lib/typescript/atoms/skeleton/skeleton.types.d.ts +3 -2
- package/lib/typescript/atoms/surface/surface.types.d.ts +2 -2
- package/lib/typescript/atoms/text/text.types.d.ts +2 -2
- package/lib/typescript/atoms/v-stack/v-stack.types.d.ts +3 -3
- package/lib/typescript/atoms/z-stack/z-stack.types.d.ts +3 -3
- package/lib/typescript/glyph/glyph.types.d.ts +2 -0
- package/lib/typescript/molecules/labeled-content/labeled-content.types.d.ts +4 -2
- package/lib/typescript/molecules/link/link.types.d.ts +2 -1
- package/lib/typescript/molecules/list-item/list-item.types.d.ts +5 -3
- package/lib/typescript/molecules/stepper/stepper.ios.d.ts +1 -1
- package/lib/typescript/motion.d.ts +8 -0
- package/lib/typescript/organisms/fab-menu/fab-menu.types.d.ts +5 -0
- package/lib/typescript/organisms/snackbar/snackbar.types.d.ts +38 -5
- 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 +2 -0
- package/src/atoms/avatar/avatar.tsx +5 -1
- package/src/atoms/avatar/avatar.types.ts +5 -0
- 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 +2 -0
- 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 +8 -7
- package/src/atoms/checkbox/checkbox.android.tsx +1 -1
- 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 +8 -1
- package/src/atoms/glass-view/glass-view.android.tsx +1 -1
- package/src/atoms/h-stack/h-stack.ios.tsx +6 -4
- package/src/atoms/h-stack/h-stack.types.ts +17 -13
- package/src/atoms/icon-button/icon-button.android.tsx +16 -3
- package/src/atoms/icon-button/icon-button.ios.tsx +13 -4
- package/src/atoms/icon-button/icon-button.types.ts +7 -0
- package/src/atoms/image/image.tsx +3 -3
- package/src/atoms/pressable/pressable.tsx +26 -18
- package/src/atoms/pressable/pressable.types.ts +30 -29
- 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 +2 -0
- 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/skeleton/skeleton.tsx +18 -4
- package/src/atoms/skeleton/skeleton.types.ts +3 -2
- 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 +10 -9
- package/src/atoms/switch/switch.android.tsx +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 +23 -22
- package/src/atoms/v-stack/v-stack.ios.tsx +6 -4
- package/src/atoms/v-stack/v-stack.types.ts +17 -16
- package/src/atoms/z-stack/z-stack.ios.tsx +6 -4
- package/src/atoms/z-stack/z-stack.types.ts +15 -14
- package/src/glyph/glyph.android.tsx +14 -2
- package/src/glyph/glyph.ios.tsx +13 -3
- package/src/glyph/glyph.types.ts +2 -0
- package/src/molecules/collapsible/collapsible.android.tsx +27 -7
- package/src/molecules/labeled-content/labeled-content.tsx +12 -1
- package/src/molecules/labeled-content/labeled-content.types.ts +4 -2
- 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 +5 -3
- 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/rn-list-item/rn-list-item.tsx +18 -3
- package/src/molecules/scroll-edge-container/scroll-edge-container.android.tsx +3 -2
- package/src/molecules/stepper/stepper.ios.tsx +8 -2
- package/src/motion.ts +13 -0
- 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 +5 -0
- package/src/organisms/snackbar/snackbar.tsx +143 -19
- package/src/organisms/snackbar/snackbar.types.ts +41 -5
- package/src/organisms/swipe-actions/swipe-actions.android.tsx +1 -1
- package/src/use-stack-modifiers.ts +20 -7
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import type { ResponsiveSx } from '@hzblj/kara-sx';
|
|
1
|
+
import type { AccessibilityProps, ResponsiveSx } from '@hzblj/kara-sx';
|
|
2
2
|
import type { SpaceSize } from '@hzblj/kara-theme';
|
|
3
3
|
import type { ReactNode } from 'react';
|
|
4
4
|
export type VStackAlign = 'center' | 'end' | 'start';
|
|
5
5
|
/** Stacks its children top to bottom: SwiftUI `VStack` / Compose `Column`. */
|
|
6
|
-
export type VStackProps = ResponsiveSx & {
|
|
6
|
+
export type VStackProps = ResponsiveSx & AccessibilityProps & {
|
|
7
7
|
/** The children's horizontal alignment. `start` by default. */
|
|
8
8
|
align?: VStackAlign;
|
|
9
9
|
/** Laid out top to bottom, `spacing` apart. */
|
|
10
10
|
children?: ReactNode;
|
|
11
11
|
/**
|
|
12
12
|
* Makes the whole stack pressable. iOS adds a tap gesture with no press feedback; Android a `clickable` whose ripple
|
|
13
|
-
* fills the stack's shape.
|
|
13
|
+
* fills the stack's shape. Screen readers then read the stack as one button.
|
|
14
14
|
*/
|
|
15
15
|
onPress?: () => void;
|
|
16
16
|
/** The space between children. */
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import type { ResponsiveSx } from '@hzblj/kara-sx';
|
|
1
|
+
import type { AccessibilityProps, ResponsiveSx } from '@hzblj/kara-sx';
|
|
2
2
|
import type { ReactNode } from 'react';
|
|
3
3
|
export type ZStackAlign = 'bottom' | 'center' | 'top';
|
|
4
4
|
/** Layers its children on one another: SwiftUI `ZStack` / Compose `Box`. */
|
|
5
|
-
export type ZStackProps = ResponsiveSx & {
|
|
5
|
+
export type ZStackProps = ResponsiveSx & AccessibilityProps & {
|
|
6
6
|
/** Where the children sit vertically; they are always centred horizontally. `center` by default. */
|
|
7
7
|
align?: ZStackAlign;
|
|
8
8
|
/** Drawn in order, the last on top. */
|
|
9
9
|
children?: ReactNode;
|
|
10
10
|
/**
|
|
11
11
|
* Makes the whole stack pressable. iOS adds a tap gesture with no press feedback; Android a `clickable` whose ripple
|
|
12
|
-
* fills the stack's shape.
|
|
12
|
+
* fills the stack's shape. Screen readers then read the stack as one button.
|
|
13
13
|
*/
|
|
14
14
|
onPress?: () => void;
|
|
15
15
|
/** Test identifier, forwarded to the native view. */
|
|
@@ -6,6 +6,8 @@ import type { ReactNode } from 'react';
|
|
|
6
6
|
* their own icons with `Icon` / `RnIcon`.
|
|
7
7
|
*/
|
|
8
8
|
export type GlyphProps = {
|
|
9
|
+
/** What a screen reader says. Unset, the glyph is decorative and hidden from it. */
|
|
10
|
+
accessibilityLabel?: string;
|
|
9
11
|
color?: ColorToken;
|
|
10
12
|
name: GlyphName;
|
|
11
13
|
size?: SpaceSize;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import type { AccessibilityProps } from '@hzblj/kara-sx';
|
|
1
2
|
import type { SpaceSize } from '@hzblj/kara-theme';
|
|
2
3
|
import type { ReactNode } from 'react';
|
|
3
4
|
import type { IconName } from '../../atoms/icon';
|
|
4
5
|
/**
|
|
5
6
|
* A label on the leading edge and its value on the trailing edge: the settings/detail row.
|
|
6
|
-
* Pass `children` instead of `value` when the trailing side is a control rather than text.
|
|
7
|
+
* Pass `children` instead of `value` when the trailing side is a control rather than text. With a `value`, screen
|
|
8
|
+
* readers read the row as one element ("Version, 2.4"); with a control, the control stays its own.
|
|
7
9
|
*/
|
|
8
|
-
export type LabeledContentProps = {
|
|
10
|
+
export type LabeledContentProps = AccessibilityProps & {
|
|
9
11
|
/** The trailing side when it is a control, in place of `value`. */
|
|
10
12
|
children?: ReactNode;
|
|
11
13
|
/** One of the app's icons, before the label, in the secondary colour. */
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import type { AccessibilityProps } from '@hzblj/kara-sx';
|
|
1
2
|
import type { ColorToken, TextVariant } from '@hzblj/kara-theme';
|
|
2
3
|
import type { ReactNode } from 'react';
|
|
3
4
|
import type { IconName } from '../../atoms/icon';
|
|
4
5
|
/** Opens an external URL in the platform browser or the app that claims the scheme. */
|
|
5
|
-
export type LinkProps = {
|
|
6
|
+
export type LinkProps = AccessibilityProps & {
|
|
6
7
|
/** Colours the label and the icon. `content.accent` by default. */
|
|
7
8
|
color?: ColorToken;
|
|
8
9
|
/** One of the app's icons, before the label. */
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import type { AccessibilityProps } from '@hzblj/kara-sx';
|
|
1
2
|
import type { SpaceSize } from '@hzblj/kara-theme';
|
|
2
3
|
import type { ReactNode } from 'react';
|
|
3
4
|
import type { IconName } from '../../atoms/icon';
|
|
4
5
|
/**
|
|
5
|
-
* A row with an optional icon, a title and subtitle, and a chevron when it can be pressed.
|
|
6
|
-
* inside `<Screen>` or `<Island>`; `RnListItem` is
|
|
6
|
+
* A row with an optional icon, a title and subtitle, and a chevron when it can be pressed. Screen readers read it as one
|
|
7
|
+
* element (a button when it is pressable). A native atom: it renders inside `<Screen>` or `<Island>`; `RnListItem` is
|
|
8
|
+
* the same row without a host.
|
|
7
9
|
*/
|
|
8
|
-
export type ListItemProps = {
|
|
10
|
+
export type ListItemProps = AccessibilityProps & {
|
|
9
11
|
/** One of the app's icons, before the title, in the secondary colour. */
|
|
10
12
|
icon?: IconName;
|
|
11
13
|
/** Makes the row pressable and adds a chevron on the trailing edge. */
|
|
@@ -2,6 +2,6 @@ import type { StepperComponent } from './stepper.types';
|
|
|
2
2
|
/**
|
|
3
3
|
* SwiftUI's `Stepper` at the end of a row, the label leading and the value just before the control — the way iOS's own
|
|
4
4
|
* settings show a stepped value. The value rolls to the next one (`numericText`), up or down with the change, in
|
|
5
|
-
* monospaced digits so the row does not jump.
|
|
5
|
+
* monospaced digits so the row does not jump. With motion reduced it cross-fades instead.
|
|
6
6
|
*/
|
|
7
7
|
export declare const Stepper: StepperComponent;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type DurationSize, type EasingName } from '@hzblj/kara-theme';
|
|
2
|
+
import { type WithTimingConfig } from 'react-native-reanimated';
|
|
3
|
+
/**
|
|
4
|
+
* A Reanimated timing from the motion tokens, `smoothOut` unless told otherwise. `ReduceMotion.Never`, because a
|
|
5
|
+
* component has applied `useReducedMotion` before it animates: what is left (a fade, a dim) is meant to run, and
|
|
6
|
+
* Reanimated's own check reads the setting once at launch and never hears of `KaraProvider reduceMotion`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const timing: (size: DurationSize, curve?: EasingName) => WithTimingConfig;
|
|
@@ -7,6 +7,11 @@ import type { MenuAction } from '../menu';
|
|
|
7
7
|
* label of a SwiftUI `Menu`. A native atom: it renders inside `<Screen>` or `<Island>`.
|
|
8
8
|
*/
|
|
9
9
|
export type FabMenuProps = {
|
|
10
|
+
/**
|
|
11
|
+
* What VoiceOver and TalkBack say for the button, since an icon has no words of its own: "Create". Required for that
|
|
12
|
+
* reason.
|
|
13
|
+
*/
|
|
14
|
+
accessibilityLabel: string;
|
|
10
15
|
/** The actions the button unfolds into. */
|
|
11
16
|
actions: MenuAction[];
|
|
12
17
|
/** The closed button's icon, one of the app's. A plus by default. */
|
|
@@ -1,16 +1,49 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SpaceSize } from '@hzblj/kara-theme';
|
|
2
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
3
|
+
import type Animated from 'react-native-reanimated';
|
|
4
|
+
type LayoutAnimation = ComponentProps<typeof Animated.View>['entering'];
|
|
5
|
+
/** How it comes and goes. */
|
|
6
|
+
export type SnackbarAnimation = 'fade' | 'scale' | 'slide';
|
|
7
|
+
/** How long it stays: Material's short (4 s) and long (10 s), never, or a number of milliseconds. */
|
|
8
|
+
export type SnackbarDuration = 'indefinite' | 'long' | 'short' | number;
|
|
9
|
+
/** The edge of its parent it sits on. */
|
|
10
|
+
export type SnackbarPosition = 'bottom' | 'top';
|
|
2
11
|
/**
|
|
3
|
-
* A short message laid over
|
|
4
|
-
* both platforms
|
|
12
|
+
* A short message laid over an edge of its parent, with an optional action at its trailing end. The React Native tier,
|
|
13
|
+
* drawn the same on both platforms (iOS has no snackbar of its own), so it needs no host. Material's options are all
|
|
14
|
+
* here: a duration, a dismiss button, the action on a line of its own. It is announced to VoiceOver and TalkBack when
|
|
15
|
+
* it appears.
|
|
5
16
|
*/
|
|
6
17
|
export type SnackbarProps = {
|
|
7
|
-
/** The action button's text,
|
|
18
|
+
/** The action button's text, at the trailing end. No button without it. */
|
|
8
19
|
actionLabel?: string;
|
|
20
|
+
/** Puts the action under the message, at its trailing end: Material's layout for a long message or action. */
|
|
21
|
+
actionOnNewLine?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* How it comes and goes. `scale` is Material's own (a fade and a scale from 80 %), `slide` rises from its edge as it
|
|
24
|
+
* fades in, `fade` only fades. `scale` on Android and `slide` on iOS by default. With motion reduced, it fades.
|
|
25
|
+
*/
|
|
26
|
+
animation?: SnackbarAnimation;
|
|
27
|
+
/** A close button at the trailing end, Material's dismiss action; it calls `onDismiss`. */
|
|
28
|
+
dismissible?: boolean;
|
|
29
|
+
/** How long it stays up before `onDismiss` is called. `indefinite` by default: it never hides itself. */
|
|
30
|
+
duration?: SnackbarDuration;
|
|
31
|
+
/** A Reanimated entering animation of your own, e.g. `FadeInDown.springify()`. It wins over `animation`. */
|
|
32
|
+
entering?: LayoutAnimation;
|
|
33
|
+
/** A Reanimated exiting animation of your own. It wins over `animation`. */
|
|
34
|
+
exiting?: LayoutAnimation;
|
|
9
35
|
/** The message. */
|
|
10
36
|
message: string;
|
|
37
|
+
/** Between the snackbar and its edge, a space token. `s24` by default; raise it above a tab bar. */
|
|
38
|
+
offset?: SpaceSize;
|
|
11
39
|
/** The action was pressed. The snackbar stays up; turn `visible` off to hide it. */
|
|
12
40
|
onAction?: () => void;
|
|
13
|
-
/**
|
|
41
|
+
/** It asks to go: its `duration` ran out, or its dismiss button was pressed. Turn `visible` off to hide it. */
|
|
42
|
+
onDismiss?: () => void;
|
|
43
|
+
/** The edge of its parent it sits on. `bottom` by default, Material's place for it. */
|
|
44
|
+
position?: SnackbarPosition;
|
|
45
|
+
/** Shows the snackbar while true, animating it in and out. */
|
|
14
46
|
visible: boolean;
|
|
15
47
|
};
|
|
16
48
|
export type SnackbarComponent = (props: SnackbarProps) => ReactNode;
|
|
49
|
+
export {};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { type ModifierConfig } from '@expo/ui/jetpack-compose/modifiers';
|
|
2
|
-
import { type ResponsiveSx } from '@hzblj/kara-sx';
|
|
2
|
+
import { type AccessibilityProps, type ResponsiveSx } from '@hzblj/kara-sx';
|
|
3
3
|
/**
|
|
4
|
-
* A Compose stack's modifiers in the order a pressable one needs: its frame, shape and background, then the press,
|
|
5
|
-
* then its padding. Compose clips a `clickable` to what comes after it, so with the padding first the ripple
|
|
6
|
-
* at the padding and a row pressed by its edge would light up only in the middle.
|
|
4
|
+
* A Compose stack's modifiers in the order a pressable one needs: its frame, shape and background, then the press, its
|
|
5
|
+
* semantics, then its padding. Compose clips a `clickable` to what comes after it, so with the padding first the ripple
|
|
6
|
+
* would stop at the padding and a row pressed by its edge would light up only in the middle. The semantics come after
|
|
7
|
+
* the click, because a label that replaces the children's clears whatever semantics are inside it.
|
|
7
8
|
*/
|
|
8
|
-
export declare const useStackModifiers: (
|
|
9
|
+
export declare const useStackModifiers: (props: ResponsiveSx & AccessibilityProps, onPress?: () => void, testID?: string) => ModifierConfig[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hzblj/kara-components",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.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.11.0",
|
|
63
|
+
"@hzblj/kara-sx": "^0.11.0",
|
|
64
|
+
"@hzblj/kara-theme": "^0.11.0",
|
|
65
65
|
"sf-symbols-typescript": "^2.2.0"
|
|
66
66
|
},
|
|
67
67
|
"peerDependencies": {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {Host, LoadingIndicator} from '@expo/ui/jetpack-compose'
|
|
2
2
|
import {fillMaxSize, testID as testIdModifier} from '@expo/ui/jetpack-compose/modifiers'
|
|
3
|
+
import {useAccessibilityModifiers} from '@hzblj/kara-sx'
|
|
3
4
|
import {useAppTheme} from '@hzblj/kara-theme'
|
|
4
5
|
import {useMemo} from 'react'
|
|
5
6
|
import {StyleSheet} from 'react-native'
|
|
@@ -17,12 +18,17 @@ const styles = StyleSheet.create({
|
|
|
17
18
|
* anywhere and takes its place in the first frame.
|
|
18
19
|
*/
|
|
19
20
|
export const ActivityIndicator: ActivityIndicatorComponent = ({
|
|
21
|
+
accessibilityLabel,
|
|
20
22
|
color = 'fill.accent.primary',
|
|
21
23
|
size = 'small',
|
|
22
24
|
testID,
|
|
23
25
|
}: ActivityIndicatorProps) => {
|
|
24
26
|
const theme = useAppTheme()
|
|
25
|
-
const
|
|
27
|
+
const accessibilityModifiers = useAccessibilityModifiers({accessibilityLabel})
|
|
28
|
+
const modifiers = useMemo(
|
|
29
|
+
() => [fillMaxSize(), ...(testID ? [testIdModifier(testID)] : []), ...accessibilityModifiers],
|
|
30
|
+
[accessibilityModifiers, testID]
|
|
31
|
+
)
|
|
26
32
|
|
|
27
33
|
return (
|
|
28
34
|
<Host colorScheme={theme.dark ? 'dark' : 'light'} seedColor={theme.materialSeed} style={styles[size]}>
|
|
@@ -5,11 +5,19 @@ import type {ActivityIndicatorComponent, ActivityIndicatorProps} from './activit
|
|
|
5
5
|
|
|
6
6
|
/** React Native's spinner, which on iOS is UIKit's own `UIActivityIndicatorView`. */
|
|
7
7
|
export const ActivityIndicator: ActivityIndicatorComponent = ({
|
|
8
|
+
accessibilityLabel,
|
|
8
9
|
color = 'fill.accent.primary',
|
|
9
10
|
size = 'small',
|
|
10
11
|
testID,
|
|
11
12
|
}: ActivityIndicatorProps) => {
|
|
12
13
|
const theme = useAppTheme()
|
|
13
14
|
|
|
14
|
-
return
|
|
15
|
+
return (
|
|
16
|
+
<RNActivityIndicator
|
|
17
|
+
accessibilityLabel={accessibilityLabel}
|
|
18
|
+
color={theme.color(color)}
|
|
19
|
+
size={size}
|
|
20
|
+
testID={testID}
|
|
21
|
+
/>
|
|
22
|
+
)
|
|
15
23
|
}
|
|
@@ -9,6 +9,8 @@ export type ActivityIndicatorSize = 'large' | 'small'
|
|
|
9
9
|
* Android, so it renders anywhere. For how far along something is, use `Progress`.
|
|
10
10
|
*/
|
|
11
11
|
export type ActivityIndicatorProps = {
|
|
12
|
+
/** What is loading, for VoiceOver and TalkBack: "Loading photos". Unset, the platform's own word ("In progress"). */
|
|
13
|
+
accessibilityLabel?: string
|
|
12
14
|
/** Its colour. `fill.accent.primary` by default. */
|
|
13
15
|
color?: ColorToken
|
|
14
16
|
/** `small` sits in a row or a button, `large` holds a screen that is loading. `small` by default. */
|
|
@@ -17,11 +17,15 @@ const VARIANT = {
|
|
|
17
17
|
sm: 'caption',
|
|
18
18
|
} as const
|
|
19
19
|
|
|
20
|
-
export const Avatar: AvatarComponent = ({initials, size = 'md', source, testID}: AvatarProps) => {
|
|
20
|
+
export const Avatar: AvatarComponent = ({accessibilityLabel, initials, size = 'md', source, testID}: AvatarProps) => {
|
|
21
21
|
const diameter = DIAMETER[size]
|
|
22
22
|
|
|
23
23
|
return (
|
|
24
24
|
<Box
|
|
25
|
+
aria-hidden={accessibilityLabel === undefined}
|
|
26
|
+
accessibilityLabel={accessibilityLabel}
|
|
27
|
+
accessibilityRole={accessibilityLabel === undefined ? undefined : 'image'}
|
|
28
|
+
accessible={accessibilityLabel !== undefined}
|
|
25
29
|
align="center"
|
|
26
30
|
bg="fill.tertiary"
|
|
27
31
|
borderRadius="full"
|
|
@@ -5,6 +5,11 @@ export type AvatarSize = 'lg' | 'md' | 'sm'
|
|
|
5
5
|
|
|
6
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
|
+
/**
|
|
9
|
+
* Who it is, for VoiceOver and TalkBack: "Jan Blazej". Unset, the avatar is decorative and hidden from them, as one
|
|
10
|
+
* beside the person's name should be.
|
|
11
|
+
*/
|
|
12
|
+
accessibilityLabel?: string
|
|
8
13
|
/** Shown in place of the image when there is no `source`. */
|
|
9
14
|
initials?: string
|
|
10
15
|
/** The diameter: `sm` is `s24`, `md` `s40`, `lg` `s64`. `md` by default. */
|
|
@@ -9,7 +9,7 @@ type ButtonTokens = {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
const TOKENS = {
|
|
12
|
-
accent: {content: 'content.on.
|
|
12
|
+
accent: {content: 'content.on.accent', fill: 'fill.accent.primary', shadow: 'btn.accent'},
|
|
13
13
|
destructive: {content: 'content.on.destructive', fill: 'fill.destructive.primary', shadow: 'btn.destructive'},
|
|
14
14
|
glass: {content: 'content.primary', fill: 'btn.bg.glass.base', shadow: 'btn.glass'},
|
|
15
15
|
secondary: {content: 'content.primary', fill: 'btn.bg.secondary.base', shadow: 'btn.secondary'},
|
|
@@ -81,4 +81,4 @@ const currentHex = (token: ColorToken, theme: Theme): unknown => {
|
|
|
81
81
|
* content colour over a pale one (`fill.accent.base`) — the light container tokens pair with it in both appearances.
|
|
82
82
|
*/
|
|
83
83
|
export const contentOnTint = (tint: ColorToken, theme: Theme): ColorToken =>
|
|
84
|
-
(luminance(currentHex(tint, theme)) ?? 0) > 0.4 ? 'content.primary' : 'content.on.
|
|
84
|
+
(luminance(currentHex(tint, theme)) ?? 0) > 0.4 ? 'content.primary' : 'content.on.accent'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {Button as ComposeButton, Text as ComposeText, OutlinedButton} from '@expo/ui/jetpack-compose'
|
|
2
2
|
import {testID as testIdModifier} from '@expo/ui/jetpack-compose/modifiers'
|
|
3
|
-
import {useSxModifiers} from '@hzblj/kara-sx'
|
|
3
|
+
import {useAccessibilityModifiers, useSxModifiers} from '@hzblj/kara-sx'
|
|
4
4
|
import {useAppTheme} from '@hzblj/kara-theme'
|
|
5
5
|
import {useMemo} from 'react'
|
|
6
6
|
import {useHostGuard} from '../../host-context'
|
|
@@ -16,6 +16,7 @@ import {buttonTokens, contentOnTint} from './button-tokens'
|
|
|
16
16
|
* colour, as a prominent style does on iOS. `buttonStyle` and `controlSize` are SwiftUI's alone.
|
|
17
17
|
*/
|
|
18
18
|
export const Button: ButtonComponent = ({
|
|
19
|
+
accessibilityHint,
|
|
19
20
|
disabled = false,
|
|
20
21
|
label,
|
|
21
22
|
onPress,
|
|
@@ -28,9 +29,10 @@ export const Button: ButtonComponent = ({
|
|
|
28
29
|
const theme = useAppTheme()
|
|
29
30
|
const tokens = buttonTokens(variant, disabled, theme)
|
|
30
31
|
const sxModifiers = useSxModifiers({wide})
|
|
32
|
+
const accessibilityModifiers = useAccessibilityModifiers({accessibilityHint}, accessibilityHint !== undefined)
|
|
31
33
|
const modifiers = useMemo(
|
|
32
|
-
() => (testID ? [
|
|
33
|
-
[sxModifiers, testID]
|
|
34
|
+
() => [...sxModifiers, ...(testID ? [testIdModifier(testID)] : []), ...accessibilityModifiers],
|
|
35
|
+
[accessibilityModifiers, sxModifiers, testID]
|
|
34
36
|
)
|
|
35
37
|
const style = theme.typography.body
|
|
36
38
|
const outlined = variant === 'glass' && !tint
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
glassEffect as glassEffectModifier,
|
|
7
7
|
tint as tintModifier,
|
|
8
8
|
} from '@expo/ui/swift-ui/modifiers'
|
|
9
|
+
import {useAccessibilityModifiers} from '@hzblj/kara-sx'
|
|
9
10
|
import {type ColorToken, useAppTheme} from '@hzblj/kara-theme'
|
|
10
11
|
import {useMemo} from 'react'
|
|
11
12
|
import {useHostGuard} from '../../host-context'
|
|
@@ -29,6 +30,7 @@ const TINT_BY_VARIANT = {
|
|
|
29
30
|
} as const satisfies Record<ButtonVariant, ColorToken | undefined>
|
|
30
31
|
|
|
31
32
|
export const Button: ButtonComponent = ({
|
|
33
|
+
accessibilityHint,
|
|
32
34
|
buttonStyle,
|
|
33
35
|
controlSize = 'large',
|
|
34
36
|
disabled = false,
|
|
@@ -59,8 +61,14 @@ export const Button: ButtonComponent = ({
|
|
|
59
61
|
// A prominent style — and tinted glass — is coloured by the tint, so a caller's own tint picks the label on it.
|
|
60
62
|
const content = tint && filled && !disabled ? contentOnTint(tint, theme) : tokens.content
|
|
61
63
|
|
|
64
|
+
const accessibilityModifiers = useAccessibilityModifiers({accessibilityHint})
|
|
65
|
+
|
|
62
66
|
const modifiers = useMemo(() => {
|
|
63
|
-
const list = [
|
|
67
|
+
const list = [
|
|
68
|
+
buttonStyleModifier(glassTint ? 'plain' : style),
|
|
69
|
+
controlSizeModifier(controlSize),
|
|
70
|
+
...accessibilityModifiers,
|
|
71
|
+
]
|
|
64
72
|
|
|
65
73
|
if (glassTint) {
|
|
66
74
|
list.push(
|
|
@@ -75,7 +83,7 @@ export const Button: ButtonComponent = ({
|
|
|
75
83
|
}
|
|
76
84
|
|
|
77
85
|
return list
|
|
78
|
-
}, [controlSize, disabled, glassTint, resolvedTint, style, theme])
|
|
86
|
+
}, [accessibilityModifiers, controlSize, disabled, glassTint, resolvedTint, style, theme])
|
|
79
87
|
|
|
80
88
|
return (
|
|
81
89
|
<SwiftUIButton modifiers={modifiers} onPress={onPress} testID={testID}>
|
|
@@ -24,6 +24,8 @@ export type ButtonControlSize = 'extraLarge' | 'large' | 'mini' | 'regular' | 's
|
|
|
24
24
|
|
|
25
25
|
/** A text button: SwiftUI `Button` on iOS, Material's filled button (outlined for `glass`) on Android. */
|
|
26
26
|
export type ButtonProps = {
|
|
27
|
+
/** What pressing it does, when the label alone does not say. See `AccessibilityProps`. */
|
|
28
|
+
accessibilityHint?: string
|
|
27
29
|
/**
|
|
28
30
|
* Replaces the style the variant picks: `borderedProminent` for `accent` and `destructive`, `bordered` for
|
|
29
31
|
* `secondary`, `glass` for `glass`. iOS only. Android ignores it.
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import {Column} from '@expo/ui/jetpack-compose'
|
|
2
2
|
import {testID as testIdModifier} from '@expo/ui/jetpack-compose/modifiers'
|
|
3
|
-
import {useSxModifiers} from '@hzblj/kara-sx'
|
|
3
|
+
import {splitAccessibility, useAccessibilityModifiers, useSxModifiers} from '@hzblj/kara-sx'
|
|
4
4
|
import {useMemo} from 'react'
|
|
5
5
|
import {useHostGuard} from '../../host-context'
|
|
6
6
|
import type {CardComponent, CardProps} from './card.types'
|
|
7
7
|
|
|
8
|
-
export const Card: CardComponent = ({children, testID, ...
|
|
8
|
+
export const Card: CardComponent = ({children, testID, ...props}: CardProps) => {
|
|
9
9
|
useHostGuard('Card')
|
|
10
|
+
const [accessibility, sx] = splitAccessibility(props)
|
|
10
11
|
const sxModifiers = useSxModifiers({bg: 'surface.primary', borderRadius: 'large', p: 's16', shadow: 'card', ...sx})
|
|
12
|
+
const accessibilityModifiers = useAccessibilityModifiers(accessibility)
|
|
11
13
|
const modifiers = useMemo(
|
|
12
|
-
() => (testID ? [
|
|
13
|
-
[sxModifiers, testID]
|
|
14
|
+
() => [...sxModifiers, ...(testID ? [testIdModifier(testID)] : []), ...accessibilityModifiers],
|
|
15
|
+
[accessibilityModifiers, sxModifiers, testID]
|
|
14
16
|
)
|
|
15
17
|
|
|
16
18
|
return <Column modifiers={modifiers}>{children}</Column>
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import {VStack} from '@expo/ui/swift-ui'
|
|
2
|
-
import {useSxModifiers} from '@hzblj/kara-sx'
|
|
2
|
+
import {splitAccessibility, useAccessibilityModifiers, useSxModifiers} from '@hzblj/kara-sx'
|
|
3
|
+
import {useMemo} from 'react'
|
|
3
4
|
import {useHostGuard} from '../../host-context'
|
|
4
5
|
import type {CardComponent, CardProps} from './card.types'
|
|
5
6
|
|
|
6
|
-
export const Card: CardComponent = ({children, testID, ...
|
|
7
|
+
export const Card: CardComponent = ({children, testID, ...props}: CardProps) => {
|
|
7
8
|
useHostGuard('Card')
|
|
8
|
-
const
|
|
9
|
+
const [accessibility, sx] = splitAccessibility(props)
|
|
10
|
+
const sxModifiers = useSxModifiers({bg: 'surface.primary', borderRadius: 'large', p: 's16', shadow: 'card', ...sx})
|
|
11
|
+
const accessibilityModifiers = useAccessibilityModifiers(accessibility)
|
|
12
|
+
const modifiers = useMemo(() => [...sxModifiers, ...accessibilityModifiers], [accessibilityModifiers, sxModifiers])
|
|
9
13
|
|
|
10
14
|
return (
|
|
11
15
|
<VStack alignment="leading" modifiers={modifiers} testID={testID}>
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import type {ResponsiveSx} from '@hzblj/kara-sx'
|
|
1
|
+
import type {AccessibilityProps, ResponsiveSx} from '@hzblj/kara-sx'
|
|
2
2
|
import type {ReactNode} from 'react'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
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
|
-
export type CardProps = ResponsiveSx &
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
export type CardProps = ResponsiveSx &
|
|
9
|
+
AccessibilityProps & {
|
|
10
|
+
/** Native views, stacked vertically from the leading edge. */
|
|
11
|
+
children?: ReactNode
|
|
12
|
+
/** Test identifier, forwarded to the native view. */
|
|
13
|
+
testID?: string
|
|
14
|
+
}
|
|
14
15
|
|
|
15
16
|
export type CardComponent = (props: CardProps) => ReactNode
|
|
@@ -23,7 +23,7 @@ export const Checkbox: CheckboxComponent = ({disabled = false, label, onValueCha
|
|
|
23
23
|
)
|
|
24
24
|
const control = (
|
|
25
25
|
<ComposeCheckbox
|
|
26
|
-
colors={{checkedColor: theme.color('fill.accent.primary'), checkmarkColor: theme.color('content.on.
|
|
26
|
+
colors={{checkedColor: theme.color('fill.accent.primary'), checkmarkColor: theme.color('content.on.accent')}}
|
|
27
27
|
enabled={!disabled}
|
|
28
28
|
onCheckedChange={onValueChange ?? NOOP}
|
|
29
29
|
value={value}
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import {FloatingActionButton} from '@expo/ui/jetpack-compose'
|
|
2
|
+
import {useAccessibilityModifiers} from '@hzblj/kara-sx'
|
|
2
3
|
import {useAppTheme} from '@hzblj/kara-theme'
|
|
3
4
|
|
|
4
5
|
import {useHostGuard} from '../../host-context'
|
|
5
6
|
import {Icon} from '../icon'
|
|
6
7
|
import type {FabComponent, FabProps} from './fab.types'
|
|
7
8
|
|
|
8
|
-
export const Fab: FabComponent = ({name, onPress}: FabProps) => {
|
|
9
|
+
export const Fab: FabComponent = ({accessibilityHint, accessibilityLabel, name, onPress}: FabProps) => {
|
|
9
10
|
useHostGuard('Fab')
|
|
10
11
|
|
|
11
12
|
const theme = useAppTheme()
|
|
13
|
+
const modifiers = useAccessibilityModifiers({accessibilityHint}, accessibilityHint !== undefined)
|
|
12
14
|
|
|
13
15
|
return (
|
|
14
|
-
<FloatingActionButton containerColor={theme.color('fill.accent.primary')} onClick={onPress}>
|
|
16
|
+
<FloatingActionButton containerColor={theme.color('fill.accent.primary')} modifiers={modifiers} onClick={onPress}>
|
|
15
17
|
{/* `@expo/ui`'s FAB is slot-based: content outside `.Icon` is not composed at all. */}
|
|
16
18
|
<FloatingActionButton.Icon>
|
|
17
|
-
<Icon color="content.on.
|
|
19
|
+
<Icon accessibilityLabel={accessibilityLabel} color="content.on.accent" name={name} />
|
|
18
20
|
</FloatingActionButton.Icon>
|
|
19
21
|
</FloatingActionButton>
|
|
20
22
|
)
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import {Button} from '@expo/ui/swift-ui'
|
|
2
2
|
import {buttonStyle} from '@expo/ui/swift-ui/modifiers'
|
|
3
|
-
import {useSxModifiers} from '@hzblj/kara-sx'
|
|
3
|
+
import {useAccessibilityModifiers, useSxModifiers} from '@hzblj/kara-sx'
|
|
4
4
|
import {useMemo} from 'react'
|
|
5
5
|
import {useHostGuard} from '../../host-context'
|
|
6
6
|
import {Icon} from '../icon'
|
|
7
7
|
import type {FabComponent, FabProps} from './fab.types'
|
|
8
8
|
|
|
9
|
-
export const Fab: FabComponent = ({name, onPress, testID}: FabProps) => {
|
|
9
|
+
export const Fab: FabComponent = ({accessibilityHint, accessibilityLabel, name, onPress, testID}: FabProps) => {
|
|
10
10
|
useHostGuard('Fab')
|
|
11
|
+
const accessibilityModifiers = useAccessibilityModifiers({accessibilityHint})
|
|
11
12
|
|
|
12
13
|
const sxModifiers = useSxModifiers({
|
|
13
14
|
bg: 'fill.accent.primary',
|
|
@@ -17,11 +18,14 @@ export const Fab: FabComponent = ({name, onPress, testID}: FabProps) => {
|
|
|
17
18
|
shadow: 'btn.accent',
|
|
18
19
|
w: 56,
|
|
19
20
|
})
|
|
20
|
-
const modifiers = useMemo(
|
|
21
|
+
const modifiers = useMemo(
|
|
22
|
+
() => [buttonStyle('plain'), ...sxModifiers, ...accessibilityModifiers],
|
|
23
|
+
[accessibilityModifiers, sxModifiers]
|
|
24
|
+
)
|
|
21
25
|
|
|
22
26
|
return (
|
|
23
27
|
<Button modifiers={modifiers} onPress={onPress} testID={testID}>
|
|
24
|
-
<Icon color="content.on.
|
|
28
|
+
<Icon accessibilityLabel={accessibilityLabel} color="content.on.accent" name={name} />
|
|
25
29
|
</Button>
|
|
26
30
|
)
|
|
27
31
|
}
|
|
@@ -7,7 +7,14 @@ import type {IconName} from '../icon'
|
|
|
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 = {
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* What VoiceOver and TalkBack say for the button, since an icon has no words of its own: "Share", "Add to
|
|
12
|
+
* favourites". Required for that reason.
|
|
13
|
+
*/
|
|
14
|
+
accessibilityLabel: string
|
|
15
|
+
/** What pressing it does, when the label alone does not say. See `AccessibilityProps`. */
|
|
16
|
+
accessibilityHint?: string
|
|
17
|
+
/** The icon, one of the app's, drawn in `content.on.accent`. */
|
|
11
18
|
name: IconName
|
|
12
19
|
/** Called when the button is pressed. */
|
|
13
20
|
onPress?: () => void
|
|
@@ -31,7 +31,7 @@ export const GlassView: GlassViewComponent = ({
|
|
|
31
31
|
cornerRadius={radii.full}
|
|
32
32
|
fallbackTint={withOpacity(base, 'o95')}
|
|
33
33
|
glassTint={withOpacity(base, tint ? 'o85' : 'o50')}
|
|
34
|
-
hairlineColor={withOpacity(String(theme.color('content.on.
|
|
34
|
+
hairlineColor={withOpacity(String(theme.color('content.on.accent')), theme.dark ? 'o20' : 'o60')}
|
|
35
35
|
hairlineWidth={1}
|
|
36
36
|
saturation={1.6}
|
|
37
37
|
style={style}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {HStack as SwiftUIHStack} from '@expo/ui/swift-ui'
|
|
2
2
|
import {onTapGesture} from '@expo/ui/swift-ui/modifiers'
|
|
3
|
-
import {type FrameAlignment, useSxModifiers} from '@hzblj/kara-sx'
|
|
3
|
+
import {type FrameAlignment, splitAccessibility, useAccessibilityModifiers, useSxModifiers} from '@hzblj/kara-sx'
|
|
4
4
|
import {spacing} from '@hzblj/kara-theme'
|
|
5
5
|
import {useMemo} from 'react'
|
|
6
6
|
import {useHostGuard} from '../../host-context'
|
|
@@ -24,13 +24,15 @@ export const HStack: HStackComponent = ({
|
|
|
24
24
|
onPress,
|
|
25
25
|
spacing: gap,
|
|
26
26
|
testID,
|
|
27
|
-
...
|
|
27
|
+
...props
|
|
28
28
|
}: HStackProps) => {
|
|
29
29
|
useHostGuard('HStack')
|
|
30
|
+
const [accessibility, sx] = splitAccessibility(props)
|
|
30
31
|
const sxModifiers = useSxModifiers(sx, FRAME_ALIGNMENT[align])
|
|
32
|
+
const accessibilityModifiers = useAccessibilityModifiers(accessibility, onPress !== undefined)
|
|
31
33
|
const modifiers = useMemo(
|
|
32
|
-
() => (onPress ? [
|
|
33
|
-
[onPress, sxModifiers]
|
|
34
|
+
() => [...sxModifiers, ...(onPress ? [onTapGesture(onPress)] : []), ...accessibilityModifiers],
|
|
35
|
+
[accessibilityModifiers, onPress, sxModifiers]
|
|
34
36
|
)
|
|
35
37
|
|
|
36
38
|
return (
|