Skip to content

feat!: deep overhaul — builder-bob build, peer deps, accessibility, tests & CI - #819

Open
kuraydev wants to merge 2 commits into
masterfrom
chore/deep-overhaul-2026
Open

kuraydev wants to merge 2 commits into
masterfrom
chore/deep-overhaul-2026

Conversation

@kuraydev

@kuraydev kuraydev commented Jun 29, 2026

Copy link
Copy Markdown
Owner

Automated deep-overhaul PR — review before merge.

Summary

A full modernization of react-native-bouncy-checkbox that fixes packaging correctness, stands up tooling/CI/tests from scratch, and cleans up the source — without changing any public prop name, runtime default value, or the imperative ref API. The package now genuinely ships with zero runtime dependencies and modern dual-format (CJS + ESM) output with proper types.

All local checks pass: typecheck, lint, 11 tests, and a clean build.

Non-breaking improvements

Packaging & metadata

  • Removed an accidental self-dependency on react-native-bouncy-checkbox in dependencies.
  • Added honest, wide peerDependencies: react >=16.8.0, react-native >=0.63.0.
  • Added a modern exports map plus module / react-native / source / types fields and a files allowlist (tarball is now 20kB and ships only lib/ source + build/ + README/LICENSE).
  • Repointed repository / homepage / bugs / FUNDING to kuraydev. npm package name is unchanged.
  • Removed dead/abandoned devDeps: @types/react-native (deprecated stub), react-native-typescript-transformer, prettier-format, npm-post-install, cpx, and unused @react-native/* config/metro packages.

Source & a11y

  • New defaultChecked prop for uncontrolled initial state (closes add defaultChecked prop #815) — does not affect the existing isChecked / useBuiltInState model.
  • Default accessibilityRole="checkbox" + accessibilityState={{ checked }} on the touchable (overridable via props) — improves screen-reader and react-native-web semantics (check icon not rendering on react native web #103).
  • Fixed an invalid Callback<any> generic in useStateWithCallback (latent TS error); the helper is now fully generic.
  • Converted fake StyleSheet function "entries" into real static styles + typed dynamic helpers (removes per-render reallocation), moved the Animated.Value into a useRef, and memoized the render callbacks.
  • Kept the open ImageComponent / TouchableComponent props as React.ComponentType<any> (documented) so third-party touchables/images like FastImage still type-check.

Tests & CI

  • Real Jest + @testing-library/react-native suite (11 tests): render, built-in toggle, controlled mode, defaultChecked, controlled prop change, onPress/onLongPress payloads, imperative ref.onCheckboxPress()/onCheckboxLongPress(), disableText, custom textComponent/iconComponent, and a11y state.
  • GitHub Actions CI (typecheck / lint / test / build on Node 18/20/22) and a semantic-release workflow (replacing the never-run release wiring; no Travis existed).

Docs & hygiene

  • README rewritten to fix every factual error: real prop name unFillColor (capital F), useBuiltInState default true, fillColor default #ffc484, added iconImageStyle and defaultChecked rows, removed dead disableBuiltInState references, switched examples to package-name imports, added Accessibility + New Architecture/Expo/Web sections, CI/TypeScript badges, and Contributing/Changelog links. The "Zero Dependency" claim is now true (bounceable removed).
  • Added CHANGELOG.md (Keep a Changelog), CONTRIBUTING.md, issue forms, and a PR template.

Breaking changes (recommend v5.0.0 major)

  • Build output paths changed from build/dist/* to build/{commonjs,module,typescript}/* via react-native-builder-bob (CommonJS + ESM + TypeScript targets). The documented import BouncyCheckbox from "react-native-bouncy-checkbox" entry and the default export shape are unchanged; only deep imports into build/dist/* break.
  • exports map introduced — module resolution is now condition-based (require → CJS, import → ESM, types per condition, react-native/sourcelib/index.ts). Verified both require() and ESM import resolve.
  • Removed the unused @freakycoder/react-native-bounceable runtime dependency — projects that relied on it being installed transitively must add it directly.
  • peerDependencies introduced — may surface peer-range warnings; ranges were chosen wide to minimize friction.

No public prop names, runtime defaults, or the BouncyCheckboxHandle ref API changed.

Deliberately not changed

Verification

Check Result
Install ok — npm install --ignore-scripts (1269 pkgs, lockfile regenerated)
Typecheck pass — tsc --noEmit
Lint pass — eslint . (0 errors; 2 intentional no-explicit-any warnings on open component props)
Test pass — jest 11/11
Build ok — bob build, dual CJS/ESM + d.ts, check.png copied into both outputs
Resolution require()build/commonjs/index.js; ESM importbuild/module/index.js both resolve
Pack npm pack --dry-run → 20.2kB, lib source + build only (no examples/tests/gifs)

Closes

Partially addresses #103 (accessibility/web semantics); responds to #90 (keep Animated by default).

react-native-web support (Closes #103)

The bundled default check icon (lib/local-assets/check.png, loaded via require()) rendered blank on react-native-web (a few users also reported it on Android). On RNW a required PNG can be sized at 0x0 and the default resize mode is inconsistent, so the default tick was invisible — the community workaround was to pass checkIconImageSource (or an iconImageStyle with a fixed width/height) explicitly.

Fix (in lib/BouncyCheckbox.tsx): the inner check Image is now made robust on web only:

  • It is guaranteed explicit numeric width/height (falling back to the existing 10 default via StyleSheet.flatten if a consumer's iconImageStyle omits them).
  • It is given resizeMode: "contain".

Both behaviors are gated behind Platform.OS === "web". On native (iOS/Android) the component returns the exact same [styles.iconImageStyle, iconImageStyle] style array and passes no resizeMode prop, so native rendering is byte-for-byte unchanged. (The icon asset is square — 64×64 into a square 10×10 box — so contain and the native default cover yield identical pixels regardless.)

No public prop or export was renamed and no default value or visual changed. lib/BouncyCheckbox.style.ts extracts the literal 10 into an exported DEFAULT_ICON_IMAGE_SIZE constant (same value).

Tests: added a react-native-web describe block that, under a mocked Platform.OS === "web", asserts the default check icon renders with explicit width/height (10) and resizeMode: "contain", plus a native guard test asserting no resizeMode prop is set when Platform.OS === "ios". All 13 tests pass.

Verification: tsc --noEmit (clean), eslint . (0 errors), jest (13/13), bob build (commonjs + module + typescript targets succeed). README "New Architecture / Expo / Web" section and CHANGELOG.md ([Unreleased] → Fixed) updated.

kuraydev added 2 commits June 29, 2026 15:57
Modernize tooling, packaging, and source quality without changing any public
prop name, runtime default, or the imperative ref API.

Packaging & deps:
- Remove accidental self-dependency on react-native-bouncy-checkbox.
- Drop unused runtime dep @freakycoder/react-native-bounceable -> the package
  is now truly zero-runtime-dependency.
- Add peerDependencies (react >=16.8.0, react-native >=0.63.0).
- Add exports map, module/react-native/source/types fields, and a files
  allowlist; repoint repo/homepage/bugs/funding URLs to kuraydev.
- Remove dead devDeps (@types/react-native, react-native-typescript-transformer,
  prettier-format, npm-post-install, cpx, unused @react-native/* configs).

Build:
- Migrate from hand-rolled tsc+cpx to react-native-builder-bob (CommonJS + ESM +
  TypeScript targets). Published output moves from build/dist/* to
  build/{commonjs,module,typescript}/*. The default export and bare package
  import are unchanged.

Source:
- Add defaultChecked prop (#815) for uncontrolled initial state.
- Default accessibilityRole="checkbox" + accessibilityState (overridable) (#103).
- Fix invalid Callback<any> generic in useStateWithCallback (now fully generic).
- Convert fake StyleSheet function entries to static styles + typed helpers;
  hold Animated.Value in useRef; memoize render callbacks.

Tests & CI:
- Add Jest + @testing-library/react-native suite (11 tests).
- Add GitHub Actions CI (typecheck/lint/test/build on Node 18/20/22) and a
  semantic-release workflow.

Docs & hygiene:
- Rewrite README: fix unFillColor casing, useBuiltInState=true and
  fillColor=#ffc484 defaults, add iconImageStyle/defaultChecked rows, drop dead
  disableBuiltInState references, package-name imports, a11y + New Arch/Expo/Web
  notes, CI/TS badges.
- Add CHANGELOG, CONTRIBUTING, issue forms and PR template.

BREAKING CHANGE: published module output paths changed (build/dist -> build/
commonjs|module|typescript) and the build now uses react-native-builder-bob with
an exports map. Deep imports into build/dist/* will break; the documented
`import BouncyCheckbox from "react-native-bouncy-checkbox"` entry is unchanged.
The unused @freakycoder/react-native-bounceable runtime dependency was removed;
projects that relied on it being installed transitively must add it directly.
The bundled default check icon (lib/local-assets/check.png, loaded via
require) rendered blank on react-native-web because RNW can size a
required PNG at 0x0 and applies an inconsistent resize mode. Guarantee
explicit dimensions and resizeMode: "contain" on web only
(Platform.OS === "web"); native iOS/Android passes no resizeMode and
keeps the same style array, so its rendering is byte-for-byte unchanged.

No public prop or default value changes. Adds Platform.OS='web' Jest
coverage for the icon dimensions/resizeMode and a native byte-for-byte
guard test.

Closes #103
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.

add defaultChecked prop check icon not rendering on react native web

1 participant