Skip to content

Commit

Permalink
drawer.updateOptions added
Browse files Browse the repository at this point in the history
  • Loading branch information
kanzitelli committed Mar 19, 2023
1 parent 59933ff commit a6b8ccd
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 39 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -873,11 +873,11 @@ If you've found any diffilculties with using Navio and [React Navigation](https:

There are still some things I would like to add to the library:

- [x] `.updateOptions()` for specific tab.
- [x] `.updateOptions()` for specific tab and drawer.
- [x] Tabs can be placed inside Drawer and vice versa.
- [ ] Make deeplinking easier by providing `linking` prop to screens.
- [ ] Improve docs. Deeplinking section, etc. Based on this [issue](https://github.com/kanzitelli/expo-starter/issues/29).
- [ ] Make Navio universal by adding [RNN](https://github.com/wix/react-native-navigation) and [rnn-screens](https://github.com/kanzitelli/rnn-screens).
- [ ] Make deeplinking easier by providing `linking` prop to screens.
- [ ] Extend Navio funtionality and app layout.
- [ ] Easy integration of Navio with React Navigation (eg. navio.Stack())
- [ ] TypeScript issues @ `index.tsx` file.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rn-navio",
"version": "0.0.6",
"version": "0.0.7-rc.1",
"description": "🧭 Navigation library for React Native (Expo). Build once, navigate from anywhere to everywhere!",
"author": "Batyr <dev@batyr.io>",
"homepage": "https://github.com/kanzitelli/rn-navio",
Expand Down
110 changes: 79 additions & 31 deletions src/navio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import {
TTabsContentValue,
TDrawerContentValue,
DefaultOptions,
TunnelEvent$Tabs$UpdateOptions$Params,
TunnelEvent$UpdateOptions$Params,
} from './types';
import {NavioTunnel} from './tunnel';
import {safeOpts} from './help';
Expand Down Expand Up @@ -135,6 +135,7 @@ export class Navio<

// we use them to store tabs updated options during session
private __tabsUpdatedOptions: Record<string, BottomTabNavigationOptions> = {};
private __drawerUpdatedOptions: Record<string, DrawerNavigationOptions> = {};

// ========
// | Init |
Expand Down Expand Up @@ -400,7 +401,7 @@ export class Navio<
self.tunnel.echo('tabs.updateOptions', {
name,
options,
} as TunnelEvent$Tabs$UpdateOptions$Params<TabsContentName>);
} as TunnelEvent$UpdateOptions$Params<TabsContentName, BottomTabNavigationOptions>);
}
},

Expand Down Expand Up @@ -500,6 +501,21 @@ export class Navio<
}
},

/**
* `updateOptions(...)` action updates provided drawer's options.
*
* @param name name of the drawer content
* @param options `DrawerNavigationOptions` options for the drawer.
*/
updateOptions<T extends DrawersContentName>(name: T, options: DrawerNavigationOptions) {
if (self.navIsReady) {
self.tunnel.echo('drawer.updateOptions', {
name,
options,
} as TunnelEvent$UpdateOptions$Params<DrawersContentName, DrawerNavigationOptions>);
}
},

/**
* `setRoot(...)` action sets a new app root from drawers.
*
Expand Down Expand Up @@ -635,9 +651,6 @@ export class Navio<
return <></>;
}

// -- getting navigator props
const navigatorProps = this.__StackGetNavigatorProps(stackDef);

// -- building navigator
const Stack = createNativeStackNavigator();
const StackScreensMemo = useMemo(() => {
Expand All @@ -646,6 +659,9 @@ export class Navio<
);
}, [stackDef, screens, stacks]);

// -- getting navigator props
const navigatorProps = this.__StackGetNavigatorProps(stackDef);

return <Stack.Navigator {...navigatorProps}>{StackScreensMemo}</Stack.Navigator>;
};

Expand Down Expand Up @@ -753,7 +769,7 @@ export class Navio<
useEffect(() => {
this.tunnel.on(
'tabs.updateOptions',
(params: TunnelEvent$Tabs$UpdateOptions$Params<string>) => {
(params: TunnelEvent$UpdateOptions$Params<string, BottomTabNavigationOptions>) => {
const tcname = params.name;
const tcopts = params.options;
this.__tabsUpdatedOptions = {
Expand Down Expand Up @@ -873,10 +889,7 @@ export class Navio<
private Drawer: React.FC<{
drawerDef: TDrawerDefinition<DrawersName> | undefined;
}> = ({drawerDef}) => {
const {drawers, hooks} = this.layout;

// -- running hooks
if (hooks) for (const h of hooks) if (h) h();
const {drawers, defaultOptions, hooks} = this.layout;

if (!drawers) {
this.log('No drawers registered');
Expand All @@ -890,25 +903,72 @@ export class Navio<
return <></>;
}

// -- building navigator
const Drawer = useMemo(() => createDrawerNavigator(), [drawers]);
const currentDrawersContentKeys = useMemo(
() => Object.keys(currentDrawer.content),
[currentDrawer.content],
// -- internal state
const [updatedOptions, setUpdatedOptions] = useState<Record<string, DrawerNavigationOptions>>(
{},
);

// -- internal effects
useEffect(() => {
this.tunnel.on(
'drawer.updateOptions',
(params: TunnelEvent$UpdateOptions$Params<string, DrawerNavigationOptions>) => {
const name = params.name;
const opts = params.options;
this.__drawerUpdatedOptions = {
...this.__drawerUpdatedOptions,
[name]: {...this.__drawerUpdatedOptions[name], ...opts},
};
setUpdatedOptions(this.__drawerUpdatedOptions);
},
);
}, [drawerDef]);

// -- internal memos
const currentDrawerContent = useMemo(() => currentDrawer.content, [currentDrawer]);
const currentDrawerContentKeys = useMemo(
() => Object.keys(currentDrawerContent),
[currentDrawerContent],
);

// -- running hooks
if (hooks) for (const h of hooks) if (h) h();

// -- building navigator
const Drawer = useMemo(() => createDrawerNavigator(), [drawers]);
const DrawerScreensMemo = useMemo(() => {
return currentDrawersContentKeys.map(key =>
return currentDrawerContentKeys.map(key =>
this.DrawerScreen({
name: key,
DrawerNavigator: Drawer,
content: currentDrawer.content[key],
}),
);
}, [Drawer, currentDrawersContentKeys]);
}, [Drawer, currentDrawerContentKeys]);

// options
const Opts: BaseOptions<BottomTabNavigationOptions> = props => {
const rName = props?.route?.name;
if (!rName) return {};

const customDefaultOptions = this.getCustomDefaultOptions()?.drawers?.screen ?? {};
const dcsDefaultOpts = defaultOptions?.drawers?.screen ?? {};
const dcsOpts = (currentDrawer?.content[rName] as any)?.options ?? {};
const dcnpOpts = currentDrawer?.navigatorProps?.screenOptions ?? {};
const updOpts = updatedOptions[rName] ?? {};
return {
...safeOpts(customDefaultOptions)(props), // [!] custom default options
...safeOpts(dcsDefaultOpts)(props), // navio.defaultOptions.drawers.screen
...safeOpts(dcnpOpts)(props), // navio.drawers.[].navigatorProps.screenOptions -- because we override it below
...safeOpts(dcsOpts)(props), // tab-based options
...safeOpts(updOpts)(props), // upddated options (navio.drawers.updateOptions())
};
}; // must be function. merge options from buildNavio. also providing default options

return (
<Drawer.Navigator {...currentDrawer.navigatorProps}>{DrawerScreensMemo}</Drawer.Navigator>
<Drawer.Navigator {...currentDrawer.navigatorProps} screenOptions={Opts}>
{DrawerScreensMemo}
</Drawer.Navigator>
);
};

Expand All @@ -917,8 +977,6 @@ export class Navio<
name: string;
content: TDrawerContentValue<ScreensName, StacksName, TabsName>;
}> = ({DrawerNavigator, name, content}) => {
const {defaultOptions} = this.layout;

if (!content.stack && !content.tabs) {
this.log(`Either 'stack' or 'tabs' must be provided for "${name}" drawer content.`);
return null;
Expand All @@ -932,18 +990,8 @@ export class Navio<
? this.Tabs({tabsDef: content.tabs})
: null;

// options
const customDefaultOptions = this.getCustomDefaultOptions()?.drawers?.screen ?? {};
const dcsDefaultOptions = defaultOptions?.drawers?.screen ?? {};
const dcsOpts = content?.options ?? {};
const Opts: BaseOptions<DrawerNavigationOptions> = props => ({
...safeOpts(customDefaultOptions)(props), // [!] custom default options
...safeOpts(dcsDefaultOptions)(props), // navio.defaultOptions.drawers.screen
...safeOpts(dcsOpts)(props), // drawer-based options
}); // must be function. merge options from buildNavio. also providing default options

// screen
return <DrawerNavigator.Screen key={name} name={name} component={C} options={Opts} />;
return <DrawerNavigator.Screen key={name} name={name} component={C} />;
};

// | Modals |
Expand Down
7 changes: 2 additions & 5 deletions src/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,12 @@ export type RootProps<RootName extends string> = {
};

// Tunnel (Event Emitter)
export type TunnelEvent$Tabs$UpdateOptions$Params<
Name = string,
Options = BottomTabNavigationOptions,
> = {
export type TunnelEvent$UpdateOptions$Params<Name = string, Options = any> = {
name: Name;
options: Options;
};

export type TunnelEvent = 'tabs.updateOptions';
export type TunnelEvent = 'tabs.updateOptions' | 'drawer.updateOptions';
export type TunnelParams<T = any> = T;
export type TunnelListener = (params: TunnelParams) => void;
export type TunnelEvents = Partial<Record<TunnelEvent, TunnelListener[]>>;

0 comments on commit a6b8ccd

Please sign in to comment.