Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "react-logo.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ class TabScreenViewManager :
value: String?,
) = Unit

override fun setIconXcassetsName(
view: TabScreen?,
value: String?,
) = Unit

override fun setSelectedIconImageSource(
view: TabScreen?,
value: ReadableMap?,
Expand All @@ -94,6 +99,11 @@ class TabScreenViewManager :
value: String?,
) = Unit

override fun setSelectedIconXcassetsName(
view: TabScreen?,
value: String?,
) = Unit

// Annotation is Paper only
@ReactProp(name = "isFocused")
override fun setIsFocused(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
import com.facebook.react.uimanager.LayoutShadowNode;

@SuppressWarnings("deprecation")
public class RNSBottomTabsScreenManagerDelegate<T extends View, U extends BaseViewManager<T, ? extends LayoutShadowNode> & RNSBottomTabsScreenManagerInterface<T>> extends BaseViewManagerDelegate<T, U> {
public class RNSBottomTabsScreenManagerDelegate<T extends View, U extends BaseViewManager<T, ? extends LayoutShadowNode> & RNSBottomTabsScreenManagerInterface<T>>
extends BaseViewManagerDelegate<T, U> {
public RNSBottomTabsScreenManagerDelegate(U viewManager) {
super(viewManager);
}

@Override
public void setProperty(T view, String propName, @Nullable Object value) {
switch (propName) {
Expand Down Expand Up @@ -71,12 +73,18 @@ public void setProperty(T view, String propName, @Nullable Object value) {
case "iconSfSymbolName":
mViewManager.setIconSfSymbolName(view, value == null ? null : (String) value);
break;
case "iconXcassetsName":
mViewManager.setIconXcassetsName(view, value == null ? null : (String) value);
break;
case "selectedIconImageSource":
mViewManager.setSelectedIconImageSource(view, (ReadableMap) value);
break;
case "selectedIconSfSymbolName":
mViewManager.setSelectedIconSfSymbolName(view, value == null ? null : (String) value);
break;
case "selectedIconXcassetsName":
mViewManager.setSelectedIconXcassetsName(view, value == null ? null : (String) value);
break;
case "systemItem":
mViewManager.setSystemItem(view, (String) value);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ public interface RNSBottomTabsScreenManagerInterface<T extends View> extends Vie
void setIconType(T view, @Nullable String value);
void setIconImageSource(T view, @Nullable ReadableMap value);
void setIconSfSymbolName(T view, @Nullable String value);
void setIconXcassetsName(T view, @Nullable String value);
void setSelectedIconImageSource(T view, @Nullable ReadableMap value);
void setSelectedIconSfSymbolName(T view, @Nullable String value);
void setSelectedIconXcassetsName(T view, @Nullable String value);
void setSystemItem(T view, @Nullable String value);
void setSpecialEffects(T view, @Nullable ReadableMap value);
void setOverrideScrollViewContentInsetAdjustmentBehavior(T view, boolean value);
Expand Down
23 changes: 22 additions & 1 deletion apps/src/screens/BarButtonItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const Stack = createNativeStackNavigator();
const demoScreens = [
{ name: 'PlainButtonDemo', title: 'Plain Button' },
{ name: 'IconButtonDemo', title: 'Icon Button' },
{ name: 'XcassetsIconButtonDemo', title: 'Xcassets Icon Button' },
{ name: 'SystemIconButtonDemo', title: 'System Icon Button' },
{ name: 'MenuButtonDemo', title: 'Menu Button' },
{ name: 'BadgeButtonDemo', title: 'Badge Button' },
Expand Down Expand Up @@ -63,6 +64,7 @@ const DemoScreenContent = () => (

const PlainButtonDemo = DemoScreenContent;
const IconButtonDemo = DemoScreenContent;
const XcassetsIconButtonDemo = DemoScreenContent;
const MenuButtonDemo = DemoScreenContent;
const BadgeButtonDemo = DemoScreenContent;
const DisabledButtonDemo = DemoScreenContent;
Expand Down Expand Up @@ -128,6 +130,24 @@ export default function BarButtonItemsExample() {
],
}}
/>
<Stack.Screen
name="XcassetsIconButtonDemo"
component={XcassetsIconButtonDemo}
options={{
title: 'Icon Button',
unstable_headerRightItems: () => [
{
type: "button",
icon: {
type: "xcassets",
name: "logo",
},
label: "Xcassets",
onPress: () => Alert.alert('Icon Xcassets pressed'),
}
],
}}
/>
<Stack.Screen
name="SystemIconButtonDemo"
component={IconButtonDemo}
Expand Down Expand Up @@ -419,7 +439,7 @@ export default function BarButtonItemsExample() {
items: [
{
label: 'Action 1',
icon: { type: 'sfSymbol', name: 'star' },
icon: { type: 'xcassets', name: 'logo' },
type: 'action',
state: 'on',
destructive: true,
Expand Down Expand Up @@ -451,6 +471,7 @@ export default function BarButtonItemsExample() {
destructive: true,
keepsMenuPresented: true,
discoverabilityLabel: 'Sub Action 1',
icon: { type: "xcassets", name: "logo" }
},
{
label: 'Sub Action 2',
Expand Down
36 changes: 36 additions & 0 deletions apps/src/tests/Test3443/BottomTabsScenario.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { useState } from "react";
import { SCROLL_EDGE_EFFECT_DEFAULTS, ScrollEdgeEffects, ScrollEdgeEffectsConfigContext } from "./context";
import { NavigationContainer, NavigationIndependentTree } from "@react-navigation/native";
import { BottomTabsContainer } from "../../shared/gamma/containers/bottom-tabs/BottomTabsContainer"
import { Config } from "./Config";
import { ScrollViewTemplate } from "./ScrollViewTemplate";
import { ScrollView } from "react-native";

function ConfigComponent() {
// Add ScrollView for automatic insets which are missing in BottomTabsScreen
return (
<ScrollView>
<Config title='Stack / scrollEdgeEffects:' />
</ScrollView>
);
}

export function BottomTabsScenario() {
const [config, setConfig] = useState<ScrollEdgeEffects>({ ...SCROLL_EDGE_EFFECT_DEFAULTS });

return (
<NavigationIndependentTree>
<ScrollEdgeEffectsConfigContext.Provider value={{ config, setConfig }}>
<NavigationContainer>
<BottomTabsContainer
tabConfigs={[
{ component: ConfigComponent, tabScreenProps: { tabKey: 'config', title: 'Config', icon: { ios: { type: "xcassets", name: "logo" } } } },
// Using `freezeContents` for testing purposes, to make the ScrollView searching algorithm's success verifiable
{ component: ScrollViewTemplate, tabScreenProps: { tabKey: 'stack', title: 'Scroll', freezeContents: false, scrollEdgeEffects: config } },
]}
/>
</NavigationContainer>
</ScrollEdgeEffectsConfigContext.Provider>
</NavigationIndependentTree>
);
}
71 changes: 71 additions & 0 deletions apps/src/tests/Test3443/Config.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React, { Button, Text } from "react-native";
import { useScrollEdgeEffectsConfigContext } from './context';
import { NavigationProp, useNavigation } from "@react-navigation/core";
import { SettingsPicker } from "../../shared";
import { ScrollEdgeEffect } from "react-native-screens";

interface ConfigProps {
title: string;
navigation?: NavigationProp<{ Test: undefined }>;
}

const SCROLL_EDGE_EFFECT_OPTIONS: ScrollEdgeEffect[] = ['automatic', 'hard', 'soft', 'hidden'];

function ConfigWithOptionalNavigation(props: ConfigProps) {
const { title, navigation } = props;

const { config, setConfig } = useScrollEdgeEffectsConfigContext();

return (
<>
<Text style={{ margin: 8, fontSize: 18 }}>{title}</Text>
<SettingsPicker
label="bottom"
value={config.bottom}
items={SCROLL_EDGE_EFFECT_OPTIONS}
onValueChange={value =>
setConfig({...config, bottom: value})
}
/>
<SettingsPicker
label="top"
value={config.top}
items={['automatic', 'hard', 'soft', 'hidden']}
onValueChange={value =>
setConfig({...config, top: value})
}
/>
<SettingsPicker
label="left"
value={config.left}
items={['automatic', 'hard', 'soft', 'hidden']}
onValueChange={value =>
setConfig({...config, left: value})
}
/>
<SettingsPicker
label="right"
value={config.right}
items={['automatic', 'hard', 'soft', 'hidden']}
onValueChange={value =>
setConfig({...config, right: value})
}
/>
{ navigation && <Button title="Go" onPress={() => navigation.navigate('Test')} /> }
</>
);
}

export function Config(props: Pick<ConfigProps, 'title'>) {
return (
<ConfigWithOptionalNavigation title={props.title}/>
);
}

export function ConfigWithNavigation(props: Pick<ConfigProps, 'title'>) {
const navigation: NavigationProp<{ Test: undefined}> = useNavigation();

return (
<ConfigWithOptionalNavigation title={props.title} navigation={navigation}/>
);
}
19 changes: 19 additions & 0 deletions apps/src/tests/Test3443/ScrollViewTemplate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from "react";
import { Button, ScrollView, Text } from "react-native";
import { useScrollEdgeEffectsConfigContext } from "./context";

export function ScrollViewTemplate() {
const emoji = ['😎', '🍏', '👀', '🤖', '👾', '👨‍💻'];
const { setConfig } = useScrollEdgeEffectsConfigContext();

return (
<ScrollView contentInsetAdjustmentBehavior="automatic">
<Button title="Set effects to hidden" onPress={() => {
setConfig({ bottom: 'hidden', top: 'hidden', left: 'hidden', right: 'hidden' });
}}/>
<Text style={{ fontSize: 21 }}>
{Array.from({ length: 1000 }).map(_ => emoji[Math.floor(Math.random() * emoji.length)])}
</Text>
</ScrollView>
);
}
36 changes: 36 additions & 0 deletions apps/src/tests/Test3443/context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { createContext, Dispatch, SetStateAction, useContext } from 'react';
import { ScrollEdgeEffect } from 'react-native-screens';

export interface ScrollEdgeEffects {
bottom: ScrollEdgeEffect,
top: ScrollEdgeEffect,
left: ScrollEdgeEffect,
right: ScrollEdgeEffect,
}

export interface ScrollEdgeEffectsConfigContext {
config: ScrollEdgeEffects;
setConfig: Dispatch<SetStateAction<ScrollEdgeEffects>>;
}

export const ScrollEdgeEffectsConfigContext =
createContext<ScrollEdgeEffectsConfigContext | null>(null);

export const SCROLL_EDGE_EFFECT_DEFAULTS: ScrollEdgeEffects= {
bottom: 'automatic',
top: 'automatic',
left: 'automatic',
right: 'automatic',
};

export const useScrollEdgeEffectsConfigContext = () => {
const ctx = useContext(ScrollEdgeEffectsConfigContext);

if (!ctx) {
throw new Error(
'useScrollEdgeEffectsConfigContext must be used within <ScrollEdgeEffectsConfigContext.Provider>',
);
}

return ctx;
};
36 changes: 36 additions & 0 deletions apps/src/tests/Test3443/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { useState } from "react";
import { SCROLL_EDGE_EFFECT_DEFAULTS, ScrollEdgeEffects, ScrollEdgeEffectsConfigContext } from "./context";
import { NavigationContainer, NavigationIndependentTree } from "@react-navigation/native";
import { BottomTabsContainer } from "../../shared/gamma/containers/bottom-tabs/BottomTabsContainer"
import { Config } from "./Config";
import { ScrollViewTemplate } from "./ScrollViewTemplate";
import { ScrollView } from "react-native";

function ConfigComponent() {
// Add ScrollView for automatic insets which are missing in BottomTabsScreen
return (
<ScrollView>
<Config title='Stack / scrollEdgeEffects:' />
</ScrollView>
);
}

export default function App() {
const [config, setConfig] = useState<ScrollEdgeEffects>({ ...SCROLL_EDGE_EFFECT_DEFAULTS });

return (
<NavigationIndependentTree>
<ScrollEdgeEffectsConfigContext.Provider value={{ config, setConfig }}>
<NavigationContainer>
<BottomTabsContainer
tabConfigs={[
{ component: ConfigComponent, tabScreenProps: { tabKey: 'config', title: 'Config', icon: { ios: { type: "xcassets", name: "logo" } } } },
// Using `freezeContents` for testing purposes, to make the ScrollView searching algorithm's success verifiable
{ component: ScrollViewTemplate, tabScreenProps: { tabKey: 'stack', title: 'Scroll', freezeContents: false, scrollEdgeEffects: config } },
]}
/>
</NavigationContainer>
</ScrollEdgeEffectsConfigContext.Provider>
</NavigationIndependentTree>
);
}
1 change: 1 addition & 0 deletions apps/src/tests/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ export { default as Test3369 } from './Test3369';
export { default as Test3379 } from './Test3379';
export { default as Test3422 } from './Test3422';
export { default as Test3425 } from './Test3425';
export { default as Test3443 } from './Test3443';
export { default as TestScreenAnimation } from './TestScreenAnimation';
// The following test was meant to demo the "go back" gesture using Reanimated
// but the associated PR in react-navigation is currently put on hold
Expand Down
Loading