Bearer provide advanced Components to easily build complex custom logic.
The Navigator is in charge of handling the stacking and rooting of components, aka Navigation! (learn more)
Bearer provide three components to handle Navigation, <bearer-navigator />
, bearer-navigator-screen />
and <bearer-navigator-auth-screen />
. Those components should be used in Root Components.
Navigator
The <bearer-navigator />
component is the one encapsulating the inner stacking of components. By default <bearer-navigator />
is rendered as a popover, embedding the nested components inside it.
Scenario UX
In order for a Scenario to easily be Integrated, it's usually important that that UI has a limited scope and footprint on the host application. Having most of a Scenario's UI embedded into popover or modal is a good way of achieving this.
//Opening the popover on the right, using button style 'primary' and having the button name 'Attach Pull Request'
<bearer-navigator direction="right">
<span slot="navigator-btn-content">Feature Action</span>
// put you screens here
</bearer-navigator>
The <bearer-navigator/>
offers configurable properties:
direction
: Direction of the opening of the popover (top, bottom, right or left)
Navigator Screen
The bearer-screen-navigator />
component is in charge of adding a component to the Navigator stack. It must be nested inside a <bearer-navigator />
.
s <list-repositories />
</bearer-navigator-screen>
// or using renderFunc method
<bearer-navigator-screen
name="pullRequest"
navigationTitle="Pick Pull Request"
renderFunc={
({ data, next, prev, complete }) =>
<list-pull-requests repository={data.repository} />
}/>
The <bearer-navigator-screen/>
offers configurable properties:
renderFunc
: Reference the component to add to the stack (above<list-repositories/>
)name
: Used by navigator to locally store data during the navigation flow. You can refer to data coming from previous screen when usingrenderFunc
.navigationTitle
: Title of the popover
Passing data from one screen to another one
If we want to pass data from one screen to an other then we must use the renderFunc
property
RenderFunc Screen Property
Sometimes, component needs to get more control from the navigator. To achieve this, we have the ability to customize what property are passed to component:
import { RootComponent } from '@bearer/core'
@RootComponent()
class AComponentWithLotOfPower{
@Prop() next: () => void
@Prop() prev: () => void
@Prop() complete: () => void
render() {
return (
<bearer-navigator>
<bearer-navigator-screen
name="first"
navigationTitle="First screen"
renderFunc={
({ next, prev, complete, data }) =>
<powerful-component next={next} prev={prev} complete={complete} data={data} value="FromScreen1" />
}
/>
// simpler way
<bearer-navigator-screen
name="second"
navigationTitle="Third screen"
renderFunc={
(screenProps) => <powerful-component {screenProps} value="FromScreen2"/>
}
/>
<bearer-navigator-screen
name="last"
navigationTitle="last screen"
renderFunc={
({ data }) => <div>{data}</div>
}
/>
</bearer-navigator>
)
}
}
import { Component, Prop } from '@bearer/core'
@Component({
tag: 'powerful-component'
})
class PowerfulComponent{
@Prop() next: () => void
@Prop() prev: () => void
@Prop() complete: () => void
@Prop() data: any // you can add you own type if you want
// adding an extra prop for demo purpose
@Prop() value: string
goNext = () => {
this.next(this.value)
}
render() {
return (
<div>
<bearer-button onClick={this.prev}>Go back<bearer-button>
<bearer-button onClick={this.goNext}>Go Next<bearer-button>
<bearer-button onClick={this.complete}>Complete the navigator flow<bearer-button>
<pre>
{JSON.stringify(this.data)}
</pre>
</div>
)
}
}
In the example above, if we click on next
on the first two screens then we should see the last component displaying this:
{
first: "FromScreen1",
second: "FromScreen2",
}
Data format
We can call data
as a Navigator State, a temporary state which keeps the current status of what the user is selecting (if a scenario needs multiple screen for example).
When a name is given to a bearer-navigator-screen
, this name is automatically used by the bearer-navigator
to store the information given when calling the next
method. It's totally up to you to use whatever name you want.
The value passed to the next
can be of any type, string, boolean, number, Object etc.
Navigator Auth Screen
The bearer-navigator-auth-screen />
component is in charge of adding the authentication logic to the Navigator stack. It must be used inside a <bearer-navigator />
. Usually it is the first item of the <bearer-navigator />
.
<bearer-navigator>
<bearer-navigator-auth-screen />
</bearer-navigator>
<bearer-navigator direction="right">
<span slot="navigator-btn-content">Attach Pull Request</span>
// Authentication screen
<bearer-navigator-auth-screen />
// Fist screen: select a repository, will pass selected repository to navigator state repository attribute
<bearer-navigator-screen name="repository" navigationTitle="Pick Repository">
<list-repositories />
</bearer-navigator-screen>
//Second screen
<bearer-navigator-screen
renderFunc={
({ data }) => <list-pull-requests repository={data.repository}/>
}
name="pullRequest"
navigationTitle={data => data.repository.full_name} />
//Third screen:
<bearer-navigator-screen
renderFunc={({ complete, data }) =>
<attach-pull-request-screen intent={this.attachPullRequest(data)} next={complete} />
}
navigationTitle="Attaching pull request"
/>
</bearer-navigator>
And the result:
Sometimes it's important to be able to change the behavior of our display component depending of the fact if a user is authenticated or not. The <bearer-authenticated />
component is in charge of dealing with this:
<bearer-authenticated
renderAuthorized={() => <my-component-which-fetch-data /> }
renderUnAuthorized={() => <placeholder-component /> }
/>
// If you scenario is a button only scenario then you can do this
<bearer-authorized
renderAuthorized={() =>
<bearer-button onClick={this.performIntent} {otherProps} />
}
renderUnauthorized={({ authenticate }) =>
<bearer-button onClick={() => authenticate().then(() => this.performIntent())} {otherProps} />
}
/>
The <bearer-authenticated/>
offers configurable properties:
renderAuthorized
: Must return valid TSXrenderUnauthorized
: Must return valid TSX. Has an authenticate parameter which is a function returning a Promise than can be used to trigger an Intent after user is authenticated
The <bearer-scrollable />
component is in charge of building a scrollable paginated list from a Hash of data, usually fetched from an Intent.
<bearer-scrollable />
//same as below (default properties)
<bearer-scrollable
fetcher={this.fetcher}
perPage={10}
renderCollection={collection => (
<bearer-navigator-collection
data={collection}
renderFunc={repository => repository.name}
/>
)}
/>
<bearer-scrollable />
offers configurable properties:
fetcher
: A BearerFetch instance used to fetch dataperPage
: Number of data shown per pagerenderCollection
: let you customize renderedCollection, except if you need a specific behaviour, we recommend not to use it :-)rendererProps
: Let you override item rendering. see examples above for more options
// displayMemberProp: string
// Use a different property to render an item: displayMemberProp: string
<bearer-scrollable
fetcher={this.fetcher}
perPage={10}
rendererProps={{displayMemberProp: 'title'}} // use item.item instead of item.name
/>
// renderFunc: (item: any) => any
// Custom Item rendering
<bearer-scrollable
fetcher={this.fetcher}
perPage={10}
rendererProps={{renderFunc: (item) => <div>{item.first_name} {item.last_name}</div> }}
/>