Skip to content

chore: deep overhaul — function-component rewrite, builder-bob build, CI, tests & docs (v3.0.0) - #134

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

chore: deep overhaul — function-component rewrite, builder-bob build, CI, tests & docs (v3.0.0)#134
kuraydev wants to merge 9 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.

Review fixes applied: before any npm publish, bump package.json version 2.0.2 → 3.0.0 to match the CHANGELOG and PR title (publish-time step; not a PR blocker).

Summary

This is a full modernization of react-native-dynamic-search-bar, which had not shipped in ~4.5 years (last release 2.0.2, 2021-12-11) and whose tooling was broken (the lint script invoked an uninstalled tslint, the eslint config was legacy and incompatible with the installed eslint 9, scripts targeted a non-existent src/, and there was no CI, no tests, and no committed build).

The library stays a pure-JS React Native component (no native module of its own). The npm package name is unchanged (react-native-dynamic-search-bar). All runtime prop names and default values are preserved; only the things called out under Breaking changes alter the published contract, and each is documented with a migration path.

Non-breaking improvements

  • Imperative handle (create searchBarRef, how to get text? #97): forwardRef + useImperativeHandle exposes focus(), blur(), clear(), and getTextInput() so you can drive the input and read its value.
  • spinnerComponent prop: supply your own JS-only spinner (ideal for Expo / New Architecture, e.g. react-native-animated-spinkit) instead of the native react-native-spinkit.
  • Accessibility: added roles/labels/hints to the container, search icon, clear icon, and the search field.
  • Tooling fixed: dead tslint replaced with eslint 9 flat config (typescript-eslint + react/react-hooks); legacy .eslintrc.js/.eslintignore removed; format/version script globs repointed to src/.
  • Tests: new jest + @testing-library/react-native suite (15 cases) covering render, default/custom placeholder, dark mode placeholder color, onChangeText/onSearchPress/onClearPress, spinner visibility, custom spinnerComponent/searchIconComponent/ImageComponent, and the ref handle — plus a regression test for Bug: onSubmitEditing called twice #108.
  • CI: .github/workflows/ci.yml runs install + typecheck + lint + test + build on a Node 18/20/22 matrix for push/PR.
  • Types tightened: removed any/string escapes — spinnerType is the spinkit union, ISource aligns with ImageSourcePropType, icon component props use React.ReactNode.
  • Metadata: repointed homepage/bugs/repository/author URLs to kuraydev; added peerDependenciesMeta, a files allowlist, sideEffects: false; removed dead devDeps (tslint, @types/react-native, react-native-typescript-transformer, husky cruft).
  • Docs/hygiene: README rewritten (accurate props/API table, fixed the duplicate clearIconImageSource row and the spinnerType name/default mismatch, TS + ref usage, New Architecture/Expo note, single-line install, TOC, Contributing); added CHANGELOG (Keep a Changelog), CONTRIBUTING, issue templates, and a PR template. All README media references verified to still exist.

Breaking changes (recommend v3.0.0 major)

  1. Class -> forwardRef function component. Ref users now get an imperative handle (focus/blur/clear/getTextInput) instead of a class instance; reliance on other class internals (old inputRef field, arbitrary methods) breaks.
  2. react-native-spinkit is now an OPTIONAL peer dependency, resolved lazily. If you use the built-in spinner, keep spinkit installed; otherwise it renders nothing — use the new spinnerComponent prop. Migration: install spinkit OR pass spinnerComponent.
  3. Bug: onSubmitEditing called twice #108 prop-routing fix. Props no longer spread onto both the outer touchable and the inner TextInput. Apps relying on a prop landing on both surfaces change behavior.
  4. Build migrated to react-native-builder-bob. Output moved from build/dist/SearchBar.js to lib/commonjs + lib/module + lib/typescript; main/module/types/react-native/exports updated. The bare package-name import (default + named SearchBar) is preserved and verified; deep imports into build/dist/* break.
  5. TS public types tightened (ISource, spinnerType, ImageComponent, icon component props). Runtime unchanged; strict consumers may need type tweaks.
  6. react & react-native peerDependencies now declared (wide * ranges). Effectively non-breaking, but newly surfaced by package managers.

Verification

  • npm install --legacy-peer-deps — ok (1167 packages); prepare ran the build.
  • tsc --noEmitpass, no errors.
  • eslint . (flat config) — pass, no issues.
  • jestpass, 15/15 tests (incl. Bug: onSubmitEditing called twice #108 regression).
  • bob buildpass, emits CommonJS + ESM + TypeScript; all entry files present.
  • Entry resolvability — lib/commonjs/index.js is valid CommonJS exporting the default + named SearchBar; the only bare-node require() failure is require("react-native") (Flow-typed RN source), which is universal to every RN component lib and resolves under Metro/bundlers.
  • Example app left intact; not exercised locally — CI covers the full gate.

Closes #108
Closes #97
Addresses #98
Addresses #102

react-native-web support (Closes #98, #102)

Both issues ("Cannot build app" / "Failing to build on Expo") trace back to the native module react-native-spinkit being pulled into web/Expo bundles. This change finishes making it truly optional and web-safe.

What changed

  • react-native-spinkit is never imported statically and never required on web. Resolution goes through a single cached helper that short-circuits with if (Platform.OS === 'web') return null before the lazy require, then requires the module inside a try/catch only the first time the built-in spinner actually renders. The previous module-top resolveSpinKit() call was removed, so nothing touches spinkit at import time.
  • When spinkit is unavailable (react-native-web, or Expo without the package), the spinner slot now falls back to React Native's cross-platform ActivityIndicator instead of crashing the bundle.
  • The native path is unchanged: when react-native-spinkit is installed and Platform.OS !== 'web', the exact same <SpinKit .../> renders. No public prop names, defaults, or visuals changed.

Non-breaking

  • The only guard added is web-only (Platform.OS === 'web'); iOS/Android behavior with spinkit installed is byte-for-byte identical.

Tests / docs

  • New src/__tests__/SearchBar.web.test.tsx: renders under a mocked Platform.OS = 'web' (placeholder + search icon, spinnerVisibility without throwing, custom spinnerComponent honored) and asserts the source has no static react-native-spinkit import. Existing suite stays green (19 passing total).
  • README gains a "react-native-web" subsection under New Architecture / Expo; CHANGELOG [Unreleased] documents the web support and the lazy/guarded require.

Verified locally: tsc --noEmit, eslint ., jest, and bob build all pass.

kuraydev added 7 commits June 29, 2026 15:57
…spinner

- Rewrite SearchBar from a class to a function component using hooks.
- Expose focus()/blur()/clear()/getTextInput() via forwardRef +
  useImperativeHandle (closes #97).
- Split props explicitly so TextInputProps reach the TextInput and touchable
  props reach the container, fixing onSubmitEditing firing twice (closes #108).
- Make react-native-spinkit optional via a guarded lazy require so apps that do
  not use the built-in spinner no longer fail to build (closes #98, #102).
- Add a spinnerComponent prop for JS-only spinners (Expo / New Architecture).
- Tighten types: drop any, add SpinnerType union, ReactNode, ImageSourcePropType.
- Add accessibility roles/labels. Preserve all public prop names and defaults.
…data

- Build CommonJS + ESM + TypeScript definitions via react-native-builder-bob;
  source moves to src/, output to lib/ (gitignored).
- Add main/module/types/react-native/source fields, an exports map (dual
  package), sideEffects:false and a files allowlist; default and named imports
  both resolve.
- Declare react and react-native as peerDependencies (none were declared);
  mark react-native-spinkit as an optional peer via peerDependenciesMeta.
- Repoint homepage/bugs/repository from WrathChaos to kuraydev; keep the npm
  package name and MIT license unchanged.
- Remove dead/abandoned devDeps (react-native-typescript-transformer,
  @types/react-native, @react-native-community/eslint-config, eslint-config-airbnb,
  npm-post-install, prettier-format).
- Add eslint.config.js (flat) using typescript-eslint, react and react-hooks
  plugins, prettier compatibility.
- Remove legacy .eslintrc.js (@react-native-community, eslint 9 incompatible),
  .eslintignore, and the broken husky hooks.
- The lint script now runs eslint instead of the uninstalled tslint; the format
  script targets src/ instead of a non-existent path.
Covers default/custom placeholder, onChangeText, onSearchPress, onClearPress,
dark-mode placeholder colors, spinner visibility, custom spinnerComponent,
custom icon/ImageComponent, the imperative ref handle, and a regression test
asserting onSubmitEditing fires exactly once (#108). 15 tests.
- New ci.yml runs install, typecheck, lint, test and build on a Node 18/20/22
  matrix for push and pull_request (replaces the absent automation).
- Add bug/feature issue templates and a pull request template.
- Group dependabot dev-dependency updates, switch to weekly, add the
  github-actions ecosystem; point FUNDING at kuraydev.
- Fix the props table (remove duplicate clearIconImageSource row, correct
  spinnerType name/default, document inherited TextInputProps).
- Add TypeScript usage, imperative ref API, custom spinner, New Architecture /
  Expo notes, a single copy-paste install, ToC and Contributing section.
- Repoint badges/links to kuraydev; keep existing valid media references.
- Add a Keep a Changelog Unreleased section with the v3 migration notes and a
  CONTRIBUTING guide.
@kuraydev kuraydev changed the title Deep overhaul: function component + forwardRef, optional spinner, builder-bob build, ESLint 9, tests & CI chore: deep overhaul — function-component rewrite, builder-bob build, CI, tests & docs (v3.0.0) Jun 29, 2026
kuraydev added 2 commits June 30, 2026 09:45
Guard the optional native spinner behind Platform.OS === 'web' and a lazy,
cached require so react-native-web / Expo projects without react-native-spinkit
bundle and render the search bar with no spinner-related crash. The native code
path is unchanged; on web (or when spinkit is absent) the spinner slot falls
back to RN's cross-platform ActivityIndicator. Adds a web-platform Jest suite
and documents the react-native-web path in the README.
…pinkit

The fallback triggers whenever react-native-spinkit is absent (web, Expo,
or native iOS/Android without the optional package), not just on web. Note
the intentional native behavior change: a requested spinner now renders an
ActivityIndicator instead of nothing when the optional module is missing.
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.

Bug: onSubmitEditing called twice Cannot build app create searchBarRef, how to get text?

1 participant