Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[1.2.4] - 2026-08-09
Added
Popup's prop and context types are now exported from the package root.PopupProps,PopupType,PopupHeaderProps,PopupToggleButtonProps, andPopupContextwere defined but never re-exported, so consumers could renderPopup,PopupHeader, andPopupToggleButtonbut had no way to name their props — e.g. when writing a wrapper component or typing the return ofusePopup(). They're now importable from@multinaire/expo-uialongside the components themselves.Inputgained amaxHeightprop. Caps how tall amultilinefield grows, in pixels. Once the cap is reached the content scrolls inside the field instead of expanding further and pushing the rest of the layout down. Defaults to three times the theme'sheight.large(300px with the stock theme); passmaxHeightto override it. Ignored unlessmultilineis set.
Changed
- Buttons pulse more visibly while
isLoading. The loading pulse onButton,ActionButton,IconButton,MenuButton,FloatingActionButton, andSocialLoginButtonwas easy to miss: it only faded to 0.5 opacity. It now dips to 0.35, so a busy button reads as busy at a glance. The 800ms half-cycle is unchanged — the pulse is deeper, not faster. Layout, sizing, and the button's content are unchanged. Skeleton placeholders (Animate, and theisLoadingstate ofTypography,Icon,Photo, and friends) keep the original gentler pulse — a screenful of placeholders at the stronger setting is distracting. TypographywithonPressnow renders as a pressable.onPressused to be forwarded to the underlying RNText, which fires the handler but gives no visual feedback. The text is now wrapped in anAnimatedPressabledriven byusePressableInteraction, so it dims on press and hover like the button components.marginandflexmove to the wrapper (the innerTextkeepsflexso vertical alignment still works), leaving outer layout unchanged;testIDstays on theText. Text withoutonPressis unchanged.IconwithonPressnow renders as a pressable. PreviouslyonPresswas forwarded straight to the underlying SVG, which gave no press feedback and behaved inconsistently across platforms and between the custom and Iconsax icon sets. The icon is now wrapped in anAnimatedPressabledriven byusePressableInteraction, so it dims on press and hover likeButton,IconButton, andBadge.testIDmoves to the pressable whenonPressis set, and stays on the icon itself otherwise. Icons withoutonPressare unchanged.
Fixed
Accordionanimating to a stale height when its content changed. The content height was measured once on the first layout pass and locked in for the lifetime of the panel — it had to be, because the measured node sat in flow inside the clipped wrapper and so kept re-reporting the wrapper's animated height on every frame of an expand/collapse. Content that arrived or changed after that first pass (async-loaded text, a growing list, re-wrapping after a rotation or font-scale change) left the panel expanding to the old height, clipping or over-padding its content. The measured node is now absolutely positioned inside the wrapper, so it is always laid out at its own natural size regardless of how far the wrapper is collapsed;onLayouttherefore reports the real content height every time it changes, and an open panel animates smoothly to its new size. Measurement is held in a Reanimated shared value rather than component state, so re-measuring no longer costs a render.Inputwithmultilinenot growing with its content on web. On native the field expands as text wraps, but on webmultilinerenders a real<textarea>, whose height comes from itsrowsattribute rather than its content — so it stayed a fixed height and scrolled internally instead. The field now uses CSSfield-sizing: contenton web, letting the browser size it to its content. In browsers withoutfield-sizingsupport (notably Firefox) it keeps the previous fixed-height, internally-scrolling behavior. The scrollbar shown once amultilinefield reaches its cap is hidden on web viascrollbar-width: none; the field still scrolls, and native is unaffected.Input's wrapper row not following itsmultilinefield's height on web. Even once the field itself grew, the row around it stayed locked atheight.medium. The row cancelled its own fixed height withheight: undefined, which works under React Native'sStyleSheet.flatten(it copies theundefinedover the earlier value) but not understyleq, which react-native-web uses — there, a property whose value isundefinedis skipped without claiming the property, leaving the earlier height in force. It now usesheight: 'auto', which overrides consistently on both platforms.ListPickerrows with long labels wrapping out of their row. Each row is a fixed-heightCard(height.medium), but its label was free to wrap onto a second line — so a longtexteither overflowed the row's bounds or pushed its leading icon and selected checkmark out of vertical alignment, and rows stopped lining up with each other. Labels are now capped at a single line and truncate with an ellipsis instead of wrapping. Short labels are unaffected.
[1.2.3] - 2026-07-29
Changed
- BREAKING (behavioral):
ScrollContainerno longer fills its parent by default. Previously,ScrollContaineralways appliedflexGrow: 1internally — via React Native'sScrollViewbase style — even when noflexprop was passed, because an omittedflexcouldn't override it. If you rely on aScrollContainerwithoutflexto fill the remaining screen height, passflex={1}explicitly now. This matches the prop's documented default, which has always been "none".
Fixed
Popupfilling the entire screen on native when its children include aScrollContainer.Popupsizes itself on native by measuring how tall its content naturally is inside a full-window wrapper; aScrollContainer's always-onflexGrow: 1(see above) made it greedily expand to fill that wrapper, blowing the sheet out to full height regardless of how little content it held.ScrollContainernow only grows whenflexis explicitly passed, so it sizes to its content insidePopupby default.ListPickerresizing on web as content changed in'list'mode. On web there's no ancestor with a definite height forflex: 1to grow into (unlike native's bottom sheet), so the list shrink-wrapped to whatever was currently rendered and visibly resized on every keystroke while searching or as items loaded.ListPickernow gives its list a fixed height on web (8 rows) in'list'mode, so it stays stable and scrolls internally instead of resizing.Accordionnot expanding on native (iOS and Android). Its content height was measured viaonLayouton a child laid out inside an already-collapsed (height: 0)Animated.View; on native, a normal in-flow child of a collapsed animated parent never receives a real layout pass, so the measured height stayed stuck at0forever and the panel never grew (web was unaffected, since it goes through real CSS layout instead). Fixed by leaving the wrapper unclipped (and invisible) until the first real measurement lands, so that first layout pass happens naturally instead of being deferred, then switching to the normal animatedheight. Also addedcollapsable={false}to the wrapper to keep it from being optimized out of Android's native view hierarchy.
[1.2.2] - 2026-07-28
Added
- Native bottom sheet presentation for
Popup. On native,Popupnow renders as a true bottom sheet (via@swmansion/react-native-bottom-sheet) with drag-to-dismiss and keyboard-aware height, instead of aModal-based sheet simulation.MultinaireUInow wraps its children in aPopupWrapper(BottomSheetProvider) automatically — no additional setup is required. @swmansion/react-native-bottom-sheetpeer dependency (required,>=0.16.2).usePopup().isDialog. Convenience boolean shorthand forusePopup().type === 'dialog', used internally byDialog,Menu,ListPicker, andDateTimePickerand available to any custom popup content.
Changed
- BREAKING:
Popupno longer accepts atypeprop. Presentation is now fully automatic and platform-based — always a bottom sheet on native, always a centered dialog on web. Remove anytype="sheet"/type="dialog"passed toPopup.usePopup().typestill reports the resolved presentation (read-only) so children (e.g.Dialog,Menu,ListPicker,DateTimePicker) can adjust for bottom safe-area insets.
Fixed
Popupcontent overflowing on web. Modal content is now capped to 80% of the viewport height and clips overflow, instead of growing past the edges of the screen for tall content.AutoCompleteInputsuggestion panel layout jump. The suggestion list now expands/collapses by animating its measured content height, instead of snapping to full height and fading opacity in/out, which used to shift surrounding layout abruptly.Accordionexpand/collapse layout jump. Same fix as above — content height is now measured and animated instead of relying onLinearTransition/fade transitions.
[1.2.1] - 2026-07-27
Fixed
- peerDependencies version mismatch fixed an issue where peerDependencies for react* is mismatched.
[1.2.0] - 2026-07-27
Added
Accordioncomponent (common). Collapsible panel built onCard, with an animated header (leadingicon,title, optionalbadge, and atrailingchevron icon that defaults toArrowUp2/ArrowDown2based onactive). It's a controlled component — the parent ownsactivestate and toggles it viaonPress. Expand/collapse and layout shifts are animated withreact-native-reanimated.AutoCompleteInputcomponent (inputs), plus its row rendererAutoCompleteInputItem. A text input built on the sameInputWrapperasInput, with an animated suggestion panel (Card-based,react-native-reanimatedfade/layout transitions) that appears below it. Suggestions are supplied viaitemsand filtered either client-side withsearchPredicateor externally (e.g. server-side search wired up throughonChangeText, togglingisLoading). Selecting a suggestion viaonSelectauto-fills the input with itstext. SupportsminCharacters,maxVisibleItems(scrollable beyond that),noResultsText, and query highlighting in each row viahighlightMatch.- Markdown component category. New theme-aware markdown renderer, usable with just a
markdownstring (no hook wiring required):MarkdownTypography— a thin wrapper aroundreact-native-enriched-markdown'sEnrichedMarkdownText, typed directly from its props. Styling is theme-derived by default; pass a partialmarkdownStyleto override.useEnrichedMarkdownStylehook — exposes the theme-derivedMarkdownStyle(typed fromreact-native-enriched-markdown) used byMarkdownTypography, for customEnrichedMarkdownTextcomposition.
react-native-enriched-markdownpeer dependency (required,>=0.7.0).- New
src/constants.tsmodule, exported from the package root:BREAKPOINTSandMAX_WIDTHS(previously internal touseResponsiveDesign), plusIS_ANDROID,IS_IOS, andIS_WEBplatform flags. hoverBackgroundColorinTabButtonStyleandSideBarButtonStyle.TabBar,TabContainer, andSideBarbuttons now tint their background on hover (web/desktop only) when unfocused, distinct from the existing global press/hover opacity dim. Defaults to'base'for top/bottom tabs and'backgroundVariant'for sidebar items.Containergained matchingonHoverIn/onHoverOutprops to support this.
Fixed
- Rapid taps selecting button/tab text on web.
Typography(and everything built on it — buttons, tabs, badges, labels) rendered RN'sText, which is selectable by default on React Native Web (unlike native, whereTextisn't selectable unless opted in). A quick second tap landed as a browser double-click on selectable text and selected it instead of registering as a second press.Typographynow defaultsselectabletofalse, matching native behavior; passselectableexplicitly to opt back in for content that should support copy/select. - Remaining SSR hydration mismatch in
useResponsiveDesign. Its module-level width/height fallback still calledDimensions.get('window')directly instead of a fixed literal — on web this resolves to0/0on the server but the real viewport size on the client (read at bundle-evaluation time, before hydration), so the twoisHydrated-gated fallback branches held different values per environment. The fallback is now the deterministic literal0/0. Also fixed viewport width/height never updating after mount (useWindowDimensionschanges weren't propagated into state); the hook'sonLayoutnow only overrides the auto-tracked dimensions when explicitly wired up. - Light/dark theme flash on mount with SSR.
useIsHydratedpreviously flipped fromfalsetotrueviauseSyncExternalStore, which React resolves through a passive effect — running after the browser paints. This meantThemeProvider(anduseResponsiveDesign) briefly painted their placeholder value ('light'/0,0), then visibly repainted with the real value a frame later.useIsHydratednow flips inside a layout effect instead, which React guarantees resolves before the hydrated frame is painted — the placeholder is never actually shown on screen. - Persisted theme/language flash on mount, on web.
ThemeProviderandLocalizationProviderread the persisted theme mode/language viaAsyncStorage.getItem()inside auseEffect, so even though@react-native-async-storage/async-storage's web backend is justlocalStoragewrapped in aPromise, the applied value always landed a frame after the initial paint. On web, both providers now readlocalStoragedirectly and synchronously, from inside a layout effect — the persisted value is applied before the first paint instead of after it. Native is unaffected (still reads viaAsyncStoragein an effect, which has no equivalent paint-timing concern).
[1.1.1] - 2026-07-17
Added
useIsHydratedhook — returnsfalseon the server and during the client's hydration render,trueimmediately after mount. Exported so consumers can gate their own browser/device-only reads (window,matchMedia, etc.) behind hydration the same way the library now does internally.onLayouthandler inuseResponsiveDesign. - setting internal width/height instead of windows's default.
Fixed
- SSR hydration mismatches in
ThemeProvider,LocalizationProvider, anduseResponsiveDesign. On web,useColorScheme()anduseWindowDimensions()read real browser state synchronously during render, andLocalizationProviderresolved the persisted/system language from AsyncStorage — none of which the server can know, so the client's hydration render diverged from the server-rendered markup. Color scheme, viewport dimensions, and the initial language now render with deterministic values ('light',0/0, and the first configured/passed language respectively) until hydration completes, then switch to the real values immediately after mount. Translation resource bundles are also now registered synchronously during render instead of in auseEffect, sot()resolves correctly on the very first render everywhere.
[1.1.0] - 2026-07-13
Added
create-appCLI (@multinaire/create-app) — scaffolds a new project from a@multinaire/expo-uitemplate:npx @multinaire/create-app my-app. Supports--type expo(default, available now);--type react-nativeis reserved for an upcoming bare React Native CLI template.- Expo project template (
templates/expo-template) — a production-ready Expo Router app pre-wired with@multinaire/expo-ui,theme.json, i18n (i18next/react-i18next), Iconsax icons,DateTimePicker, and AsyncStorage-backed theme/language persistence. Ships its own.npmrc,AGENTS.md, and.claude/config. - Templates documentation — new "Templates" section in the docs site covering
create-appusage and the Expo Template's structure and pre-installed modules.
Changed
- Default
backgroundVarianttheme color (light & dark) now uses a translucent overlay (rgba(0, 0, 0, 0.04)light /rgba(255, 255, 255, 0.04)dark) instead of a flat gray, matching the value already used across templates and the Theme Builder. - GitHub Packages authentication docs standardized on the
PERSONAL_ACCESS_TOKENenvironment variable name (previouslyAUTH_TOKENin Installation), matching the.npmrcshipped in every template.
Fixed
package.jsonrepository/bugs/homepageURLs — corrected from the pre-renamemultinaire/uitomultinaire/expo-ui, matching the actual repository (stale since the 1.0.7 package rename).
CI
- Added a manual
workflow_dispatchworkflow (publish-create-app.yml) to publish@multinaire/create-appto GitHub Packages independently of the library's release cycle.
[1.0.8] - 2026-07-04
Fixed
- Published package was missing the
build/directory. The SDK 56 upgrade in 1.0.7 bumpedexpo-module-scriptsto a version whereexpo-module prepareno longer builds the package (it's now a no-op). Since nothing else innpm ci/npm publishran the build step, the 1.0.7 tarball published to GitHub Packages shipped without compiled output. Added aprepublishOnlyscript (expo-module prepublishOnly) so the library is always cleaned and rebuilt before publishing.
CI
- Bumped
actions/checkoutandactions/setup-nodetov5in both workflows, clearing the "Node.js 20 is deprecated" warning from GitHub Actions (v4 bundled a Node 20 runtime; v5 targets Node 24). - Added a manual
workflow_dispatchtrigger to the npm publish workflow so it can be run on demand instead of only on release creation.
[1.0.7] - 2026-07-03
Breaking Changes
Package renamed: @multinaire/ui → @multinaire/expo-ui. Update your dependency and every import:
npm uninstall @multinaire/ui
npm install @multinaire/expo-ui
// Before
import MultinaireUI, { Button, Typography } from '@multinaire/ui';
// After
import MultinaireUI, { Button, Typography } from '@multinaire/expo-ui';
Also update any declare module '@multinaire/ui' TranslationSchema augmentation and tsconfig.json path mappings to @multinaire/expo-ui. See the Migration Guide.
Changed
- Upgraded to Expo SDK 56. Bumped peer/dev dependencies accordingly:
expo~56.0.13,react19.2.3,react-native0.85.3,react-native-reanimated4.3.1,react-native-worklets0.8.3,react-native-screens4.25.2,react-native-svg15.15.4,typescript~6.0.3, and theexpo-*family to their SDK 56 releases. Minimum supported versions are now Expo SDK 56 and React Native 0.85. expo-navigation-bar/expo-status-bar/expo-system-uiusage updated for their SDK 56 APIs (declarative<NavigationBar>/<StatusBar>components instead of imperative calls). No change toMultinaireUI's public behavior.
Removed
@react-navigation/nativepeer dependency — navigation-related types are now sourced throughexpo-router's re-exports, so the package no longer needs to be installed separately alongsideexpo-router.
[1.0.6] - 2026-06-27
Added
Dialog.onCancelprop — optional() => voidcallback invoked when the cancel button is pressed (used whentype="confirm"). Previously the cancel button only calledonRequestCloseon the parentPopup.
Fixed
DancingScriptandOpenSansmissing locale font keys — theMultinaireUIfont map was missingmyandthlocale entries forDancingScriptandOpenSans, causing text to fall back to the wrong font when the active locale was Myanmar or Thai. The locale-specific keys are now registered.
[1.0.5] - 2026-06-26
Added
- NotoSans font family —
"NotoSans"is now a validfontFamilyvalue intheme.json. The library bundles NotoSans (Latin), NotoSans Myanmar, and NotoSans Thai. The correct glyph set is selected automatically based on the active locale:my→ Myanmar,th→ Thai, anything else → Latin. translate(key, options?)interpolation parameter —LocalizationContext.translatenow accepts an optionaloptions: Record<string, unknown>second argument for i18next variable substitution (e.g.translate('welcome', { appName: 'MyApp' })).
Fixed
Popupbackdrop tap on Android — tapping outside the modal no longer dismisses it on Android, preventing accidental dismissals. iOS behavior is unchanged.Inputmultiline padding — vertical padding on multiline inputs is now applied to the innerTextInputrather than the container, ensuring correct text alignment on all platforms.
[1.0.4] - 2026-06-02
Added
- Hover & press interaction states on all interactive components —
Button,ActionButton,IconButton,MenuButton,SocialLoginButton,FloatingActionButton,Card,Container(whenonPressis set),Checkbox, andInputWrappernow animate their opacity on hover (web/desktop) and press, with a smooth 150ms timing transition. The animation is automatically disabled while a button is loading or has noonPresshandler. usePressableInteractionhook exported from@multinaire/ui— returns ananimatedStyleand a set ofoverrideProps(onHoverIn,onHoverOut,onPressIn,onPressOut) you can spread onto anyPressableto add the same hover/press opacity feedback used by the built-in components.useButtonStyleshook is now exported from@multinaire/ui(previously an internal button helper) — resolves the background, foreground, and disabled styles for a given buttontype.
Changed
- All interactive components migrated from
TouchableOpacitytoPressable— this enables hover support on web/desktop and aligns with the React Native recommended interaction primitive. The previousactiveOpacityfeedback is replaced by the newusePressableInteractionanimation. AnimatedTouchableOpacityexport renamed toAnimatedPressable— anAnimated-wrappedPressable. Update any imports ofAnimatedTouchableOpacitytoAnimatedPressable. See the migration guide.- Minimum Node version raised to
>=22(was>=18).
Fixed
Popupsafe-area insets on Android — popup content is now wrapped in aSafeAreaProviderwith explicit initial metrics so the safe-area insets resolve correctly inside the Modal's Android window.Popupopen delay removed — the child content no longer waits on a 50mssetTimeoutbefore rendering, so popups open immediately.ListPickerlayout on Android — now renders using the dialog layout on Android (previously only when the popuptypewasdialog), preventing clipped sheet content.
[1.0.3] - 2026-05-20
Added
testIDauto-detection onTypography— whenchildrenis a string, the component automatically setstestIDto that string value so text elements are addressable in tests without extra configuration.testIDfallback toplaceholderonInput,PickerButton, andMediaPickerButton— when no explicittestIDis provided, theplaceholdervalue is used as the test identifier.- Built-in
testIDonInputWrapperclear button — always"clear-input". - Built-in
testIDmarkers onPagination— the animated label receives the current item value as itstestID; the focused step container receives"<item>-is-focused". - Built-in
testIDmarkers onDateTimePickernavigation buttons — previous icon is"previous", next icon is"next".
Changed
LocalizationProvider.defaultLanguage— the'system'option is renamed to'auto'. Update any explicitdefaultLanguage="system"todefaultLanguage="auto".LocalizationContext.language— type narrowed from'system' | LanguagetoLanguage; the active locale is always a concrete code.LocalizationContext.languages— type narrowed from('system' | Language)[]toLanguage[]; the array no longer includes'system'as a first entry.LocalizationContext.changeLanguage— parameter type narrowed from'system' | LanguagetoLanguage.
Fixed
StackHeadertop safe area — simplified the safe-area condition: the inset is now skipped only when the parent navigator is atabordrawer. The grandparent-stack detection introduced in 1.0.2 has been removed.
Removed
useScreenOptionsdeprecated properties —stack,stackWithOverrides,topTab,topTabWithOverrides,bottomTab,bottomTabWithOverrides,sideBar,sideBarWithOverrideshave been removed (deprecated in 1.0.2). UseuseScreenOptions(type).screenOptionsinstead.
[1.0.2] - 2026-05-09
Added
testIDprop on all interactive components —Button,ActionButton,IconButton,MenuButton,SocialLoginButton,FloatingActionButton,BottomTabButton,SideBarButton,TopTabButton,Container,Icon,Badge,Card,Input,InputWrapper,Checkbox,Toggle,PickerButton,MediaPickerButton,ListPickerItem. When atitleis available the prop defaults to the title value so most components are automatically addressable without extra configuration.- Built-in
testIDmarkers on structural elements: Popup overlay ("modal-overlay"), PopupHeader close button ("modal-close"), StackHeader back button ("navigation-back"), StackHeader close button ("navigation-close"). defaultLanguageprop onMultinaireUIandLocalizationProvider— set the initial language. Pass'system'(default) to auto-detect from the device locale viaexpo-localization, or a locale code (e.g.'fr') to hard-code the startup language.languagesarray inLocalizationContext— ordered list of all supported locales derived from thetranslationsprop. Always starts with'system'so you can offer an "Auto-detect" option in a language picker.defaultThemeModeprop onMultinaireUIandThemeProvider— set the initial theme mode ('system'|'light'|'dark'). Defaults to'system'.themeModesarray inThemeContext— always['system', 'light', 'dark'].TranslationSchemaaugmentation interface — declare your locale types once in a.d.tsfile and get type-safe locale codes (Language) and translation keys (TranslationKey) across all components and hooks.LanguageandTranslationKeytypes exported from@multinaire/ui.backTitleprop onStackHeader— override the back-button label. Defaults to'Back'.closeTitleprop onStackHeader— override the modal close-button label. Defaults to'Close'.confirmTitleprop onDateTimePicker— override the confirm button label. Defaults to'Confirm'.previousTitle,nextTitle,doneTitleprops onPageContainer— override the navigation button labels. Defaults are'Previous','Next','Done'.NavigatorTypetype ('stack' | 'top-tab' | 'bottom-tab' | 'side-bar') exported from@multinaire/ui.useScreenOptions(type)now accepts a navigator type and returns a unifiedscreenOptionsfunction plustitle(),tabBarLabel(), andtabBarIcon()helper functions for type-safe screen configuration.
Changed
Toggledefaultcolorchanged from'primary'to'success'. Passcolor="primary"explicitly to preserve the previous appearance.- String props that display user-facing text (button titles, input labels, placeholders, error messages, popup titles, etc.) are now typed as
TranslationKey. WhenTranslationSchemais augmented this provides compile-time checking that only defined keys are passed. Without augmentation the type staysstring. TypographyProps.childrenis now typed asTranslationKey | Exclude<ReactNode, string>. String literals passed as children must be valid translation keys whenTranslationSchemais in use.useScreenOptionslegacy return properties (stack,topTab,bottomTab,sideBar, and their*WithOverridesvariants) are deprecated. They continue to work but will be removed in a future minor version. Migrate touseScreenOptions(type).screenOptions.
Fixed
Toggleinternal state was updated even whenonChangewas not provided. State now only updates when a handler is present.- Tab bar icon color no longer falls back to
'transparent'; the color is correctly cast from the theme context. Containerwith bothsafeAreaEdgesandonPressnow throws a descriptive runtime error — these two props are mutually exclusive.StackHeadertop safe area — stacks nested inside another user stack no longer double-apply the top safe area inset. The header now checks for a grandparent navigator to detect genuine nesting, covering the common Expo Router case.StackHeaderdesktop title — when navigating back, the right-side container switched to a column layout but keptflex={1}, which prevented the title from rendering. The flex is now only applied when there is no back button (row layout).
Deprecated
useScreenOptions()return properties:stack,stackWithOverrides,topTab,topTabWithOverrides,bottomTab,bottomTabWithOverrides,sideBar,sideBarWithOverrides. UseuseScreenOptions(type).screenOptionsinstead.createTabSceenOptions(typo) renamed tocreateTabScreenOptions. The old name is no longer exported.
[1.0.1] - 2026-04-18
Changed
useUIrenamed touseTheme— the hook was shipped under the wrong name in 1.0.0. Update every call site:const { colors, variables, fonts } = useTheme().
[1.0.0] - 2026-04-17
Breaking Changes
Package renamed: @multinaire/multinaire-design → @multinaire/ui
All Multinaire prefixes removed from the public API. Update every import accordingly.
Provider / root entry point
| Before | After |
|---|---|
MultinaireDesignProvider (default export) | MultinaireUI (named + default export) |
MultinaireDesignProps | MultinaireUIProps |
Hooks
| Before | After |
|---|---|
useMultinaireTheme | useTheme |
useMultinaireThemeMode | useThemeMode |
useMultinaireLocalization | useLocalization |
useMultinaireModal | usePopup |
useMultinaireKeyboard | useKeyboard |
useMultinaireResponsiveDesign | useResponsiveDesign |
useMultinaireLoadingAnimation | useAnimate |
Icons
| Before | After |
|---|---|
MultinaireIcons | Icons |
Components — renamed
| Before | After |
|---|---|
MultinaireText | Typography |
MultinaireImage | Photo |
MultinaireLoading | Animate |
MultinaireScrollView | ScrollContainer |
MultinaireSwitch | Toggle |
MultinaireModal | Popup |
MultinaireModalHeader | PopupHeader |
MultinaireModalToggleButton | PopupToggleButton |
MultinaireKeyboardAvoidingView | KeyboardAvoidingContainer |
MultinaireListView | ListContainer |
MultinairePageView | PageContainer |
MultinaireTabView | TabContainer |
All other Multinaire* components drop the prefix (e.g. MultinaireButton → Button).
Prop types renamed to match their component names exactly:
| Old name | New name |
|---|---|
TextProps | TypographyProps |
ImageProps | PhotoProps |
SwitchProps | ToggleProps |
KeyboardAvoidingViewProps | KeyboardAvoidingContainerProps |
ScrollViewProps | ScrollContainerProps |
ListViewProps | ListContainerProps |
TabViewProps | TabContainerProps |
PageViewProps | PageContainerProps |
ListPickerItem | ListPickerItemData |
DatePickerProps | DateTimePickerProps |
Removed
MenuButton.typeprop ('default' | 'warning' | 'error') — foreground color is now alwaysonBackgroundButtonType.destructive— use'error'instead
Changed
Pageanimation changed from fade to directional slide (forward slides in from the right, backward from the left)
Added
MultinaireUIis now also the default export of@multinaire/ui
See the Migration Guide for a full upgrade walkthrough.