Skip to content

Releases: nandorojo/zeego

Zeego 2.0

18 Sep 15:38
Compare
Choose a tag to compare

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?

  1. 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.
  2. You can use any props that Radix's components accept, including className, which React Native Web did not support.
  3. Zeego now supports Tailwind styles on Web.
  4. 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.
  5. 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 base index.tsx files, and using .ios and .android extensions for native projects.
    c. For React Native users/library authors, take note of this. Make your base index.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 from react-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 and flexDirection: column. This behavior is gone. Web is truly unstyled.
  • Zeego component style props no longer accepts the result of StyleSheet.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 from ViewStyle to React.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 pass asChild.
    • I recommend passing asChild and ensuring you have a valid React element as the direct descendant of Trigger.
    • <Trigger asChild
    • The one component where I considered an exception to unstyled elements is Trigger, since Trigger is the only UI element that renders on both web and native. But I plan on keeping the TypeScript type for its style as React.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 for Trigger to display: 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 your Trigger by default. Or, even better, pass your own element as the direct child and use the asChild prop.
  • ItemImage
    • No longer uses Image from React Native, instead opting for img 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 using require() or import, unless your Web bundler supports this for plain img tags. Under the hood, ItemImage simply renders img src=. To fix this, see the bottom of the release notes.
      • This does not affect Vite or Next.js.
  • The following components are now fully unstyled and render a plain span on Web. Previously, they rendered a Text from react-native-web, which applied default styles. These styles have been removed, including the default font: '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 in px, but this will no longer happen, resulting in line height numbers being treated as em instead of px.
  • If you used the rare animationKeyframes for your menu's animations, this will no longer work, as this is a react-native-web only feature.
  • menuify has been removed. This was deprecated in v1. Use DropdownMenu.create or ContextMenu.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

18 Mar 18:00
Compare
Choose a tag to compare

This version fixes support for checkboxes not showing on Android, closing #45

What's Changed

New Contributors

Full Changelog: v1.9...v1.10.0

1.9

16 Feb 23:20
Compare
Choose a tag to compare
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

16 Feb 23:03
Compare
Choose a tag to compare

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

16 Feb 22:33
Compare
Choose a tag to compare
1.8

New Features πŸ•

Horizontal groups (iOS)

On iOS, you can use the horizontal prop render items like so:

image
<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>
image

New SF Symbols

Upgraded to SF Symbols v2!

image

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

Full Changelog: v1.7.1...v1.8.0

1.7.3

16 Feb 21:40
Compare
Choose a tag to compare

Fixes

  • Fix Android callback not existing when onSelect / onValueChange isn't added to an item
  • Prevent long press gestures from propagating on iOS

1.7.1

05 Oct 18:26
Compare
Choose a tag to compare

Fix: Add asChild support to ContextMenu.Trigger on Web.

1.7.0 πŸŽ‰

16 Aug 17:14
Compare
Choose a tag to compare

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 for ContextMenu.Root. This is now fixed.

1.5.2

15 May 16:51
Compare
Choose a tag to compare

Fix #41

1.5.0

29 Mar 17:12
Compare
Choose a tag to compare

New Features

Trigger now accepts an action prop, which lets you control whether the menu should open on press or longPress.

<DropdownMenu.Trigger action="longPress">
  <Text>Open</Text>
</DropdownMenu.Trigger>

For ContextMenu, this defaults to longPress. For DropdownMenu, it defaults to press.