From e76679c77c2d9cf8a1e750ee7aa3518b62aa19de Mon Sep 17 00:00:00 2001 From: Jacek Pudysz Date: Thu, 30 Jan 2025 13:05:13 +0100 Subject: [PATCH 1/4] feat: native breakpoints - add config to use points instead of pixel --- cxx/core/UnistylesRegistry.h | 2 ++ cxx/hybridObjects/HybridStyleSheet.cpp | 29 ++++++++++++++++++++++++-- cxx/parser/Parser.cpp | 6 +++++- expo-example/unistyles.ts | 2 +- src/specs/StyleSheet/index.ts | 3 ++- 5 files changed, 37 insertions(+), 5 deletions(-) diff --git a/cxx/core/UnistylesRegistry.h b/cxx/core/UnistylesRegistry.h index a2f0d6e4..57f61705 100644 --- a/cxx/core/UnistylesRegistry.h +++ b/cxx/core/UnistylesRegistry.h @@ -27,6 +27,8 @@ struct UnistylesRegistry: public StyleSheetRegistry { UnistylesRegistry(const UnistylesRegistry&) = delete; UnistylesRegistry(const UnistylesRegistry&&) = delete; + + bool shouldUsePointsForBreakpoints = false; void registerTheme(jsi::Runtime& rt, std::string name, jsi::Value& theme); void registerBreakpoints(jsi::Runtime& rt, std::vector>& sortedBreakpoints); diff --git a/cxx/hybridObjects/HybridStyleSheet.cpp b/cxx/hybridObjects/HybridStyleSheet.cpp index 9b1282bd..841be4a3 100644 --- a/cxx/hybridObjects/HybridStyleSheet.cpp +++ b/cxx/hybridObjects/HybridStyleSheet.cpp @@ -127,6 +127,20 @@ void HybridStyleSheet::parseSettings(jsi::Runtime &rt, jsi::Object settings) { if (propertyName == "CSSVars") { return; } + + if (propertyName == "nativeBreakpointsMode") { + helpers::assertThat(rt, propertyValue.isString(), "StyleSheet.configure's nativeBreakpointsMode must be a string"); + + auto mode = propertyValue.asString(rt).utf8(rt); + + helpers::assertThat(rt, mode == "pixels" || mode == "points", "StyleSheet.configure's nativeBreakpointsMode must be one of: pixels or points"); + + if (mode == "points") { + registry.shouldUsePointsForBreakpoints = true; + } + + return; + } helpers::assertThat(rt, false, "StyleSheet.configure's settings received unexpected key: '" + std::string(propertyName) + "'"); }); @@ -142,7 +156,13 @@ void HybridStyleSheet::parseBreakpoints(jsi::Runtime &rt, jsi::Object breakpoint auto& state = registry.getState(rt); registry.registerBreakpoints(rt, sortedBreakpoints); - state.computeCurrentBreakpoint(this->_unistylesRuntime->getScreen().width); + + auto rawWidth = this->_unistylesRuntime->getScreen().width; + auto width = registry.shouldUsePointsForBreakpoints + ? rawWidth / this->_unistylesRuntime->getPixelRatio() + : rawWidth; + + state.computeCurrentBreakpoint(width); } void HybridStyleSheet::parseThemes(jsi::Runtime &rt, jsi::Object themes) { @@ -293,7 +313,12 @@ void HybridStyleSheet::onPlatformNativeDependenciesChange(std::vector_unistylesRuntime->getScreen().width); + auto rawWidth = this->_unistylesRuntime->getScreen().width; + auto width = registry.shouldUsePointsForBreakpoints + ? rawWidth / this->_unistylesRuntime->getPixelRatio() + : rawWidth; + + registry.getState(rt).computeCurrentBreakpoint(width); } // check if color scheme changed and then if Unistyles state depend on it (adaptive themes) diff --git a/cxx/parser/Parser.cpp b/cxx/parser/Parser.cpp index 72c574e7..6f764be1 100644 --- a/cxx/parser/Parser.cpp +++ b/cxx/parser/Parser.cpp @@ -653,7 +653,11 @@ jsi::Value parser::Parser::getValueFromBreakpoints(jsi::Runtime& rt, Unistyle::S auto sortedBreakpoints = state.getSortedBreakpointPairs(); auto hasBreakpoints = !sortedBreakpoints.empty(); auto currentBreakpoint = state.getCurrentBreakpointName(); - auto dimensions = this->_unistylesRuntime->getScreen(); + auto rawDimensions = this->_unistylesRuntime->getScreen(); + auto pixelRatio = this->_unistylesRuntime->getPixelRatio(); + auto dimensions = registry.shouldUsePointsForBreakpoints + ? Dimensions(rawDimensions.width / pixelRatio, rawDimensions.height / pixelRatio) + : rawDimensions; auto currentOrientation = dimensions.width > dimensions.height ? "landscape" : "portrait"; diff --git a/expo-example/unistyles.ts b/expo-example/unistyles.ts index 381e68d8..a596e18e 100644 --- a/expo-example/unistyles.ts +++ b/expo-example/unistyles.ts @@ -62,7 +62,7 @@ declare module 'react-native-unistyles' { StyleSheet.configure({ settings: { - adaptiveThemes: true, + adaptiveThemes: true }, breakpoints, themes: { diff --git a/src/specs/StyleSheet/index.ts b/src/specs/StyleSheet/index.ts index 0a444c05..4f8e3387 100644 --- a/src/specs/StyleSheet/index.ts +++ b/src/specs/StyleSheet/index.ts @@ -12,7 +12,8 @@ type UnistylesThemeSettings = { } type UnistylesSettings = UnistylesThemeSettings & { - CSSVars?: boolean + CSSVars?: boolean, + nativeBreakpointsMode?: 'pixels' | 'points' } export type UnistylesConfig = { From d1533c44c829ac57733b4e68bcdfa766892e4874 Mon Sep 17 00:00:00 2001 From: Jacek Pudysz Date: Thu, 30 Jan 2025 13:22:31 +0100 Subject: [PATCH 2/4] docs: add section about nativeBreakpointsMode --- docs/.astro/settings.json | 2 +- docs/astro.config.mjs | 12 ++++++------ docs/src/content/docs/v3/guides/merging-styles.mdx | 4 ++++ docs/src/content/docs/v3/references/breakpoints.mdx | 8 ++++++++ docs/src/content/docs/v3/start/configuration.mdx | 3 ++- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/docs/.astro/settings.json b/docs/.astro/settings.json index 07e74934..bbfd7dbc 100644 --- a/docs/.astro/settings.json +++ b/docs/.astro/settings.json @@ -1,5 +1,5 @@ { "_variables": { - "lastUpdateCheck": 1737126711469 + "lastUpdateCheck": 1738238865697 } } \ No newline at end of file diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 618ff302..d8aa4a5d 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -73,7 +73,7 @@ export default defineConfig({ items: [ { label: 'Introduction', slug: 'v3/start/introduction' }, { label: 'Getting started', slug: 'v3/start/getting-started' }, - { label: 'Configuration', slug: 'v3/start/configuration' }, + { label: 'Configuration', slug: 'v3/start/configuration', badge: 'Updated' }, { label: 'New features', slug: 'v3/start/new-features' }, { label: 'Look under the hood', slug: 'v3/start/how-unistyles-works' }, { label: 'Migration guide', slug: 'v3/start/migration-guide' } @@ -82,12 +82,12 @@ export default defineConfig({ { label: 'Guides', items: [ - { label: 'Merging styles', slug: 'v3/guides/merging-styles', badge: 'New!' }, + { label: 'Merging styles', slug: 'v3/guides/merging-styles', badge: 'Updated' }, { label: 'Theming', slug: 'v3/guides/theming' }, { label: 'Avoiding Keyboard', slug: 'v3/guides/avoiding-keyboard' }, { label: 'Expo Router', slug: 'v3/guides/expo-router' }, { label: 'Custom web', slug: 'v3/guides/custom-web', badge: 'WIP' }, - { label: 'Server side rendering', slug: 'v3/guides/server-side-rendering', badge: 'New!' }, + { label: 'Server side rendering', slug: 'v3/guides/server-side-rendering' }, ] }, { @@ -102,11 +102,11 @@ export default defineConfig({ { label: 'Variants', slug: 'v3/references/variants' }, { label: 'Compound Variants', slug: 'v3/references/compound-variants' }, { label: 'Web styles', slug: 'v3/references/web-styles' }, - { label: 'Web Only Features', slug: 'v3/references/web-only', badge: 'Updated' }, + { label: 'Web Only Features', slug: 'v3/references/web-only' }, { label: 'Scoped theme', slug: 'v3/references/scoped-theme' }, - { label: 'Update 3rd party views', slug: 'v3/references/3rd-party-views', badge: 'New!' }, + { label: 'Update 3rd party views', slug: 'v3/references/3rd-party-views' }, { label: 'withUnistyles', slug: 'v3/references/with-unistyles' }, - { label: 'useUnistyles', slug: 'v3/references/use-unistyles', badge: 'New!' }, + { label: 'useUnistyles', slug: 'v3/references/use-unistyles' }, { label: 'Display and Hide', slug: 'v3/references/display-hide' }, { label: 'Edge to edge', slug: 'v3/references/edge-to-edge' }, { label: 'Dimensions', slug: 'v3/references/dimensions' }, diff --git a/docs/src/content/docs/v3/guides/merging-styles.mdx b/docs/src/content/docs/v3/guides/merging-styles.mdx index 8d8d79cf..16113ccc 100644 --- a/docs/src/content/docs/v3/guides/merging-styles.mdx +++ b/docs/src/content/docs/v3/guides/merging-styles.mdx @@ -44,6 +44,10 @@ When you see this warning, your component will render correctly, but any new eve It's critical to ship Unistyles 3.0 apps without this warning, as it can cause unexpected behavior. + + ### Spreading a single Unistyle Another problematic case is spreading a single Unistyle and merging it, e.g., with inline styles: diff --git a/docs/src/content/docs/v3/references/breakpoints.mdx b/docs/src/content/docs/v3/references/breakpoints.mdx index 470e9afd..a8dd53b6 100644 --- a/docs/src/content/docs/v3/references/breakpoints.mdx +++ b/docs/src/content/docs/v3/references/breakpoints.mdx @@ -136,6 +136,14 @@ const styles = StyleSheet.create(theme => ({ })) ``` +### Pixel/Point mode for native breakpoints + +By default, Unistyles will use `pixels` for native breakpoints. This means that the breakpoints and [mq](/v3/references/media-queries) will be computed based on mobile screen pixels. +You can change this behavior by setting `nativeBreakpointsMode` to `points` in your [configuration](/v3/start/configuration#settings-optional). + +If `nativeBreakpointsMode` is set to `points` all breakpoints and `mq` will be computed based on mobile screen points (screen in pixels divided by pixel ratio). + + ### Show/Hide your components based on breakpoints In order to show or hide your components based on the screen size, you can leverage the `mq` utility and one of the two built-in components: `Display` and `Hide`. diff --git a/docs/src/content/docs/v3/start/configuration.mdx b/docs/src/content/docs/v3/start/configuration.mdx index 7cf88ebf..a4593c22 100644 --- a/docs/src/content/docs/v3/start/configuration.mdx +++ b/docs/src/content/docs/v3/start/configuration.mdx @@ -73,11 +73,12 @@ const breakpoints = { ### Settings (Optional) -The `Settings` object has been simplified, and in the most recent version, it supports only three properties: +The `Settings` object has been simplified, and in the most recent version, it supports only four properties: - **`adaptiveThemes`** – a boolean that enables or disables adaptive themes [learn more](/v3/guides/theming#adaptive-themes) - **`initialTheme`** – a string or a synchronous function that sets the initial theme - **`CSSVars`** – a boolean that enables or disables CSS variables (defaults to `true`) [learn more](/v3/references/web-only#css-variables) +- **`nativeBreakpointsMode`** - iOS/Android only. User preferred mode for breakpoints. Can be either `points` or `pixels` (defaults to `pixels`) [learn more](/v3/references/breakpoints#pixelpoint-mode-for-native-breakpoints) ```tsx title="unistyles.ts" const settings = { From 07e5b6c1e7bfd090fe18b53e90843d6557206082 Mon Sep 17 00:00:00 2001 From: Jacek Pudysz Date: Thu, 30 Jan 2025 13:47:47 +0100 Subject: [PATCH 3/4] docs: add babel autoRemapImports --- .../content/docs/v3/other/babel-plugin.mdx | 50 +++++++- plugin/index.d.ts | 112 ++++++++++++------ plugin/index.js | 1 + 3 files changed, 129 insertions(+), 34 deletions(-) diff --git a/docs/src/content/docs/v3/other/babel-plugin.mdx b/docs/src/content/docs/v3/other/babel-plugin.mdx index e0831c7b..ab400087 100644 --- a/docs/src/content/docs/v3/other/babel-plugin.mdx +++ b/docs/src/content/docs/v3/other/babel-plugin.mdx @@ -222,9 +222,57 @@ It can be useful for monorepos that use Unistyles with absolute paths, such as ` } ``` +#### `autoRemapImports` + +This is the most powerful option, but most likely you won't need to use it. +It allows you to remap uncommon imports to Unistyles components. + +This may happen if a 3rd library does not import `react-native` components directly, but instead uses its own factory or a relative path. +Unistyles uses it internally to support the following imports from `react-native` internals: + +```js +import { NativeText } from "react-native/Libraries/Text/TextNativeComponent" +import View from "react-native/Libraries/Components/View/ViewNativeComponent" +``` + +Let's say you have a library called `custom-library` that imports `react-native` raw components directly: + +```js title="node_modules/custom-library/components/index.js" +import { NativeText } from "react-native/Libraries/Text/TextNativeComponent" +import View from "react-native/Libraries/Components/View/ViewNativeComponent" +``` + +To convert it to Unistyles, you can use following configuration: + +```ts +{ + autoRemapImports: [ + path: 'node_modules/custom-library/components', // <- must be path from node_modules + imports: [ + { + isDefault: false, // <- is default import? + name: 'NativeText', // <- if not, what's the import name? + path: 'react-native/Libraries/Text/TextNativeComponent' // <- what's the import source? + mapTo: 'NativeText' // <- which Unistyles component should be used? Check react-native-unistyles/src/components/native + }, + { + isDefault: true, + path: 'react-native/Libraries/Components/View/ViewNativeComponent', + mapTo: 'NativeView' + } + ] + ] +} +``` + +:::caution +If you use raw `react-native` imports within your code, Unistyles will auto map it to `react-native-unistyles` factories. +This options should be only used for 3rd party libraries from `node_modules`. +::: + #### `autoProcessPaths` -This configuration is unrelated to the `autoProcessRoot` and `autoProcessImports` options and can be used alongside them. +This configuration is unrelated to the `autoProcessRoot`, `autoProcessImports` and `autoRemapImports` options and can be used alongside them. By default, the Babel plugin ignores `node_modules`. However, you can extend these paths to attempt converting 3rd components into Unistyles compatible ones. Within these paths, we will replace `react-native` imports with `react-native-unistyles` factories that borrow component refs. [Read more](/v3/other/babel-plugin#3-component-factory-borrowing-ref). diff --git a/plugin/index.d.ts b/plugin/index.d.ts index 885af55f..8ff9ec37 100644 --- a/plugin/index.d.ts +++ b/plugin/index.d.ts @@ -1,43 +1,89 @@ +type RemapImport = { + name?: string, + isDefault: boolean, + path: string, + mapTo: string +} + +type RemapConfig = { + path: string, + imports: Array +} + export interface UnistylesPluginOptions { /** * Example: "src" or "apps/mobile" * Add this option if some of your components don't have `react-native-unistyles` import. * Babel plugin will automatically process all files under this root. */ - autoProcessRoot?: string - - /** - * Example: ['@codemask/styles'] - * Enable this option if you want to process only files containing specific imports. - */ - autoProcessImports?: string[] - - /** - * Example: ['external-library/components'] - * Enable this option to process some 3rd party components under `node_modules`. - * Under these paths we will replace `react-native` imports with `react-native-unistyles` factories that will borrow components refs [read more](https://www.unistyl.es/v3/other/babel-plugin#3-component-factory-borrowing-ref). - * - * Defaults to: - * - * ```ts - * ['react-native-reanimated/src/component', 'react-native-gesture-handler/src/components'] - * ``` - */ - autoProcessPaths?: string[]; - - /** - * In order to list detected dependencies by the Babel plugin you can enable the `debug` flag. - * It will `console.log` name of the file and component with Unistyles dependencies. - */ - debug?: boolean; - - /** - * Only applicable for Unistyles monorepo for - * path resolution, don't use it! - */ - isLocal?: boolean; + autoProcessRoot?: string, + + /** + * Example: ['@codemask/styles'] + * Enable this option if you want to process only files containing specific imports. + */ + autoProcessImports?: Array, + + /** + * Example: [{ + * path: "node_modules/custom-library/components", + * imports: [ + * { + * name: "NativeText", + * isDefault: false, + * path: "react-native/Libraries/Text/TextNativeComponent", + * mapTo: "NativeText" + * }, + * { + * isDefault: true, + * path: "react-native/Libraries/Components/View/ViewNativeComponent", + * mapTo: "NativeView" + * } + * ] + * }] + * + * Will map: + * import { NativeText } from "react-native/Libraries/Text/TextNativeComponent" + * to Unistyles "NativeText" + * + * import View from "react-native/Libraries/Components/View/ViewNativeComponent" + * to Unistyles "NativeView" + * + * This is the most powerful way of remapping imports. If 3rd party library uses imports different from `react-native` we can remap them to `react-native-unistyles` factories. + * Internally we do that for raw RCTView and RCTText components. + * + * path -> must be within node_modules folder + * imports.name is Optional if library used export default + * imports.mapTo - name of the component from react-native-unistyles/src/components/native + */ + autoRemapImports?: Array, + + /** + * Example: ['external-library/components'] + * Enable this option to process some 3rd party components under `node_modules`. + * Under these paths we will replace `react-native` imports with `react-native-unistyles` factories that will borrow components refs [read more](https://www.unistyl.es/v3/other/babel-plugin#3-component-factory-borrowing-ref). + * + * Defaults to: + * + * ```ts + * ['react-native-reanimated/src/component', 'react-native-gesture-handler/src/components'] + * ``` + */ + autoProcessPaths?: Array, + + /** + * In order to list detected dependencies by the Babel plugin you can enable the `debug` flag. + * It will `console.log` name of the file and component with Unistyles dependencies. + */ + debug?: boolean, + + /** + * Only applicable for Unistyles monorepo for + * path resolution, don't use it! + */ + isLocal?: boolean } export interface UnistylesPluginPass { - opts: UnistylesPluginOptions; + opts: UnistylesPluginOptions } diff --git a/plugin/index.js b/plugin/index.js index 5ad4e2e9..a4de8d3c 100644 --- a/plugin/index.js +++ b/plugin/index.js @@ -81,6 +81,7 @@ module.exports = function ({ types: t }) { /** @param {import('./index').UnistylesPluginPass} state */ ImportDeclaration(path, state) { const exoticImport = REPLACE_WITH_UNISTYLES_EXOTIC_PATHS + .concat(state.opts.autoRemapImports ?? []) .find(exotic => state.filename.includes(exotic.path)) if (exoticImport) { From 31dda70cc2ad8878c030814cbae986f0e8347da4 Mon Sep 17 00:00:00 2001 From: Jacek Pudysz Date: Thu, 30 Jan 2025 13:59:38 +0100 Subject: [PATCH 4/4] chore: update sponsors --- README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b526008f..b8589949 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,9 @@ Then follow [installation guides](https://unistyl.es/v3/start/getting-started) f galaxies-dev + + FTCHD + mobily @@ -62,8 +65,14 @@ Then follow [installation guides](https://unistyl.es/v3/start/getting-started) f oscklm - - giovannilondero + + guillaumehcht + + + FilipiRafael + + + 4cc3ssX ## Past sponsors @@ -89,6 +98,9 @@ Then follow [installation guides](https://unistyl.es/v3/start/getting-started) f hyoban + + giovannilondero + ## Sponsor my work