How to call scrollTo function from react-navigation tab bar - react-navigation

I have create a function which scrolls a ScrollView to a set position when it is called (near top). I would like for the function to be called from the react-navigation tab bar. Calling the function is easy, but I am struggling to get it to communicate with the scrollRef from the screen component.
Here's my snack: https://snack.expo.dev/#dazzerr/scroll-to-top-function
You'll find this function in App.js which is called when the tab bar is pressed:
const onTabPress = () => {
scrollRef.current?.scrollTo({ // how do I get ref={scrollRef} from component.js ScrollView?
y: 0,
animated: true,
});
};
and in component.js is the ScrollView in question:
<ScrollView
ref={scrollRef}
style={styles.container}
scrollEventThrottle={16}
>
{ScreenContent()}
</ScrollView>
How can I get the scrollRef from component.js called from inside the onTabPress function from app.js? 🤔

You'll need to pass the function through react-navigation setParams like this:
This goes inside your createBottomTabNavigator:
tabBarOnPress: (scene, jumpToIndex) => {
scene.navigation.state.params.scrollToTop(); // Here's the magic!
},
And this inside your component:
useEffect(() => {
props.navigation.setParams({
scrollToTop: () => {
onTabPress();
},
});
}, []);
const onTabPress = () => {
scrollRef.current?.scrollTo({
y: 600, // whatever number you want here
animated: true,
});
};
Of course don't forget to add the scrollRef to your ScrollView, and make sure that your ScrollView is from react-native and not react-navigation. You might also want to add conditionals inside the tabBarOnPress such as:
if (
isFocused &&
typeof route.routes[0]?.params?.onTabBarPress !== "function"
)
But that's your doing 👍
Here's a working snack: https://snack.expo.dev/#dazzerr/ontabpress-scrollto

Related

three.js intersectObjects doesn't display functions in userData object

when I do raycasting trying to apply function from clicked object. without a problem I found which object clicked via raycaster. But when I try to get the function -I already gave it to the mesh- it doesn't display.
mesh.children.forEach((child: any) => {
child.name = "portal"
child.userData.clickable = true
child.userData.dblclick = function () {
window.location.href = "example"
}
})
console.log(mesh)
I can see the clickable prop, but not the dblclick prop. But If I change the value to string, then dblclick shows as a prop.
raycasting:
this.raycaster.setFromCamera(this.mouse, this.camera);
const intersects = this.raycaster.intersectObjects(this.scene.children, true);
if (intersects.length > 0) {
intersects.forEach((mesh: any) => {
if (mesh.object.userData.hasOwnProperty("clickable")) {
console.log(mesh.object.userData)
mesh.object.userData.dblclick();
}
});
}
Is it mean that intersects doesn't apply function as a value?

How to make a context menu in a custom ckeditor5 widget?

I made a inline widget similar a placeholder (ckeditor4), but now I want to render a dropdown when the widget is selected to show options values to replace the placeholder. I trying use BalloonPanelView but no success until now, someone have a idea about how to make it?
this.editor.editing.view.document.on('click', (evt, data) => {
evt.stop();
const element = data.target;
if (element && element.hasClass('placeholder')) {
if (!element.getAttribute('data-is-fixed')) {
const balloonPanelView = new BalloonPanelView();
balloonPanelView.render();
['option1', 'option2', 'option3'].forEach((value) => {
const view = new View();
view.set({
label: value,
withText: true
});
balloonPanelView.content.add(view);
});
balloonPanelView.pin({
target: element
});
}
}
});
I found the solution using ContextualBalloon class:
import ContextualBalloon from "#ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon";
// Define ballon
const balloon = editor.plugins.get(ContextualBalloon);
const placeholderOptions = // Here I defined list with buttons '<li><button></li>'
// Finnaly render ballon
balloon.add({
view: placeholderOptions,
singleViewMode: true,
position: {
target: data.domTarget
}
});

drag and drop with auto scrolling (dom-autoscrolling)

I have a list of text elements and want to automatically scroll my list to the bottom when I'm dragging my new element.
This example below works properly once I drag-and-dropped one time an element in a list.
I believe I need to call once an observable before the drag.
I'm using dragula and dom-autoscrolling.
import {takeUntil} from "rxjs/internal/operators/takeUntil";
import * as autoScroll from 'dom-autoscroller';
const drake = this.dragulaService.find(this.dragulaBagName);
this.dragulaService.drag.pipe(
takeUntil(this.destroyed$),
).subscribe(([bag, movingEl, containerEl]) => {
autoScroll(containerEl.parentNode, {
margin: 20,
pixels: 10,
scrollWhenOutside: true,
autoScroll: function () {
return this.down && drake && drake.drake && drake.drake.dragging;
}
});
});
Apparently, this.down in callback autoScroll is set to false at the beginning... once drag-and-dropped one time, it works correctly.
Any ideas?
try use (mousedown)="initAutoScroll()"
initAutoScroll(){
const drake = this.dragulaService.find(this.dragulaBagName);
this.scroll = autoScroll(
containerEl.parentNode,
{
margin: 30,
maxSpeed: 25,
scrollWhenOutside: true,
autoScroll: function () {
return this.down && drake.drake.dragging;
}
});
}
this.dragulaService.dragend.asObservable().subscribe(value => {
if (this.scroll) {
this.scroll.destroy(); // destroy when don't use auto-scroll
}
});

Flickering when using Scrollify

I seem to be encountering issues when attempting to scroll between a regular scrollify panel and interstitialSection. I need to add the elements within the interstitialSection to the standardScrollElements as they need to be scrollable.
When you scroll quickly on a desktop there is flickering and when using a mobile it exhibits other issues like not enabling scrollify on scrolling. When you clear the 'StandardScrollElements' it stops the flickering but doesn't allow scrolling of the content on the slide mainly on mobile.
$.scrollify({
section: ".slide",
scrollbars: true,
easing: "easeOutExpo",
scrollSpeed: 800,
updateHash: false,
standardScrollElements: ".footer-content,.news",
interstitialSection: ".slide-content,.clients,footer",
before: function () {
},
after: function (i) {
$.scrollify.current().find("[data-animated]").each(function () {
var animClass = $(this).attr("data-animated");
$(this).addClass("animated");
$(this).addClass(animClass);
});
},
afterRender: function () {
$.scrollify.current().find("[data-animated]").each(function () {
var animClass = $(this).attr("data-animated");
$(this).addClass("animated");
$(this).addClass(animClass);
});
}
});

Open only one React-Bootstrap Popover at a time

I'm using React-Bootstrap Popover and I was wondering if there is any builtin property that I can add either to Popover itself or to OverlayTrigger so only one popover will display at a time.
You can try rootClose props which will trigger onHide when the user clicks outside the overlay. Please note that in this case onHide is mandatory. e.g:
const Example = React.createClass({
getInitialState() {
return { show: true };
},
toggle() {
this.setState({ show: !this.state.show });
},
render() {
return (
<div style={{ height: 100, position: 'relative' }}>
<Button ref="target" onClick={this.toggle}>
I am an Overlay target
</Button>
<Overlay
show={this.state.show}
onHide={() => this.setState({ show: false })}
placement="right"
container={this}
target={() => ReactDOM.findDOMNode(this.refs.target)}
rootClose
>
<CustomPopover />
</Overlay>
</div>
);
},
});
I managed to do this in a somewhat unconventional manner. You can create a class which tracks the handlers of all of your tooltips:
export class ToolTipController {
showHandlers = [];
addShowHandler = (handler) => {
this.showHandlers.push(handler);
};
setShowHandlerTrue = (handler) => {
this.showHandlers.forEach((showHandler) => {
if (showHandler !== handler) {
showHandler(false);
}
});
handler(true);
};
}
Then in your tooltip component:
const CustomToolTip = ({
children,
controller,
}: CustomToolTipProps) => {
const [showTip, setShowTip] = useState(false);
useEffect(() => {
if (!controller) return;
controller.addShowHandler(setShowTip);
}, []);
return (
<OverlayTrigger
onToggle={(nextShow) => {
if (!nextShow) return setShowTip(false);
controller ? controller.setShowHandlerTrue(setShowTip) : setShowTip(true);
}}
show={showTip}
overlay={(props: any) => <Overlay {...props}/>}
>
<div className={containerClassName}>{children}</div>
</OverlayTrigger>
);
};
It's not really a 'Reacty' solution but it works quite nicely. Note that the controller is completely optional here so if you wanted you could not pass that in and it would then behave like a normal popover allowing multiple tooltips at once.
Basically to use it you can create another component and instantiate a controller which you pass into CustomToolTip. Then for any tooltips which are rendered using that component, only 1 will appear at a time.
STEP 1: we declare a currentPopover variable that contain current popover id, so we are sure that there is only one popover at a time.
const [currentPopover, setCurrentPopover] = useState(null);
STEP 2: the OverlayTrigger from react-bootstrap has properties to set popover state manually. If the currentPopover variable is equal to popover id then we show the popover.
show={currentPopover === `${i}`}
STEP 3: the OverlayTrigger from react-bootstrap has properties to handle popover click manually. On click we update the currentPopover variable with the new id, except if we clicked on the current.
onToggle={() => {
if( currentPopover === `${i}` )
setCurrentPopover(null)
else
setCurrentPopover(`${i}`)
}}
RESULT:
const [currentPopover, setCurrentPopover] = useState(null);
<OverlayTrigger
trigger="click"
show={currentPopover == `${i}`}
onToggle={() => {
if( currentPopover == `${i}` )
setCurrentPopover(null)
else
setCurrentPopover(`${i}`)
}}
>
(I use ${i} as id cause my OverlayTrigger is in a loop where i is the index)

Resources