-
Notifications
You must be signed in to change notification settings - Fork 3
Task DS-549: [React Native] Поддержка UniStyles: Компоненты #38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
d7e2dce
perf: ускорение eslint
ragozin-nikita 5e2e726
perf: ускорение jest
ragozin-nikita 53e7390
test: обновил снапшоты, добавил новые моки
ragozin-nikita 55bca58
chore: обновлены eslint/prettier конфиги
ragozin-nikita 7cd5b48
feat(unistyles): миграция стилей на unistyles
ragozin-nikita ce4408e
fix: eslint
ragozin-nikita 2f51d50
feat(unistyles): перевод ui kit на unistyles
ragozin-nikita 770526a
build: фиксация обновленных зависимостей
ragozin-nikita 0e0c89b
build: обновление зависимостей
ragozin-nikita 883dcf2
fix: исправлены проблемы после локального тестирования
ragozin-nikita 2bb8102
fix: исправлено нереактивное поведение Svg ассетов
ragozin-nikita 2c6757b
fix: eslint
ragozin-nikita ca89f23
fix: анимация skeleton
ragozin-nikita 435a41a
fix: исправлены замечания по code review
ragozin-nikita 1043202
fix: themecontext стал тупым в целях безопасности
ragozin-nikita c786d7b
fix: code review
ragozin-nikita 17bed58
style: визуальное уменьшение diff в pr
ragozin-nikita c92f9d8
fix: локальный код ревью
ragozin-nikita 8abe938
fix: небольшое изменение нейминга
ragozin-nikita da052c3
fix: code review
ragozin-nikita 1a5fa35
fix: зачистка diff
ragozin-nikita File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,47 +1,52 @@ | ||
| /* do not change this file, it is auto generated by storybook. */ | ||
| import { start, updateView, View } from '@storybook/react-native'; | ||
|
|
||
| import { start, updateView } from '@storybook/react-native' | ||
|
|
||
| import '@storybook/addon-ondevice-notes/register' | ||
| import '@storybook/addon-ondevice-controls/register' | ||
| import '@storybook/addon-ondevice-actions/register' | ||
| import "@storybook/addon-ondevice-notes/register"; | ||
| import "@storybook/addon-ondevice-controls/register"; | ||
| import "@storybook/addon-ondevice-actions/register"; | ||
|
|
||
| const normalizedStories = [ | ||
| { | ||
| titlePrefix: '', | ||
| directory: './src', | ||
| files: '**/*.stories.?(ts|tsx|js|jsx)', | ||
| importPathMatcher: | ||
| /^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(?:ts|tsx|js|jsx)?)$/, | ||
| titlePrefix: "", | ||
| directory: "./src", | ||
| files: "**/*.stories.?(ts|tsx|js|jsx)", | ||
| importPathMatcher: /^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(?:ts|tsx|js|jsx)?)$/, | ||
| // @ts-ignore | ||
| req: require.context( | ||
| '../src', | ||
| true, | ||
| /^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(?:ts|tsx|js|jsx)?)$/ | ||
| ), | ||
| }, | ||
| ] | ||
| } | ||
| ]; | ||
|
|
||
|
|
||
| declare global { | ||
| var view: ReturnType<typeof start> | ||
| var STORIES: typeof normalizedStories | ||
| var view: View; | ||
| var STORIES: typeof normalizedStories; | ||
| } | ||
|
|
||
|
|
||
| const annotations = [ | ||
| require('./preview'), | ||
| require('@storybook/react-native/dist/preview'), | ||
| require('@storybook/addon-actions/preview'), | ||
| ] | ||
| require("@storybook/react-native/preview") | ||
| ]; | ||
|
|
||
| global.STORIES = normalizedStories | ||
| global.STORIES = normalizedStories; | ||
|
|
||
| // @ts-ignore | ||
| module?.hot?.accept?.() | ||
| module?.hot?.accept?.(); | ||
|
|
||
|
|
||
|
|
||
| if (!global.view) { | ||
| global.view = start({ annotations, storyEntries: normalizedStories }) | ||
| global.view = start({ | ||
| annotations, | ||
| storyEntries: normalizedStories, | ||
|
|
||
| }); | ||
| } else { | ||
| updateView(global.view, annotations, normalizedStories) | ||
| updateView(global.view, annotations, normalizedStories); | ||
| } | ||
|
|
||
| export const view: ReturnType<typeof start> = global.view | ||
| export const view: View = global.view; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,216 @@ | ||
| # Миграция на Unistyles V3 | ||
|
|
||
| Стили переведены на `react-native-unistyles`. `ThemeContextProvider` доступен | ||
| как внешний конфигуратор тем и шрифтов, но чтение темы и шрифтов теперь идет | ||
| через API `unistyles`. | ||
|
|
||
| ## Изменения | ||
|
|
||
| ### `ThemeContextProvider` — доступен | ||
|
|
||
| UI kit по-прежнему использует `react-native-unistyles` внутри, но для внешнего | ||
| потребителя снова доступен `ThemeContextProvider` как единая точка конфигурации | ||
| тем и шрифтов. | ||
|
|
||
| Если приложению нужны кастомные шрифты, настройте их через провайдер: | ||
|
|
||
| ```tsx | ||
| import { | ||
| ThemeContextProvider, | ||
| ThemeVariant, | ||
| } from '@cdek-it/react-native-ui-kit' | ||
|
|
||
| export const Root = () => ( | ||
| <ThemeContextProvider | ||
| fonts={{ primary: 'MyFont', secondary: 'MySecondaryFont' }} | ||
| initialTheme={ThemeVariant.Light} | ||
| > | ||
| <App /> | ||
| </ThemeContextProvider> | ||
| ) | ||
| ``` | ||
|
|
||
| Провайдер также принимает `lightTheme` и `darkTheme`, если нужно передать | ||
| полностью кастомные темы. | ||
|
|
||
| ### `useFonts` | ||
|
|
||
| Используйте `useUnistyles`: | ||
|
|
||
| ```tsx | ||
| import { useUnistyles } from '@cdek-it/react-native-ui-kit' | ||
|
|
||
| const { theme } = useUnistyles() | ||
| theme.fonts | ||
| ``` | ||
|
|
||
| Или прямо в стилях через `StyleSheet.create(...)`: | ||
|
|
||
| ```tsx | ||
| import { StyleSheet } from 'react-native-unistyles' | ||
|
|
||
| const styles = StyleSheet.create(({ fonts }) => ({ | ||
| title: { fontFamily: fonts.primary }, | ||
| })) | ||
| ``` | ||
|
|
||
| ### `useTheme()` / `useChangeTheme()` | ||
|
|
||
| `ThemeContextProvider` больше не является источником `theme/fonts` через React | ||
| context. Он только конфигурирует `react-native-unistyles`. | ||
|
|
||
| - `useTheme()` читает `UnistylesRuntime.themeName` | ||
| - `useFonts()` читает `useUnistyles().theme.fonts` | ||
| - `ThemeContext` остается пустым и имеет значение `null` | ||
| - `useChangeTheme()` всегда вызывает `UnistylesRuntime.setTheme(...)` | ||
|
|
||
| ### `makeStyles` — removed | ||
|
|
||
| Используйте `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` и | ||
|
isokolovskii marked this conversation as resolved.
|
||
| `withUnistyles`, поэтому потребителям не нужно импортировать | ||
| `react-native-unistyles` напрямую. | ||
|
|
||
| ### `useTheme()` — removed | ||
|
|
||
| ```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()` — removed | ||
|
|
||
| ```tsx | ||
| import { UnistylesRuntime } from '@cdek-it/react-native-ui-kit' | ||
|
|
||
| UnistylesRuntime.setTheme('dark') | ||
| ``` | ||
|
|
||
| ## ESLint Правила для Unistyles | ||
|
|
||
| Три обязательных ESLint правила защищают от потери скрытого `unistyles` payload: | ||
|
|
||
| ### ⛔ `unistyles/no-spread-unistyles` (error) | ||
|
|
||
| **Проблема**: Spread оператор теряет скрытый payload unistyles, что приводит к | ||
| потере темы и реактивности при её смене. | ||
|
|
||
| ```typescript | ||
| // ❌ Неправильно — payload теряется | ||
| const myStyle = { ...styles.button } | ||
| const btn = { ...styles.button, marginTop: 10 } | ||
| Object.assign({}, styles.button) | ||
| const { button, text } = styles | ||
|
|
||
| // ✅ Правильно — payload сохранится | ||
| const myStyle = styles.button | ||
| style={[styles.button, { marginTop: 10 }]} | ||
| style={[styles.button, isActive && styles.buttonActive]} | ||
| ``` | ||
|
|
||
| ### ⛔ `unistyles/no-unistyles-in-worklet` (error) | ||
|
|
||
| **Проблема**: Worklet функции (`useAnimatedStyle`, `runOnJS`, `withSpring`) | ||
| передаются в native код и не могут захватить весь unistyles объект. Нужно | ||
| вытащить примитивы. | ||
|
|
||
| ```typescript | ||
| // ❌ Неправильно — styles целиком в worklet | ||
| const animStyle = useAnimatedStyle(() => ({ color: styles.text.color })) | ||
|
|
||
| // ✅ Правильно — примитив вытащен перед worklet | ||
| const color = styles.text.color | ||
| const animStyle = useAnimatedStyle(() => ({ | ||
| color, // Теперь это просто строка | ||
| })) | ||
| ``` | ||
|
|
||
| ### ⚠️ `unistyles/no-spread-icon-styles` (warn) | ||
|
|
||
| Рекомендуется передавать явные props для Icon компонентов вместо spread. | ||
|
|
||
| ```typescript | ||
| // ❌ Не рекомендуется | ||
| <Icon {...styles.icon} /> | ||
|
|
||
| // ✅ Рекомендуется | ||
| const color = styles.icon.color | ||
| const width = styles.icon.width | ||
| <Icon width={width} height={24} color={color} /> | ||
| ``` | ||
|
|
||
| ### Почему это важно | ||
|
|
||
| `react-native-unistyles` добавляет скрытый payload в каждый объект из | ||
| `StyleSheet.create()`. Этот payload содержит информацию о: | ||
|
|
||
| - **Активной теме** (light/dark) | ||
| - **Responsive breakpoint** (размер экрана) | ||
| - **Unistyles runtime configuration** | ||
|
|
||
| Если потерять payload, нативная часть больше не сможет: | ||
|
|
||
| - Применить правильную тему | ||
| - Обновить стиль при смене темы/breakpoint | ||
| - Корректно интерпретировать значения | ||
|
|
||
| Подробнее: | ||
| [ESLint Rules for Unistyles](./configs/eslint/rules/unistyles/README.md) | ||
|
|
||
| ## Babel конфигурация | ||
|
|
||
| Для получения нативного обновления стилей без React-ререндеров: | ||
|
|
||
| 1. Используйте `StyleSheet.create(...)`. | ||
| 2. Добавьте `autoProcessPaths` в Babel-конфиг вашего приложения. | ||
|
|
||
| Это нужно потому, что UI kit подключается из `node_modules`, а `unistyles` по | ||
| умолчанию не обрабатывает такие файлы. | ||
|
|
||
| Пример для приложения-потребителя: | ||
|
|
||
| ```js | ||
| module.exports = function (api) { | ||
| api.cache(true) | ||
|
|
||
| return { | ||
| presets: ['babel-preset-expo'], | ||
| plugins: [ | ||
| [ | ||
| 'react-native-unistyles/plugin', | ||
| { root: 'src', autoProcessPaths: ['@cdek-it/react-native-ui-kit'] }, | ||
| ], | ||
| ], | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| Если Babel plugin у вас уже настроен, достаточно добавить путь | ||
| `@cdek-it/react-native-ui-kit` в существующий `autoProcessPaths`. | ||
|
|
||
| Документация: | ||
|
|
||
| - [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/) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.