@hzblj/kara-ui 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,196 @@
1
- # Temporary Holding Version
1
+ # @hzblj/kara-ui
2
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.
3
+ A native-first design system for Expo. Components render **real SwiftUI and Jetpack Compose views**
4
+ through [`@expo/ui`](https://docs.expo.dev/versions/latest/sdk/ui/), not styled `View`s, and every
5
+ one of them is styled through one token-typed `sx` surface — `p="s16"`, `bg="surface.primary"`,
6
+ `borderRadius="large"`. A raw number or hex does not type-check.
7
+
8
+ - **Platform colours by default.** Most tokens resolve to UIKit semantic colours on iOS and Material 3
9
+ roles on Android, so light/dark, increased contrast and Material You are the platform's job.
10
+ - **The platform's typeface by default.** SF Pro on iOS, Roboto on Android, with your own exact sizes
11
+ that still follow Dynamic Type. Bring your own font with one config entry.
12
+ - **Override anything, keep the types.** Colours, fonts and the Android seed are set once on the
13
+ provider; every token name stays the same, so every component keeps type-checking.
14
+ - **Atomic tiers.** Atoms, molecules, organisms and a `Screen` template — plus a React Native tier
15
+ (`Box`, `RnView`, `RnText`, lists) with the same `sx` surface for layouts that host native views.
16
+
17
+ React Native and Expo only (iOS and Android), Expo SDK 57. A development build is required — the
18
+ package includes a native module.
19
+
20
+ ## Install
21
+
22
+ ```bash
23
+ npx expo install @hzblj/kara-ui @expo/ui @shopify/flash-list expo-haptics expo-image react-native-reanimated react-native-worklets
24
+ # optional, for `@hzblj/kara-ui/router` (native tabs)
25
+ npx expo install expo-router
26
+ ```
27
+
28
+ Then rebuild the native app (`npx expo prebuild` / `npx expo run:ios`).
29
+
30
+ ## Use
31
+
32
+ ```tsx
33
+ import {Button, KaraProvider, Screen, Text, VStack} from '@hzblj/kara-ui'
34
+
35
+ export default function App() {
36
+ return (
37
+ <KaraProvider>
38
+ <Screen>
39
+ <VStack p="s16" spacing="s12" wide>
40
+ <Text variant="headingS">Hello</Text>
41
+ <Button label="Continue" variant="accent" wide />
42
+ </VStack>
43
+ </Screen>
44
+ </KaraProvider>
45
+ )
46
+ }
47
+ ```
48
+
49
+ **Native views need a host.** `@expo/ui`-backed components render inside `<Screen>` (full-bleed,
50
+ one per screen) or `<Island>` (a native island inside React Native layout). Outside one they do not
51
+ appear, and development builds warn.
52
+
53
+ `KaraProvider` takes `themePreference` (`'system' | 'light' | 'dark'`). A pinned preference is pushed
54
+ down to the platform too, so the SwiftUI/Compose hosts and every `PlatformColor` agree.
55
+
56
+ ## Theme
57
+
58
+ Pass a theme to the provider. Declare it at module scope so its identity is stable:
59
+
60
+ ```tsx
61
+ import {adaptive, defineTheme, KaraProvider} from '@hzblj/kara-ui'
62
+
63
+ const theme = defineTheme({
64
+ // Override any token's value — a hex, `adaptive({light, dark})`, or `native({ios, android})`.
65
+ colors: {
66
+ content: {accent: adaptive({dark: '#a5b4fc', light: '#4338ca'})},
67
+ fill: {accent: {primary: '#4f46e5'}},
68
+ },
69
+ // Your own typeface, by role and weight — the names you registered the files under (e.g. with expo-font).
70
+ fonts: {
71
+ text: {regular: 'Inter-Regular', medium: 'Inter-Medium', semibold: 'Inter-SemiBold', bold: 'Inter-Bold'},
72
+ display: {medium: 'InterDisplay-Medium'}, // headings; falls back to `text`
73
+ },
74
+ // The colour Android's Material 3 scheme grows from.
75
+ materialSeed: '#4f46e5',
76
+ })
77
+
78
+ export const App = ({children}) => <KaraProvider theme={theme}>{children}</KaraProvider>
79
+ ```
80
+
81
+ - **Colours** are merged over the defaults; you override values, never token names. A token that
82
+ supports dimming (`fill.accent.base:o50`) only accepts a value that stays dimmable — a hex,
83
+ `adaptive(...)`, or `native({android, light, dark})` — never a UIKit semantic colour.
84
+ - **Fonts** are optional. Without them, text uses the platform's face. With them, each text variant
85
+ picks the face for its weight (falling back to the role's `regular`). Native text keeps scaling with
86
+ Dynamic Type either way.
87
+ - Read the resolved theme anywhere with `useAppTheme()`: `theme.color('content.accent')`,
88
+ `theme.typography.body`, `theme.dark`.
89
+
90
+ ### Material You (Android)
91
+
92
+ ```tsx
93
+ const theme = defineTheme({dynamicColor: true})
94
+ ```
95
+
96
+ On Android 12+ the whole Material scheme follows the device wallpaper, and the accent tokens take
97
+ Material's `primary` roles — buttons, switches, links, FABs and tinted backgrounds move with it. A new
98
+ wallpaper is picked up when the app returns to the foreground, without a restart. Below Android 12 the
99
+ scheme grows from `materialSeed` instead. iOS has no wallpaper colours and keeps your accent; every
100
+ dimmed token (`:o50`) keeps working on both. `theme.dynamicColor` tells whether it is active on this
101
+ device.
102
+
103
+ `materialSeed: null` is the halfway house: the wallpaper's neutrals and controls, your own accent.
104
+
105
+ ### iOS semantic colours
106
+
107
+ The theme decides which colour a token *uses*. To redefine what a UIKit semantic colour *is*, app-wide
108
+ and natively (e.g. `labelColor`), use the config plugin:
109
+
110
+ ```ts
111
+ plugins: [['@hzblj/kara-ui', {icons: {source: './assets/icons'}, iosSemanticColors: {file: './ios-colors.json'}}]]
112
+ ```
113
+
114
+ `ios-colors.json` maps semantic names (with their `Color` suffix) to `{light, dark, highContrastLight?, highContrastDark?}`.
115
+ It has no Android counterpart; use `colors` in the theme for both platforms.
116
+
117
+ ## Icons
118
+
119
+ kara-ui ships no icon set — your app brings its own SVGs, and kara turns them into **native assets** on both
120
+ platforms. No icon font, no JavaScript rendering.
121
+
122
+ ```ts
123
+ // app.config.ts
124
+ plugins: [['@hzblj/kara-ui', {icons: {source: './assets/icons'}}]]
125
+ ```
126
+
127
+ ```
128
+ assets/icons/
129
+ bolt.svg → <Icon name="bolt" />
130
+ share.svg → iOS
131
+ share.android.svg → Android's own share glyph
132
+ ```
133
+
134
+ ```tsx
135
+ <Icon name="bolt" /> // inside <Screen> / <Island>: SwiftUI Image · Compose Icon
136
+ <RnIcon name="bolt" color="content.accent" /> // anywhere: UIImageView · ImageView
137
+ <Tabs.Screen icon="home" selectedIcon="home-filled" name="index" title="Home" />
138
+ ```
139
+
140
+ - At prebuild every SVG becomes a template image set in the iOS asset catalog (vector data kept, so it scales crisply)
141
+ and a vector drawable in Android's resources. A new or changed icon needs `npx expo prebuild`.
142
+ - Whenever the app config is read — `expo start` included — the plugin writes `kara-icons.d.ts`, so `name` only accepts
143
+ icons that exist. `npx kara-icons ./assets/icons` does the same without Expo (CI).
144
+ - One single-colour glyph per file, made of `<path>`s (`fill-rule="evenodd"` is fine). Groups, clips, masks and strokes
145
+ must be flattened first — the plugin fails loudly rather than shipping a broken icon. The platform tints every icon
146
+ with the `color` token.
147
+ - `x.ios.svg` / `x.android.svg` replace `x.svg` on that platform, for glyphs that differ (share, back).
148
+
149
+ ## Components
150
+
151
+ | Tier | |
152
+ | --- | --- |
153
+ | Atoms | `Box`, `Text`, `Button`, `IconButton`, `TextField`, `Switch`, `Checkbox`, `Slider`, `Picker`, `DatePicker`, `ColorPicker`, `SegmentedControl`, `Icon`, `Image`, `Avatar`, `Badge`, `Chip`, `Card`, `Surface`, `Progress`, `ActivityIndicator`, `Skeleton`, `Fab`, `Divider`, `Spacer`, `VStack` / `HStack` / `ZStack`, `ScrollView`, `List`, `Island`, `Pressable`, `GlassView` |
154
+ | React Native tier | `RnView`, `RnText`, `RnIcon`, `RnScrollView`, `RnFlatList`, `RnSectionList`, `FlashList` — the same `sx` surface on plain React Native views |
155
+ | Molecules | `Label`, `LabeledContent`, `ListItem`, `Link`, `SearchBar`, `EmptyState`, `Collapsible`, `Pager`, `RadioGroup`, `Stepper`, `Tooltip`, `RnTooltip`, `NavigationBar`, `ScrollEdgeContainer` |
156
+ | Organisms | `Sheet`, `ActionSheet`, `Alert`, `Menu`, `ContextMenu`, `Form`, `SwipeActions`, `Snackbar`, `FabMenu` |
157
+ | Templates | `Screen` |
158
+
159
+ A few come from the package's own native module rather than `@expo/ui`: `GlassView` (iOS 26 Liquid
160
+ Glass around React Native children), `ScrollEdgeContainer` (the iOS 26 scroll edge effect under your
161
+ bars), `NavigationBar` (real `UINavigationBar` items in a sheet), `ContextMenu` (long-press menu
162
+ with a custom preview), `RnTooltip` (rich,
163
+ controlled tooltip) and `FabMenu` (Material 3 Expressive on Android). Each falls back gracefully where
164
+ the platform lacks the feature.
165
+
166
+ ## Entry points
167
+
168
+ | Import | What it is |
169
+ | --- | --- |
170
+ | `@hzblj/kara-ui` | Components, `sx`, theme, `KaraProvider`, hooks. |
171
+ | `@hzblj/kara-ui/router` | `Tabs` (native tabs on Expo Router) and `navigationTheme(theme)` for expo-router's `ThemeProvider`. Needs `expo-router`. |
172
+ | `@hzblj/kara-ui/swift-ui` | The raw SwiftUI/UIKit views and modifiers of the native module (iOS only). |
173
+ | `@hzblj/kara-ui/jetpack-compose` | The raw Compose views and modifiers of the native module (Android only). |
174
+
175
+ ## Packages
176
+
177
+ `@hzblj/kara-ui` is all you install. It is built from scoped packages, versioned together, which you
178
+ never need to depend on directly:
179
+
180
+ | Package | |
181
+ | --- | --- |
182
+ | `@hzblj/kara-theme` | Tokens, palette, typography, `defineTheme`, `KaraProvider` |
183
+ | `@hzblj/kara-sx` | The `sx` styling engine |
184
+ | `@hzblj/kara-native` | The `KaraUI` Expo native module (Swift/Kotlin) and its bindings |
185
+ | `@hzblj/kara-components` | Atoms, molecules, organisms, templates |
186
+ | `@hzblj/kara-router` | `Tabs`, `navigationTheme` |
187
+ | `@hzblj/kara-expo-plugin` | The config plugin (icons, iOS semantic colours) and the `kara-icons` CLI |
188
+
189
+ ## Development
190
+
191
+ All of them live in the [kara-ui monorepo](https://github.com/hzblj/kara-ui) together with an example
192
+ app (Showcase, Gallery and on-device Storybook). See the repository README.
193
+
194
+ ## License
195
+
196
+ MIT
package/app.plugin.js ADDED
@@ -0,0 +1,2 @@
1
+ // The Expo config plugin: `plugins: ['@hzblj/kara-ui']`. Lives in @hzblj/kara-expo-plugin.
2
+ module.exports = require('@hzblj/kara-expo-plugin/app.plugin.js')
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ // `npx kara-icons <source>` — validates an icon folder and writes its type declaration. Lives in @hzblj/kara-expo-plugin.
3
+ process.exitCode = require('@hzblj/kara-expo-plugin/cli').main(process.argv.slice(2))
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+
3
+ export * from '@hzblj/kara-components';
4
+ export * from '@hzblj/kara-sx';
5
+ export * from '@hzblj/kara-theme';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;AAAA,cAAc,wBAAwB;AACtC,cAAc,gBAAgB;AAC9B,cAAc,mBAAmB","ignoreList":[]}
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export * from '@hzblj/kara-native/jetpack-compose';
4
+ //# sourceMappingURL=jetpack-compose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../src","sources":["jetpack-compose.ts"],"mappings":";;AAAA,cAAc,oCAAoC","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export * from '@hzblj/kara-router';
4
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../src","sources":["router.ts"],"mappings":";;AAAA,cAAc,oBAAoB","ignoreList":[]}
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export * from '@hzblj/kara-native/swift-ui';
4
+ //# sourceMappingURL=swift-ui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../src","sources":["swift-ui.ts"],"mappings":";;AAAA,cAAc,6BAA6B","ignoreList":[]}
@@ -0,0 +1,3 @@
1
+ export * from '@hzblj/kara-components';
2
+ export * from '@hzblj/kara-sx';
3
+ export * from '@hzblj/kara-theme';
@@ -0,0 +1 @@
1
+ export * from '@hzblj/kara-native/jetpack-compose';
@@ -0,0 +1 @@
1
+ export * from '@hzblj/kara-router';
@@ -0,0 +1 @@
1
+ export * from '@hzblj/kara-native/swift-ui';
package/package.json CHANGED
@@ -1,6 +1,134 @@
1
1
  {
2
2
  "name": "@hzblj/kara-ui",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.0",
4
+ "description": "A native-first design system for Expo: real SwiftUI and Jetpack Compose views through @expo/ui, styled by one token-typed sx engine.",
5
+ "author": "Jan Blazej",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/hzblj/kara-ui.git",
10
+ "directory": "packages/kara-ui"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/hzblj/kara-ui/issues"
14
+ },
15
+ "homepage": "https://github.com/hzblj/kara-ui#readme",
16
+ "keywords": [
17
+ "react-native",
18
+ "expo",
19
+ "expo-ui",
20
+ "swiftui",
21
+ "jetpack-compose",
22
+ "design-system",
23
+ "ui-kit",
24
+ "components",
25
+ "liquid-glass",
26
+ "material-3",
27
+ "material-you",
28
+ "theme",
29
+ "tokens"
30
+ ],
31
+ "main": "./lib/module/index.js",
32
+ "types": "./lib/typescript/index.d.ts",
33
+ "exports": {
34
+ ".": {
35
+ "source": "./src/index.ts",
36
+ "types": "./lib/typescript/index.d.ts",
37
+ "default": "./lib/module/index.js"
38
+ },
39
+ "./router": {
40
+ "source": "./src/router.ts",
41
+ "types": "./lib/typescript/router.d.ts",
42
+ "default": "./lib/module/router.js"
43
+ },
44
+ "./swift-ui": {
45
+ "source": "./src/swift-ui.ts",
46
+ "types": "./lib/typescript/swift-ui.d.ts",
47
+ "default": "./lib/module/swift-ui.js"
48
+ },
49
+ "./jetpack-compose": {
50
+ "source": "./src/jetpack-compose.ts",
51
+ "types": "./lib/typescript/jetpack-compose.d.ts",
52
+ "default": "./lib/module/jetpack-compose.js"
53
+ },
54
+ "./app.plugin.js": "./app.plugin.js",
55
+ "./package.json": "./package.json"
56
+ },
57
+ "files": [
58
+ "src",
59
+ "lib",
60
+ "app.plugin.js",
61
+ "bin",
62
+ "!**/*.stories.tsx",
63
+ "!**/contract.check.ts",
64
+ "!**/story-decorators.tsx",
65
+ "!**/__tests__"
66
+ ],
67
+ "scripts": {
68
+ "build": "bob build && tsc -p ./tsconfig.build.json && node ../../scripts/fallback-declarations.mjs",
69
+ "clean": "rm -rf lib",
70
+ "prepack": "yarn run -T turbo run build --filter=$npm_package_name...",
71
+ "lint": "yarn run -T concurrently \"yarn biome:check\" \"yarn tsc:check\"",
72
+ "lint:fix": "yarn run -T biome check --write .",
73
+ "biome:check": "yarn run -T biome check .",
74
+ "tsc:check": "yarn run -T concurrently \"tsc -p ./tsconfig.ios.json\" \"tsc -p ./tsconfig.android.json\""
75
+ },
76
+ "react-native-builder-bob": {
77
+ "source": "src",
78
+ "output": "lib",
79
+ "exclude": "{**/__tests__/**,**/__fixtures__/**,**/__mocks__/**,**/*.stories.tsx,**/contract.check.ts,**/story-decorators.tsx}",
80
+ "targets": [
81
+ [
82
+ "module",
83
+ {
84
+ "esm": true
85
+ }
86
+ ]
87
+ ]
88
+ },
89
+ "dependencies": {
90
+ "@hzblj/kara-components": "workspace:^",
91
+ "@hzblj/kara-expo-plugin": "workspace:^",
92
+ "@hzblj/kara-native": "workspace:^",
93
+ "@hzblj/kara-router": "workspace:^",
94
+ "@hzblj/kara-sx": "workspace:^",
95
+ "@hzblj/kara-theme": "workspace:^"
96
+ },
97
+ "peerDependencies": {
98
+ "@expo/ui": "~57.0.0",
99
+ "@shopify/flash-list": ">=2.0.0",
100
+ "expo": "~57.0.0",
101
+ "expo-haptics": "*",
102
+ "expo-image": "*",
103
+ "expo-router": "*",
104
+ "react": "*",
105
+ "react-native": "*",
106
+ "react-native-reanimated": ">=4.0.0"
107
+ },
108
+ "peerDependenciesMeta": {
109
+ "expo-router": {
110
+ "optional": true
111
+ }
112
+ },
113
+ "devDependencies": {
114
+ "@expo/ui": "~57.0.18",
115
+ "@shopify/flash-list": "^2.3.2",
116
+ "@types/react": "~19.2.18",
117
+ "expo": "~57.0.22",
118
+ "expo-haptics": "~57.0.3",
119
+ "expo-image": "~57.0.5",
120
+ "expo-router": "~57.0.21",
121
+ "react": "19.2.3",
122
+ "react-native": "0.86.3",
123
+ "react-native-builder-bob": "^0.43.0",
124
+ "react-native-reanimated": "4.5.1",
125
+ "react-native-worklets": "0.10.1",
126
+ "typescript": "~7.0.2"
127
+ },
128
+ "publishConfig": {
129
+ "access": "public"
130
+ },
131
+ "bin": {
132
+ "kara-icons": "./bin/kara-icons.js"
133
+ }
134
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from '@hzblj/kara-components'
2
+ export * from '@hzblj/kara-sx'
3
+ export * from '@hzblj/kara-theme'
@@ -0,0 +1 @@
1
+ export * from '@hzblj/kara-native/jetpack-compose'
package/src/router.ts ADDED
@@ -0,0 +1 @@
1
+ export * from '@hzblj/kara-router'
@@ -0,0 +1 @@
1
+ export * from '@hzblj/kara-native/swift-ui'