1 | # @bearer/react
|
2 |
|
3 | [![Version](https://img.shields.io/npm/v/@bearer/react.svg)](https://npmjs.org/package/@bearer/react)
|
4 | ![npm bundle size (scoped)](https://img.shields.io/bundlephobia/minzip/@bearer/react.svg)
|
5 | ![node (scoped)](https://img.shields.io/node/v/@bearer/node.svg)
|
6 | [![Downloads/week](https://img.shields.io/npm/dw/@bearer/react.svg)](https://npmjs.org/package/@bearer/react)
|
7 | ![NPM](https://img.shields.io/npm/l/@bearer/react)
|
8 |
|
9 | React tooling for bearer.sh components
|
10 |
|
11 | ## Installation
|
12 |
|
13 | Install dependencies
|
14 |
|
15 | ```bash
|
16 | yarn add @bearer/js @bearer/react
|
17 | ```
|
18 |
|
19 | ## Factory
|
20 |
|
21 | Factory lets you create components or HOC scoped for an integration. It prevents your to repeat yourself.
|
22 | We recommend creating a file per integration so that it is easier to maintain on the long run (totaly up to you of course)
|
23 |
|
24 | ```tsx
|
25 | import { factory, Bearer } from '@bearer/react'
|
26 | const { Connect, withInvoke } = factory('my-integration-name')
|
27 | ```
|
28 |
|
29 | ### `Connect` component
|
30 |
|
31 | This component expect a `setupId` to authenticate the final user.
|
32 |
|
33 | ```tsx
|
34 | import { factory } from '@bearer/react'
|
35 | const { Connect } = factory('my-integration-name')
|
36 |
|
37 | class MyComponent extends React.Component {
|
38 | handleSuccess = ({ authId }) => {
|
39 | // do whatever you want with the authId received
|
40 | }
|
41 | render() {
|
42 | return (
|
43 | <Bearer clientId="BEARER_PUBLISHABLE_KEY">
|
44 | <Connect
|
45 | setupId="setupId"
|
46 | render={({ loading, connect, error }) => {
|
47 | if (loading) {
|
48 | return <Loading />
|
49 | }
|
50 | if (error) {
|
51 | return (
|
52 | <div>
|
53 | Error, please retry <button onClick={() => connect()}>Retry</button>
|
54 | </div>
|
55 | )
|
56 | }
|
57 | return <button onClick={connect}>Connect ...</button>
|
58 | }}
|
59 | />
|
60 | </Bearer>
|
61 | )
|
62 | }
|
63 | }
|
64 | ```
|
65 |
|
66 | ### `withInvoke` HOC
|
67 |
|
68 | If for any reasons you want to display data coming bearer but without using built in Web Components, you can easily connect your React application with Bearer servers. More on React HOCs [here](https://reactjs.org/docs/higher-order-components.html)
|
69 |
|
70 | Assuming we have a backend function named `GimmeData` returning an array of string
|
71 |
|
72 | ```tsx
|
73 | // myConnectedToBearerComponent.tsx
|
74 | import { factory } from '@bearer/react'
|
75 | const { withInvoke } = factory('my-integration-name')
|
76 |
|
77 | interface TProps {
|
78 | loading: boolean
|
79 | error?: any
|
80 | data?: { title: string }
|
81 | invoke: (params: any) => void
|
82 | otherDataYouWantToPass: string
|
83 | }
|
84 |
|
85 | function DisplayComponent(props: TProps) {
|
86 | if (props.loading) {
|
87 | return 'Loading'
|
88 | }
|
89 | if (props.error) {
|
90 | return <div>Error: {props.error}</div>
|
91 | }
|
92 | if (props.data) {
|
93 | return <div>Some data passed: {props.data}</div>
|
94 | }
|
95 |
|
96 | const invoke = () => {
|
97 | props.invoke({ query: { authId: 'AUTH_ID' } })
|
98 | }
|
99 |
|
100 | return (
|
101 | <div>
|
102 | {props.otherDataYouWantToPass}
|
103 | <button onClick={invoke}>Click to invoke</button>
|
104 | </div>
|
105 | )
|
106 | }
|
107 |
|
108 | export default withInvoke('GimmeData')(DisplayComponent)
|
109 | // if you want to add typing
|
110 | //export default withInvoke<string[], { otherDataYouWantToPass: string }>('GimmeData')(DisplayComponent)
|
111 | ```
|
112 |
|
113 | ## fromBearer
|
114 |
|
115 | This component takes html tag name of a component as well as optional type information to produce a react component that can we re-used throughout an application.
|
116 |
|
117 | ```tsx
|
118 | import * as React from 'react'
|
119 | const MyText = fromBearer<{ text?: string; anotherPropery: string }>('bearer-my-text')
|
120 |
|
121 | class ReactComponent extends React.Component {
|
122 | render() {
|
123 | return <MyText text="hello" anotherPropery="world" />
|
124 | }
|
125 | }
|
126 | ```
|
127 |
|
128 | Output events can be handled by simply adding the eventname as a prop on the component and adding a basic handler
|
129 |
|
130 | ```tsx
|
131 | <Share bearer-uuid-feature-shared={this.onShared} />
|
132 | ```
|
133 |
|
134 | For these tags to work correctly they must have a parent `Bearer`
|
135 |
|
136 | ## Bearer
|
137 |
|
138 | This component maintains a shared state for a group of components as well as adding the bearer script tags to the page. This tag can be added at any level of the application as is convenient for the implementation
|
139 |
|
140 | ### Example Use
|
141 |
|
142 | we will use [this integration](https://app.bearer.sh/integrations/6d29c4-share-slack-beta-4/preview) for our examples:
|
143 |
|
144 | First on the preview page obtain a setup-id from the setup components so we do not need to include these in our page. Next lets define our components in a constants file:
|
145 |
|
146 | `bearer.ts`
|
147 |
|
148 | ```TS
|
149 | import { fromBearer } from '@bearer/react'
|
150 |
|
151 | export const ChannelSelect = fromBearer('bearer-6d29c4-share-slack-beta-4-channel-action')
|
152 | export const Share = fromBearer<{message?:string, text?:string}>('bearer-6d29c4-share-slack-beta-4-feature-action')
|
153 | export const SlackConnect = fromBearer('bearer-6d29c4-share-slack-beta-4-connect-action')
|
154 | ```
|
155 |
|
156 | We can include the `Bearer` at any level but in this example lets use it all together in the same component
|
157 |
|
158 | `slack-share-component.tsx`
|
159 |
|
160 | ```tsx
|
161 | import * as React from 'react'
|
162 | import { Bearer } from '@bearer/react'
|
163 | import { SlackConnect, ChannelSelect, Share } from '../../constants/bearer'
|
164 |
|
165 | export default class SlackShareSetup extends React.Component {
|
166 | public render() {
|
167 | const intialContext = { 'setup-id': 'SETUP_ID_SAMPLE' }
|
168 | return (
|
169 | <Bearer clientId="BEARER_PUBLISHABLE_KEY" initialContext={intialContext}>
|
170 | <SlackConnect />
|
171 | <ChannelSelect />
|
172 | <Share message="hello world!" text="Test!" bearer-6d29c4-share-slack-beta-4-feature-shared={this.onShared} />
|
173 | </Bearer>
|
174 | )
|
175 | }
|
176 | }
|
177 | ```
|
178 |
|
179 | This allows to share messages but what if we want to persist the users setup information. @bearer/react provides two methods to acomplish this.
|
180 |
|
181 | ### Using onUpdate
|
182 |
|
183 | `Bearer` has an `onUpdate`callback we can hook into which is called every time data changes within the provider
|
184 |
|
185 | `slack-share-component.tsx`
|
186 |
|
187 | ```tsx
|
188 | import * as React from 'react'
|
189 | import { Bearer } from '@bearer/react'
|
190 | import { SlackConnect, ChannelSelect, Share } from '../../constants/bearer'
|
191 |
|
192 | export default class SlackShareSetup extends React.Component {
|
193 | public render() {
|
194 | const intialContext = { 'setup-id': 'SETUP_ID_SAMPLE' }
|
195 | return (
|
196 | <Bearer
|
197 | clientId="BEARER_PUBLISHABLE_KEY"
|
198 | initialContext={intialContext}
|
199 | onUpdate={(data: any) => {
|
200 | this.setState({ data })
|
201 | }}
|
202 | >
|
203 | <SlackConnect />
|
204 | <ChannelSelect />
|
205 | <Share message="hello world!" text="Test!" bearer-6d29c4-share-slack-beta-4-feature-shared={this.onShared} />
|
206 | <button onClick={this.handleSave}>Save Setup</button>
|
207 | </Bearer>
|
208 | )
|
209 | }
|
210 | private handleSave = () => console.log('handleSave', this.state.data)
|
211 | }
|
212 | ```
|
213 |
|
214 | ### using a context consumer
|
215 |
|
216 | Internally `Bearer` uses the [react context API](https://reactjs.org/docs/context.html). For a more advaned but flexable method we can access the consumer directly via `BearerContext` and then use the currently set details as we wish.
|
217 |
|
218 | `slack-share-component.tsx`
|
219 |
|
220 | ```tsx
|
221 | import * as React from 'react'
|
222 | import { Bearer, BearerContext } from '@bearer/react'
|
223 | import { SlackConnect, ChannelSelect, Share } from '../../constants/bearer'
|
224 |
|
225 | export default class SlackShareSetup extends React.Component {
|
226 | public render() {
|
227 | const intialContext = { 'setup-id': 'SETUP_ID_SAMPLE' }
|
228 | return (
|
229 | <Bearer clientId="BEARER_PUBLISHABLE_KEY" initialContext={intialContext}>
|
230 | <SlackConnect />
|
231 | <ChannelSelect />
|
232 | <Share message="hello world!" text="Test!" bearer-6d29c4-share-slack-beta-4-feature-shared={this.onShared} />
|
233 | <BearerContext.Consumer>
|
234 | {context => <button onClick={this.handleSave(context.state)}>Save Setup</button>}
|
235 | </BearerContext.Consumer>
|
236 | </Bearer>
|
237 | )
|
238 | }
|
239 | private handleSave = (data: any) => () => {
|
240 | console.log('handleSave', data)
|
241 | }
|
242 | }
|
243 | ```
|