@apple-pie/slice-native 0.1.6 → 0.1.7

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 (124) hide show
  1. package/README.md +138 -261
  2. package/SliceNative.podspec +24 -0
  3. package/dist/cjs/components.js +4 -0
  4. package/dist/cjs/hooks.js +2 -0
  5. package/dist/cjs/index.js +9 -0
  6. package/dist/cjs/src/components/SliceBackgroundBlur/SliceBackgroundBlur.js +11 -0
  7. package/dist/cjs/src/components/SliceButton/SliceButton.js +50 -23
  8. package/dist/cjs/src/components/SliceLiquidGlassView/SliceLiquidGlassView.js +12 -0
  9. package/dist/cjs/src/components/SliceTextInput/SliceTextInput.js +39 -9
  10. package/dist/cjs/src/hooks/useDeviceCapabilities/useDeviceCapabilities.js +19 -0
  11. package/dist/cjs/src/utils/sizes/sizes.js +40 -0
  12. package/dist/cjs/utils.js +3 -0
  13. package/dist/esm/components.mjs +2 -0
  14. package/dist/esm/hooks.mjs +1 -0
  15. package/dist/esm/index.mjs +4 -0
  16. package/dist/esm/src/components/SliceBackgroundBlur/SliceBackgroundBlur.mjs +9 -0
  17. package/dist/esm/src/components/SliceButton/SliceButton.mjs +50 -23
  18. package/dist/esm/src/components/SliceLiquidGlassView/SliceLiquidGlassView.mjs +10 -0
  19. package/dist/esm/src/components/SliceTextInput/SliceTextInput.mjs +39 -9
  20. package/dist/esm/src/hooks/useDeviceCapabilities/useDeviceCapabilities.mjs +17 -0
  21. package/dist/esm/src/utils/sizes/sizes.mjs +37 -0
  22. package/dist/esm/utils.mjs +1 -0
  23. package/dist/react-native/native/src/components/SliceBackgroundBlur/SliceBackgroundBlur.js +6 -0
  24. package/dist/react-native/native/src/components/SliceBackgroundBlur/SliceBackgroundBlur.native.js +6 -0
  25. package/dist/react-native/native/src/components/SliceBackgroundBlur/_types.js +1 -0
  26. package/dist/react-native/native/src/components/SliceBackgroundBlur/index.js +1 -0
  27. package/dist/react-native/native/src/components/SliceButton/SliceButton.js +141 -0
  28. package/dist/react-native/native/src/components/SliceButton/_types.js +1 -0
  29. package/dist/react-native/native/src/components/SliceButton/index.js +1 -0
  30. package/dist/react-native/native/src/components/SliceIcon/SliceIcon.js +15 -0
  31. package/dist/react-native/native/src/components/SliceIcon/_types.js +1 -0
  32. package/dist/react-native/native/src/components/SliceIcon/iconRegistry.js +663 -0
  33. package/dist/react-native/native/src/components/SliceIcon/icons.js +140 -0
  34. package/dist/react-native/native/src/components/SliceIcon/index.js +2 -0
  35. package/dist/react-native/native/src/components/SliceLiquidGlassView/SliceLiquidGlassView.ios.js +6 -0
  36. package/dist/react-native/native/src/components/SliceLiquidGlassView/SliceLiquidGlassView.js +7 -0
  37. package/dist/react-native/native/src/components/SliceLiquidGlassView/_types.js +1 -0
  38. package/dist/react-native/native/src/components/SliceLiquidGlassView/index.js +1 -0
  39. package/dist/react-native/native/src/components/SliceText/SliceText.js +16 -0
  40. package/dist/react-native/native/src/components/SliceText/_types.js +1 -0
  41. package/dist/react-native/native/src/components/SliceText/index.js +1 -0
  42. package/dist/react-native/native/src/components/SliceTextInput/SliceTextInput.js +111 -0
  43. package/dist/react-native/native/src/components/SliceTextInput/_types.js +1 -0
  44. package/dist/react-native/native/src/components/SliceTextInput/index.js +1 -0
  45. package/dist/react-native/native/src/components/index.js +6 -0
  46. package/dist/react-native/native/src/hooks/index.js +2 -0
  47. package/dist/react-native/native/src/hooks/useCreateThemedStyles/index.js +1 -0
  48. package/dist/react-native/native/src/hooks/useCreateThemedStyles/useCreateThemedStyles.js +8 -0
  49. package/dist/react-native/native/src/hooks/useDeviceCapabilities/_types.js +1 -0
  50. package/dist/react-native/native/src/hooks/useDeviceCapabilities/index.js +1 -0
  51. package/dist/react-native/native/src/hooks/useDeviceCapabilities/useDeviceCapabilities.js +14 -0
  52. package/dist/react-native/native/src/hooks/useDeviceCapabilities/useDeviceCapabilities.native.js +23 -0
  53. package/dist/react-native/native/src/index.js +6 -0
  54. package/dist/react-native/native/src/providers/SliceThemeProvider.js +30 -0
  55. package/dist/react-native/native/src/providers/index.js +1 -0
  56. package/dist/react-native/native/src/specs/BackgroundBlurNativeComponent.ts +16 -0
  57. package/dist/react-native/native/src/specs/LiquidGlassNativeComponent.ts +18 -0
  58. package/dist/react-native/native/src/specs/NativeDeviceCapabilities.ts +13 -0
  59. package/dist/react-native/native/src/theme/index.js +69 -0
  60. package/dist/react-native/native/src/theme/motion.js +43 -0
  61. package/dist/react-native/native/src/types/index.js +1 -0
  62. package/dist/react-native/native/src/types/sharedTypes.js +1 -0
  63. package/dist/react-native/native/src/utils/index.js +2 -0
  64. package/dist/react-native/native/src/utils/sizes/index.js +1 -0
  65. package/dist/react-native/native/src/utils/sizes/sizes.js +35 -0
  66. package/dist/react-native/native/src/utils/typography/index.js +1 -0
  67. package/dist/react-native/native/src/utils/typography/typography.js +13 -0
  68. package/dist/react-native/src/theme/colors/colors.js +385 -0
  69. package/dist/react-native/src/theme/colors/types.js +1 -0
  70. package/dist/react-native/src/theme/corners/corners.js +10 -0
  71. package/dist/react-native/src/theme/corners/types.js +1 -0
  72. package/dist/react-native/src/theme/elevations/_types.js +1 -0
  73. package/dist/react-native/src/theme/elevations/elevations.js +13 -0
  74. package/dist/react-native/src/theme/motion/_types.js +1 -0
  75. package/dist/react-native/src/theme/motion/motion.js +11 -0
  76. package/dist/react-native/src/theme/spacing/_types.js +1 -0
  77. package/dist/react-native/src/theme/spacing/spacing.js +10 -0
  78. package/dist/react-native/src/theme/type/type.js +371 -0
  79. package/dist/react-native/src/theme/type/types.js +1 -0
  80. package/dist/types/native/src/components/SliceBackgroundBlur/SliceBackgroundBlur.d.ts +3 -0
  81. package/dist/types/native/src/components/SliceBackgroundBlur/SliceBackgroundBlur.native.d.ts +2 -0
  82. package/dist/types/native/src/components/SliceBackgroundBlur/_types.d.ts +24 -0
  83. package/dist/types/native/src/components/SliceBackgroundBlur/index.d.ts +2 -0
  84. package/dist/types/native/src/components/SliceButton/_types.d.ts +33 -2
  85. package/dist/types/native/src/components/SliceLiquidGlassView/SliceLiquidGlassView.d.ts +3 -0
  86. package/dist/types/native/src/components/SliceLiquidGlassView/SliceLiquidGlassView.ios.d.ts +2 -0
  87. package/dist/types/native/src/components/SliceLiquidGlassView/_types.d.ts +17 -0
  88. package/dist/types/native/src/components/SliceLiquidGlassView/index.d.ts +2 -0
  89. package/dist/types/native/src/components/SliceTextInput/_types.d.ts +23 -1
  90. package/dist/types/native/src/components/index.d.ts +4 -0
  91. package/dist/types/native/src/hooks/index.d.ts +2 -0
  92. package/dist/types/native/src/hooks/useDeviceCapabilities/_types.d.ts +17 -0
  93. package/dist/types/native/src/hooks/useDeviceCapabilities/index.d.ts +2 -0
  94. package/dist/types/native/src/hooks/useDeviceCapabilities/useDeviceCapabilities.d.ts +3 -0
  95. package/dist/types/native/src/hooks/useDeviceCapabilities/useDeviceCapabilities.native.d.ts +7 -0
  96. package/dist/types/native/src/index.d.ts +12 -0
  97. package/dist/types/native/src/specs/BackgroundBlurNativeComponent.d.ts +9 -0
  98. package/dist/types/native/src/specs/LiquidGlassNativeComponent.d.ts +9 -0
  99. package/dist/types/native/src/specs/NativeDeviceCapabilities.d.ts +11 -0
  100. package/dist/types/native/src/types/index.d.ts +1 -0
  101. package/dist/types/native/src/types/sharedTypes.d.ts +14 -0
  102. package/dist/types/native/src/utils/index.d.ts +1 -0
  103. package/dist/types/native/src/utils/sizes/index.d.ts +1 -0
  104. package/dist/types/native/src/utils/sizes/sizes.d.ts +7 -0
  105. package/package.json +30 -13
  106. package/platform/android/build.gradle +22 -0
  107. package/platform/android/src/main/AndroidManifest.xml +1 -0
  108. package/platform/android/src/main/java/com/slice/SliceBackgroundBlurManager.java +28 -0
  109. package/platform/android/src/main/java/com/slice/SliceBackgroundBlurView.java +98 -0
  110. package/platform/android/src/main/java/com/slice/SliceDeviceCapabilitiesModule.java +25 -0
  111. package/platform/android/src/main/java/com/slice/SlicePackage.java +25 -0
  112. package/platform/ios/BackgroundBlurSurface.swift +89 -0
  113. package/platform/ios/LiquidGlassSurface.swift +82 -0
  114. package/platform/ios/RCTBackgroundBlurView.h +3 -0
  115. package/platform/ios/RCTBackgroundBlurView.mm +42 -0
  116. package/platform/ios/RCTLiquidGlassView.h +8 -0
  117. package/platform/ios/RCTLiquidGlassView.mm +73 -0
  118. package/platform/ios/SliceDeviceCapabilities.h +4 -0
  119. package/platform/ios/SliceDeviceCapabilities.mm +35 -0
  120. package/react-native.config.js +1 -0
  121. package/src/specs/BackgroundBlurNativeComponent.ts +16 -0
  122. package/src/specs/LiquidGlassNativeComponent.ts +18 -0
  123. package/src/specs/NativeDeviceCapabilities.ts +13 -0
  124. package/dist/types/native/index.d.ts +0 -8
package/README.md CHANGED
@@ -1,310 +1,187 @@
1
1
  # @apple-pie/slice-native
2
2
 
3
- Experimental React Native SVG icons, with the same names and artwork as the web UIKit.
4
- Includes native light/dark theme tokens and a theme provider.
5
- It is built and published independently
6
- of `@apple-pie/slice` and does not require that package at runtime.
3
+ **Alpha software — APIs, styling, and platform behavior may change between releases.**
7
4
 
8
- ```tsx
9
- import { SliceIcon, SliceIcons } from '@apple-pie/slice-native';
10
-
11
- <SliceIcon
12
- name={SliceIcons.ui.home}
13
- size={24}
14
- strokeColor="#334155"
15
- accessibilityLabel="Go home"
16
- onPress={() => navigation.navigate('Home')}
17
- />
18
- ```
19
-
20
- Supply native SVG props and
21
- native `style` objects; use `onPress` instead of `onClick`. CSS classes, cursor
22
- styling (`pointer`), and browser keyboard handlers are not part of this API.
23
- Use an enclosing React Native `Pressable` when you need a larger touch target or
24
- button feedback, and mark the icon `accessible={false}` when it is decorative.
25
-
26
- Defaults are 20×20, stroke width 1.5, and black/white colors based on the system
27
- color scheme. Pass `strokeColor` and `coverUp` explicitly to match an app theme.
28
- `fillColor` retains the web API's meaning: **opacity from 0 to 1**, not a color.
29
- `fill` enables that opacity (default 0.125 in light mode, 0.2 in dark mode).
30
- `toggle` selects the on variant when available; unknown names render nothing.
31
- `disabled` blocks press callbacks and halves the specified opacity.
32
-
33
- The package requires React, React Native, and react-native-svg as peers. Install
34
- the native SVG dependency in the consuming app using its normal native/Expo setup.
35
-
36
- ## Development
37
-
38
- The package manifest and entry point live in `native/`. Icon components, types,
39
- generated artwork, and tests live in `native/src/components/SliceIcon/`.
40
-
41
- From this directory, run `npm run generate` after changing the web icon registry
42
- or `SliceIcons` constants. Generated files contain native SVG components and have
43
- no runtime imports from the web UIKit. Run `npm run typecheck` with the peer
44
- dependencies installed and TypeScript available from the repository.
45
-
46
- From the repository root:
47
-
48
- ```sh
49
- npm install
50
- npm install --prefix native
51
- npm run lint --prefix native
52
- npm test --prefix native
53
- npm run build --prefix native
54
- ```
55
-
56
- The build refreshes generated icons, checks types, and produces `dist/cjs/index.js`,
57
- `dist/esm/index.mjs`, and declarations under `dist/types`. React, React Native, and
58
- react-native-svg stay external peer dependencies. The web build is independent.
59
-
60
- Native tests use their own `vitest.config.mts` and mocked native components. Install native
61
- dependencies before running them. Root tests and coverage do not include the native package;
62
- passing the native unit tests does not replace device rendering checks.
63
-
64
- ### Native coverage
5
+ A React Native UI kit with themed components, SVG icons, native blur, and Liquid Glass.
6
+ It shares Slice’s visual language with the web UIKit, but is packaged independently
7
+ and does not require `@apple-pie/slice` at runtime.
65
8
 
66
- From the repository root, run:
67
-
68
- ```sh
69
- npm run coverage --prefix native
70
- ```
71
-
72
- This runs only the native tests and measures runtime TypeScript in native components,
73
- providers, theme modules, and the package entry point, including generated icon artwork.
74
- Tests and type-only files are excluded. Shared web sources, build scripts, and dependencies
75
- are outside this report. Files without tests are included in the coverage calculation.
76
-
77
- Open `native/coverage/index.html` for the interactive report. The command also prints
78
- a terminal summary and writes `native/coverage/lcov.info` and
79
- `native/coverage/coverage-summary.json` for tooling. Reports are ignored by Git.
80
- The coverage provider comes from the repository's existing `@vitest/coverage-v8`
81
- development dependency; install both root and native dependencies as described above.
82
-
83
- CI runs these checks independently in **Slice Native Lint, Build, Test** on Node 24.
84
- It uses `npm run lint:ci --prefix native` to check formatting and types without writing
85
- fixes, then runs native tests, builds, and inspects the package contents. Root dependencies
86
- provide shared tooling such as Biome; native dependencies are installed separately.
87
-
88
- Run `npm pack --dry-run` from `native/` to inspect the publishable files, or
89
- `npm pack` to create a tarball. The `prepack` hook builds automatically. Build and
90
- pack from this repository: generation uses the web artwork in `src/components/Icon`.
91
-
92
- To build a local installable tarball without publishing to npm, run from the repository root:
93
-
94
- ```sh
95
- npm run pack:tarball --prefix native
96
- ```
9
+ **Blur, gradient masking, Liquid Glass, and device capability detection are built
10
+ into this package and connected directly to native platform code.** No additional
11
+ blur, gradient, masking, or glass libraries are required—including `expo-blur`,
12
+ `expo-linear-gradient`, and `@react-native-masked-view/masked-view`.
97
13
 
98
- The archive is written to `native/pack/apple-pie-slice-native-<version>.tgz`.
99
- The `pack/` directory is ignored by Git. Install the archive in another project:
14
+ ## Installation
100
15
 
101
16
  ```sh
102
- npm install /absolute/path/to/uikit/native/pack/apple-pie-slice-native-<version>.tgz
17
+ npm install @apple-pie/slice-native
103
18
  ```
104
19
 
105
- Then import from `@apple-pie/slice-native` normally. The consuming app must have
106
- compatible React, React Native, SVG, and Reanimated peer dependencies configured.
107
- After library changes, regenerate the tarball and reinstall it in the consuming
108
- project. Increment the native package version for each shared build to distinguish archives.
109
-
110
- ## Theme tokens
111
-
112
- ### Buttons
20
+ Configure the package’s peer dependencies in your app: React 18/19, React Native
21
+ 0.80+, `react-native-svg` 15, and Reanimated 4 with its compatible Worklets setup.
22
+ For Expo projects, use `npx expo install` for native peers to select compatible versions.
23
+ These general UI dependencies are separate from the built-in native visual effects.
113
24
 
114
- `SliceButton` uses the shared theme provider.
115
- It supports `primary` and `secondary` variants, optional left/right icons, disabled
116
- state, native Pressable props, and Reanimated layout/enter/exit animations.
117
- Reanimated 4 and its compatible Worklets setup are required in the consuming app.
118
- Supply an `accessibilityLabel` for icon-only buttons; button icons are decorative.
119
-
120
- ```tsx
121
- import { SliceButton, SliceThemeProvider } from '@apple-pie/slice-native';
122
-
123
- <SliceThemeProvider>
124
- <SliceButton icon="home" onPress={() => navigation.navigate('Home')}>
125
- Go home
126
- </SliceButton>
127
- </SliceThemeProvider>
128
- ```
25
+ Native components require the New Architecture. iOS builds require Xcode 26+.
26
+ Install iOS pods and rebuild your app after installing or updating the package.
27
+ Expo apps need a development build; the custom native components are not available
28
+ in Expo Go. Restarting Metro alone does not register new native code.
129
29
 
130
- Wrap the app in `SliceThemeProvider` and read its theme with `useSliceTheme`:
30
+ ## Quick start
131
31
 
132
32
  ```tsx
133
- import { SliceThemeProvider, useSliceTheme } from '@apple-pie/slice-native';
134
-
135
- function App() {
136
- return <SliceThemeProvider>{/* app content */}</SliceThemeProvider>;
137
- }
138
- ```
139
-
140
- The provider follows the system appearance by default. Pass `preference="light"`
141
- or `preference="dark"` to override it. For an app-controlled preference, pass
142
- `preference` and `onPreferenceChange`; the app owns updating and persisting that
143
- value. `useSliceContext` exposes `theme`, `mode`, `preference`, and the optional
144
- `setPreference` callback. Both hooks require a surrounding `SliceThemeProvider`.
145
- Use this exported provider and its hooks together so app and library components
146
- share the same context.
147
-
148
- ```tsx
149
- import { Text, View, useColorScheme } from 'react-native';
150
- import { lightTheme, darkTheme } from '@apple-pie/slice-native/theme';
151
-
152
- function Card() {
153
- const theme = useColorScheme() === 'dark' ? darkTheme : lightTheme;
33
+ import { View } from 'react-native';
34
+ import {
35
+ SliceButton,
36
+ SliceIcons,
37
+ SliceTextInput,
38
+ SliceThemeProvider,
39
+ } from '@apple-pie/slice-native';
40
+
41
+ export default function App() {
154
42
  return (
155
- <View style={{
156
- backgroundColor: theme.colors['core-surface-primary'],
157
- padding: theme.spacing.m,
158
- borderRadius: theme.corners['corner-m'],
159
- ...theme.shadows['surface-shadow-soft'],
160
- }}>
161
- <Text style={{ ...theme.type['body-m-regular'], color: theme.colors['core-text-primary'] }}>
162
- Hello Slice
163
- </Text>
164
- </View>
43
+ <SliceThemeProvider>
44
+ <View style={{ padding: 24, gap: 16 }}>
45
+ <SliceTextInput accessibilityLabel="Search tasks" placeholder="Search…" />
46
+ <SliceButton icon={SliceIcons.ui.home} onPress={() => console.log('Home')}>
47
+ Go home
48
+ </SliceButton>
49
+ </View>
50
+ </SliceThemeProvider>
165
51
  );
166
52
  }
167
53
  ```
168
54
 
169
- `lightTheme`, `darkTheme`, `createTypography`, and the `SliceNativeTheme` type are
170
- also available from the package root. `SliceTheme` aliases the native theme type.
171
- The dedicated `/theme` entry has no runtime React Native, React, or SVG imports.
172
- It also exports `coreColors`, `corners`, `spacing`, `elevations`, `type`, and `motion`.
55
+ ## Components
173
56
 
174
- Colors, spacing, corners, and stacking levels are sourced from the web tokens at
175
- build time and bundled into this package. No web package is needed in an app.
176
- CSS shadow strings are removed from `colors` and `coreColors`; use `theme.shadows`
177
- instead. Shadows use native `boxShadow` arrays, which require the New Architecture
178
- and supported Android versions (outset shadows require Android 9+).
57
+ | Component | Summary |
58
+ | --- | --- |
59
+ | `SliceButton` | Primary/secondary buttons, optional icons, disabled states, Reanimated transitions, and optional Liquid Glass backgrounds. |
60
+ | `SliceTextInput` | Themed native input with icons, optional focus control, focus callbacks, and opt-in clearing on blur. |
61
+ | `StyledText` | Theme-based typography presets with native text props. |
62
+ | `SliceIcon` / `SliceIcons` | Native SVG artwork and typed icon names shared with the web UIKit. Supports toggles, fills, sizing, and press handlers. |
63
+ | `SliceLiquidGlassView` | Native glass container with children, tint, interaction feedback, and rounded corners. |
64
+ | `SliceBackgroundBlur` | Background blur overlay with an optional directional fade on iOS. |
179
65
 
180
- Typography uses a fixed 16dp base for rem conversion and numeric line heights and
181
- letter spacing. Load Funnel Sans in your app, or replace `theme.type` with
182
- `createTypography('YourLoadedFontName')`. Exact font weights depend on the font
183
- and platform; test your loaded font on devices. This package does not load fonts.
66
+ Buttons and inputs support `size` (`s`, `m`, `l`, or a number), `borderRadius`
67
+ (`pill`, `rectangular`, or a number), `borderWidth`, `borderColor`, and
68
+ `backgroundColor`. Sizes define minimum heights, allowing room for larger text.
69
+ Inputs forward `style` to the underlying text field. Buttons expose `animatedStyle`
70
+ for their wrapper.
184
71
 
185
- Motion durations are milliseconds. Curve tokens are easing functions suitable for
186
- `Animated.timing`'s `easing` option; the CSS spring is interpolated from its original
187
- samples, preserving overshoot. They are ordinary JavaScript functions, not Reanimated
188
- worklets. `elevations` retains the web stacking levels for `zIndex`; do not pass these
189
- values to Android's `elevation` property.
72
+ `SliceButton`, `SliceTextInput`, and `StyledText` use `SliceThemeProvider`. Give
73
+ inputs and icon-only buttons an accessible name. Icons inside these components
74
+ are decorative; standalone icons can use `accessibilityLabel` and `onPress`.
75
+ For `SliceIcon`, `fillColor` means fill opacity, not a color value.
190
76
 
191
- Build from the repository so shared source tokens are available. All generated
192
- JavaScript and declarations are included under `dist/`, including declarations for
193
- shared source types. Changes to web tokens are picked up by the next native build.
77
+ ### Built-in Liquid Glass and blur
194
78
 
195
- ## Themed styles hook
79
+ | Effect | iOS | Android | Web |
80
+ | --- | --- | --- | --- |
81
+ | `SliceLiquidGlassView` | Native Liquid Glass on iOS 26+; system blur on older iOS. | Tinted color fallback. | Tinted color fallback. |
82
+ | `SliceBackgroundBlur` | Native backdrop blur; optional directional fade. | Uniform backdrop blur when the required API is present (SDK 37.2+) and hardware acceleration is available; otherwise a color fallback. | Color fallback. |
196
83
 
197
- Define the style factory outside the component so its identity stays stable:
84
+ The implementations ship with the package: Swift/UIKit and Fabric on iOS, and Java
85
+ platform code on Android. Consumers do not need to install another effects library.
86
+ iOS respects Reduce Transparency and renders a fallback when it is enabled.
198
87
 
199
88
  ```tsx
200
- import { StyleSheet, View } from 'react-native';
201
- import { useCreateThemedStyles, type SliceNativeTheme } from '@apple-pie/slice-native';
202
-
203
- const createStyles = (theme: SliceNativeTheme) => StyleSheet.create({
204
- container: {
205
- backgroundColor: theme.colors['core-surface-primary'],
206
- padding: theme.spacing.m,
207
- },
208
- divider: { height: 1 }, // Styles do not have to use the theme.
209
- });
210
-
211
- function Card() {
212
- const styles = useCreateThemedStyles(createStyles);
213
- return <View style={styles.container} />;
214
- }
215
- ```
216
-
217
- The component must be inside `SliceThemeProvider`. Style keys and property types
218
- are inferred from the factory return value. The hook recalculates when the theme
219
- or factory changes; an inline factory works but is recreated every render. If
220
- styles depend on component props, wrap the factory in `useCallback` with those
221
- props in its dependency list. The hook accepts ordinary native style objects too;
222
- calling `StyleSheet.create` inside the factory is optional.
223
-
224
- ## Typography utility
89
+ import { SliceBackgroundBlur, SliceLiquidGlassView } from '@apple-pie/slice-native';
225
90
 
226
- `lineHeightTextStyle` derives an absolute line height and returns a new style object:
91
+ // Place over background content; fills its parent by default.
92
+ <SliceBackgroundBlur blurIntensity={20} fadeStop={0.5} direction="down" />
227
93
 
228
- ```tsx
229
- import { lineHeightTextStyle } from '@apple-pie/slice-native';
94
+ <SliceLiquidGlassView cornerRadius={24} glassStyle="regular" style={{ padding: 20 }}>
95
+ {/* Foreground content */}
96
+ </SliceLiquidGlassView>
230
97
 
231
- const label = lineHeightTextStyle({ fontSize: 20, color: '#123456' }, 1.5);
232
- // { fontSize: 20, color: '#123456', lineHeight: 30 }
98
+ <SliceButton liquidGlassBackground={{ glassStyle: 'clear', fallbackColor: '#eeeeee' }}>
99
+ Continue
100
+ </SliceButton>
233
101
  ```
234
102
 
235
- The defaults are a 16 font size and a 1.2 multiplier. The multiplier must be a
236
- finite number from 0 through 2. Existing line height is replaced; the input is unchanged.
103
+ Blur defaults to intensity `12` and `fadeStop={0}`, which renders uniform blur
104
+ without a mask. A positive `fadeStop` (0–1) enables fading on iOS. Directions are
105
+ `down`, `up`, `left`, and `right`, from transparent toward full blur. Android
106
+ ignores fading props. This fades the visibility of a uniform blur rather than
107
+ varying the blur radius across the view.
108
+
109
+ Use `cornerRadius` to control a glass container’s shape. Supported glass buttons
110
+ keep their background transparent; unsupported devices use their solid background
111
+ or configured fallback. Both effect components accept `fallbackColor`. Avoid opaque
112
+ content over glass when you want the backdrop to remain visible. Android backdrop
113
+ blur samples the same window; separately composed surfaces such as video may differ.
237
114
 
238
- ## Text input
115
+ ## Hooks, provider, and theme
239
116
 
240
- `SliceTextInput` and `SliceTextInputProps` are exported from the package root.
241
- Use it within `SliceThemeProvider` and give each field an accessible name that
242
- identifies its purpose, rather than relying on a placeholder alone:
117
+ | Export | Purpose |
118
+ | --- | --- |
119
+ | `SliceThemeProvider` | Light/dark themes; follows the system by default. Use `preference="light"` or `"dark"` to override. |
120
+ | `useSliceTheme()` | Returns the active theme. |
121
+ | `useSliceContext()` | Returns the theme, mode, preference, and optional preference setter. |
122
+ | `useCreateThemedStyles(factory)` | Creates memoized styles from the active theme. Define the factory outside the component for stable reuse. |
123
+ | `useDeviceCapabilities()` | Reports native effect support, platform, OS/API version, and device information. Does not require the theme provider. |
243
124
 
244
125
  ```tsx
245
- <SliceTextInput
246
- accessibilityLabel="Email address"
247
- accessibilityHint="Used to send your receipt"
248
- placeholder="you@example.com"
249
- keyboardType="email-address"
250
- autoCapitalize="none"
251
- value={email}
252
- onChangeText={setEmail}
253
- />
126
+ const {
127
+ supportsLiquidGlass,
128
+ supportsNativeBlur,
129
+ platform,
130
+ iosVersion,
131
+ androidSdkVersion,
132
+ deviceName,
133
+ deviceModel,
134
+ } = useDeviceCapabilities();
254
135
  ```
255
136
 
256
- Native TextInput props and styles are forwarded. Icons are decorative and hidden
257
- from accessibility focus. Font scaling remains enabled by default, and the field
258
- uses a minimum height rather than a fixed height. Check large text and multiline
259
- layouts on devices with VoiceOver/TalkBack enabled.
137
+ Capability flags describe API availability, not live accessibility settings or
138
+ per-view rendering conditions. They return `false` when the native module is absent.
139
+ `iosVersion` is a full version string; `androidSdkVersion` is an integer API level
140
+ without minor-release information. Use the support flags for effects decisions.
141
+ Unavailable fields are `null`. iOS device names may be generic; its model is a
142
+ hardware identifier such as `iPhone17,1`, not a marketing name. Android reports
143
+ the system model name/code.
260
144
 
261
- `focused` optionally requests native focus or blur; omit it for normal native
262
- focus handling. `didFocus` reports focus changes alongside `onFocus`/`onBlur`.
263
- Icons hide on actual focus unless `hideIconOnFocus={false}`. `blurClears` defaults
264
- to false; when enabled, blur clears the native input and calls `onChangeText('')`
265
- so controlled consumers can update their value. Initial values are never cleared
266
- on mount.
145
+ `lightTheme`, `darkTheme`, and `createTypography` are exported alongside theme types.
146
+ Themes include colors, spacing, corners, typography, shadows, stacking levels, and
147
+ motion. The `/theme` entry also exposes the underlying token groups. Typography
148
+ uses Funnel Sans by default; load it in your app or use `createTypography` with
149
+ your own loaded font. Fonts are not loaded by the package.
267
150
 
268
- ## Package entry points and tree shaking
151
+ ## Utilities and entry points
269
152
 
270
- The base barrels under `native/src` are public package entry points:
153
+ | Utility | Purpose |
154
+ | --- | --- |
155
+ | `sizeToNumber(size)` | Resolves size presets to points: `s` = 40, `m` = 48, `l` = 56. |
156
+ | `borderRadiusToNumber(radius)` | Resolves `pill` to 1000, `rectangular` to 4, and numeric radii to nonnegative points. |
157
+ | `lineHeightTextStyle(style, multiplier)` | Returns a new text style with an absolute line height. |
271
158
 
272
- ```tsx
273
- import { SliceButton, SliceTextInput } from '@apple-pie/slice-native/components';
274
- import { useCreateThemedStyles } from '@apple-pie/slice-native/hooks';
275
- import { SliceThemeProvider } from '@apple-pie/slice-native/providers';
276
- import { lineHeightTextStyle } from '@apple-pie/slice-native/utils';
277
- import { lightTheme, darkTheme } from '@apple-pie/slice-native/theme';
278
- ```
159
+ Public types include `Size`, `BorderRadius`, `LiquidGlassBackground`,
160
+ `DeviceCapabilities`, component props, and theme/provider types.
279
161
 
280
- Root imports remain supported. Each entry provides ESM, CommonJS, and TypeScript
281
- declarations. The build preserves individual modules and the package declares
282
- `sideEffects: false` so compatible consuming bundlers can remove unused exports.
283
- Actual tree shaking depends on the consuming app's bundler and configuration;
284
- CommonJS consumers should not assume the same elimination as ESM consumers.
285
- The theme and utility entry points do not import React, SVG, or Reanimated at runtime.
162
+ Import from the package root or the dedicated `/components`, `/hooks`, `/providers`,
163
+ `/theme`, and `/utils` entry points. ESM, CommonJS, TypeScript declarations, and
164
+ Metro platform files are included. Theme tokens and utilities can be used independently
165
+ of the component runtime.
286
166
 
287
- Run `npm run test:package --prefix native` to build and verify export targets and
288
- representative ESM consumer bundles. These checks verify that selecting only the
289
- line-height utility removes other package code and that hooks do not pull in SVG
290
- or Reanimated.
291
-
292
- ## Native Storybook (browser documentation)
167
+ ## Development
293
168
 
294
- From the repository root, after installing both root and native dependencies:
169
+ From the repository root:
295
170
 
296
171
  ```sh
297
- npm run storybook:native
298
- npm run typecheck:storybook:native
299
- npm run build-storybook:native
172
+ npm install
173
+ npm install --prefix native
174
+ npm run lint:ci --prefix native
175
+ npm run coverage --prefix native
176
+ npm run test:package --prefix native
177
+ npm run pack:tarball --prefix native
300
178
  ```
301
179
 
302
- The development server uses port 6007. The static build goes to
303
- `storybook-native-static/`, independently of the existing React Storybook.
304
- Stories live in `native/stories/`; configuration lives in `.storybook-native/`.
305
- The theme toolbar uses the native provider. React Native Web, SVG's web rendering,
306
- and Reanimated's web implementation render the actual components; these are not
307
- native-platform screenshots. Browser stories supplement device testing.
180
+ Builds regenerate and automatically format native icons from the shared web artwork,
181
+ check types, and emit the package distributions. The tarball is written to
182
+ `native/pack/apple-pie-slice-native-<version>.tgz`; reinstall it and rebuild the
183
+ consuming native app when testing platform changes.
308
184
 
309
- Deploy with `Dockerfile.react-native` and target `react-native-docs`, as described
310
- in `deployment/README.md` at the repository root.
185
+ Browser documentation runs with `npm run storybook:native` from the repository root.
186
+ It previews web fallbacks; native effects need simulator/device checks. Native unit
187
+ coverage enforces a 95% overall threshold and does not measure Swift/Java rendering.
@@ -0,0 +1,24 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'SliceNative'
7
+ s.module_name = 'SliceNative'
8
+ s.version = package['version']
9
+ s.summary = package['description']
10
+ s.homepage = 'https://github.com/uris/slice'
11
+ s.license = package['license']
12
+ s.authors = package['author']
13
+ s.source = { :git => 'https://github.com/uris/slice.git', :tag => "native-v#{s.version}" }
14
+ s.platforms = { :ios => min_ios_version_supported }
15
+ s.swift_version = '5.0'
16
+ s.requires_arc = true
17
+ s.source_files = 'platform/ios/**/*.{h,m,mm,swift}'
18
+ # Keep C++ React headers out of the module imported by the Swift compiler.
19
+ s.private_header_files = 'platform/ios/RCT*View.h', 'platform/ios/SliceDeviceCapabilities.h'
20
+ s.frameworks = 'UIKit'
21
+ s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
22
+
23
+ install_modules_dependencies(s)
24
+ end
@@ -5,6 +5,8 @@ var icons = require('./src/components/SliceIcon/icons.js');
5
5
  var SliceText = require('./src/components/SliceText/SliceText.js');
6
6
  var SliceButton = require('./src/components/SliceButton/SliceButton.js');
7
7
  var SliceTextInput = require('./src/components/SliceTextInput/SliceTextInput.js');
8
+ var SliceLiquidGlassView = require('./src/components/SliceLiquidGlassView/SliceLiquidGlassView.js');
9
+ var SliceBackgroundBlur = require('./src/components/SliceBackgroundBlur/SliceBackgroundBlur.js');
8
10
 
9
11
 
10
12
 
@@ -13,3 +15,5 @@ exports.SliceIcons = icons.SliceIcons;
13
15
  exports.StyledText = SliceText.StyledText;
14
16
  exports.SliceButton = SliceButton.SliceButton;
15
17
  exports.SliceTextInput = SliceTextInput.SliceTextInput;
18
+ exports.SliceLiquidGlassView = SliceLiquidGlassView.SliceLiquidGlassView;
19
+ exports.SliceBackgroundBlur = SliceBackgroundBlur.SliceBackgroundBlur;
package/dist/cjs/hooks.js CHANGED
@@ -1,7 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  var useCreateThemedStyles = require('./src/hooks/useCreateThemedStyles/useCreateThemedStyles.js');
4
+ var useDeviceCapabilities = require('./src/hooks/useDeviceCapabilities/useDeviceCapabilities.js');
4
5
 
5
6
 
6
7
 
7
8
  exports.useCreateThemedStyles = useCreateThemedStyles.useCreateThemedStyles;
9
+ exports.useDeviceCapabilities = useDeviceCapabilities.useDeviceCapabilities;
package/dist/cjs/index.js CHANGED
@@ -5,10 +5,14 @@ var icons = require('./src/components/SliceIcon/icons.js');
5
5
  var SliceText = require('./src/components/SliceText/SliceText.js');
6
6
  var SliceButton = require('./src/components/SliceButton/SliceButton.js');
7
7
  var SliceTextInput = require('./src/components/SliceTextInput/SliceTextInput.js');
8
+ var SliceLiquidGlassView = require('./src/components/SliceLiquidGlassView/SliceLiquidGlassView.js');
9
+ var SliceBackgroundBlur = require('./src/components/SliceBackgroundBlur/SliceBackgroundBlur.js');
8
10
  var theme = require('./theme.js');
9
11
  var SliceThemeProvider = require('./src/providers/SliceThemeProvider.js');
10
12
  var useCreateThemedStyles = require('./src/hooks/useCreateThemedStyles/useCreateThemedStyles.js');
13
+ var useDeviceCapabilities = require('./src/hooks/useDeviceCapabilities/useDeviceCapabilities.js');
11
14
  var typography = require('./src/utils/typography/typography.js');
15
+ var sizes = require('./src/utils/sizes/sizes.js');
12
16
 
13
17
 
14
18
 
@@ -17,6 +21,8 @@ exports.SliceIcons = icons.SliceIcons;
17
21
  exports.StyledText = SliceText.StyledText;
18
22
  exports.SliceButton = SliceButton.SliceButton;
19
23
  exports.SliceTextInput = SliceTextInput.SliceTextInput;
24
+ exports.SliceLiquidGlassView = SliceLiquidGlassView.SliceLiquidGlassView;
25
+ exports.SliceBackgroundBlur = SliceBackgroundBlur.SliceBackgroundBlur;
20
26
  exports.createTypography = theme.createTypography;
21
27
  exports.darkTheme = theme.darkTheme;
22
28
  exports.lightTheme = theme.lightTheme;
@@ -24,4 +30,7 @@ exports.SliceThemeProvider = SliceThemeProvider.SliceThemeProvider;
24
30
  exports.useSliceContext = SliceThemeProvider.useSliceContext;
25
31
  exports.useSliceTheme = SliceThemeProvider.useSliceTheme;
26
32
  exports.useCreateThemedStyles = useCreateThemedStyles.useCreateThemedStyles;
33
+ exports.useDeviceCapabilities = useDeviceCapabilities.useDeviceCapabilities;
27
34
  exports.lineHeightTextStyle = typography.lineHeightTextStyle;
35
+ exports.borderRadiusToNumber = sizes.borderRadiusToNumber;
36
+ exports.sizeToNumber = sizes.sizeToNumber;
@@ -0,0 +1,11 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var reactNative = require('react-native');
5
+
6
+ /** Web/other-platform fallback. Metro selects the native implementation on iOS/Android. */
7
+ function SliceBackgroundBlur({ style, fallbackColor = 'rgba(128, 128, 128, 0.18)', }) {
8
+ return jsxRuntime.jsx(reactNative.View, { pointerEvents: "none", style: [reactNative.StyleSheet.absoluteFill, style, { backgroundColor: fallbackColor }] });
9
+ }
10
+
11
+ exports.SliceBackgroundBlur = SliceBackgroundBlur;