Skip to content

Feat/nitro035 support#2

Merged
mCodex merged 10 commits into
mainfrom
feat/nitro035Support
Apr 28, 2026
Merged

Feat/nitro035 support#2
mCodex merged 10 commits into
mainfrom
feat/nitro035Support

Conversation

@mCodex
Copy link
Copy Markdown
Owner

@mCodex mCodex commented Apr 28, 2026

This pull request introduces a number of foundational improvements and maintenance updates to the project, focusing on documentation, platform requirements, development tooling, and Android platform behavior. The key changes include a major version bump with a detailed changelog, stricter platform requirements (notably raising the minimum iOS version to 16.0), improved Android stub implementation, and the addition of configuration files for funding, security, and automated tooling.

Documentation and Versioning:

  • Added a comprehensive CHANGELOG.md following Keep a Changelog and Semantic Versioning, documenting all notable changes for version 2.0.0, including breaking changes, new features, removals, and bug fixes.
  • Added a SECURITY.md file outlining supported versions and responsible disclosure guidelines for security vulnerabilities.
  • Added a pull request template in .github/pull_request_template.md to standardize PR submissions.

Platform and Compatibility Updates:

  • Raised the minimum supported iOS version to 16.0 in both the CocoaPods spec (NitroSfsymbols.podspec) and the example Xcode project, and updated other Apple platform minimums (macOS 13.0, tvOS 16.0). [1] [2] [3]
  • Updated Xcode project settings to specify supported platforms and targeted device families.

Android Implementation:

  • Refactored the Android stub (NitroSfsymbols.kt) for <SFSymbolView /> to render an empty, zero-cost view, and log a single warning on first use, replacing the previous verbose placeholder and per-prop warnings. This makes the Android behavior lighter and less noisy for developers.

Development and Tooling:

  • Added configuration files for funding (.github/FUNDING.yml), automated dependency updates (.github/dependabot.yml), code formatting and linting (biome.json), and removed the old ESLint config in favor of Biome. [1] [2] [3] [4]
  • Integrated the React Compiler Babel plugin in both the main and example app Babel configs for improved React performance and compatibility. [1] [2]

Other Notable Changes:

  • Added nkf gem to the example app's Gemfile for improved text processing.
  • Minor code style and ordering fixes in the example app's entry point.

These updates collectively modernize the project, improve cross-platform developer experience, and lay a solid foundation for future development.

mCodex and others added 4 commits April 27, 2026 19:46
Prepare v2.0.0: large refactor and docs overhaul. Adds CHANGELOG, SECURITY, dependabot and PR template, and Biome config; rewrites README with new API and migration notes (icons moved to subpath export, enums -> as const, iOS min bumped to 16, WCAG & Dynamic Type improvements). Simplifies Android implementation to a no-op stub that emits a single warning (AtomicBoolean) and removes verbose placeholder UI. Updates example, generated config, types, and build/project tweaks. Breaking changes and migration steps are documented in README/CHANGELOG.
Drop the reserved/no-op native APIs (reduceComplexity, updateSymbol, animateSymbol) from Android and iOS implementations and remove the generated NitroSfsymbolsConfig.json and its sync script. Inline the host component config in src/index.tsx and update getHostComponent to use it, removing the runtime JSON sync. Simplify package.json nitrogen script to remove the extra sync step. These changes remove dead/ABI-reserved code and eliminate a build-time file sync to streamline the module.
…ns; update SFSymbolView for dynamic font scaling

Co-authored-by: Copilot <copilot@github.com>
Raise minimum platform versions to iOS 16.0 (podspec, example project, Podfile) and bump macOS/tvOS mins in the podspec. Update example Xcode project's IPHONEOS_DEPLOYMENT_TARGET entries to 16.0. Add .github/FUNDING.yml. Regenerate example/ios/Podfile.lock (checksums updated). These changes align the example and podspec with the new minimum supported OS versions.
Copilot AI review requested due to automatic review settings April 28, 2026 11:47
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR modernizes react-native-nitro-sfsymbols for a 2.0.0 release by updating the public TypeScript API, switching to tree-shakable constants and an opt-in icon catalog subpath, refactoring native iOS/Android implementations, and refreshing repo tooling/docs to match updated platform baselines (notably iOS 16+).

Changes:

  • Introduces a new public API surface for <SFSymbolView /> (Dynamic Type scaling, accessibility defaults, fallback symbols) and converts enums to tree-shakable as const constants.
  • Moves the curated SF Symbols catalog behind an ./icons subpath export and updates TS pathing/exports accordingly.
  • Refactors native implementations: iOS coalesced render pipeline + caching + symbol effects; Android becomes a zero-cost stub with a single warning; updates tooling/docs (Biome, React Compiler, changelog/security policy).

Reviewed changes

Copilot reviewed 35 out of 43 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
turbo.json Formats Turbo env list for build:ios.
tsconfig.test.json Adds a dedicated ts-jest/Node-oriented TS config for tests.
tsconfig.json Adds TS path mapping for react-native-nitro-sfsymbols/icons.
src/utils.ts Removes the previous runtime utility helpers module.
src/types.ts Reworks public types/constants to as const, adds new props and exports (e.g., minTouchTargetStyle).
src/index.tsx Rebuilds the public entry with a new host config, accessibility behavior, Dynamic Type scaling, and wire-shape adapters.
src/icons.ts Replaces the enum-based catalog with a tree-shakable SFIcons const object and type export.
src/generated/NitroSfsymbolsConfig.json Removes generated host config JSON (now inlined).
src/tests/types.test.ts Adds tests validating exported constants and catalog shape.
src/tests/index.test.tsx Removes the previous broad test suite (icons/utils/etc.).
src/NitroSfsymbols.nitro.ts Simplifies the Nitro view spec; adds new wire props (e.g., fallbackName) and removes imperative methods.
scripts/sync-nitro-config.cjs Removes the script that copied generated host config JSON into src/.
package.json Bumps to 2.0.0, adds subpath exports, switches linting to Biome, updates dev deps, and changes Jest config to ts-jest.
nitro.json Updates autolinking config format (separate ios/android blocks).
lefthook.yml Switches pre-commit linting to Biome and expands glob to include JSON.
ios/NitroSfsymbols.swift Major refactor: coalesced renders, per-config image cache, hex parsing cache, symbol effects, fallback symbol support.
android/src/main/java/com/margelo/nitro/nitrosfsymbols/NitroSfsymbols.kt Replaces verbose Android placeholder with an empty view + one-time warning.
SECURITY.md Adds supported versions + responsible disclosure guidance.
README.md Rewrites docs for v2 API, new platform minimums, /icons subpath, and migration guidance.
NitroSfsymbols.podspec Raises Apple platform minimums (iOS 16, macOS 13, tvOS 16).
CHANGELOG.md Adds a Keep a Changelog / SemVer changelog for 2.0.0.
.github/pull_request_template.md Adds a PR template/checklist.
.github/dependabot.yml Adds Dependabot config for npm + GitHub Actions.
.github/FUNDING.yml Adds GitHub funding configuration.
biome.json Adds Biome formatter/linter configuration with repo-specific overrides.
babel.config.js Adds the React Compiler Babel plugin for the library build pipeline.
eslint.config.mjs Removes the old ESLint flat config (replaced by Biome).
example/src/App.tsx Updates example imports to use /icons subpath and applies formatting tweaks.
example/package.json Bumps RN/Nitro versions and tooling deps in the example app; updates Node engine requirement.
example/ios/Podfile Pins iOS deployment target to 16.0 in the example.
example/ios/NitroSfsymbolsExample/Images.xcassets/Contents.json Re-formats JSON (Biome).
example/ios/NitroSfsymbolsExample/Images.xcassets/AppIcon.appiconset/Contents.json Re-formats JSON (Biome).
example/ios/NitroSfsymbolsExample.xcodeproj/project.pbxproj Updates iOS deployment target and tweaks Xcode build settings.
example/index.js Minor import ordering change.
example/babel.config.js Adds React Compiler plugin to the example app Babel config.
example/Gemfile Adds nkf gem to the example Ruby deps.
example/Gemfile.lock Locks updated Ruby dependencies including nkf.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ios/NitroSfsymbols.swift Outdated
Comment on lines +148 to +162
// Only freeze the tint when the user supplied one explicitly. Otherwise
// we leave the image as `.alwaysTemplate` so that `imageView.tintColor`
// reacts dynamically to dark/light mode and Increase Contrast.
if mode == "monochrome", hasExplicitTint, let tint = uiColorFromHex(tintHex) {
resolved = resolved.withTintColor(tint, renderingMode: .alwaysOriginal)
}

/**
* Apply hierarchical color rendering
*
* Creates opacity-based color layers using primary, secondary, and tertiary colors.
*
* @private
* @method applyHierarchicalMode
* @param {UIImage} image - Base symbol image
* @returns {UIImage} Image with hierarchical colors applied
*/
@available(iOS 15.0, *)
private func applyHierarchicalMode(_ image: UIImage) -> UIImage {
guard let config = hierarchicalConfig,
let primaryColorHex = config["primaryColor"] else {
return image
}
Self.imageCache.setObject(resolved, forKey: cacheKey, cost: Int(pointSize * pointSize * 4))
return resolved
}()

let primaryColor = hexStringToUIColor(primaryColorHex)
let symbolConfig = UIImage.SymbolConfiguration(hierarchicalColor: primaryColor)
imageView.image = image
if mode == "monochrome", !hasExplicitTint {
imageView.tintColor = .label
}
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If tintColor is provided but not a parseable hex string, hasExplicitTint stays true so the view won’t fall back to .label, and uiColorFromHex() returning nil means the tint is not applied. This can lead to stale tint from a previous render. Consider treating “invalid hex” the same as “no explicit tint” (and optionally logging a DEBUG warning) so the icon renders predictably.

Copilot uses AI. Check for mistakes.
Comment thread example/src/App.tsx
SF Symbols 7.0+ • Supports iOS 13+
</Text>
<Text style={styles.footerText}>Built with React Native Nitro 🚀</Text>
<Text style={styles.footerSubtext}>SF Symbols 7.0+ • Supports iOS 16+</Text>
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example app UI still says “Supports iOS 13+”, but this PR raises the minimum iOS version to 16.0 (Podfile/podspec). Update this footer text to avoid misleading users testing the example app.

Suggested change
<Text style={styles.footerSubtext}>SF Symbols 7.0+ • Supports iOS 16+</Text>
<Text style={styles.footerSubtext}>SF Symbols 7.0+ • Supports iOS 16+</Text>

Copilot uses AI. Check for mistakes.
Comment thread src/types.ts
Comment on lines 129 to +135
/**
* Supported animation types for SF Symbols (iOS 17+).
* Branded string type for the curated SF Symbols catalog.
*
* @enum {string}
* Importing the catalog (`react-native-nitro-sfsymbols/icons`) widens the
* `name` prop to the curated names while still allowing any string.
*/
export enum SFSymbolAnimationType {
/** No animation */
NONE = 'none',
/** Bounce animation */
BOUNCE = 'bounce',
/** Scale animation */
SCALE = 'scale',
/** Pulse animation */
PULSE = 'pulse',
/** Rotate animation */
ROTATE = 'rotate',
/** Appear animation */
APPEAR = 'appear',
/** Disappear animation */
DISAPPEAR = 'disappear',
/** Replace animation */
REPLACE = 'replace',
}
export type SFIconName = string;
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SFIconName is documented as a branded type that gets widened by importing the /icons catalog, but it's currently just type SFIconName = string, so no branding or widening can occur. Either adjust the docstring to reflect the actual behavior (autocomplete via SFIcons.* constants) or implement a real branded/augmented type strategy.

Copilot uses AI. Check for mistakes.
Comment thread src/types.ts Outdated
Comment on lines +184 to +188
/**
* Color used to tint the symbol. When omitted and the user has *Increase
* Contrast* enabled, the system label color is used for guaranteed contrast.
*/
tintColor?: ColorValue;
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tintColor is typed as ColorValue, but the JS layer only forwards string values and the native iOS implementation only parses hex strings. This makes non-hex ColorValues (e.g. rgb(...), hsl(...), processColor numbers) silently drop or mis-render. Consider narrowing the public type/docs to a hex string, or add proper React Native color resolution and pass a supported wire format to native.

Copilot uses AI. Check for mistakes.
Comment thread src/index.tsx Outdated
Comment on lines +74 to +79
function resolveColor(color: ColorValue | undefined): string | undefined {
if (color == null) return undefined;
if (typeof color === 'string') return color;
// OpaqueColorValue / number — let RN handle resolution downstream.
return undefined;
}
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolveColor() claims to let RN resolve non-string ColorValues downstream, but it returns undefined for numeric/opaque colors, effectively dropping the tint. This should either resolve numeric colors (e.g. via processColor) or the public type/docs should be restricted to the supported string format to avoid surprising no-ops.

Copilot uses AI. Check for mistakes.
Comment thread ios/NitroSfsymbols.swift Outdated
Comment on lines 296 to 301
/// Hex representation of the system label color so cache keys remain stable
/// when no explicit tint is provided. Honors *Increase Contrast*.
private static func systemTintHex() -> String {
if UIAccessibility.isDarkerSystemColorsEnabled { return "@label-hc" }
return "@label"
}
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

systemTintHex() is currently unused (no call sites). Either remove it to keep the implementation lean, or use it in the cache key construction so the intent of stable cache keys for system tint is actually realized.

Suggested change
/// Hex representation of the system label color so cache keys remain stable
/// when no explicit tint is provided. Honors *Increase Contrast*.
private static func systemTintHex() -> String {
if UIAccessibility.isDarkerSystemColorsEnabled { return "@label-hc" }
return "@label"
}

Copilot uses AI. Check for mistakes.
Comment thread README.md Outdated
Comment on lines +146 to +163
## Migrating from 1.x

```bash
yarn lint --fix
```

### 🏗️ Build

```bash
yarn prepare
```

> [!NOTE]
> Run `yarn nitrogen` after modifying `NitroSfsymbols.nitro.ts`

---

## 🤝 Contributing

Contributions are **welcome and encouraged**! 🎉

Please read [CONTRIBUTING.md](./CONTRIBUTING.md) for:
- 📋 Development workflow
- ✅ Code style guidelines
- 🧪 Testing requirements
- 📤 Pull request process
- 📖 [Code of Conduct](./CODE_OF_CONDUCT.md)

---

## 📄 License

MIT © [Mateus Andrade](https://github.com/mCodex)

<div align="center">

**[↑ back to top](#-react-native-nitro-sfsymbols)**

</div>

---

## 🔗 Resources

| Resource | Link |
|----------|------|
| 📖 SF Symbols Guide | [developer.apple.com/design/human-interface-guidelines/sf-symbols](https://developer.apple.com/design/human-interface-guidelines/sf-symbols) |
| 🎨 SF Symbols Browser | [developer.apple.com/sf-symbols](https://developer.apple.com/sf-symbols/) |
| ⚡ Nitro Modules Docs | [nitro.margelo.com](https://nitro.margelo.com/) |
| 🚀 React Native Docs | [reactnative.dev](https://reactnative.dev/) |
| 🎨 Material Icons | [fonts.google.com/icons](https://fonts.google.com/icons) |

---
1. **Bump `react-native-nitro-modules` to `>= 0.35`.**
2. **Imports**: `SFIcons` moved to a subpath:
```diff
- import { SFIcons } from 'react-native-nitro-sfsymbols';
+ import { SFIcons } from 'react-native-nitro-sfsymbols/icons';
```
3. **Removed runtime helpers** (use the constants directly):
- `isValidSFIcon`, `getAllSFIcons`, `camelCaseToSFSymbol`, `searchSFIcon`
- `isValidColor`, `normalizeColor`, `clampOpacity`, `validateConfig`,
`applyDefaults`, `optimizeProps`, `createHierarchicalConfig`,
`createPaletteConfig`, `dimensionToSymbolSize`, `getPresetSize`
4. **Constants are now plain objects** (no longer `enum`s). Member access is
identical (`SFSymbolWeight.BOLD`); the type is a string-literal union.
5. **Color config keys**: `primaryColor` → `primary`, `secondaryColor` → `secondary`, etc.
```diff
- hierarchical={{ primaryColor: '#FF5722' }}
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The migration guide mentions moving SFIcons to the /icons subpath, but the actual catalog also changes/renames entries (e.g. TOGGLE_POWER is gone and POWER exists). Since this is a breaking change for consumers, the migration steps should call out that the catalog is curated and some keys were removed/renamed, with guidance on how to update.

Copilot uses AI. Check for mistakes.
Comment thread src/NitroSfsymbols.nitro.ts Outdated
Comment on lines 32 to 35
/** `{ primary, secondary?, tertiary? }` hex colors. */
hierarchicalConfig?: Record<string, string>;

/**
* Palette color configuration
* Used when renderingMode is "palette"
*/
/** `{ primary, secondary?, tertiary? }` hex colors. */
paletteConfig?: Record<string, string>;
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doc comment for hierarchicalConfig/paletteConfig says the wire shape is { primary, secondary?, tertiary? }, but the JS adapter sends { primaryColor, secondaryColor, tertiaryColor } and the iOS implementation reads primaryColor keys. Please update the comment to reflect the actual wire keys to avoid confusion when debugging native props.

Copilot uses AI. Check for mistakes.
Comment thread ios/NitroSfsymbols.swift Outdated
Comment on lines +100 to +114
let pointSize = CGFloat(size ?? 24)
let weightVal = parseWeight(weight ?? "regular")
let scaleVal = parseScale(scale ?? "medium")
let mode = renderingMode ?? "monochrome"
let hasExplicitTint = (tintColor != nil)
let tintHex = tintColor ?? "@label"

let cacheKey = NSString(format: "%@|%@|%.1f|%d|%d|%@|%@|%@|%@|%d|%d",
symbolName, fallbackName ?? "_",
pointSize, weightVal.rawValue, scaleVal.rawValue,
mode, tintHex,
hashConfig(hierarchicalConfig),
hashConfig(paletteConfig),
hasExplicitTint ? 1 : 0,
(variableColor ?? false) ? 1 : 0)
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

variableColor is included in the cache key and exposed as a prop, but it isn't actually applied to the UIImage configuration anywhere in render(). As-is, toggling variableColor appears to be a no-op (aside from cache misses). Either implement the intended variable-color configuration on iOS (iOS 16+) or remove/deprecate the prop and update the docs/changelog accordingly.

Copilot uses AI. Check for mistakes.
mCodex added 4 commits April 28, 2026 08:59
- Drop variableColor boolean prop (was a no-op; use animation={{type:'variableColor'}})
- Narrow tintColor to string (hex); drop redundant resolveColor helper
- Treat invalid hex as no-tint instead of leaving stale color in cache key
- Remove unused systemTintHex Swift helper
- Fix SFIconName, hierarchicalConfig, paletteConfig doc comments
- README/CHANGELOG: document tintColor narrowing + catalog renames
Validate and resolve tintColor hex up-front to avoid rendering stale tints from previous passes, falling back to the system label color when the hex is unparseable. Update image cache key and remove the old systemTintHex helper. Remove variableColor from the native view, JS props, and type definitions, and simplify the React wrapper by removing resolveColor and related wiring. Docs/types updated: tintColor now accepts #RRGGBB or #RRGGBBAA and SFIconName/docs clarified; package.json version adjusted.
Revamp README presentation and content: add centered header, additional badges (npm downloads, PRs welcome), and a Table of Contents; update headings with emojis and improved wording for Highlights, Install, Usage, Accessibility and Performance sections. Add new sections for Contributing, Support and Acknowledgments with a quick-start contributor workflow and example app instructions. Clarify API docs (tintColor now documented as a string hex format) and remove the variableColor prop entry. Minor copy edits: platform table iconography, animation/reduce-motion note, install callout, and update license attribution link to GitHub profile.
Upgrade GitHub Actions references and platform/tool versions across CI. Switched action pins to stable tags (actions/setup-node@v4, actions/cache@v4, actions/checkout@v5, actions/setup-java@v4, maxim-lobanov/setup-xcode@v1) and updated internal setup action to use setup-node@v4. Bumped Java to 21, Node (.nvmrc) to v24, macOS runner to macos-15 and Xcode to 26.2. These changes refresh action versions and align CI with newer toolchains and runners.
@mCodex mCodex merged commit e2a54a4 into main Apr 28, 2026
5 checks passed
@mCodex mCodex deleted the feat/nitro035Support branch April 28, 2026 12:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants