Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
ios/Pods
ios
.github/workflows
.yarn
android/app/.cxx
CHANGELOG.md
android/app/build
android/build
CHANGELOG.md
79 changes: 79 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Миграция на Unistyles V3

Стили переведены на `react-native-unistyles`. Удален собственный `React Context`
и провайдер.

## Изменения

### `ThemeContextProvider` — удалён

Темы регистрируются автоматически. Обёртка больше не нужна.

### `useFonts` — deprecated

Используйте `useUnistyles`:

```tsx
import { useUnistyles } from '@cdek-it/react-native-ui-kit'

const { theme } = useUnistyles()
theme.fonts
```

Или прямо в стилях через `StyleSheet.create(...)`.

### `makeStyles` — deprecated

Используйте `StyleSheet.create(...)`:

```tsx
import { StyleSheet } from '@cdek-it/react-native-ui-kit'

const styles = StyleSheet.create((theme) => ({
container: { backgroundColor: theme.Button.Brand.buttonBg },
}))
```

`makeStyles` использует `useUnistyles()`, что вызывает React-ререндеры при смене
темы. `StyleSheet.create(...)` — нативный путь, обновляет стили **без**
ререндеров.

SDK реэкспортирует `StyleSheet`, `useUnistyles`, `UnistylesRuntime` и
`withUnistyles`, поэтому потребителям не нужно импортировать
`react-native-unistyles` напрямую.

### `useTheme()` — deprecated

```tsx
import { UnistylesRuntime, useUnistyles } from '@cdek-it/react-native-ui-kit'

const themeName = UnistylesRuntime.themeName // 'light' | 'dark'
```

Для реактивного поведения используйте `useUnistyles()`:

```tsx
const { rt } = useUnistyles()
rt.themeName
```

### `useChangeTheme()` — deprecated

```tsx
import { UnistylesRuntime } from '@cdek-it/react-native-ui-kit'

UnistylesRuntime.setTheme('dark')
```

## Babel конфигурация

Для получения нативного обновления стилей без React-ререндеров:

1. Используйте `StyleSheet.create(...)`.
2. Добавьте `autoProcessPaths` в Babel-конфиг вашего приложения.

Документация:

- [useUnistyles](https://www.unistyl.es/v3/references/use-unistyles/)
- [StyleSheet](https://www.unistyl.es/v3/references/stylesheet/)
- [Babel plugin](https://www.unistyl.es/v3/other/babel-plugin/)
19 changes: 19 additions & 0 deletions eslint.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,28 @@ import { MobileConfig } from './configs/eslint'
export default defineConfig([
...MobileConfig,
{ files: ['configs/eslint/**/*'], rules: { 'max-lines': 'off' } },
// Временное решение до миграции компонентов
{
files: ['src/components/**/*.{ts,tsx}'],
rules: { '@typescript-eslint/no-deprecated': 'off' },
},
{
ignores: [
'node_modules/**/*',
'.expo/**/*',
'.git/**/*',
'.idea/**/*',
'dist/**/*',
'build/**/*',
'coverage/**/*',
'**/*.min.js',
'.gradle/**/*',
'android/**/*',
'ios/**/*',
'.yarn/**/*',
'.vscode/**/*',
'.jest/**/*',
'.gemini/**/*',
'.storybook/**/*',
'configs/cz-conventional-mobile/**/*',
],
Expand Down
2 changes: 1 addition & 1 deletion jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const config: Config.InitialOptions = {
coverageReporters: ['text', 'text-summary'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
testRunner: 'jest-circus',
maxWorkers: 4,
maxWorkers: '100%',
rootDir: '.',
moduleNameMapper: { '\\.svg': '<rootDir>/__mocks__/svgMock.js' },
setupFiles: ['<rootDir>/jest.setup.ts'],
Expand Down
6 changes: 6 additions & 0 deletions jest.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,9 @@ type PropertyCombinations<T> = { [K in keyof T]: Array<T[K]> }
declare let generatePropsCombinations: <T>(
properties: PropertyCombinations<T>
) => T[]

declare module '@react-native/normalize-colors' {
const normalizeColors: (color: string | number) => number | null

export default normalizeColors
}
47 changes: 47 additions & 0 deletions jest.setup.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,56 @@
import 'jest-extended'
import 'react-native-gesture-handler/jestSetup'
import { setUpTests } from 'react-native-reanimated'
import 'react-native-unistyles/mocks'

setUpTests()

type ThemeName = 'light' | 'dark'

interface MockedUnistylesModule {
StyleSheet: { create: (...args: unknown[]) => unknown }
UnistylesRuntime: {
miniRuntime: unknown
setTheme: jest.Mock<void, [ThemeName]>
themeName: ThemeName | undefined
}
useUnistyles: jest.Mock
withUnistyles: jest.Mock
}

const { darkTheme, lightTheme } = require('./src/theme')

const unistyles = jest.requireMock(
'react-native-unistyles'
) as MockedUnistylesModule

const getTheme = (themeName: ThemeName | undefined) =>
themeName === 'dark' ? darkTheme : lightTheme

const originalStyleSheetCreate = unistyles.StyleSheet.create
const runtime = unistyles.UnistylesRuntime

runtime.themeName = 'light'
runtime.setTheme = jest.fn((themeName: ThemeName) => {
runtime.themeName = themeName
})

unistyles.useUnistyles = jest.fn(() => ({
theme: getTheme(runtime.themeName),
rt: runtime,
}))

unistyles.StyleSheet.create = jest.fn(
(stylesheet: Parameters<typeof originalStyleSheetCreate>[0]) =>
typeof stylesheet === 'function'
? originalStyleSheetCreate(() =>
stylesheet(getTheme(runtime.themeName), runtime.miniRuntime)
)
: originalStyleSheetCreate(stylesheet)
)

unistyles.withUnistyles = jest.fn(<T>(Component: T) => Component)

generatePropsCombinations = <T>(properties: PropertyCombinations<T>): T[] => {
const keys = Object.keys(properties) as Array<keyof T>

Expand Down
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,17 @@
"storybook-generate": "sb-rn-get-stories --config-path .storybook && sed -i -e 's/export const view = global.view/export const view: ReturnType<typeof start> = global.view/' .storybook/storybook.requires.ts && prettier .storybook --write",
"doctor": "expo-doctor",
"check": "expo install --check",
"lint:check": "eslint .",
"lint:fix": "eslint --fix .",
"lint:check": "eslint --cache .",
"lint:fix": "eslint --fix --cache .",
"prettier:check": "prettier . --check",
"prettier:fix": "prettier . --write",
"prettier:watch": "onchange . -- prettier --write --ignore-unknown \"{{changed}}\"",
"release": "release-it",
"pod-install": "bundle exec pod install --project-directory=ios"
},
"dependencies": {
"@tabler/icons-react-native": "^3.36.0"
"@tabler/icons-react-native": "3.36.1",
"react-native-unistyles": "3.2.3"
},
"devDependencies": {
"@babel/core": "7.28.5",
Expand Down Expand Up @@ -106,6 +107,7 @@
"react-native": "0.81.5",
"react-native-advanced-input-mask": "1.4.6",
"react-native-gesture-handler": "2.29.1",
"react-native-nitro-modules": "0.35.2",
"react-native-reanimated": "4.1.1",
"react-native-safe-area-context": "5.6.2",
"react-native-svg": "15.15.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ exports[`Accordion Header elements maximal 1`] = `
strokeWidth={2}
>
<RNSVGPath
d="M20 6v12a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2z"
d="M20 6v12a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2"
fill={null}
propList={
[
Expand Down Expand Up @@ -386,7 +386,7 @@ exports[`Accordion Header elements maximal 1`] = `
strokeWidth={2}
/>
<RNSVGPath
d="M13 11m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0"
d="M11 11a2 2 0 1 0 4 0a2 2 0 1 0 -4 0"
fill={null}
propList={
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ exports[`DialogHeader {"onClose": [Function mockConstructor], "severity": "dange
strokeWidth={2}
>
<RNSVGPath
d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"
d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"
fill={null}
propList={
[
Expand Down Expand Up @@ -957,7 +957,7 @@ exports[`DialogHeader {"onClose": [Function mockConstructor], "severity": "succe
strokeWidth={2}
>
<RNSVGPath
d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"
d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"
fill={null}
propList={
[
Expand Down Expand Up @@ -1261,7 +1261,7 @@ exports[`DialogHeader {"onClose": [Function mockConstructor], "severity": "warni
strokeWidth={2}
/>
<RNSVGPath
d="M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.87l-8.106 -13.536a1.914 1.914 0 0 0 -3.274 0z"
d="M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.87l-8.106 -13.536a1.914 1.914 0 0 0 -3.274 0"
fill={null}
propList={
[
Expand Down Expand Up @@ -1726,7 +1726,7 @@ exports[`DialogHeader {"onClose": undefined, "severity": "danger", "title": "Dia
strokeWidth={2}
>
<RNSVGPath
d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"
d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"
fill={null}
propList={
[
Expand Down Expand Up @@ -2208,7 +2208,7 @@ exports[`DialogHeader {"onClose": undefined, "severity": "success", "title": "Di
strokeWidth={2}
>
<RNSVGPath
d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"
d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"
fill={null}
propList={
[
Expand Down Expand Up @@ -2376,7 +2376,7 @@ exports[`DialogHeader {"onClose": undefined, "severity": "warning", "title": "Di
strokeWidth={2}
/>
<RNSVGPath
d="M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.87l-8.106 -13.536a1.914 1.914 0 0 0 -3.274 0z"
d="M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.87l-8.106 -13.536a1.914 1.914 0 0 0 -3.274 0"
fill={null}
propList={
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ exports[`MenuItemTemplate tests MenuItemTemplate full disabled 1`] = `
strokeWidth={2}
>
<RNSVGPath
d="M5 13a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-6z"
d="M5 13a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-6"
fill={null}
propList={
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ exports[`Message {"body": [Object], "footer": [Object], "severity": "warning"} 1
testID="Icon"
/>
<RNSVGPath
d="M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.87l-8.106 -13.536a1.914 1.914 0 0 0 -3.274 0z"
d="M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.87l-8.106 -13.536a1.914 1.914 0 0 0 -3.274 0"
fill={null}
propList={
[
Expand Down Expand Up @@ -737,7 +737,7 @@ exports[`Message {"closeLabel": "Close", "footer": [Object], "onClose": [Functio
strokeWidth={2}
>
<RNSVGPath
d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"
d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"
fill={null}
propList={
[
Expand Down Expand Up @@ -973,7 +973,7 @@ exports[`Message {"footer": [Object], "onClose": [Function mockConstructor], "se
strokeWidth={2}
>
<RNSVGPath
d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"
d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"
fill={null}
propList={
[
Expand Down
Loading
Loading