Is it possible to globally define links to use a specific component? - office-ui-fabric

I'm currently trying to use Nav with react-router. The default behavior reloads the page, so I'm trying to use the Link component from react-router-dom.
It's quite difficult to preserve the default styling when overriding linkAs.
Is there any global way to override link navigation behavior?
Like defining a global link render function, which I can then set to render the Link component from react-router-dom?

Yes, it's possible!
2 things are required:
Make a wrapper component that translates the Nav API to react-router-dom links.
Specify the linkAs prop to the Nav component.
Wrapper component
This is a simple component that creates a react-router-dom link while using styles from Fabric:
import { Link } from "react-router-dom";
const LinkTo = props => {
return (
<Link to={props.href} className={props.className} style={props.style}>
{props.children}
</Link>
);
};
Specify component for use in Nav
<Nav groups={links} linkAs={LinkTo} />
Have also created a full working example at https://codesandbox.io/s/xenodochial-wozniak-y10tr?file=/src/index.tsx:605-644

Related

Vue 3 pass tamplate part to another component

I have a Vue 3 application with router. (Using Bootstrap)
I have deep component in header, and main container (page in RouterView).
Question: I want to show few icons in header, but use it from page component.
What I must to use to do that?
I try to send template, dynamic import and etc, but as i understand it`s wrong ways.
I have same struct:
App
Header
Title
Icons
LeftMenu
MainContant
PageTitle
PageContant <- RouterView
Footer
So I have special template to Header Icons for each page. And I want to work with icons from page component. For example make submit icon.
I'm not completely sure if I understand the question correctly. But from what I get you want to have a slot in your Header component - docs.
So you can use it in MainContainer as follows:
<div>
<Header>
<Icon />
</Header>
</div>
In this case you'll have access to the Icon components in your MainContainer template.

Testing visibility of React component with Tailwind CSS transforms using jest-dom

How can I test whether or not a React component is visible in the DOM when that component is hidden using a CSS transition with transform: scale(0)?
jest-dom has a .toBeVisible() matcher, but this doesn't work because transform: scale(0) is not one of the supported visible/hidden triggers. Per the docs:
An element is visible if all the following conditions are met:
it is present in the document
it does not have its css property display set to none
it does not have its css property visibility set to either hidden or collapse
it does not have its css property opacity set to 0
its parent element is also visible (and so on up to the top of the DOM tree)
it does not have the hidden attribute
if <details /> it has the open attribute
I am not using the hidden attribute because it interfered with my transition animations. I am using aria-hidden, but that is also not one of the supported triggers.
The simplified version of my component is basically this. I am using Tailwind CSS for the transform and the transition.
import React from "react";
import clsx from "clsx";
const MyComponent = ({isSelected = true, text}) => (
<div
className={clsx(
isSelected ? "transform scale-1" : "transform scale-0",
"transition-all duration-500"
)}
aria-hidden={!isSelected}
>
<span>{text}</span>
</div>
)
I could potentially check for hidden elements with:
toHaveClass("scale-0")
toHaveAttribute("aria-hidden", true)
But unlike toBeVisible, which evaluates the entire parent tree, these matchers only look at the element itself.
If I use getByText from react-testing-library then I am accessing the <span> inside the <div> rather than the <div> which I want to be examining. So this doesn't work:
import React from "react";
import { render } from "#testing-library/react";
import "#testing-library/jest-dom/extend-expect";
import { MyComponent } from "./MyComponent";
it("is visible when isSelected={true}", () => {
const {getByText} = render(
<MyComponent
isSelected={true}
text="Hello World"
/>
);
expect(getByText("Hello World")).toHaveClass("scale-1");
});
What's the best way to approach this?

Control Vue component from nested layout using Inertia JS

I'm using Inertia JS using Vue and nested Layouts.
My main layout looks something like this:
<template>
<div>
<app-bar title="App title" type="back|dismiss|sidebar">
<!-- Slot for icons in the top right corner -->
</app-bar>
<slot />
</div>
</template>
So, an AppBar component accepting a title, a link with a back icon, dismiss icon or sidebar icon, and a slot (optionally) to provide icon links relevant to the current page.
<script>
import Layout from '#/Pages/Messenger/Layout';
export default {
metaInfo: { title: 'Report new problem' },
layout: [Layout],
...
</script>
This is a Page that is nested in the Layout.
So my question is: what is the best/preferred way to control the props and slot of the AppBar from nested Pages?
A bit like as you would do using Blade templates in Laraval or as Vue Meta does for the document page title as seen in the example above.
Maybe this is not even the best approach, in that case also let me know :)
If you are trying to pass information from your child component to your parent component such as a title, you can use $emit.
Here is a article describing how: https://hvekriya.medium.com/pass-data-from-child-to-parent-in-vue-js-b1ff917f70cc
And another SO question: https://stackoverflow.com/a/52479745/4517964
The fast way I found to pass data to persistent layouts is by:
in the child
use this:
layout: (h, page) => { return h(Layout, () => page) }
instead of:
layout: Layout,
and in the parent layout you can access your child with this.$slots.default()[0]

Rendering stenciljs stateless components

I've been using StencilJS for some time now,
and coming from React background, my immediate instinct for writing some components is to write them stateless.
However, the stencil documentation doesn't mention the stateless components at all.
That's why I am writing here to learn other people experience with it
You should look at functional components: https://stenciljs.com/docs/functional-components to create stateless components, and they:
aren't compiled into web components,
don't create a DOM node,
don't have a Shadow DOM or scoped styles,
don't have lifecycle hooks,
According to the doc, if a component has to hold state, deal with events, etc, it should probably be a class component. If a component's purpose is to simply encapsulate some markup so it can be reused across your app, it can probably be a functional component
You can write functional components inside Stencil elements. As an example:
#Component({
tag: 'my-app',
styleUrl: 'my-app.css',
shadow: true
})
export class MyApp {
render() {
return (
<div>
<Loading />
</div>
);
}
}
const Loading = () => {
return (
<div class="loading">
<h1>Activating Santa</h1>
<span>🎅🎄🎁</span>
</div>
);
};
In this case <Loading> is a stateless functional component similar to React's model - you can obtain its props and get children, etc.
Stateless Stencil components can not be exported as top-level Web Components - those must be defined as classes.

Render global footer in react-native-router-flux 3.x

I have an app where on all scenes I want to render a global navigation footer at the bottom of the screen. This was a very easy thing to do in RNRF 2.x with the footer prop, but I'm having quite a lot of trouble implementing it in 3.x since the footer prop does not exist anymore. Anyone know how to go about doing this?
You can do this with only React Native. Just wrap your old main component in a new View that contains the old main component and the footer. Then the footer will always be shown.
Assuming you have a main component named MainComponent in a file path/to/main/component.js:
// path/to/main/component.js
export default class MainComponent extends React.Component {
...
}
Just change it to this:
// path/to/main/component.js
class MainComponent extends React.Component {
...
}
export default () => (
<View styles={styles.newMainComponent}>
<MainComponent />
<GlobalFooter />
</View>
);
You may need to move some styles from your old main component to the new view that wraps it.