@webority/mobile-ui 0.11.0 → 0.12.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.
Files changed (63) hide show
  1. package/lib/commonjs/components/Avatar/Avatar.js +1 -1
  2. package/lib/commonjs/components/Chip/Chip.js +1 -1
  3. package/lib/commonjs/components/Descriptions/Descriptions.js +1 -1
  4. package/lib/commonjs/components/EmptyState/EmptyState.js +1 -1
  5. package/lib/commonjs/components/FileViewer/FileViewer.js +1 -1
  6. package/lib/commonjs/components/FileViewer/FileViewerPage.js +1 -0
  7. package/lib/commonjs/components/FileViewer/useFileViewerZoom.js +1 -0
  8. package/lib/commonjs/components/FilterChipRow/FilterChipRow.js +1 -0
  9. package/lib/commonjs/components/FilterChipRow/index.js +1 -0
  10. package/lib/commonjs/components/FloatingActionButton/FloatingActionButton.js +1 -1
  11. package/lib/commonjs/components/KeyboardAwareScrollView/KeyboardAwareScrollView.js +1 -1
  12. package/lib/commonjs/components/ProgressBar/ProgressBar.js +1 -1
  13. package/lib/commonjs/components/SignaturePad/SignaturePad.js +1 -1
  14. package/lib/commonjs/components/SquircleView/SquircleView.js +1 -0
  15. package/lib/commonjs/components/SquircleView/index.js +1 -0
  16. package/lib/commonjs/components/index.js +1 -1
  17. package/lib/commonjs/theme/tokens.js +1 -1
  18. package/lib/module/components/Avatar/Avatar.js +1 -1
  19. package/lib/module/components/Chip/Chip.js +1 -1
  20. package/lib/module/components/Descriptions/Descriptions.js +1 -1
  21. package/lib/module/components/EmptyState/EmptyState.js +1 -1
  22. package/lib/module/components/FileViewer/FileViewer.js +1 -1
  23. package/lib/module/components/FileViewer/FileViewerPage.js +1 -0
  24. package/lib/module/components/FileViewer/useFileViewerZoom.js +1 -0
  25. package/lib/module/components/FilterChipRow/FilterChipRow.js +1 -0
  26. package/lib/module/components/FilterChipRow/index.js +1 -0
  27. package/lib/module/components/FloatingActionButton/FloatingActionButton.js +1 -1
  28. package/lib/module/components/KeyboardAwareScrollView/KeyboardAwareScrollView.js +1 -1
  29. package/lib/module/components/ProgressBar/ProgressBar.js +1 -1
  30. package/lib/module/components/SignaturePad/SignaturePad.js +1 -1
  31. package/lib/module/components/SquircleView/SquircleView.js +1 -0
  32. package/lib/module/components/SquircleView/index.js +1 -0
  33. package/lib/module/components/index.js +1 -1
  34. package/lib/module/theme/tokens.js +1 -1
  35. package/lib/typescript/commonjs/components/Avatar/Avatar.d.ts +25 -1
  36. package/lib/typescript/commonjs/components/Chip/Chip.d.ts +15 -2
  37. package/lib/typescript/commonjs/components/Descriptions/Descriptions.d.ts +9 -2
  38. package/lib/typescript/commonjs/components/FileViewer/FileViewer.d.ts +21 -10
  39. package/lib/typescript/commonjs/components/FileViewer/FileViewerPage.d.ts +12 -0
  40. package/lib/typescript/commonjs/components/FileViewer/useFileViewerZoom.d.ts +41 -0
  41. package/lib/typescript/commonjs/components/FilterChipRow/FilterChipRow.d.ts +55 -0
  42. package/lib/typescript/commonjs/components/FilterChipRow/index.d.ts +3 -0
  43. package/lib/typescript/commonjs/components/FloatingActionButton/FloatingActionButton.d.ts +8 -0
  44. package/lib/typescript/commonjs/components/SignaturePad/SignaturePad.d.ts +8 -2
  45. package/lib/typescript/commonjs/components/SquircleView/SquircleView.d.ts +22 -0
  46. package/lib/typescript/commonjs/components/SquircleView/index.d.ts +3 -0
  47. package/lib/typescript/commonjs/components/index.d.ts +4 -0
  48. package/lib/typescript/commonjs/theme/types.d.ts +4 -0
  49. package/lib/typescript/module/components/Avatar/Avatar.d.ts +25 -1
  50. package/lib/typescript/module/components/Chip/Chip.d.ts +15 -2
  51. package/lib/typescript/module/components/Descriptions/Descriptions.d.ts +9 -2
  52. package/lib/typescript/module/components/FileViewer/FileViewer.d.ts +21 -10
  53. package/lib/typescript/module/components/FileViewer/FileViewerPage.d.ts +12 -0
  54. package/lib/typescript/module/components/FileViewer/useFileViewerZoom.d.ts +41 -0
  55. package/lib/typescript/module/components/FilterChipRow/FilterChipRow.d.ts +55 -0
  56. package/lib/typescript/module/components/FilterChipRow/index.d.ts +3 -0
  57. package/lib/typescript/module/components/FloatingActionButton/FloatingActionButton.d.ts +8 -0
  58. package/lib/typescript/module/components/SignaturePad/SignaturePad.d.ts +8 -2
  59. package/lib/typescript/module/components/SquircleView/SquircleView.d.ts +22 -0
  60. package/lib/typescript/module/components/SquircleView/index.d.ts +3 -0
  61. package/lib/typescript/module/components/index.d.ts +4 -0
  62. package/lib/typescript/module/theme/types.d.ts +4 -0
  63. package/package.json +3 -3
@@ -11,14 +11,25 @@ import type { SlotIcon } from '../AppIcon/slotIcon';
11
11
  export type ChipVariant = 'filled' | 'outlined' | 'soft';
12
12
  export type ChipTone = 'primary' | 'neutral' | 'success' | 'warning' | 'error' | 'info';
13
13
  export type ChipSize = 'sm' | 'md';
14
- export type ChipSelectionMode = 'single' | 'multiple';
14
+ export type ChipSelectionMode = 'single' | 'multiple' | 'radio';
15
15
  export interface ChipProps {
16
16
  label: string;
17
+ /**
18
+ * A figure after the label, drawn quieter than it (regular weight, caption
19
+ * size, tabular digits): "Open" with `count={4}`. `0` is shown; `undefined`
20
+ * and an empty string draw nothing, so a count still loading leaves the
21
+ * label alone. The accessibility label becomes "Open, 4" unless
22
+ * `accessibilityLabel` is set.
23
+ */
24
+ count?: number | string;
17
25
  selected?: boolean;
18
26
  /**
19
27
  * How a pressable chip announces itself. `'single'` (default) is a button
20
28
  * with a selected state; `'multiple'` is a checkbox whose checked state
21
- * follows `selected`, for chips that toggle independently.
29
+ * follows `selected`, for chips that toggle independently; `'radio'` is a
30
+ * radio whose checked state follows `selected`, for one-of-many chips inside
31
+ * a radiogroup. A disabled `'radio'` chip with an `onPress` stays a radio
32
+ * (announced disabled) instead of falling back to plain text.
22
33
  */
23
34
  selectionMode?: ChipSelectionMode;
24
35
  onPress?: () => void;
@@ -51,6 +62,8 @@ export interface ChipProps {
51
62
  textStyle?: StyleProp<TextStyle>;
52
63
  /** Style override for the chip outer container (alias to style, applied after). */
53
64
  containerStyle?: StyleProp<ViewStyle>;
65
+ /** Style override for the count text. */
66
+ countStyle?: StyleProp<TextStyle>;
54
67
  /** Style override for the close (×) button pressable. */
55
68
  closeButtonStyle?: StyleProp<ViewStyle>;
56
69
  /** Style override for the close (×) glyph text. */
@@ -4,9 +4,16 @@ import type { TextColor } from '../Text/Text';
4
4
  export type DescriptionsSize = 'sm' | 'md';
5
5
  export type DescriptionsVariant = 'list' | 'summary';
6
6
  export interface DescriptionItem {
7
- /** A string renders as text; a node (a symbol with a subscript, say) renders as-is. */
7
+ /**
8
+ * A string renders as text. A node (a symbol with a subscript, say) sits in the label's Text, so
9
+ * its base and subscript take the label's size and colour; a string inside a node list is fine.
10
+ */
8
11
  label: React.ReactNode;
9
- /** A string renders as text; a node renders as-is. Empty renders as a plain hyphen, "-". */
12
+ /**
13
+ * A string, a number, a `sym()` / `Notation` or a list of those renders as text in the value's
14
+ * size, weight and colour (`strong`, `tone`), the subscript included. Any other node (a badge, a
15
+ * Text of your own) renders as-is in a View and owns its type. Empty renders as a plain hyphen, "-".
16
+ */
10
17
  value?: React.ReactNode;
11
18
  /** Make this row span both columns. Ignored when `columns` is 1. */
12
19
  full?: boolean;
@@ -20,22 +20,33 @@ export interface FileViewerProps {
20
20
  onError?: (error: Error) => void;
21
21
  /** Replaces the default themed spinner shown while the document loads. */
22
22
  loadingIndicator?: () => React.ReactNode;
23
+ /** Pinch, double-tap zoom and pan while zoomed. Default true. */
24
+ zoomEnabled?: boolean;
25
+ /** Upper bound on pinch zoom, as a multiple of the page fitting the width. Default 4. */
26
+ maxZoom?: number;
23
27
  style?: StyleProp<ViewStyle>;
24
28
  testID?: string;
25
29
  accessibilityLabel?: string;
26
30
  }
27
31
  /**
28
32
  * Renders a PDF via our own native rasterizer (Core Graphics on iOS, PdfRenderer on
29
- * Android) — no third-party PDF dependency. Pages are paged through a plain
30
- * `ScrollView` with manual windowed mounting (render the visible page ±
31
- * `RENDER_WINDOW`), not a `FlatList` — a `VirtualizedList`-based component
32
- * would trip React Native's "VirtualizedLists should never be nested inside
33
- * plain ScrollViews" the moment a consumer embeds FileViewer in their own
34
- * scrolling screen, which is a completely ordinary way to use it. Avoiding the
35
- * VirtualizedList primitive entirely removes that whole class of warning
36
- * rather than working around one instance of it. The WebView fallback
37
- * consumer apps use for non-PDF office documents is a distinct rendering
38
- * strategy and stays app-side.
33
+ * Android), with no third-party PDF dependency. Pages are paged through a plain
34
+ * `ScrollView` with manual windowed mounting, not a `FlatList`: a
35
+ * `VirtualizedList`-based component would trip React Native's "VirtualizedLists
36
+ * should never be nested inside plain ScrollViews" the moment a consumer embeds
37
+ * FileViewer in their own scrolling screen, which is a completely ordinary way to
38
+ * use it. Avoiding the VirtualizedList primitive entirely removes that whole class
39
+ * of warning rather than working around one instance of it. The WebView fallback
40
+ * consumer apps use for non-PDF office documents is a distinct rendering strategy
41
+ * and stays app-side.
42
+ *
43
+ * Pages render one at a time, nearest the reader first, `RENDER_AHEAD` each way,
44
+ * and their files are kept, so scrolling back or ahead never lands on a blank
45
+ * page; only `MOUNT_AROUND` pages each side decode their image. Pinch zooms around
46
+ * the fingers and a double tap zooms in on the tap or back out; the transform sits
47
+ * on the whole scroll view, so while zoomed a one-finger drag pans and, past the
48
+ * zoomed page's top or bottom edge, carries on into the document's scroll. A
49
+ * settled zoom re-renders the page in view at the sharper scale it needs.
39
50
  */
40
51
  export declare const FileViewer: React.FC<FileViewerProps>;
41
52
  export default FileViewer;
@@ -0,0 +1,12 @@
1
+ import type React from 'react';
2
+ export interface FileViewerPageProps {
3
+ width: number;
4
+ height: number;
5
+ /** The rendered page file: `undefined` while it renders, `null` when it failed to render. */
6
+ uri: string | null | undefined;
7
+ /** Only pages near the reader decode their image, so memory stays flat on a long document. */
8
+ mounted: boolean;
9
+ renderLoading: () => React.ReactNode;
10
+ }
11
+ export declare const FileViewerPage: React.NamedExoticComponent<FileViewerPageProps>;
12
+ //# sourceMappingURL=FileViewerPage.d.ts.map
@@ -0,0 +1,41 @@
1
+ /** A zoom that ends at or below this counts as none and springs back to 1x. */
2
+ export declare const ZOOM_REST = 1.01;
3
+ interface UseFileViewerZoomOptions {
4
+ zoomEnabled: boolean;
5
+ maxZoom: number;
6
+ viewportWidth: number;
7
+ viewportHeight: number;
8
+ /** The furthest the document scrolls, so a pan carried into the scroll stops at the end. */
9
+ maxScroll: number;
10
+ }
11
+ /**
12
+ * FileViewer's zoom: a scale and translate on the whole scroll view, so the
13
+ * maths stays in viewport space. Pinch zooms around the fingers, a double tap
14
+ * zooms in on the tap or back out, and while zoomed a one-finger drag pans and,
15
+ * past the zoomed page's top or bottom edge, carries on into the document's
16
+ * scroll. `zoomLevel` reaches React only when a gesture settles, never per frame.
17
+ */
18
+ export declare const useFileViewerZoom: ({ zoomEnabled, maxZoom, viewportWidth, viewportHeight, maxScroll }: UseFileViewerZoomOptions) => {
19
+ scrollRef: import("react-native-reanimated").AnimatedRef<import("react-native").ReactNativeElement>;
20
+ scrollGesture: import("react-native-gesture-handler/lib/typescript/handlers/gestures/nativeGesture").NativeGesture;
21
+ zoomGesture: import("react-native-gesture-handler/lib/typescript/handlers/gestures/gestureComposition").SimultaneousGesture;
22
+ zoomStyle: import("react-native-reanimated/lib/typescript/hook/commonTypes").AnimatedStyleHandle<{
23
+ transform: ({
24
+ translateX: number;
25
+ translateY?: undefined;
26
+ scale?: undefined;
27
+ } | {
28
+ translateY: number;
29
+ translateX?: undefined;
30
+ scale?: undefined;
31
+ } | {
32
+ scale: number;
33
+ translateX?: undefined;
34
+ translateY?: undefined;
35
+ })[];
36
+ }>;
37
+ zoomLevel: number;
38
+ resetZoom: () => void;
39
+ };
40
+ export {};
41
+ //# sourceMappingURL=useFileViewerZoom.d.ts.map
@@ -0,0 +1,55 @@
1
+ /**
2
+ * FilterChipRow: a horizontal row of single-choice filter chips, each with an
3
+ * optional count ("Open 4"), above a list.
4
+ *
5
+ * The row scrolls edge to edge: `bleed` pulls it out by the page gutter on both
6
+ * sides and pads its content by the same amount, so the first chip lines up
7
+ * with the page content and the row still runs to the screen edge. Choosing a
8
+ * chip scrolls the row to centre it, so one past the screen edge never stays
9
+ * out of sight. The first placement is not animated; later ones glide, unless
10
+ * the OS asks for reduced motion.
11
+ *
12
+ * Accessibility is a radiogroup of radios, like SegmentedControl and
13
+ * ChoiceGroup: a filter picks a value on the same data. Sections of a screen
14
+ * are `Tabs`, not this.
15
+ */
16
+ import type { View as RNView, StyleProp, ViewStyle } from 'react-native';
17
+ import type { HapticType } from '../../utils';
18
+ import type { ChipSize, ChipTone, ChipVariant } from '../Chip';
19
+ export interface FilterChipItem {
20
+ /** Stable id of the chip; `value` and `onChange` carry it. */
21
+ key: string;
22
+ label: string;
23
+ /** Shown after the label; leave it undefined while it loads and the label shows alone. */
24
+ count?: number | string;
25
+ disabled?: boolean;
26
+ }
27
+ export interface FilterChipRowProps {
28
+ items: ReadonlyArray<FilterChipItem>;
29
+ /** Key of the selected item. */
30
+ value: string;
31
+ /** Fired with the key of a chip the person picks. Not fired for the chip that is already selected. */
32
+ onChange: (key: string) => void;
33
+ /**
34
+ * The page gutter in points. The row extends this far past its parent on
35
+ * both sides and pads its content by the same amount. The theme carries no
36
+ * screen gutter, so the default is 0 (the row stays inside its parent).
37
+ */
38
+ bleed?: number;
39
+ size?: ChipSize;
40
+ variant?: ChipVariant;
41
+ tone?: ChipTone;
42
+ /** Haptic feedback for interactions. Pass false to disable; pass a HapticType to override the default. */
43
+ haptic?: HapticType | false;
44
+ /** Names the radiogroup for screen readers, e.g. "Filter by status". */
45
+ accessibilityLabel?: string;
46
+ /** Style of the outer view, applied after the bleed margin. */
47
+ style?: StyleProp<ViewStyle>;
48
+ /** Style of the scrolling content, applied after the bleed padding and the chip gap. */
49
+ contentContainerStyle?: StyleProp<ViewStyle>;
50
+ testID?: string;
51
+ }
52
+ declare const FilterChipRow: import("react").ForwardRefExoticComponent<FilterChipRowProps & import("react").RefAttributes<RNView>>;
53
+ export { FilterChipRow };
54
+ export default FilterChipRow;
55
+ //# sourceMappingURL=FilterChipRow.d.ts.map
@@ -0,0 +1,3 @@
1
+ export type { FilterChipItem, FilterChipRowProps } from './FilterChipRow';
2
+ export { default, FilterChipRow } from './FilterChipRow';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -8,7 +8,15 @@ export interface FloatingActionButtonProps {
8
8
  /** JSX element for the icon. The FAB sizes it via the `size` prop's iconSize token. */
9
9
  icon: React.ReactNode;
10
10
  onPress: () => void;
11
+ /** Text beside the icon; makes the button extended (a pill). */
11
12
  label?: string;
13
+ /**
14
+ * Folds an extended button to its round icon alone (the size's diameter) with
15
+ * the label fading out, and unfolds it when false. Drive it from scroll state
16
+ * to cover less of the rows moving underneath. Does nothing without a `label`;
17
+ * the accessibility label is unchanged. Independent of `hideOnScroll`.
18
+ */
19
+ collapsed?: boolean;
12
20
  size?: FloatingActionButtonSize;
13
21
  tone?: FloatingActionButtonTone;
14
22
  position?: FloatingActionButtonPosition;
@@ -71,9 +71,15 @@ export interface SignaturePadProps {
71
71
  height?: number;
72
72
  /** Longest typed name. Default 100. */
73
73
  maxNameLength?: number;
74
- /** Ink of the strokes and the typed name. Defaults to the light theme's primary text, in both colour schemes. */
74
+ /**
75
+ * Ink of the strokes and the typed name, on the pad and in `toFile()` and `toSvg()`. With neither
76
+ * `inkColor` nor `paperColor` set, the pad follows the active theme (primary text on the elevated
77
+ * surface), while `toFile()` and `toSvg()` stay the library's dark ink on light paper in every
78
+ * colour scheme so the file is ready for a document. Set one and the other keeps the light
79
+ * theme's colour.
80
+ */
75
81
  inkColor?: string;
76
- /** Ground of the pad and of the PNG. Defaults to the light theme's elevated surface, in both colour schemes. */
82
+ /** Ground of the pad and of the PNG. See `inkColor` for the defaults. */
77
83
  paperColor?: string;
78
84
  /**
79
85
  * Font family of the typed name. Default a system script face: Snell Roundhand on iOS, `cursive`
@@ -0,0 +1,22 @@
1
+ import type { View as RNView, ViewProps } from 'react-native';
2
+ export type SquircleViewProps = ViewProps;
3
+ /**
4
+ * A `View` whose rounded corners are smooth on both platforms, for a surface
5
+ * the library has no component for (a photo tile, a signature pad frame).
6
+ * Give it `borderRadius`, and `backgroundColor` and a border in `style`.
7
+ *
8
+ * iOS draws the continuous curve natively (`borderCurve`). Android draws the
9
+ * fill and border as one SVG path behind the children, with the theme's
10
+ * `cornerSmoothing`, so it matches Box, Card and Button. The view keeps its
11
+ * native corner until it is measured, and where the curve cannot apply: a
12
+ * radius under 6, a pill, a different radius or border per corner or side, a
13
+ * dashed border, `overflow: 'hidden'`, `elevation`, or a colour that is not a
14
+ * string.
15
+ *
16
+ * Children are not clipped to the curve. Use `Card` or `Box` when the surface
17
+ * is a themed card or a spacing container.
18
+ */
19
+ declare const SquircleView: import("react").ForwardRefExoticComponent<ViewProps & import("react").RefAttributes<RNView>>;
20
+ export { SquircleView };
21
+ export default SquircleView;
22
+ //# sourceMappingURL=SquircleView.d.ts.map
@@ -0,0 +1,3 @@
1
+ export type { SquircleViewProps } from './SquircleView';
2
+ export { SquircleView } from './SquircleView';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -68,6 +68,8 @@ export type { FilePickerFile, FilePickerFileState, FilePickerFileStatus, FilePic
68
68
  export { FilePicker, formatFileSize } from './FilePicker';
69
69
  export type { FileViewerProps, FileViewerSource } from './FileViewer';
70
70
  export { FileViewer } from './FileViewer';
71
+ export type { FilterChipItem, FilterChipRowProps } from './FilterChipRow';
72
+ export { FilterChipRow } from './FilterChipRow';
71
73
  export type { FloatingActionButtonGroupAction, FloatingActionButtonGroupProps, FloatingActionButtonPosition, FloatingActionButtonProps, FloatingActionButtonSize, FloatingActionButtonTone } from './FloatingActionButton';
72
74
  export { FloatingActionButton, FloatingActionButtonGroup } from './FloatingActionButton';
73
75
  export type { ForceUpdateDialogProps } from './ForceUpdateDialog';
@@ -160,6 +162,8 @@ export type { SparklineProps, SparklineTone } from './Sparkline';
160
162
  export { Sparkline } from './Sparkline';
161
163
  export type { SpinnerProps, SpinnerSize, SpinnerVariant } from './Spinner';
162
164
  export { Spinner } from './Spinner';
165
+ export type { SquircleViewProps } from './SquircleView';
166
+ export { SquircleView } from './SquircleView';
163
167
  export type { StatTileProps, StatTileTrend } from './StatTile';
164
168
  export { StatTile } from './StatTile';
165
169
  export type { StatusBadgeProps, StatusBadgeSize, StatusBadgeTone, StatusBadgeVariant } from './StatusBadge';
@@ -359,6 +359,10 @@ export interface EmptyStateSizeTokens {
359
359
  descriptionFontSize: keyof TypographyScale['fontSize'];
360
360
  /** Resolves against the active theme's spacing scale. */
361
361
  paddingVertical: keyof SpacingScale;
362
+ /** Space between the icon and the title; a spacing scale key. Library default: "md". */
363
+ titleGap?: keyof SpacingScale;
364
+ /** Space between the title and the description; a spacing scale key. Library default: "xs". */
365
+ descriptionGap?: keyof SpacingScale;
362
366
  }
363
367
  export interface ListItemSizeTokens {
364
368
  /** Resolves against the active theme's spacing scale. */
@@ -1,6 +1,7 @@
1
1
  import type React from 'react';
2
- import type { ImageSourcePropType, ImageStyle, View as RNView, StyleProp, TextStyle, ViewStyle } from 'react-native';
2
+ import type { GestureResponderEvent, ImageSourcePropType, ImageStyle, PressableProps, View as RNView, StyleProp, TextStyle, ViewStyle } from 'react-native';
3
3
  import type { Theme } from '../../theme/types.js';
4
+ import type { HapticType } from '../../utils/hapticUtils.js';
4
5
  /**
5
6
  * Props passed to a custom {@link AvatarProps.ImageComponent}. The built-in
6
7
  * image is expo-image's `Image`, and both it (`contentFit`) and React Native's
@@ -72,7 +73,30 @@ export interface AvatarProps {
72
73
  * when data arrives. Use this while the data driving the component is being fetched.
73
74
  */
74
75
  loading?: boolean;
76
+ /**
77
+ * Accessible name. The default is `"<name>'s avatar"`, or the name alone
78
+ * when the avatar is pressable.
79
+ */
75
80
  accessibilityLabel?: string;
81
+ /**
82
+ * Makes the avatar a button: it is announced as one, dims while pressed and
83
+ * fires the haptic. Pass it to open a profile or a photo menu. Ignored
84
+ * while `loading`.
85
+ */
86
+ onPress?: (event: GestureResponderEvent) => void;
87
+ /** Long press; also makes the avatar a button. The `longPress` haptic fires first. */
88
+ onLongPress?: (event: GestureResponderEvent) => void;
89
+ /**
90
+ * Haptic on a press (default `'selection'`) and a long press (default
91
+ * `'longPress'`). A type replaces both; `false` turns both off. Only a
92
+ * pressable avatar fires one.
93
+ */
94
+ haptic?: HapticType | false;
95
+ /**
96
+ * Extra touch area of a pressable avatar. Unset, it grows the avatar to
97
+ * 44 points on each side, so `xs` and `sm` stay easy to hit.
98
+ */
99
+ hitSlop?: PressableProps['hitSlop'];
76
100
  style?: StyleProp<ViewStyle>;
77
101
  textStyle?: StyleProp<TextStyle>;
78
102
  testID?: string;
@@ -11,14 +11,25 @@ import type { SlotIcon } from '../AppIcon/slotIcon.js';
11
11
  export type ChipVariant = 'filled' | 'outlined' | 'soft';
12
12
  export type ChipTone = 'primary' | 'neutral' | 'success' | 'warning' | 'error' | 'info';
13
13
  export type ChipSize = 'sm' | 'md';
14
- export type ChipSelectionMode = 'single' | 'multiple';
14
+ export type ChipSelectionMode = 'single' | 'multiple' | 'radio';
15
15
  export interface ChipProps {
16
16
  label: string;
17
+ /**
18
+ * A figure after the label, drawn quieter than it (regular weight, caption
19
+ * size, tabular digits): "Open" with `count={4}`. `0` is shown; `undefined`
20
+ * and an empty string draw nothing, so a count still loading leaves the
21
+ * label alone. The accessibility label becomes "Open, 4" unless
22
+ * `accessibilityLabel` is set.
23
+ */
24
+ count?: number | string;
17
25
  selected?: boolean;
18
26
  /**
19
27
  * How a pressable chip announces itself. `'single'` (default) is a button
20
28
  * with a selected state; `'multiple'` is a checkbox whose checked state
21
- * follows `selected`, for chips that toggle independently.
29
+ * follows `selected`, for chips that toggle independently; `'radio'` is a
30
+ * radio whose checked state follows `selected`, for one-of-many chips inside
31
+ * a radiogroup. A disabled `'radio'` chip with an `onPress` stays a radio
32
+ * (announced disabled) instead of falling back to plain text.
22
33
  */
23
34
  selectionMode?: ChipSelectionMode;
24
35
  onPress?: () => void;
@@ -51,6 +62,8 @@ export interface ChipProps {
51
62
  textStyle?: StyleProp<TextStyle>;
52
63
  /** Style override for the chip outer container (alias to style, applied after). */
53
64
  containerStyle?: StyleProp<ViewStyle>;
65
+ /** Style override for the count text. */
66
+ countStyle?: StyleProp<TextStyle>;
54
67
  /** Style override for the close (×) button pressable. */
55
68
  closeButtonStyle?: StyleProp<ViewStyle>;
56
69
  /** Style override for the close (×) glyph text. */
@@ -4,9 +4,16 @@ import type { TextColor } from '../Text/Text.js';
4
4
  export type DescriptionsSize = 'sm' | 'md';
5
5
  export type DescriptionsVariant = 'list' | 'summary';
6
6
  export interface DescriptionItem {
7
- /** A string renders as text; a node (a symbol with a subscript, say) renders as-is. */
7
+ /**
8
+ * A string renders as text. A node (a symbol with a subscript, say) sits in the label's Text, so
9
+ * its base and subscript take the label's size and colour; a string inside a node list is fine.
10
+ */
8
11
  label: React.ReactNode;
9
- /** A string renders as text; a node renders as-is. Empty renders as a plain hyphen, "-". */
12
+ /**
13
+ * A string, a number, a `sym()` / `Notation` or a list of those renders as text in the value's
14
+ * size, weight and colour (`strong`, `tone`), the subscript included. Any other node (a badge, a
15
+ * Text of your own) renders as-is in a View and owns its type. Empty renders as a plain hyphen, "-".
16
+ */
10
17
  value?: React.ReactNode;
11
18
  /** Make this row span both columns. Ignored when `columns` is 1. */
12
19
  full?: boolean;
@@ -20,22 +20,33 @@ export interface FileViewerProps {
20
20
  onError?: (error: Error) => void;
21
21
  /** Replaces the default themed spinner shown while the document loads. */
22
22
  loadingIndicator?: () => React.ReactNode;
23
+ /** Pinch, double-tap zoom and pan while zoomed. Default true. */
24
+ zoomEnabled?: boolean;
25
+ /** Upper bound on pinch zoom, as a multiple of the page fitting the width. Default 4. */
26
+ maxZoom?: number;
23
27
  style?: StyleProp<ViewStyle>;
24
28
  testID?: string;
25
29
  accessibilityLabel?: string;
26
30
  }
27
31
  /**
28
32
  * Renders a PDF via our own native rasterizer (Core Graphics on iOS, PdfRenderer on
29
- * Android) — no third-party PDF dependency. Pages are paged through a plain
30
- * `ScrollView` with manual windowed mounting (render the visible page ±
31
- * `RENDER_WINDOW`), not a `FlatList` — a `VirtualizedList`-based component
32
- * would trip React Native's "VirtualizedLists should never be nested inside
33
- * plain ScrollViews" the moment a consumer embeds FileViewer in their own
34
- * scrolling screen, which is a completely ordinary way to use it. Avoiding the
35
- * VirtualizedList primitive entirely removes that whole class of warning
36
- * rather than working around one instance of it. The WebView fallback
37
- * consumer apps use for non-PDF office documents is a distinct rendering
38
- * strategy and stays app-side.
33
+ * Android), with no third-party PDF dependency. Pages are paged through a plain
34
+ * `ScrollView` with manual windowed mounting, not a `FlatList`: a
35
+ * `VirtualizedList`-based component would trip React Native's "VirtualizedLists
36
+ * should never be nested inside plain ScrollViews" the moment a consumer embeds
37
+ * FileViewer in their own scrolling screen, which is a completely ordinary way to
38
+ * use it. Avoiding the VirtualizedList primitive entirely removes that whole class
39
+ * of warning rather than working around one instance of it. The WebView fallback
40
+ * consumer apps use for non-PDF office documents is a distinct rendering strategy
41
+ * and stays app-side.
42
+ *
43
+ * Pages render one at a time, nearest the reader first, `RENDER_AHEAD` each way,
44
+ * and their files are kept, so scrolling back or ahead never lands on a blank
45
+ * page; only `MOUNT_AROUND` pages each side decode their image. Pinch zooms around
46
+ * the fingers and a double tap zooms in on the tap or back out; the transform sits
47
+ * on the whole scroll view, so while zoomed a one-finger drag pans and, past the
48
+ * zoomed page's top or bottom edge, carries on into the document's scroll. A
49
+ * settled zoom re-renders the page in view at the sharper scale it needs.
39
50
  */
40
51
  export declare const FileViewer: React.FC<FileViewerProps>;
41
52
  export default FileViewer;
@@ -0,0 +1,12 @@
1
+ import type React from 'react';
2
+ export interface FileViewerPageProps {
3
+ width: number;
4
+ height: number;
5
+ /** The rendered page file: `undefined` while it renders, `null` when it failed to render. */
6
+ uri: string | null | undefined;
7
+ /** Only pages near the reader decode their image, so memory stays flat on a long document. */
8
+ mounted: boolean;
9
+ renderLoading: () => React.ReactNode;
10
+ }
11
+ export declare const FileViewerPage: React.NamedExoticComponent<FileViewerPageProps>;
12
+ //# sourceMappingURL=FileViewerPage.d.ts.map
@@ -0,0 +1,41 @@
1
+ /** A zoom that ends at or below this counts as none and springs back to 1x. */
2
+ export declare const ZOOM_REST = 1.01;
3
+ interface UseFileViewerZoomOptions {
4
+ zoomEnabled: boolean;
5
+ maxZoom: number;
6
+ viewportWidth: number;
7
+ viewportHeight: number;
8
+ /** The furthest the document scrolls, so a pan carried into the scroll stops at the end. */
9
+ maxScroll: number;
10
+ }
11
+ /**
12
+ * FileViewer's zoom: a scale and translate on the whole scroll view, so the
13
+ * maths stays in viewport space. Pinch zooms around the fingers, a double tap
14
+ * zooms in on the tap or back out, and while zoomed a one-finger drag pans and,
15
+ * past the zoomed page's top or bottom edge, carries on into the document's
16
+ * scroll. `zoomLevel` reaches React only when a gesture settles, never per frame.
17
+ */
18
+ export declare const useFileViewerZoom: ({ zoomEnabled, maxZoom, viewportWidth, viewportHeight, maxScroll }: UseFileViewerZoomOptions) => {
19
+ scrollRef: import("react-native-reanimated").AnimatedRef<import("react-native").ReactNativeElement>;
20
+ scrollGesture: import("react-native-gesture-handler/lib/typescript/handlers/gestures/nativeGesture").NativeGesture;
21
+ zoomGesture: import("react-native-gesture-handler/lib/typescript/handlers/gestures/gestureComposition").SimultaneousGesture;
22
+ zoomStyle: import("react-native-reanimated/lib/typescript/hook/commonTypes").AnimatedStyleHandle<{
23
+ transform: ({
24
+ translateX: number;
25
+ translateY?: undefined;
26
+ scale?: undefined;
27
+ } | {
28
+ translateY: number;
29
+ translateX?: undefined;
30
+ scale?: undefined;
31
+ } | {
32
+ scale: number;
33
+ translateX?: undefined;
34
+ translateY?: undefined;
35
+ })[];
36
+ }>;
37
+ zoomLevel: number;
38
+ resetZoom: () => void;
39
+ };
40
+ export {};
41
+ //# sourceMappingURL=useFileViewerZoom.d.ts.map
@@ -0,0 +1,55 @@
1
+ /**
2
+ * FilterChipRow: a horizontal row of single-choice filter chips, each with an
3
+ * optional count ("Open 4"), above a list.
4
+ *
5
+ * The row scrolls edge to edge: `bleed` pulls it out by the page gutter on both
6
+ * sides and pads its content by the same amount, so the first chip lines up
7
+ * with the page content and the row still runs to the screen edge. Choosing a
8
+ * chip scrolls the row to centre it, so one past the screen edge never stays
9
+ * out of sight. The first placement is not animated; later ones glide, unless
10
+ * the OS asks for reduced motion.
11
+ *
12
+ * Accessibility is a radiogroup of radios, like SegmentedControl and
13
+ * ChoiceGroup: a filter picks a value on the same data. Sections of a screen
14
+ * are `Tabs`, not this.
15
+ */
16
+ import type { View as RNView, StyleProp, ViewStyle } from 'react-native';
17
+ import type { HapticType } from '../../utils/index.js';
18
+ import type { ChipSize, ChipTone, ChipVariant } from '../Chip/index.js';
19
+ export interface FilterChipItem {
20
+ /** Stable id of the chip; `value` and `onChange` carry it. */
21
+ key: string;
22
+ label: string;
23
+ /** Shown after the label; leave it undefined while it loads and the label shows alone. */
24
+ count?: number | string;
25
+ disabled?: boolean;
26
+ }
27
+ export interface FilterChipRowProps {
28
+ items: ReadonlyArray<FilterChipItem>;
29
+ /** Key of the selected item. */
30
+ value: string;
31
+ /** Fired with the key of a chip the person picks. Not fired for the chip that is already selected. */
32
+ onChange: (key: string) => void;
33
+ /**
34
+ * The page gutter in points. The row extends this far past its parent on
35
+ * both sides and pads its content by the same amount. The theme carries no
36
+ * screen gutter, so the default is 0 (the row stays inside its parent).
37
+ */
38
+ bleed?: number;
39
+ size?: ChipSize;
40
+ variant?: ChipVariant;
41
+ tone?: ChipTone;
42
+ /** Haptic feedback for interactions. Pass false to disable; pass a HapticType to override the default. */
43
+ haptic?: HapticType | false;
44
+ /** Names the radiogroup for screen readers, e.g. "Filter by status". */
45
+ accessibilityLabel?: string;
46
+ /** Style of the outer view, applied after the bleed margin. */
47
+ style?: StyleProp<ViewStyle>;
48
+ /** Style of the scrolling content, applied after the bleed padding and the chip gap. */
49
+ contentContainerStyle?: StyleProp<ViewStyle>;
50
+ testID?: string;
51
+ }
52
+ declare const FilterChipRow: import("react").ForwardRefExoticComponent<FilterChipRowProps & import("react").RefAttributes<RNView>>;
53
+ export { FilterChipRow };
54
+ export default FilterChipRow;
55
+ //# sourceMappingURL=FilterChipRow.d.ts.map
@@ -0,0 +1,3 @@
1
+ export type { FilterChipItem, FilterChipRowProps } from './FilterChipRow.js';
2
+ export { default, FilterChipRow } from './FilterChipRow.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -8,7 +8,15 @@ export interface FloatingActionButtonProps {
8
8
  /** JSX element for the icon. The FAB sizes it via the `size` prop's iconSize token. */
9
9
  icon: React.ReactNode;
10
10
  onPress: () => void;
11
+ /** Text beside the icon; makes the button extended (a pill). */
11
12
  label?: string;
13
+ /**
14
+ * Folds an extended button to its round icon alone (the size's diameter) with
15
+ * the label fading out, and unfolds it when false. Drive it from scroll state
16
+ * to cover less of the rows moving underneath. Does nothing without a `label`;
17
+ * the accessibility label is unchanged. Independent of `hideOnScroll`.
18
+ */
19
+ collapsed?: boolean;
12
20
  size?: FloatingActionButtonSize;
13
21
  tone?: FloatingActionButtonTone;
14
22
  position?: FloatingActionButtonPosition;
@@ -71,9 +71,15 @@ export interface SignaturePadProps {
71
71
  height?: number;
72
72
  /** Longest typed name. Default 100. */
73
73
  maxNameLength?: number;
74
- /** Ink of the strokes and the typed name. Defaults to the light theme's primary text, in both colour schemes. */
74
+ /**
75
+ * Ink of the strokes and the typed name, on the pad and in `toFile()` and `toSvg()`. With neither
76
+ * `inkColor` nor `paperColor` set, the pad follows the active theme (primary text on the elevated
77
+ * surface), while `toFile()` and `toSvg()` stay the library's dark ink on light paper in every
78
+ * colour scheme so the file is ready for a document. Set one and the other keeps the light
79
+ * theme's colour.
80
+ */
75
81
  inkColor?: string;
76
- /** Ground of the pad and of the PNG. Defaults to the light theme's elevated surface, in both colour schemes. */
82
+ /** Ground of the pad and of the PNG. See `inkColor` for the defaults. */
77
83
  paperColor?: string;
78
84
  /**
79
85
  * Font family of the typed name. Default a system script face: Snell Roundhand on iOS, `cursive`
@@ -0,0 +1,22 @@
1
+ import type { View as RNView, ViewProps } from 'react-native';
2
+ export type SquircleViewProps = ViewProps;
3
+ /**
4
+ * A `View` whose rounded corners are smooth on both platforms, for a surface
5
+ * the library has no component for (a photo tile, a signature pad frame).
6
+ * Give it `borderRadius`, and `backgroundColor` and a border in `style`.
7
+ *
8
+ * iOS draws the continuous curve natively (`borderCurve`). Android draws the
9
+ * fill and border as one SVG path behind the children, with the theme's
10
+ * `cornerSmoothing`, so it matches Box, Card and Button. The view keeps its
11
+ * native corner until it is measured, and where the curve cannot apply: a
12
+ * radius under 6, a pill, a different radius or border per corner or side, a
13
+ * dashed border, `overflow: 'hidden'`, `elevation`, or a colour that is not a
14
+ * string.
15
+ *
16
+ * Children are not clipped to the curve. Use `Card` or `Box` when the surface
17
+ * is a themed card or a spacing container.
18
+ */
19
+ declare const SquircleView: import("react").ForwardRefExoticComponent<ViewProps & import("react").RefAttributes<RNView>>;
20
+ export { SquircleView };
21
+ export default SquircleView;
22
+ //# sourceMappingURL=SquircleView.d.ts.map