"Sekali bikin satu komponen, jadi di web + desktop + mobile. Saya tidak mau pusing di deploy sebagai apa — langsung jalan."
Visi ini tidak baru — sudah implisit di ADR-002 Section 1 yang memasukan React Native ke Tier A. Tapi ADR-002 belum mendefinisikan bagaimana caller (developer yang pakai library) memperoleh pengalaman "satu import, jalan semua platform" tanpa peduli implementasi internal.
ADR-006 mengisi gap itu: execution strategy untuk komponen lintas-platform dari sudut pandang caller.
- Tim besar (bukan solo dev) → constraint waktu/throughput tidak ketat.
- Mobile = prioritas tinggi, sejajar dengan web (bukan after-thought).
- Desktop ada user nyata via Tauri (
packages/tauri/) — bukan eksperimen. - BitCode engine menyesuaikan UI, bukan sebaliknya — tidak ada blocker downstream.
- Stencil dipertahankan sebagai legacy target (engine BitCode existing konsumsi Stencil).
- Tamagui/gluestack tetap ditunda (Tier B per ADR-002) — visi "satu Tailwind" tidak boleh dilanggar.
- Lynx eksperimen drop:
output/lynx/,scripts/lynx-generator.mjs,demos/lynx-app/dibersihkan.
| Aspek | State sekarang | Konsekuensi untuk visi |
|---|---|
| mitosis.config.js targets | ['stencil', 'react', 'vue'] | Belum ada react-native target → blocker mobile |
| package.json peerDeps | react>=18, vue>=3.4 | Belum ada react-native → blocker mobile |
| tokens/tailwind.preset.cjs | Pakai hsl(var(--bc-*)) dari theme.css | OK, single source = theme.css |
| tokens/nativewind.preset.cjs | Hardcoded HSL palette di file itu sendiri | Drift risk — tidak auto-generate dari theme.css |
| Mitosis 0.13.1 RN output | Tidak terverifikasi suport NativeWind className | Spike wajib sebelum lock strategi |
| Build resolver per-platform (.web.tsx/.native.tsx) | Tidak ada | Blocker untuk komponen Adapt |
| Tauri integration | Repo terpisah packages/tauri/, belum konsumsi @bitcode/ui | OK secara implisit (Tauri = web bundle) |
- Single Caller API — caller selalu
import { BcXxx } from '@bitcode/ui'. Tidak ada import path platform-specific. Bundler resolve otomatis. - Two-Implementation Tier:
- Pure: 1 source
.lite.tsxMitosis → compile ke semua target. Implementasi identik antar platform. - Adapt: 2 source manual (
.web.tsx+.native.tsx), kontrak prop sama, bundler resolve. - Tidak ada Tier "platform-only". Semua komponen wajib jalan di semua target deploy (web + RN + Tauri). Yang berbeda: berapa file source yang author tulis. Caller tidak peduli.
- Pure: 1 source
- Platform Resolver di Build Tooling:
- Vite (web/Tauri):
.web.tsx>.tsx>.ts - Metro (RN):
.native.tsx>.tsx>.ts(default Metro behavior) - Tauri: pakai output Vite (web), tidak ada target terpisah
- Vite (web/Tauri):
- Token Pipeline = Single Source of Truth:
theme.css(Tailwind 4@themesyntax) = source.nativewind.preset.cjsauto-generated daritheme.css(saat ini hardcoded — Phase 0 task).- Tidak boleh ada drift antara web dan RN tokens.
- Mitosis Targets Final:
- Tier A inti:
react,vue,react-native(NativeWind) - Legacy preserved:
stencil(engine BitCode existing — frozen, tidak dapat fitur baru) - Total: 4 target Mitosis output
- Tier A inti:
- Definition of Done diperluas — komponen wajib pass kontrak test + smoke compile di semua 4 target sebelum ditandai Done. Runtime test mobile (iOS/Android device atau simulator) tidak blocking dev, dijalankan di CI nightly atau pre-release.
Caller selalu menulis kode yang sama persis, di semua platform:
// di Vite project (web atau Tauri)
import { BcDataTable, BcForm, BcSplitter } from '@bitcode/ui';
<BcSplitter panels={[
{ id: 'left', content: <BcForm ... /> },
{ id: 'right', content: <BcDataTable ... /> },
]} />// di React Native (Expo / RN CLI)
import { BcDataTable, BcForm, BcSplitter } from '@bitcode/ui';
// ↑ exact same import path — bundler (Metro) resolve otomatis ke .native.tsx
<BcSplitter panels={[
{ id: 'left', content: <BcForm ... /> },
{ id: 'right', content: <BcDataTable ... /> },
]} />
// ↑ exact same JSX — caller tidak peduli BcSplitter di-render sebagai
// drag-resize panels (web) atau stacked collapsible (mobile).Yang berubah otomatis (bundler-resolved, tidak ditulis caller):
- BcSplitter web: drag handle + continuous resize
- BcSplitter native: stacked panels + collapse toggle (orientation prop di-honor sebisa mungkin)
Yang TIDAK berubah: API komponen, prop, event, type signature.
Definisi: Komponen yang implementasi-nya identik antar platform — beda hanya output Mitosis (React vs Vue vs RN syntax).
Contoh kandidat (estimasi):
- Primitif layout: BcStack, BcXStack, BcYStack, BcBox, BcCenter
- Primitif a11y: BcSlot, BcPortal, BcVisuallyHidden, BcAspectRatio
- Display sederhana: BcBadge, BcAvatar, BcSeparator, BcLabel, BcSkeleton, BcSpinner
- Forms simple: BcInput, BcCheckbox, BcRadio, BcSwitch, BcTextarea
- Feedback: BcEmpty, BcStatistic, BcResult
Source file: BcXxx.lite.tsx tunggal di src/components/<group>/<name>/.
Mitosis akan emit:
output/react/.../BcXxx.tsxoutput/vue/.../BcXxx.vueoutput/native/.../BcXxx.tsx(RN dengan NativeWind classes)output/stencil/.../bc-xxx/bc-xxx.tsx(frozen — kalau komponen baru, opt-out via flagmitosisTargets: ['react','vue','native'])
Konstrain: Tidak boleh pakai web-only API (document, window, localStorage, dll) di .lite.tsx. Pakai abstraksi core/hooks/ atau core/providers/ (lihat ADR-002 Section 9).
Definisi: Komponen yang harus berbeda implementasi web vs native untuk memenuhi UX expectation per platform, tapi punya kontrak prop yang identik.
Contoh kandidat (estimasi):
- Layout interaktif: BcSplitter (drag vs collapse), BcDrawer (slide vs sheet)
- Overlay: BcPopover (floating vs sheet), BcContextMenu (right-click vs long-press actionsheet), BcTooltip (hover vs nonaktif)
- Picker: BcDateField (custom vs native picker), BcTimeField, BcSelect (native vs custom)
- Heavy interaction: BcDataTable (full grid vs MobileList variant)
- Mobile-affine: BcBottomTabs, BcSwipeableRow, BcPullToRefresh — ada implementasi web fallback (Sidebar tabs, hover actions, refresh button)
Source files:
src/components/overlays/popover/
BcPopover.contract.ts ← KONTRAK PROP (TS interface, source of truth)
BcPopover.web.tsx ← React/Vue impl (Mitosis)
BcPopover.native.tsx ← RN impl (manual, NativeWind)
BcPopover.test.ts ← contract test (jalan di semua target)
index.ts ← re-export type + impl, bundler resolve
index.ts pattern:
// Default re-export delegates to platform-specific via bundler resolution
export type { BcPopoverProps } from './BcPopover.contract';
export { BcPopover } from './BcPopover.web'; // default to .web for type/web
// Metro auto-resolve will use './BcPopover.native' instead of './BcPopover.web'
// when bundling for RN (via package.json `react-native` field or Metro config)Strategi resolver alternatif (kalau ternyata tidak bekerja):
- Pakai conditional exports di
package.json:"exports": { "./components/overlays/popover": { "react-native": "./src/components/overlays/popover/BcPopover.native.tsx", "default": "./src/components/overlays/popover/BcPopover.web.tsx" } }
- Atau pakai
*.native.tsxconvention yang Metro auto-resolve secara default
Phase 0 spike akan validasi mana yang reliable.
Komponen di-klasifikasi Adapt kalau salah satu kondisi terpenuhi:
- Implementasi web pakai DOM API yang tidak ada padanan langsung di RN (mouse events, hover, drag).
- UX expectation per platform fundamental berbeda (right-click vs long-press; calendar grid vs wheel picker).
- Performa beda asimetris yang butuh strategi optimasi platform-spesifik (virtualization).
Selain itu, default ke Pure. Ini meminimalkan maintenance burden.
Definisi: Komponen yang implementasi-nya bergantung pada web-only API yang tidak punya padanan langsung di React Native dan tidak feasible di-port dengan effort wajar. Berbeda dari Adapt (yang punya .native.tsx hand-written), komponen web-only tidak di-emit ke target RN sama sekali.
Klasifikasi:
- Inline SVG berat (
<svg>,<path>,<rect>,<line>,<circle>,<g>) yang butuhreact-native-svgadapter besar. - Komponen yang pakai DOM API spesifik (canvas, WebGL, dll) tanpa abstraksi cross-platform.
Mekanisme:
scripts/apply-adapt-overrides.mjsmenghapus file mitosis-generated dioutput/react-native/src/components/.../BcXxx.tsxpasca-build.- Konsumer RN yang meng-import komponen web-only akan dapat resolver error (clear signal bahwa komponen tidak tersedia di RN), bukan build rusak diam-diam.
- Daftar komponen web-only didefinisikan di
WEB_ONLY_COMPONENTSarray dalam script tersebut.
Komponen web-only saat ini:
BcViewGantt— Gantt chart dengan inline SVG berat (<svg>,<path>,<rect>,<line>,<circle>,<g>). Adapterreact-native-svgpenuh di-defer sampai ada permintaan konsumen RN yang konkret.
Catatan: Web-only adalah pilihan terakhir. Setiap komponen web-only adalah tech debt yang harus di-revisit kalau ada kebutuhan RN. Alternatif jangka panjang: tulis ulang dengan react-native-svg, atau mark sebagai Adapt dengan .native.tsx minimal (loading state / "not available" message).
vite.config.ts di consumer atau di internal demo:
export default {
resolve: {
extensions: ['.web.tsx', '.web.ts', '.tsx', '.ts', '.jsx', '.js'],
},
};Vite auto-pick .web.tsx > .tsx saat resolve. Adapt component otomatis dapat web impl.
Metro default resolve .native.tsx > .tsx. Tidak butuh konfigurasi tambahan.
Untuk komponen Adapt, file BcPopover.native.tsx akan dipilih otomatis saat Metro bundling.
Tauri pakai web bundle (Vite output). Resolver = Vite resolver di atas. Tidak ada target terpisah.
Stencil tidak punya konsep platform resolver. Komponen Pure di-emit ke Stencil seperti biasa. Komponen Adapt tidak di-emit ke Stencil (stencil target di-skip via mitosisTargets flag per komponen). Stencil legacy tidak dapat fitur baru — hanya bug fix kritis.
Ditulis pakai Tailwind 4 @theme syntax:
@theme {
--color-bc-primary: hsl(222 47% 40%);
--color-bc-background: hsl(0 0% 100%);
/* ... */
}
@theme dark {
--color-bc-background: hsl(222 47% 11%);
/* ... */
}Build script scripts/generate-tokens.mjs (BARU, belum ada) akan:
- Parse
tokens/theme.css - Emit:
tokens/tailwind.preset.cjs(Tailwind v3 fallback) — sudah ada manual, di-overwrite oleh scripttokens/tailwind.theme.css(Tailwind v4@themeblok terpisah) — sudah ada manual, di-overwritetokens/nativewind.preset.cjs(RN palette) — saat ini hardcoded, akan digantitokens/tokens.ts(object untuk runtime use, kalau diperlukan)
- CI guard:
npm run tokens:check— fail kalau output drift dari source.
Setelah Phase 0:
theme.css= satu-satunya tempat ubah token.nativewind.preset.cjsjadi artifact (boleh di-gitignore atau di-commit untuk audit). Saya rekomendasi commit supaya CI bisa verifikasi tidak drift.- Web Tailwind 3 user dan v4 user dapat preset/theme yang konsisten dari source yang sama.
Komponen ditandai Done hanya jika:
- ✅ Kontrak prop di
BcXxx.contract.ts(TS interface) — source of truth untuk semua impl. - ✅ Implementasi:
- Pure:
BcXxx.lite.tsx— Mitosis emit sukses untuk react, vue, react-native, stencil (kecuali stencil di-skip). - Adapt:
BcXxx.web.tsx+BcXxx.native.tsx— keduanya conform ke kontrak.
- Pure:
- ✅ Token-based styling — no hardcoded color/size; dari
theme.cssatau Tailwind utility yang resolve ke token. - ✅ A11y verified:
- Web: keyboard nav (Tab, Enter, Esc, Arrow), screen reader (VoiceOver/NVDA), touch target ≥44px.
- Mobile: TalkBack (Android) / VoiceOver (iOS), touch target ≥44pt.
- ✅ Contract test (
BcXxx.test.ts) pass di semua target:- Vitest jalan di Node (logic test).
- Smoke render di React (Vitest + Testing Library).
- Smoke render di Vue (Vitest + Vue Test Utils).
- Smoke render di RN (Vitest + RN Testing Library, tidak butuh device).
- ✅ E2E smoke (manual atau automated) di setidak-tidaknya:
- Web (Playwright)
- Mobile (Maestro / Detox — tidak blocking dev, jalan di CI nightly)
- Tauri (Playwright + Tauri webdriver — sat available)
- ✅ Docs entry: contract description + sample usage + live playground (kalau ada).
Yang TIDAK blocking dev (per kebijakan stakeholder):
- Test runtime dijalankan terpisah, bukan pre-commit.
- Pre-commit hanya: typecheck + lint + Mitosis build sukses.
- Runtime mobile test = pre-release gate, bukan per-commit gate.
Pre-conditions sebelum mulai komponen baru di bawah arsitektur ini.
Status: semua selesai 2026-06-14. Lihat verdict [verified] per item.
- Drop Lynx artifacts:
- Hapus
packages/ui/output/lynx/ - Hapus
packages/ui/scripts/lynx-generator.mjs,scripts/generate-lynx.mjs - Hapus
packages/ui/demos/lynx-app/ - Hapus referensi Lynx di
mitosis.config.js,package.jsonscripts,src/index.tsexports - Update ADR-001 Section 15 (Lynx) → tandai sebagai superseded oleh ADR-006
- Hapus
- Auto-generate token pipeline:
- Tulis
scripts/generate-tokens.mjs - Replace
tokens/nativewind.preset.cjshardcoded jadi auto-generated - Tambah
npm run tokens:checkdi CI
- Tulis
- Tambah RN target ke Mitosis: (verified)
mitosis.config.jstargets:['stencil', 'react', 'vue', 'reactNative'](camelCase target key per Mitosis registry; output folder isreact-native/).options.reactNative.stylesType = 'native-wind'triggers built-in NativeWind plugin.- Finding: Mitosis 0.13.1 NATIVE_WIND_STYLES_PLUGIN has a bug where dynamic class bindings (template literals / ternaries) get stringified to
[object Object]. Fixed in-tree via patch-package — seepatches/@builder.io+mitosis+0.13.1.patch. Postinstall script auto-applies the patch onnpm install. package.jsonexports added./native(resolves tooutput/react-native/src/index.ts).peerDependenciesaddedreact-native >=0.74(optional) andnativewind >=4(optional).
- Build resolver setup: (verified)
demos/react-app/vite.config.tsaddsresolve.extensions: ['.web.tsx', '.web.ts', '.web.jsx', '.web.js', '.tsx', '.ts', '.jsx', '.js', '.mjs', '.json']so Vite picks.web.tsxfirst.- Metro's default
sourceExtsalready prioritize.native.tsxover.tsxfor thenativeplatform — no Metro config needed. demos/rn-app/scripts/resolver-check.mjsreplays both bundlers' resolution algorithms against the filesystem and asserts the right file wins (3/3 PASS).- Note: a full Metro/RN runtime app is intentionally out of scope for Phase 0 — runtime mobile validation is a pre-release gate per Section 5.
- Sample Adapt component: (verified — BcPopover under
src/components/adapt-poc/popover/)- Files:
BcPopover.contract.ts(shared types) +BcPopover.web.tsx+BcPopover.native.tsx+index.ts(barrel). - Resolver smoke 3/3 PASS: Vite picks
.web.tsx, Metro picks.native.tsx, both findindex.ts. - Contract tests 8/8 PASS: both impls import the shared contract type, web has no
react-nativeimport, native uses<View>/<Modal>, both exportBcPopover+ default,data-bc-platformmarker differs.
- Files:
- Sample Pure component: (verified — BcStack under
src/components/layout/stack/)- Single
BcStack.lite.tsx. Mitosis emits 66/66 components × 4 targets including BcStack. - Container:
<div>(web) vs<View>(RN); identical Tailwind classes (flex flex-col items-stretch …). - RN output uses
className={\tpl ${expr}`}, not[object Object]` (regression test included). - Contract tests 16/16 PASS across all 4 targets.
- Single
Phase 0 verdict (2026-06-14): All spike acceptance criteria met. ADR-006 promoted from "Proposed pending Phase 0" to Accepted. Single biggest finding: Mitosis 0.13.1 RN+NativeWind has an upstream bug requiring patch-package; this is documented in the patch file and ADR. If/when Mitosis fixes it upstream, the patch can be retired.
- Lynx artifacts dihapus, ADR-001 Section 15 ditandai superseded. (Verified: 0 Lynx references in
packages/ui/. ADR-001 §15 marked SUPERSEDED.) -
scripts/generate-tokens.mjsjalan dan generatenativewind.preset.cjsdaritheme.css. (Verified:tokens:generate+tokens:checkpass. 4 artifacts auto-generated. Drift detection works.) -
mitosis.config.jstargets['stencil', 'react', 'vue', 'reactNative']. (Note: Mitosis target key is camelCasereactNative; output folder isreact-native/.) - Mitosis emit RN dengan NativeWind classes. (Verified: 66/66 RN outputs use proper static
className="..."or dynamicclassName={\tpl`}. Requiredpatch-packagefix for upstream[object Object]bug; seepatches/@builder.io+mitosis+0.13.1.patch`.) - PoC Pure component (BcStack) jalan di 4 target. (Verified: contract tests 16/16 PASS across react / vue / reactNative / stencil. Container is
<div>on web,<View>on RN, same Tailwind classes.) - PoC Adapt component (BcPopover) —
.web.tsxdi-resolve Vite,.native.tsxdi-resolve Metro. (Verified:demos/rn-app/scripts/resolver-check.mjsreplays both algorithms — 3/3 PASS. Contract tests 8/8 PASS.) - Contract test jalan di semua 4 target untuk PoC. (BcStack covers all 4; BcPopover web/native covered with cross-impl parity assertions.)
- Phase 0 AC semua centang.
- ADR-006 di-update dengan temuan konkret dari spike (replace "estimasi" jadi "verified" in Section 6 pre-conditions).
-
components-progress.mddi-restructure jadi 2-tier (Pure / Adapt) — done in earlier session, refined with Phase 0 verdicts. - Definition of Done di Section 5 di-validasi pada PoC component.
Runtime Part Resolution (ADR-009) has been rolled out to all Core Integration Surface components:
- All 25 Pure components import
partClass/partAttrfromcore/part-props.ts - All 25 Pure components emit
data-partattributes for CSS selector targeting - Adapt components (BcPopover, BcDrawer) use same helpers in both
.web.tsxand.native.tsx - 2,058 tests passing including
runtime-part-rollout.test.tsverification -
slotPropsworks identically across React, Vue, Svelte, Solid, Angular, React Native, Stencil - Additive className verified: consumer classes never replace base token classes
- 22 P0 komponen Done sesuai DoD Section 5.
- Tidak ada komponen yang break di salah satu dari 4 target.
- Token pipeline auto-sync (CI guard pass).
- Sample app demo (web + mobile + desktop Tauri) konsumsi semua 22 P0.
All Pure components in the Core Integration Surface use Runtime Part Resolution:
Implementation pattern:
import { partClass, partAttr } from '@/core/part-props';
export default function BcXxx(props) {
return (
<div
class={partClass(props.slotProps, 'root', 'base-class')}
data-part="root"
>
<label
class={partClass(props.slotProps, 'label', 'label-base')}
data-part="label"
>
{props.label}
</label>
<input
class={partClass(props.slotProps, 'input', 'input-base')}
data-part="input"
aria-label={partAttr(props.slotProps, 'input', 'aria-label')}
/>
</div>
);
}Components wired:
- Form Controls (10): BcInput, BcSelect, BcCombobox, BcCheckbox, BcToggle, BcSegmented, BcNumberField, BcDateField, BcTimeField, BcMultiSelect
- Forms (1): BcForm
- Overlays (8): BcDialog, BcAlertDialog, BcDrawer, BcPopover, BcTooltip, BcDropdown, BcContextMenu, BcCommand
- Navigation/Layout (4): BcTabs, BcAccordion, BcDisclosure, BcSplitter
- Data (1): BcDataTable
Adapt components have separate .web.tsx and .native.tsx implementations, but both support slotProps:
components/overlays/popover/
├── BcPopover.contract.ts # Shared slotProps interface
├── BcPopover.web.tsx # Uses partClass/partAttr
├── BcPopover.native.tsx # Uses partClass/partAttr (same helpers)
└── BcPopover.test.ts # Contract tests verify both
Both implementations use the same pure function helpers, ensuring consistent customization API across platforms.
All components emit data-part attributes to enable cross-platform CSS selector targeting:
/* Target specific parts via CSS */
[data-part="root"] { margin: 1rem; }
[data-part="label"] { font-weight: 600; }
[data-part="input"] { border-radius: 4px; }Verification: runtime-part-rollout.test.ts confirms all 25 components emit data-part attributes.
| Platform | slotProps Support | Notes |
|---|---|---|
| React | ✅ Full | partClass adds CSS classes |
| Vue | ✅ Full | partClass adds CSS classes |
| Svelte | ✅ Full | partClass adds CSS classes |
| Solid | ✅ Full | partClass adds CSS classes |
| Angular | ✅ Full | partClass adds CSS classes |
| React Native | ✅ Full | partClass adds NativeWind classes |
| Stencil | ✅ Full | partClass adds CSS classes (shadow DOM) |
Key insight: partClass/partAttr are pure functions with no DOM dependencies, making them portable to Flutter (Tier C) and future adapters (Tier B).
- Caller experience benar-benar universal — sesuai visi stakeholder.
- Token pipeline single-source mencegah drift web/RN.
- Library author beban kompleksitas dipindah ke build tooling, bukan ke caller.
- Fondasi kuat untuk metadata-driven UI (ADR-005) — semua komponen punya kontrak prop serializable.
- Pintu Tier B/C tetap terbuka karena kontrak komponen sudah platform-neutral.
- Maintenance per-Adapt-component 2x lipat — author tulis web + native impl terpisah.
- CI lebih berat — 4 target Mitosis + RN smoke test + Tauri smoke test.
- Build tooling kompleks — resolver, token generator, contract test runner.
- Phase 0 spike sebagai prerequisite — tidak boleh skip atau ekspansi cepat ke P0 sebelum spike sukses.
- Mitosis 0.13.1 RN output mungkin tidak optimal — kalau pakai StyleSheet inline (bukan NativeWind className), perlu plugin custom atau upgrade Mitosis.
- Metro vs Vite resolver behavior bisa subtle berbeda — perlu integration test di kedua bundler.
- Conditional exports di package.json punya gotcha (tooling lama mungkin tidak suport) — backup strategi: pakai
*.native.tsxfilename convention saja.
- Phase 0 spike validasi semua asumsi sebelum lock.
- ADR-006 status Proposed pending Phase 0 — boleh direvisi setelah spike.
- Backup strategi tertulis di Section 3 untuk setiap titik risk.
| ADR | Relationship |
|---|---|
| ADR-001 | Section 15 (Lynx) superseded oleh ADR-006 Section 6 (drop Lynx). |
| ADR-002 | Extended. Section 1 Tier A diperjelas (RN sekarang inti, bukan opsional). Section 9.4 Adapt contract diperluas dengan strategi build resolver. Section 5.3 DoD diperluas jadi Section 5 ADR ini. |
| ADR-003 | Tidak berubah. Taxonomy dan prioritization tetap berlaku. Section 5 build sequence diadjust: Phase 0 baru sebelum Phase 1. |
| ADR-004 | Tidak berubah. Reactive engine konsumsi kontrak komponen ADR-006. |
| ADR-005 | Diperkuat. BcRenderer butuh komponen punya kontrak serializable — ini sudah jadi syarat DoD ADR-006 Section 5. |
During the 2026-06-21 session, while fixing BcViewGantt.lite.tsx and
BcKanbanBoard.lite.tsx (which were incorrectly importing react-native
primitives directly in their cross-platform .lite.tsx), it was confirmed
that Mitosis 0.13.1 already auto-maps web HTML elements to React Native
primitives in the RN target output. No manual import { View, Text } from 'react-native' is needed in .lite.tsx source.
Source .lite.tsx |
RN output | Notes |
|---|---|---|
<div> |
<View> |
Container primitive |
<span>, <p>, <h1>-<h6> |
<Text> |
Text primitive |
<button> |
<Button> |
onClick → onPress auto-mapped |
<input> |
<TextInput> |
onInput → onChangeText auto-mapped (with e.target.value extraction) |
<img> |
<Image> |
src → source={{ uri }} auto-mapped |
<svg>, <circle>, <path> |
<View> (incorrect) |
SVG elements are NOT auto-mapped to react-native-svg — see "Web-only components" section |
-
Single source code for web + RN is achievable for most components. Developers write standard HTML elements in
.lite.tsx; Mitosis handles the RN translation. -
Do NOT import
react-nativein.lite.tsx. Direct imports ofView/Text/Pressable/TextInput/Imagecause the web/vue/stencil targets to fail because they cannot resolve thereact-nativemodule. -
.native.tsxoverrides remain for Adapt components that need platform-specific UX (bottom sheet vs modal, etc.). See the Adapt component section above. -
SVG-heavy components are still web-only (BcViewGantt) or need
react-native-svgadapter. The auto-mapper does not handle SVG elements correctly (maps them to<View>).
- BcKanbanBoard: 196 replacements (View→div, Text→span, Pressable→button, TextInput→input, Image→img). RN output confirmed all auto-mappings present.
- BcViewGantt: 28 replacements. Marked web-only (SVG-heavy) so RN output
is intentionally deleted post-build by
apply-adapt-overrides.mjs.
- ADR-002 Section 1 (target tiering), Section 4 (contract layer), Section 9 (cross-tier infrastructure).
- ADR-003 Section 1 (taxonomy), Section 3 (prioritization P0).
- Mitosis docs: targets, useTarget, plugin API.
- NativeWind v4 docs: preset config, Metro setup.
- Tailwind 4
@themedirective documentation. - React Native Metro resolver:
*.native.tsxconvention. - Vite resolver:
extensionsconfig untuk.web.tsxpriority. - Tauri 2: webview deployment patterns.
- Conditional exports spec (Node.js, package.json
exportsfield).