@isoline-ui/react-native 0.0.0-stage → 1.0.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 (167) hide show
  1. package/LICENSE +22 -0
  2. package/NOTICE.md +12 -0
  3. package/README.md +104 -3
  4. package/dist/amount.d.ts +3 -0
  5. package/dist/calendar.d.ts +7 -0
  6. package/dist/components/action-chip.d.ts +9 -0
  7. package/dist/components/amount-field.d.ts +12 -0
  8. package/dist/components/avatar.d.ts +17 -0
  9. package/dist/components/back-button.d.ts +12 -0
  10. package/dist/components/back-icon.d.ts +3 -0
  11. package/dist/components/badge.d.ts +13 -0
  12. package/dist/components/banner.d.ts +14 -0
  13. package/dist/components/bottom-sheet-native.d.ts +11 -0
  14. package/dist/components/bottom-sheet-web.d.ts +18 -0
  15. package/dist/components/bottom-sheet.d.ts +3 -0
  16. package/dist/components/button-group.d.ts +26 -0
  17. package/dist/components/button.d.ts +48 -0
  18. package/dist/components/checkbox.d.ts +12 -0
  19. package/dist/components/color-picker.d.ts +21 -0
  20. package/dist/components/context-menu.d.ts +26 -0
  21. package/dist/components/date-picker.d.ts +64 -0
  22. package/dist/components/dialog-context.d.ts +2 -0
  23. package/dist/components/dialog.d.ts +20 -0
  24. package/dist/components/empty-state.d.ts +15 -0
  25. package/dist/components/expand-indicator.d.ts +27 -0
  26. package/dist/components/expressive-shape.d.ts +18 -0
  27. package/dist/components/fab-menu-legacy.d.ts +31 -0
  28. package/dist/components/fab-menu.d.ts +21 -0
  29. package/dist/components/filter-chip.d.ts +69 -0
  30. package/dist/components/floating-action-button.d.ts +15 -0
  31. package/dist/components/icon-button.d.ts +40 -0
  32. package/dist/components/icons.d.ts +18 -0
  33. package/dist/components/input.d.ts +9 -0
  34. package/dist/components/keyboard-inset-view.d.ts +15 -0
  35. package/dist/components/list-controls.d.ts +38 -0
  36. package/dist/components/loading-indicator.d.ts +9 -0
  37. package/dist/components/menu-sheet.d.ts +36 -0
  38. package/dist/components/panel-sheet.d.ts +8 -0
  39. package/dist/components/password-visibility.d.ts +5 -0
  40. package/dist/components/popover-layout.d.ts +25 -0
  41. package/dist/components/popover.d.ts +20 -0
  42. package/dist/components/pressable.d.ts +12 -0
  43. package/dist/components/radio-navigation.d.ts +11 -0
  44. package/dist/components/refresh-control.d.ts +16 -0
  45. package/dist/components/row-gap.d.ts +9 -0
  46. package/dist/components/search-field.d.ts +22 -0
  47. package/dist/components/select-field.d.ts +16 -0
  48. package/dist/components/settings-list.d.ts +98 -0
  49. package/dist/components/settings-row.d.ts +13 -0
  50. package/dist/components/sheet-frame.d.ts +27 -0
  51. package/dist/components/sheet-lifecycle.d.ts +36 -0
  52. package/dist/components/sheet-transition.d.ts +36 -0
  53. package/dist/components/slider.d.ts +21 -0
  54. package/dist/components/snackbar.d.ts +10 -0
  55. package/dist/components/split-button.d.ts +38 -0
  56. package/dist/components/squish.d.ts +20 -0
  57. package/dist/components/swipeable-row.d.ts +20 -0
  58. package/dist/components/switch.d.ts +8 -0
  59. package/dist/components/tab-bar.d.ts +20 -0
  60. package/dist/components/text-field.d.ts +31 -0
  61. package/dist/components/text.d.ts +9 -0
  62. package/dist/components/time-picker.d.ts +40 -0
  63. package/dist/components/toolbar.d.ts +77 -0
  64. package/dist/components/top-bar.d.ts +27 -0
  65. package/dist/components/undo-bar.d.ts +23 -0
  66. package/dist/components/wavy-progress.d.ts +21 -0
  67. package/dist/components/zoomable-image.d.ts +18 -0
  68. package/dist/expressive-shapes.d.ts +8 -0
  69. package/dist/index.d.ts +62 -0
  70. package/dist/keyboard.d.ts +2 -0
  71. package/dist/material.d.ts +11 -0
  72. package/dist/media.d.ts +11 -0
  73. package/dist/motion.d.ts +96 -0
  74. package/dist/platform.d.ts +3 -0
  75. package/dist/preset-tokens.d.ts +264 -0
  76. package/dist/provider.d.ts +59 -0
  77. package/dist/reduced-motion.d.ts +45 -0
  78. package/dist/selection.d.ts +2 -0
  79. package/dist/shape.d.ts +99 -0
  80. package/dist/sheet-physics.d.ts +37 -0
  81. package/dist/theme.d.ts +103 -0
  82. package/dist/tokens.d.ts +2 -0
  83. package/dist/use-keyboard-height.d.ts +10 -0
  84. package/dist/utils.d.ts +3 -0
  85. package/nativewind.cjs +68 -0
  86. package/package.json +63 -6
  87. package/src/amount.ts +53 -0
  88. package/src/calendar.ts +42 -0
  89. package/src/components/action-chip.tsx +64 -0
  90. package/src/components/amount-field.tsx +49 -0
  91. package/src/components/avatar.tsx +91 -0
  92. package/src/components/back-button.tsx +39 -0
  93. package/src/components/back-icon.tsx +25 -0
  94. package/src/components/badge.tsx +41 -0
  95. package/src/components/banner.tsx +63 -0
  96. package/src/components/bottom-sheet-native.tsx +52 -0
  97. package/src/components/bottom-sheet-web.tsx +193 -0
  98. package/src/components/bottom-sheet.tsx +5 -0
  99. package/src/components/button-group.tsx +326 -0
  100. package/src/components/button.tsx +337 -0
  101. package/src/components/checkbox.tsx +71 -0
  102. package/src/components/color-picker.tsx +115 -0
  103. package/src/components/context-menu.tsx +149 -0
  104. package/src/components/date-picker.tsx +466 -0
  105. package/src/components/dialog-context.ts +3 -0
  106. package/src/components/dialog.tsx +210 -0
  107. package/src/components/empty-state.tsx +49 -0
  108. package/src/components/expand-indicator.tsx +60 -0
  109. package/src/components/expressive-shape.tsx +37 -0
  110. package/src/components/fab-menu-legacy.tsx +181 -0
  111. package/src/components/fab-menu.tsx +90 -0
  112. package/src/components/filter-chip.tsx +136 -0
  113. package/src/components/floating-action-button.tsx +79 -0
  114. package/src/components/icon-button.tsx +127 -0
  115. package/src/components/icons.tsx +43 -0
  116. package/src/components/input.tsx +80 -0
  117. package/src/components/keyboard-inset-view.tsx +28 -0
  118. package/src/components/list-controls.tsx +134 -0
  119. package/src/components/loading-indicator.tsx +183 -0
  120. package/src/components/menu-sheet.tsx +133 -0
  121. package/src/components/panel-sheet.tsx +90 -0
  122. package/src/components/password-visibility.tsx +39 -0
  123. package/src/components/popover-layout.ts +47 -0
  124. package/src/components/popover.tsx +139 -0
  125. package/src/components/pressable.tsx +108 -0
  126. package/src/components/radio-navigation.ts +52 -0
  127. package/src/components/refresh-control.tsx +39 -0
  128. package/src/components/row-gap.tsx +13 -0
  129. package/src/components/search-field.tsx +92 -0
  130. package/src/components/select-field.tsx +105 -0
  131. package/src/components/settings-list.tsx +302 -0
  132. package/src/components/settings-row.tsx +61 -0
  133. package/src/components/sheet-frame.tsx +250 -0
  134. package/src/components/sheet-lifecycle.ts +233 -0
  135. package/src/components/sheet-transition.ts +105 -0
  136. package/src/components/slider.tsx +185 -0
  137. package/src/components/snackbar.tsx +97 -0
  138. package/src/components/split-button.tsx +212 -0
  139. package/src/components/squish.ts +41 -0
  140. package/src/components/swipeable-row.tsx +109 -0
  141. package/src/components/switch.tsx +77 -0
  142. package/src/components/tab-bar.tsx +195 -0
  143. package/src/components/text-field.tsx +264 -0
  144. package/src/components/text.tsx +58 -0
  145. package/src/components/time-picker.tsx +277 -0
  146. package/src/components/toolbar.tsx +406 -0
  147. package/src/components/top-bar.tsx +91 -0
  148. package/src/components/undo-bar.tsx +137 -0
  149. package/src/components/wavy-progress.tsx +150 -0
  150. package/src/components/zoomable-image.tsx +240 -0
  151. package/src/expressive-shapes.ts +25 -0
  152. package/src/index.ts +62 -0
  153. package/src/keyboard.ts +5 -0
  154. package/src/material.ts +16 -0
  155. package/src/media.ts +51 -0
  156. package/src/motion.ts +96 -0
  157. package/src/platform.ts +13 -0
  158. package/src/preset-tokens.ts +265 -0
  159. package/src/provider.tsx +201 -0
  160. package/src/reduced-motion.ts +50 -0
  161. package/src/selection.ts +11 -0
  162. package/src/shape.ts +217 -0
  163. package/src/sheet-physics.ts +73 -0
  164. package/src/theme.ts +180 -0
  165. package/src/tokens.ts +2 -0
  166. package/src/use-keyboard-height.ts +64 -0
  167. package/src/utils.ts +7 -0
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Isoline UI contributors
4
+ Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/NOTICE.md ADDED
@@ -0,0 +1,12 @@
1
+ # Source notices
2
+
3
+ The initial primitives were extracted with the owner's authorisation from the
4
+ UI code maintained for Yours, Inboki and Atlas. Product data, credentials,
5
+ artwork and feature code are not included.
6
+
7
+ The existing MIT notice for 650 Industries, Inc. (Expo) is retained in LICENSE.
8
+ Isoline-specific functional glyphs use simple original SVG paths. App-specific
9
+ Material Symbols icon collections and brand fonts are not bundled.
10
+
11
+ Runtime packages remain subject to their respective licences. Apps consuming
12
+ Isoline should regenerate their dependency licence notices after integration.
package/README.md CHANGED
@@ -1,3 +1,104 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
1
+ # @isoline-ui/react-native
2
+
3
+ Expressive shared UI with platform-aware interaction. Initial alpha distributed through GitHub Releases; not published to npm. The package name does not reserve the npm organisation.
4
+
5
+ ## Install the test release
6
+
7
+ ```sh
8
+ npm install https://github.com/isoline-ui/isoline-ui/releases/download/v0.1.0-alpha.0/isoline-ui-react-native-0.1.0-alpha.0.tgz
9
+ ```
10
+
11
+ The URL is versioned and the package imports as `@isoline-ui/react-native`.
12
+
13
+ ## Consumer setup
14
+
15
+ Install the package and the peer dependencies
16
+ matching your Expo SDK. Use `npx expo install` for native peers; do not install
17
+ a second React or React Native runtime.
18
+
19
+ Keep the usual NativeWind Babel/Metro configuration. Add the Isoline preset and
20
+ package source to Tailwind's content scan:
21
+
22
+ ```js
23
+ const path = require('node:path');
24
+ const ui = path.dirname(require.resolve('@isoline-ui/react-native/package.json'));
25
+
26
+ module.exports = {
27
+ presets: [require('@isoline-ui/react-native/nativewind')],
28
+ content: ['./app/**/*.{ts,tsx}', './src/**/*.{ts,tsx}', path.join(ui, 'src/**/*.{ts,tsx}')],
29
+ };
30
+ ```
31
+
32
+ Do not overwrite an app's custom fonts or additional semantic roles; extend
33
+ the preset in the consumer. Atlas loads its fonts itself.
34
+
35
+ ```tsx
36
+ import { IsolineProvider, Button, themes } from '@isoline-ui/react-native';
37
+
38
+ export function App() {
39
+ return (
40
+ <IsolineProvider theme={themes.violet.light} labels={{ close: 'Schließen' }}>
41
+ <Button
42
+ label="Speichern"
43
+ onPress={() => {
44
+ /* app action */
45
+ }}
46
+ />
47
+ </IsolineProvider>
48
+ );
49
+ }
50
+ ```
51
+
52
+ Place the provider inside the app's SafeAreaProvider and GestureHandlerRootView.
53
+ It paints CSS roles for NativeWind and supplies matching colours for native/SVG
54
+ props. Use a theme matching the app's light/dark preference.
55
+
56
+ `extendTheme` returns a new theme from token and typography overrides. Token
57
+ values are HSL channel triplets, not full CSS colour expressions. Dynamic
58
+ Material You roles and Yours' text preferences still require app adapters.
59
+
60
+ Haptics are opt-in: pass `haptics={{ selectionHaptic, impactHaptic }}` from the
61
+ app so its saved preference is honoured. Labels are similarly supplied from
62
+ the app's translations. There is no navigation or persistence dependency.
63
+
64
+ ## Packaging
65
+
66
+ `react-native` and default exports point to TypeScript source for Metro.
67
+ `types` point to generated declarations. This is a React Native/Metro package;
68
+ plain Node/browser UI imports are not a supported distribution target.
69
+ Pure helpers can be imported from `@isoline-ui/react-native/tokens`.
70
+
71
+ The package intentionally does not install Expo, native runtimes, app fonts
72
+ or native model/scanner integrations. Native dependency changes require a
73
+ new native app build, not only an OTA update.
74
+
75
+ ## iOS, Android and browsers
76
+
77
+ Controls follow the native OS automatically. The `platform="ios" | "android"`
78
+ provider prop selects a browser preview style and is inherited by nested providers;
79
+ it never changes the native device platform. Use Expo web with React Native Web,
80
+ React DOM, NativeWind and the normal native peers. The repository showcase includes
81
+ `npm run web --workspace isoline-showcase` and `export:web`.
82
+
83
+ Register `surfaceComponent={MaterialSurface}` and
84
+ `surfaceGroupComponent={MaterialGroup}` on `IsolineProvider` using the optional
85
+ `@isoline-ui/native` adapters. Core UI works without Expo using solid fallbacks.
86
+
87
+ The shared `MaterialOptions` contract (`material`, `glassStyle`, `tintColor`,
88
+ `fallbackColor`, `interactive`) supports buttons/icon buttons, search, segmented
89
+ controls, pickers, floating/split actions, toolbars, navigation, tabs, popovers,
90
+ context menus and optional overlay surfaces. `TabBar` is controlled; routing
91
+ remains in the app. `Popover` anchors, flips and clamps a scrollable panel.
92
+ Context menus and pickers support disabled and selected options. Action menus
93
+ also support destructive actions.
94
+
95
+ Navigation and anchored menus default to automatic material. Form/action controls,
96
+ dialogs, sheets and snackbars default to solid; opt in per surface. Android stays
97
+ solid Material UI. iOS uses native glass where available and respects Reduce
98
+ Transparency. `SurfaceGroup` uses native `GlassContainer` to blend nearby glass
99
+ surfaces and can animate `gap`, respecting reduced motion. Browser groups animate
100
+ spacing only: CSS backdrop blur approximates glass without native merging or
101
+ refraction. Use a contrasting background to make translucency visible.
102
+
103
+ The new controls require native/device verification in consumer builds; browser
104
+ checks and Metro exports do not verify UIKit rendering or accessibility.
@@ -0,0 +1,3 @@
1
+ /** Parse a locale-formatted editing value; invalid/partial input stays null. */
2
+ export declare function parseLocalizedAmount(input: string, locale?: string): number | null;
3
+ export declare function formatLocalizedAmount(value: number, locale?: string, fractionDigits?: number): string;
@@ -0,0 +1,7 @@
1
+ /** Gregorian local-date values. UTC arithmetic avoids DST changes and host time zones. */
2
+ export declare function validDate(value: string): boolean;
3
+ export declare function addDays(value: string, amount: number): string;
4
+ export declare function addMonths(month: string, amount: number): string;
5
+ export declare function monthDays(month: string, firstDayOfWeek?: number): string[];
6
+ export declare function formatCalendarDate(date: string, locale?: string, options?: Intl.DateTimeFormatOptions): string;
7
+ export declare function validTime(value: string): boolean;
@@ -0,0 +1,9 @@
1
+ import * as React from 'react';
2
+ import { type ButtonProps } from './button.tsx';
3
+ import type { IconProps } from './icons.tsx';
4
+ export interface ActionChipProps extends Omit<ButtonProps, 'children' | 'icon' | 'label' | 'variant' | 'size'> {
5
+ label: string;
6
+ icon?: React.ComponentType<IconProps>;
7
+ tone?: 'neutral' | 'primary' | 'secondary' | 'tertiary';
8
+ }
9
+ export declare function ActionChip({ label, icon: Icon, tone, style, ...props }: ActionChipProps): React.JSX.Element;
@@ -0,0 +1,12 @@
1
+ import * as React from 'react';
2
+ import { TextInput } from 'react-native';
3
+ import { type TextFieldProps } from './text-field.tsx';
4
+ export interface AmountFieldProps extends Omit<TextFieldProps, 'value' | 'onChangeText'> {
5
+ value: string;
6
+ onChangeText: (value: string) => void;
7
+ onAmountChange?: (amount: number | null) => void;
8
+ currency?: string | null;
9
+ locale?: string;
10
+ }
11
+ /** Preserve the editing string, including incomplete decimals; report numeric units separately. */
12
+ export declare const AmountField: React.ForwardRefExoticComponent<AmountFieldProps & React.RefAttributes<React.ElementRef<typeof TextInput>>>;
@@ -0,0 +1,17 @@
1
+ import * as React from 'react';
2
+ import { type ImageSourcePropType, type StyleProp, type ViewStyle } from 'react-native';
3
+ export interface AvatarProps {
4
+ accessibilityLabel: string;
5
+ initials?: string;
6
+ source?: ImageSourcePropType;
7
+ size?: number;
8
+ color?: string;
9
+ foregroundColor?: string;
10
+ accent?: string;
11
+ badge?: React.ReactNode;
12
+ renderImage?: (size: number, onError: () => void) => React.ReactNode;
13
+ style?: StyleProp<ViewStyle>;
14
+ className?: string;
15
+ }
16
+ /** Image rendering and initials only: no address book, network lookup or app preference. */
17
+ export declare function Avatar({ accessibilityLabel, initials, source, size, color, foregroundColor, accent, badge, renderImage, style, className, }: AvatarProps): React.JSX.Element;
@@ -0,0 +1,12 @@
1
+ export interface BackButtonProps {
2
+ onPress: () => void;
3
+ /** What the row leads back to, e.g. "Inbox", "Settings". Defaults to "Back". */
4
+ label?: string;
5
+ }
6
+ /**
7
+ * The `< Back` row every screen opens with.
8
+ *
9
+ * The arrow is drawn at the header icon size, so it matches the bare back
10
+ * arrow of the screens that use a top bar instead (the reader, compose).
11
+ */
12
+ export declare function BackButton({ onPress, label }: BackButtonProps): import("react").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import { type IconProps } from './icons.tsx';
2
+ /** Navigation uses the iOS chevron; directional/content arrows stay unchanged. */
3
+ export declare function BackIcon({ size, color, style, ...props }: IconProps): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import * as React from 'react';
2
+ export interface BadgeProps {
3
+ label: string;
4
+ /**
5
+ * Tints the pill and its text, for a badge that stands for something with a
6
+ * colour of its own — a tag. Left unset, the badge is the neutral container
7
+ * colour a folder name gets.
8
+ */
9
+ color?: string;
10
+ className?: string;
11
+ }
12
+ /** A small pill label, such as a folder name sitting beside a message count. */
13
+ export declare function Badge({ label, color, className }: BadgeProps): React.JSX.Element;
@@ -0,0 +1,14 @@
1
+ import * as React from 'react';
2
+ import { type IconProps } from './icons.tsx';
3
+ export interface BannerProps {
4
+ message: string;
5
+ title?: string;
6
+ tone?: 'neutral' | 'info' | 'error';
7
+ icon?: React.ComponentType<IconProps>;
8
+ actionLabel?: string;
9
+ onAction?: () => void;
10
+ onDismiss?: () => void;
11
+ dismissLabel?: string;
12
+ }
13
+ export declare function Banner({ message, title, tone, icon: Icon, actionLabel, onAction, onDismiss, dismissLabel, }: BannerProps): React.JSX.Element;
14
+ export declare const InlineNotice: typeof Banner;
@@ -0,0 +1,11 @@
1
+ import * as React from 'react';
2
+ import { type DimensionValue } from 'react-native';
3
+ import { type MaterialOptions } from '../provider.tsx';
4
+ export interface BottomSheetProps extends MaterialOptions {
5
+ visible: boolean;
6
+ onClose: () => void;
7
+ maxHeight?: DimensionValue;
8
+ onShow?: () => void;
9
+ children: React.ReactNode;
10
+ }
11
+ export declare function BottomSheet({ visible, onClose, maxHeight, onShow, children, ...materialOptions }: BottomSheetProps): React.JSX.Element;
@@ -0,0 +1,18 @@
1
+ import * as React from 'react';
2
+ import { type DimensionValue } from 'react-native';
3
+ import { type MaterialOptions } from '../provider.tsx';
4
+ export interface BottomSheetProps extends MaterialOptions {
5
+ visible: boolean;
6
+ onClose: () => void;
7
+ /** Caps long lists; the default leaves space for the status bar. */
8
+ maxHeight?: DimensionValue;
9
+ /** Runs once the sheet is on screen, e.g. to focus an input. */
10
+ onShow?: () => void;
11
+ children: React.ReactNode;
12
+ }
13
+ /**
14
+ * One branded sheet on both platforms. The handle owns the dismiss gesture
15
+ * so it cannot steal scrolling, calendar swipes or drags inside the content.
16
+ * On iOS the panel also follows the keyboard and supports VoiceOver Escape.
17
+ */
18
+ export declare function BottomSheet({ visible, onClose, maxHeight, onShow, children, material, glassStyle, tintColor, fallbackColor, interactive, }: BottomSheetProps): React.JSX.Element;
@@ -0,0 +1,3 @@
1
+ import { type BottomSheetProps } from './bottom-sheet-native.tsx';
2
+ export type { BottomSheetProps };
3
+ export declare function BottomSheet(props: BottomSheetProps): import("react").JSX.Element;
@@ -0,0 +1,26 @@
1
+ import * as React from 'react';
2
+ import { type MaterialOptions } from '../provider.tsx';
3
+ export interface ButtonGroupItem<T extends string> {
4
+ id: T;
5
+ disabled?: boolean;
6
+ label: string;
7
+ icon?: React.ComponentType<{
8
+ size?: number;
9
+ color?: string;
10
+ }>;
11
+ /** Optional trailing count, e.g. unread mail in that view. */
12
+ badge?: number;
13
+ }
14
+ export interface ButtonGroupProps<T extends string> extends MaterialOptions {
15
+ items: ButtonGroupItem<T>[];
16
+ value: T;
17
+ onChange: (value: T) => void;
18
+ className?: string;
19
+ /**
20
+ * Drop the label on unselected buttons, leaving icon + badge. Meant for
21
+ * groups where every item carries a badge, so the count alone still
22
+ * identifies it — the selected button keeps the only visible label.
23
+ */
24
+ compact?: boolean;
25
+ }
26
+ export declare function ButtonGroup<T extends string>({ items, value, onChange, className, compact, material, glassStyle, tintColor, fallbackColor, interactive, }: ButtonGroupProps<T>): React.JSX.Element;
@@ -0,0 +1,48 @@
1
+ import { type VariantProps } from 'class-variance-authority';
2
+ import * as React from 'react';
3
+ import { type MaterialOptions } from '../provider.tsx';
4
+ import type { IconProps } from './icons.tsx';
5
+ import { Pressable } from './pressable.tsx';
6
+ /**
7
+ * Material 3 Expressive button.
8
+ *
9
+ * Colour still carries emphasis — Filled for the one action that matters,
10
+ * Tonal below it, Outlined and Text lower again — but Expressive added two
11
+ * dimensions on top of that:
12
+ *
13
+ * - **Size as hierarchy.** Five sizes from XS to XL, so a primary action can
14
+ * be made important by being *large*, not just by being coloured. The larger
15
+ * sizes are meant to be used; a screen where every button is medium is the
16
+ * thing this is trying to fix.
17
+ * - **Shape as feedback.** Every button morphs between round and square while
18
+ * pressed. The shape change is felt more than it is seen, and it survives on
19
+ * a filled button where a ripple over a saturated fill barely registers.
20
+ */
21
+ declare const buttonVariants: (props?: ({
22
+ variant?: "default" | "tertiary" | "outline" | "secondary" | "tonal" | "ghost" | "destructive" | null | undefined;
23
+ size?: "s" | "xs" | "m" | "l" | "xl" | "icon" | null | undefined;
24
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
25
+ declare const labelVariants: (props?: ({
26
+ variant?: "default" | "tertiary" | "outline" | "secondary" | "tonal" | "ghost" | "destructive" | null | undefined;
27
+ size?: "s" | "xs" | "m" | "l" | "xl" | "icon" | null | undefined;
28
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
29
+ export type ButtonProps = Omit<React.ComponentProps<typeof Pressable>, 'children'> & VariantProps<typeof buttonVariants> & MaterialOptions & {
30
+ children?: React.ComponentProps<typeof Pressable>['children'];
31
+ pressableClassName?: string;
32
+ label?: string;
33
+ /** A leading symbol, drawn in the label's color. */
34
+ icon?: React.ComponentType<IconProps>;
35
+ /** Resting shape. Pressing morphs to the other one and back. */
36
+ shape?: 'round' | 'square';
37
+ /** Fires a selection tick on press. Off for destructive-adjacent actions. */
38
+ haptic?: boolean;
39
+ };
40
+ /**
41
+ * Pressable with a spring shape-and-scale morph on touch.
42
+ *
43
+ * The press feedback runs on the UI thread through Reanimated rather than
44
+ * through React state, so it stays at 60fps while the JS thread is busy
45
+ * ingesting a sync batch.
46
+ */
47
+ export declare function Button({ className, material, glassStyle, tintColor, fallbackColor, interactive, pressableClassName, style, variant, size, label, icon: Icon, shape, haptic, children, onPressIn, onPressOut, onPress, ...props }: ButtonProps): React.JSX.Element;
48
+ export { buttonVariants, labelVariants };
@@ -0,0 +1,12 @@
1
+ import * as React from 'react';
2
+ import { type StyleProp, type ViewStyle } from 'react-native';
3
+ export interface CheckboxProps {
4
+ checked: boolean | 'mixed';
5
+ onCheckedChange: (checked: boolean) => void;
6
+ accessibilityLabel: string;
7
+ label?: string;
8
+ disabled?: boolean;
9
+ style?: StyleProp<ViewStyle>;
10
+ }
11
+ /** Controlled selection; storage and selection of a collection remain caller-owned. */
12
+ export declare function Checkbox({ checked, onCheckedChange, accessibilityLabel, label, disabled, style, }: CheckboxProps): React.JSX.Element;
@@ -0,0 +1,21 @@
1
+ import * as React from 'react';
2
+ import { type MaterialOptions } from '../provider.tsx';
3
+ export interface ColorSwatch {
4
+ value: string;
5
+ label: string;
6
+ color?: string;
7
+ disabled?: boolean;
8
+ }
9
+ export interface ColorSwatchPickerProps {
10
+ value: string | null;
11
+ onChange: (value: string) => void;
12
+ swatches: ColorSwatch[];
13
+ accessibilityLabel: string;
14
+ }
15
+ export declare function ColorSwatchPicker({ value, onChange, swatches, accessibilityLabel, }: ColorSwatchPickerProps): React.JSX.Element;
16
+ export interface ColorPickerSheetProps extends ColorSwatchPickerProps, MaterialOptions {
17
+ visible: boolean;
18
+ onClose: () => void;
19
+ title: string;
20
+ }
21
+ export declare function ColorPickerSheet({ visible, onClose, title, material, glassStyle, tintColor, fallbackColor, interactive, ...props }: ColorPickerSheetProps): React.JSX.Element;
@@ -0,0 +1,26 @@
1
+ import * as React from 'react';
2
+ import type { MaterialOptions } from '../material.ts';
3
+ import { type IconProps } from './icons.tsx';
4
+ export interface ContextMenuItem {
5
+ id: string;
6
+ label: string;
7
+ onPress: () => void;
8
+ icon?: React.ComponentType<IconProps>;
9
+ disabled?: boolean;
10
+ destructive?: boolean;
11
+ selected?: boolean;
12
+ }
13
+ export interface ContextMenuProps extends MaterialOptions {
14
+ children: React.ReactNode;
15
+ accessibilityLabel: string;
16
+ items: ContextMenuItem[];
17
+ disabled?: boolean;
18
+ onOpenChange?: (open: boolean) => void;
19
+ placement?: 'top' | 'bottom';
20
+ }
21
+ /** Shared anchored menu, not a UIKit context-menu controller or an application router. */
22
+ export declare function ContextMenu({ children, accessibilityLabel, items, disabled, onOpenChange, placement, ...material }: ContextMenuProps): React.JSX.Element;
23
+ export declare function ContextMenuRows({ items, onClose, }: {
24
+ items: ContextMenuItem[];
25
+ onClose: () => void;
26
+ }): React.JSX.Element;
@@ -0,0 +1,64 @@
1
+ import * as React from 'react';
2
+ import { type MaterialOptions } from '../provider.tsx';
3
+ export interface CalendarLabels {
4
+ previousMonth: string;
5
+ nextMonth: string;
6
+ }
7
+ export interface CalendarMark {
8
+ label: string;
9
+ count?: number;
10
+ color?: string;
11
+ }
12
+ export interface MonthCalendarProps {
13
+ value: string | null;
14
+ onChange: (date: string) => void;
15
+ today: string;
16
+ locale?: string;
17
+ month?: string;
18
+ onMonthChange?: (month: string) => void;
19
+ firstDayOfWeek?: number;
20
+ minDate?: string;
21
+ maxDate?: string;
22
+ disabledDates?: readonly string[];
23
+ marks?: Record<string, CalendarMark>;
24
+ labels: CalendarLabels;
25
+ range?: {
26
+ start: string;
27
+ end: string;
28
+ } | null;
29
+ renderDayAccessory?: (date: string, selected: boolean) => React.ReactNode;
30
+ }
31
+ /** Date arithmetic and marks are independent from agenda repositories or app clocks. */
32
+ export declare function MonthCalendar({ value, onChange, today, locale, month: controlledMonth, onMonthChange, firstDayOfWeek, minDate, maxDate, disabledDates, marks, labels, range, renderDayAccessory, }: MonthCalendarProps): React.JSX.Element;
33
+ export interface WeekStripProps extends Pick<MonthCalendarProps, 'value' | 'onChange' | 'today' | 'locale' | 'marks' | 'minDate' | 'maxDate'> {
34
+ startDate: string;
35
+ renderDayAccessory?: MonthCalendarProps['renderDayAccessory'];
36
+ }
37
+ export declare function WeekStrip({ startDate, value, onChange, today, locale, marks, minDate, maxDate, renderDayAccessory, }: WeekStripProps): React.JSX.Element;
38
+ export interface QuickDateOption {
39
+ value: string;
40
+ label: string;
41
+ disabled?: boolean;
42
+ }
43
+ export interface DayPickerProps extends MonthCalendarProps, MaterialOptions {
44
+ quickDates?: QuickDateOption[];
45
+ onClear?: () => void;
46
+ clearLabel?: string;
47
+ }
48
+ export declare function DayPicker({ quickDates, onClear, clearLabel, ...calendar }: DayPickerProps): React.JSX.Element;
49
+ export interface DatePickerSheetProps extends MonthCalendarProps, MaterialOptions {
50
+ visible: boolean;
51
+ onClose: () => void;
52
+ title: string;
53
+ quickDates?: QuickDateOption[];
54
+ onClear?: () => void;
55
+ clearLabel?: string;
56
+ }
57
+ export declare function DatePickerSheet({ visible, onClose, title, quickDates, onClear, clearLabel, material, glassStyle, tintColor, fallbackColor, interactive, ...calendar }: DatePickerSheetProps): React.JSX.Element;
58
+ export interface DateFieldProps extends Omit<DatePickerSheetProps, 'visible' | 'onClose' | 'title' | 'onChange' | 'onClear'> {
59
+ label: string;
60
+ emptyLabel: string;
61
+ onChange: (date: string | null) => void;
62
+ disabled?: boolean;
63
+ }
64
+ export declare function DateField({ label, emptyLabel, onChange, disabled, ...props }: DateFieldProps): React.JSX.Element;
@@ -0,0 +1,2 @@
1
+ /** Keeps iOS alert actions styled together without changing normal buttons. */
2
+ export declare const DialogActionContext: import("react").Context<boolean>;
@@ -0,0 +1,20 @@
1
+ import * as React from 'react';
2
+ import { type MaterialOptions } from '../provider.tsx';
3
+ export interface DialogProps extends MaterialOptions {
4
+ visible: boolean;
5
+ onClose: () => void;
6
+ /** Runs once the dialog is actually on screen — for one that focuses an input. */
7
+ onShow?: () => void;
8
+ children: React.ReactNode;
9
+ }
10
+ /**
11
+ * The app's Material 3 dialog: a scrim, and a panel centred on screen that
12
+ * scales up into place. Used for a short, focused decision — naming
13
+ * something, confirming an action — where a bottom sheet's list-of-options
14
+ * shape would be the wrong read.
15
+ */
16
+ export declare function Dialog({ visible, onClose, onShow, children, material, glassStyle, tintColor, fallbackColor, interactive, }: DialogProps): React.JSX.Element;
17
+ /** A dialog's row of text actions, right-aligned per M3. */
18
+ export declare function DialogActions({ children }: {
19
+ children: React.ReactNode;
20
+ }): React.JSX.Element;
@@ -0,0 +1,15 @@
1
+ import type * as React from 'react';
2
+ import { type ExpressiveShapeName } from './expressive-shape.tsx';
3
+ import type { IconProps } from './icons.tsx';
4
+ /**
5
+ * An empty list's one thing to look at: a large Expressive shape with the
6
+ * symbol of what would be here, a line saying so, and a line saying how to
7
+ * change it.
8
+ */
9
+ export declare function EmptyState({ icon: Icon, shape, title, body, tone, }: {
10
+ icon: React.ComponentType<IconProps>;
11
+ shape: ExpressiveShapeName;
12
+ title: string;
13
+ body?: string;
14
+ tone?: 'primary' | 'tertiary';
15
+ }): React.JSX.Element;
@@ -0,0 +1,27 @@
1
+ import * as React from 'react';
2
+ /** One size for every disclosure chevron, so no two sections look differently foldable. */
3
+ export declare const EXPAND_INDICATOR_SIZE = 20;
4
+ export interface ExpandIndicatorProps {
5
+ expanded: boolean;
6
+ /** Defaults to `onSurfaceVariant`; a chip in its selected tone passes its own. */
7
+ color?: string;
8
+ }
9
+ /**
10
+ * The chevron on anything that opens in place — a message card, its details,
11
+ * the Cc/Bcc fields.
12
+ *
13
+ * Every one of those used to draw its own `ChevronDown` at whatever size
14
+ * suited the spot: 16 on a card, 12 on the details line beneath it, so two
15
+ * disclosures a finger's width apart looked like different kinds of thing.
16
+ * This is the one they share.
17
+ *
18
+ * It turns on the fast spatial spring rather than flipping, and overshoots a
19
+ * little on the way: the Expressive cue that the section is a thing being
20
+ * opened, not a picture being swapped. Reanimated drops the spring for
21
+ * "Remove animations" on its own, and the chevron still ends up pointing the
22
+ * right way — the state is carried by where it ends, not by the movement.
23
+ *
24
+ * Decorative to a screen reader: whatever it sits in owns the tap and says
25
+ * `expanded` itself.
26
+ */
27
+ export declare function ExpandIndicator({ expanded, color }: ExpandIndicatorProps): React.JSX.Element;
@@ -0,0 +1,18 @@
1
+ import * as React from 'react';
2
+ /**
3
+ * A still member of the Expressive shape library, with something inside it.
4
+ *
5
+ * Expressive leans on a small set of characterful shapes — the 4-leaf clover,
6
+ * the scalloped cookie — to mark the one thing on a screen worth looking at
7
+ * first: an empty state's symbol, a step in a flow. Drawn from the same radial
8
+ * maths the loading indicator morphs (`~/lib/shape`), so the app's shapes are
9
+ * one family.
10
+ */
11
+ export { type ExpressiveShapeName } from '../expressive-shapes.ts';
12
+ import { type ExpressiveShapeName } from '../expressive-shapes.ts';
13
+ export declare function ExpressiveShape({ shape, size, color, children, }: {
14
+ shape: ExpressiveShapeName;
15
+ size: number;
16
+ color: string;
17
+ children?: React.ReactNode;
18
+ }): React.JSX.Element;
@@ -0,0 +1,31 @@
1
+ import * as React from 'react';
2
+ import { type IconProps } from './icons.tsx';
3
+ export interface FabMenuAction {
4
+ disabled?: boolean;
5
+ destructive?: boolean;
6
+ id: string;
7
+ label: string;
8
+ icon: React.ComponentType<IconProps>;
9
+ run: () => void;
10
+ }
11
+ export interface FabMenuProps {
12
+ bottom: number;
13
+ label: string;
14
+ actions: FabMenuAction[];
15
+ }
16
+ /**
17
+ * The button's closed size: the height of the floating navigation bar it
18
+ * sits beside, so the two read as one row — and round, as the bar is.
19
+ */
20
+ export declare const FAB_MENU_SIZE = 64;
21
+ /**
22
+ * The capture button, as an Expressive FAB menu.
23
+ *
24
+ * Closed, it is the one tinted circle beside the navigation bar (or, in a
25
+ * collection, in the corner). Open, it shrinks into a smaller close button
26
+ * while the ways in — link or text, file, scan, camera — unfold above it one after
27
+ * another, each a full-width pill with its name on it. Everything else dims;
28
+ * nothing about capturing asks where a thing goes. Only ways in: a list is
29
+ * written, not captured, and is started from Collections or a collection's menu.
30
+ */
31
+ export declare function LegacyFabMenu({ bottom, label, actions }: FabMenuProps): React.JSX.Element;
@@ -0,0 +1,21 @@
1
+ import * as React from 'react';
2
+ import { type IconProps } from './icons.tsx';
3
+ import { type MaterialOptions } from '../provider.tsx';
4
+ export interface FabMenuAction {
5
+ id: string;
6
+ label: string;
7
+ icon: React.ComponentType<IconProps>;
8
+ run: () => void;
9
+ disabled?: boolean;
10
+ destructive?: boolean;
11
+ }
12
+ export interface FabMenuProps extends MaterialOptions {
13
+ /** Material of the anchored menu, independent of the floating trigger. */
14
+ menuMaterial?: MaterialOptions['material'];
15
+ bottom: number;
16
+ label: string;
17
+ actions: FabMenuAction[];
18
+ }
19
+ export declare const FAB_MENU_SIZE = 64;
20
+ /** Floating primary action with a safe, anchored overflow surface on native and web. */
21
+ export declare function FabMenu({ bottom, label, actions, material, menuMaterial, glassStyle, tintColor, fallbackColor, interactive, }: FabMenuProps): React.JSX.Element;