Releases: nandorojo/zeego
2.0.3 Type Fixes
Zeego 2.0
A brand new zeego is here πͺ
Zeego 2.0 drops react-native-web
as a dependency. It now works with zero special configuration on Web. On iOS and Android, nothing has changed.
On Web, a lot has changed. Besides a few Zeego-only components, such as ItemIcon
, ItemImage
, ItemTitle
, and ItemSubtitle
, all components return Radix UI components directly with no custom UI or React Native Web wrappers. Previously, props were highly restricted. Now, you can use any DOM props on your Zeego components.
On iOS, Zeego still wraps react-native-ios-context-menu
. You can safely upgrade that library as well as react-native-ios-utilities
.
The same goes for Android and @react-native-menu/menu
. I have hopes to someday drop this library in favor of a better looking menu for Android, while ideally keeping the implementation with Kotlin.
What's New?
- Zeego's web implementation is now an incredibly thin layer on top of Radix. In fact, almost every web component is simply a Radix component with the
displayName
set on it. - You can use any props that Radix's components accept, including
className
, which React Native Web did not support. - Zeego now supports Tailwind styles on Web.
- As a result Zeego is now compatible with @shadcn UI. But remember to always wrap custom components with
create()
for them to work on native. - Zeego now works with zero config in any web project.
a. If you aren't sure if you'll want to add native support in the future, just use Zeego anyway instead of Radix for menus, and then native just will work in the future.
b. The main change here was turning.index.web.tsx
files into the baseindex.tsx
files, and using.ios
and.android
extensions for native projects.
c. For React Native users/library authors, take note of this. Make your baseindex.tsx
files the web one, and use platform file extensions for native. Why? Because every React Native app supports platform extensions (such as.native.tsx
,.ios.tsx
, etc.) On the other hand, Vite, Next.js, Remix, and the like have no idea that they should be looking for.web
files. So setting that up suddenly requires adding file extensions to your build step.
d. Going forward, I will try to implement this for any of my universal libraries: web-first, even if they're meant for React Native.
e. This decision is the culmination of tons of pain trying to build Solito and getting React Native libraries to work on Web. It's usually full of config hell.
Breaking Changes
If you've kept all your styles for your menus in one place, upgrading should be somewhat easy. I'll do my best to be entirely comprehensive about any breaking changes.
- Components no longer set any default styles on Web. Previously, they were wrapped with
View
fromreact-native-web
.- To preserve the same styles from Zeego v1, you can apply the style reset from
react-native-web
on your components. - For example, React Native Web defaults components to
display: flex
andflexDirection: column
. This behavior is gone. Web is truly unstyled.
- To preserve the same styles from Zeego v1, you can apply the style reset from
- Zeego component
style
props no longer accepts the result ofStyleSheet.create
. Please refactor these to plain JS objects. - Zeego component
style
props no longer accept arrays of styles. Please refactor these to spreading objects.style={[style, isFocused && focusedStyle]}
βstyle={{ ...style, ...isFocused && focusedStyle }}
- The
style
prop on most components has changed fromViewStyle
toReact.CSS
properties. This aligns with React Native's plan on supporting web styles. Trigger
will now render a button on Web (since Radix does this) unless you passasChild
.- I recommend passing
asChild
and ensuring you have a valid React element as the direct descendant ofTrigger
. <Trigger asChild
- The one component where I considered an exception to unstyled elements is
Trigger
, sinceTrigger
is the only UI element that renders on both web and native. But I plan on keeping the TypeScript type for itsstyle
asReact.CSSProperties
, and keeping it unstyled on Web. This may result in small inconsistencies between and Web and Native, since native will set the default styles forTrigger
todisplay: flex
, etc. You likely won't notice it, but it's worth mentioning. - To preserve the same styles from Zeego v1, you can apply the style reset from
react-native-web
on yourTrigger
by default. Or, even better, pass your own element as the direct child and use theasChild
prop.
- I recommend passing
ItemImage
- No longer uses
Image
from React Native, instead opting forimg
directly. You may need to adjust the styles accordingly. - No longer has a
fadeDuration
prop. - Expo Web Users:
ItemImage
longer works on out of the box Web with local images imported usingrequire()
orimport
, unless your Web bundler supports this for plainimg
tags. Under the hood,ItemImage
simply rendersimg src=
. To fix this, see the bottom of the release notes.- This does not affect Vite or Next.js.
- No longer uses
- The following components are now fully unstyled and render a plain
span
on Web. Previously, they rendered aText
fromreact-native-web
, which applied default styles. These styles have been removed, including the defaultfont: 'System 14px'
:ItemTitle
Label
ItemSubtitle
- To preserve the same styles that they had before, you can apply the Text style reset from React Native Web.
- If you use
lineHeight
to style any of these components, be sure to change it to a string.react-native-web
was turning numbers into strings ending inpx
, but this will no longer happen, resulting in line height numbers being treated asem
instead ofpx
.
- If you used the rare
animationKeyframes
for your menu's animations, this will no longer work, as this is areact-native-web
only feature. menuify
has been removed. This was deprecated in v1. UseDropdownMenu.create
orContextMenu.create
instead.
Migration Guide
1. Update Trigger
On Web, Radix's Trigger
component is a <button>
. Chances are, this will render something which you don't want. To mitigate this, you can use a custom create
with asChild
.
import * as ContextMenu from 'zeego/context-menu'
// BEFORE: if you had this...
const ContextMenuTrigger = ContextMenu.Trigger
// AFTER: you might want to do this instead...
const ContextMenuTrigger = ContextMenu.create<
React.ComponentProps<typeof ContextMenu.Trigger>
>(
(props) => (
<ContextMenu.Trigger {...props} asChild>
<View aria-role="button">{props.children}</View>
</ContextMenu.Trigger>
),
'Trigger'
)
You can put anything you want inside of the custom ContextMenuTrigger
there. The code above will preserve the prior behavior of not rendering a button.
2. Remove StyleSheet.create
If you're passing any styles directly to zeego components using StyleSheet.create
, you should remove this and turn them into plain style objects.
3. Add styles for text components
If you render ItemTitle
, ItemSubtitle
, or Label
, you may need to apply base styles to them. As long as you followed the docs previously and had all the components in one file, this should be easy to update.
Also, be sure to turn any style arrays into objects.
4. Update Item
styles
You may want to preserve the v1 approach where Item
rendered a View
. To do this, simply create
a custom component for Item
.
const DropdownMenuItem = DropdownMenu.create(
(props: ComponentProps<typeof DropdownMenu.Item>) => {
return (
<DropdownMenu.Item {...props}>
<View
style={
{
...dropdownStyles.item, // you can pass your default styles here
...props.style,
} as object
}
>
{props.children}
</View>
</DropdownMenu.Item>
)
},
'Item'
)
Please refer to the breaking changes guide for more info.
5. Update ItemImage
(if you're using Expo Web / Metro Web)
If you are using Solito, Vite, Next.js, or most web-only frameworks, then this does not apply to you.
However, as of Zeego v2, locally-imported images will not work as-is with Metro Web/Expo Web.
To fix this, you should create
a custom ItemImage
component which wraps Image
from react-native
:
import { Image } from 'react-native'
import * as ContextMenu from 'zeego/context-menu'
const ItemImage = ContextMenu.create<
React.ComponentProps<typeof ContextMenu.ItemImage>
>((props) => {
return <Image {...props as any} />
}, 'ItemImage')
1.10
This version fixes support for checkboxes not showing on Android, closing #45
What's Changed
- Fix: missing checkmark icon on Android's CheckboxItem by @MarceloPrado in #81
New Contributors
- @MarceloPrado made their first contribution in #81
Full Changelog: v1.9...v1.10.0
1.9
New Features π«
shouldDismissMenuOnSelect
(iOS, Web)
You can now pass shouldDismissMenuOnSelect
to <ContextMenu.Item />
to disable closing a menu.
<ContextMenu.Item shouldDismissMenuOnSelect={false} />
This works on the CheckboxItem
and Item
for both ContextMenu
and DropdownMenu
(TODO: add to docs)
Full Changelog: v1.8.1...v1.9
1.8.1
Fixes
In order to support horizontal groups, you can now pass an empty string to textValue
in your nested item props:
<Menu.Group horizontal>
<Menu.Item key="item" textValue="">
<Menu.ItemIcon ios={{ name: 'your-icon-here' }} />
</Menu.Item>
</Menu.Group>
This lets you use icons only.
1.8
New Features π
Horizontal groups (iOS)
On iOS, you can use the horizontal
prop render items like so:
<DropdownMenu.Group horizontal>
...
</DropdownMenu.Group>
Same goes for ContextMenu
Group labels (iOS, Web)
Groups can now have labels!
To add a title to the group, pass a Label
component inside of it:
<DropdownMenu.Group>
<DropdownMenu.Label>menuTitle</DropdownMenu.Label>
</DropdownMenu.Group>
New SF Symbols
Upgraded to SF Symbols v2!
See the docs here: https://github.com/nandorojo/sf-symbols-typescript/releases/tag/v2
What's Changed
- fix: enable custom styling of arrow components by @nderscore in #68
- docs: Update start.md to include
react-native-ios-utilities
by @sidorchukandrew in #73 - docs: update cli to use npx expo and plugins config typo fix by @Just-Moh-it in #70
New Contributors
- @nderscore made their first contribution in #68
- @sidorchukandrew made their first contribution in #73
- @Just-Moh-it made their first contribution in #70
Full Changelog: v1.7.1...v1.8.0
1.7.3
1.7.1
1.7.0 π
No breaking changes in this release.
New Features
Remote Image for iOS
The following is now supported on iOS:
<DropdownMenu.ItemImage
source={{ uri: 'https://your-image-url' }}
lazy={false} // defaults to true
style={{
// a special style object for iOS
cornerRadius?: number
renderingMode?: 'automatic' | 'alwaysOriginal' | 'alwaysTemplate'
tint?: string | { dark: string, light: string }
}}
/>
asChild
for Trigger
You can now pass asChild
to DropdownMenu.Trigger
/ContextMenu.Trigger
to forward props down to the immediate child.
Bug Fixes
onOpenChange
was previously not doing anything on Web forContextMenu.Root
. This is now fixed.