@stokr/components-library 3.0.21 → 3.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +467 -261
- package/dist/analytics/index.js +5 -1
- package/dist/api/authenticationApi.js +13 -0
- package/dist/auth/index.js +4 -2
- package/dist/components/2FA/login-with-otp-flow.js +9 -4
- package/dist/components/Footer/FooterLayout.js +98 -95
- package/dist/components/Footer/FooterMenu.js +1 -1
- package/dist/components/Header/Header.js +102 -54
- package/dist/components/MainMenu/MainMenu.js +14 -4
- package/dist/components/Modal/NewVentureModal/NewVentureModal.js +6 -2
- package/dist/components/Payment/PaymentDetailsCard.js +1 -1
- package/dist/components/VerifyEmailModal/VerifyEmailModal.js +2 -1
- package/dist/components/headerHo/HeaderHo.js +8 -5
- package/dist/components/icons/LinkIcon.js +2 -2
- package/dist/config.js +5 -21
- package/dist/constants/globalVariables.js +6 -4
- package/dist/context/Auth.js +5 -2
- package/dist/context/AuthContext.js +22 -8
- package/dist/firebase-config.js +4 -18
- package/dist/index.js +36 -5
- package/dist/model/axios.js +3 -1
- package/dist/model/axiosPublic.js +2 -2
- package/dist/routing/RouterWrapper.js +17 -0
- package/dist/routing/app-routes.js +22 -0
- package/dist/routing/navigate-app.js +36 -0
- package/dist/routing/resolve-app-href.js +149 -0
- package/dist/runtime-config.js +94 -0
- package/dist/static/country-list.json +251 -251
- package/dist/static/fonts/Ionicons/ionicons.min.css +2810 -2810
- package/dist/static/fonts/Ionicons/ionicons.min.css.js +1 -1
- package/dist/static/fonts/icomoon/selection.json +910 -910
- package/dist/static/fonts/icomoon/style.css +139 -139
- package/dist/static/images/copy_icon.svg +4 -4
- package/dist/static/images/download_icon.svg +3 -3
- package/dist/static/images/numbers/number_eight.svg +3 -3
- package/dist/static/images/numbers/number_five.svg +4 -4
- package/dist/static/images/numbers/number_four.svg +3 -3
- package/dist/static/images/numbers/number_nine.svg +4 -4
- package/dist/static/images/numbers/number_one.svg +4 -4
- package/dist/static/images/numbers/number_seven.svg +4 -4
- package/dist/static/images/numbers/number_six.svg +4 -4
- package/dist/static/images/numbers/number_three.svg +3 -3
- package/dist/static/images/numbers/number_two.svg +4 -4
- package/dist/static/images/numbers/number_zero.svg +3 -3
- package/dist/static/images/plus-icon.svg +4 -4
- package/dist/static/images/search-icon.svg +3 -3
- package/dist/static/images/transfer-icon.svg +10 -10
- package/dist/static/images/warning-filled.svg +3 -3
- package/dist/utils/app-urls-analytics-backoffice.js +30 -0
- package/dist/utils/app-urls.js +28 -0
- package/dist/utils/checklistGenerator.js +6 -5
- package/dist/utils/customHooks.js +1 -1
- package/dist/utils/formatCurrencyValue.js +2 -1
- package/dist/utils/get-cookie-domain.js +4 -1
- package/dist/utils/set-redirect-cookie.js +4 -1
- package/dist/utils/withRouter.js +5 -3
- package/package.json +1 -1
- package/dist/api/auth.js +0 -15
package/README.md
CHANGED
|
@@ -1,261 +1,467 @@
|
|
|
1
|
-
# @stokr/components-library
|
|
2
|
-
|
|
3
|
-
React component library for STOKR applications. Includes modals, forms, buttons, tables, and shared styles.
|
|
4
|
-
|
|
5
|
-
## Table of contents
|
|
6
|
-
|
|
7
|
-
- [Installation](#installation)
|
|
8
|
-
- [How to start](#how-to-start)
|
|
9
|
-
- [Configuration](#configuration)
|
|
10
|
-
- [Runtime config (npm consumers)](#runtime-config)
|
|
11
|
-
- [
|
|
12
|
-
- [
|
|
13
|
-
- [
|
|
14
|
-
- [
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
- **
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
import
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
```
|
|
145
|
-
import {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
1
|
+
# @stokr/components-library
|
|
2
|
+
|
|
3
|
+
React component library for STOKR applications. Includes modals, forms, buttons, tables, and shared styles.
|
|
4
|
+
|
|
5
|
+
## Table of contents
|
|
6
|
+
|
|
7
|
+
- [Installation](#installation)
|
|
8
|
+
- [How to start](#how-to-start)
|
|
9
|
+
- [Configuration](#configuration)
|
|
10
|
+
- [Runtime config (npm consumers)](#runtime-config)
|
|
11
|
+
- [Path-based URLs vs subdomains](#path-based-urls-vs-subdomains)
|
|
12
|
+
- [Reading config with `getConfig()`](#reading-config-with-getconfig)
|
|
13
|
+
- [Ionicons](#ionicons)
|
|
14
|
+
- [React Router](#react-router)
|
|
15
|
+
- [Troubleshooting](#troubleshooting)
|
|
16
|
+
- [Development & publishing](#development--publishing)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install @stokr/components-library
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Peer dependencies** (install in your app if not already present):
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install react react-dom styled-components react-router-dom
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- **React** 18 or 19
|
|
33
|
+
- **styled-components** 6.x
|
|
34
|
+
- **react-router-dom** 6.x (required if you use routing-dependent components)
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Implementing in your app
|
|
39
|
+
|
|
40
|
+
Minimal path to use the library in a **Vite + React** consumer:
|
|
41
|
+
|
|
42
|
+
1. **Install** the package and [peer dependencies](#installation) (`react`, `react-dom`, `styled-components`, and `react-router-dom` if you use routing-heavy components).
|
|
43
|
+
2. **Router** — Wrap the tree with `BrowserRouter` (or another React Router v6 router) if you use `HeaderHo`, `MainMenu`, `LearnMore`, etc. If the host app may already provide a router (e.g. micro-frontend), use **`RouterWrapper`** from the package once at your root so you do not nest two `BrowserRouter` instances (see [step 2](#2-wrap-your-app-with-a-router-if-you-use-routing)).
|
|
44
|
+
3. **Runtime config** — Wrap your authenticated area with `<AuthProvider config={…}>` and pass **your** `import.meta.env.VITE_*` values (see [Runtime config](#runtime-config)). This is required for correct API URLs, Firebase, cookies, and domain-based links in pre-built npm installs.
|
|
45
|
+
4. **Optional** — `configure()` before `AuthProvider` if something (e.g. analytics) must read config earlier; `IoniconsStyles` or `styles.css` if you use icons or shared fonts (see below).
|
|
46
|
+
|
|
47
|
+
Then import components from `@stokr/components-library` as in [step 4 under How to start](#4-import-and-use-components).
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## How to start
|
|
52
|
+
|
|
53
|
+
### 1. Install the package and peers
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm install @stokr/components-library react react-dom styled-components react-router-dom
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 2. Wrap your app with a Router (if you use routing)
|
|
60
|
+
|
|
61
|
+
Components that use navigation (e.g. `MainMenu`, `LearnMore`, `HeaderHo`) must live inside a React Router.
|
|
62
|
+
|
|
63
|
+
**Simple app** — wrap with `BrowserRouter`:
|
|
64
|
+
|
|
65
|
+
```jsx
|
|
66
|
+
// main.jsx or App.jsx
|
|
67
|
+
import { BrowserRouter } from 'react-router-dom'
|
|
68
|
+
import App from './App'
|
|
69
|
+
|
|
70
|
+
root.render(
|
|
71
|
+
<BrowserRouter>
|
|
72
|
+
<App />
|
|
73
|
+
</BrowserRouter>,
|
|
74
|
+
)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Host already has a router** (or you want one `BrowserRouter` only when needed) — wrap the library subtree with **`RouterWrapper`** from `@stokr/components-library`. It renders `BrowserRouter` only when `useInRouterContext()` is false, so you avoid duplicate routers and keep SPA navigation for `withRouter` / `useNavigate`:
|
|
78
|
+
|
|
79
|
+
```jsx
|
|
80
|
+
import { RouterWrapper } from '@stokr/components-library'
|
|
81
|
+
import { BrowserRouter } from 'react-router-dom'
|
|
82
|
+
import App from './App'
|
|
83
|
+
|
|
84
|
+
// Host owns the router:
|
|
85
|
+
root.render(
|
|
86
|
+
<BrowserRouter>
|
|
87
|
+
<RouterWrapper>
|
|
88
|
+
<App />
|
|
89
|
+
</RouterWrapper>
|
|
90
|
+
</BrowserRouter>,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
// Standalone shell (no outer router): RouterWrapper adds BrowserRouter once.
|
|
94
|
+
root.render(
|
|
95
|
+
<RouterWrapper>
|
|
96
|
+
<App />
|
|
97
|
+
</RouterWrapper>,
|
|
98
|
+
)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 3. (Optional) Add Ionicons for icons
|
|
102
|
+
|
|
103
|
+
If you use **Modal**, **ConfirmModal**, **BackButton**, **Select**, **InfoIcon**, etc., add the icon styles once at the root:
|
|
104
|
+
|
|
105
|
+
```jsx
|
|
106
|
+
import { IoniconsStyles } from '@stokr/components-library'
|
|
107
|
+
|
|
108
|
+
function App() {
|
|
109
|
+
return (
|
|
110
|
+
<>
|
|
111
|
+
<IoniconsStyles />
|
|
112
|
+
{/* your app */}
|
|
113
|
+
</>
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
You can skip this; the library will inject icon styles when you first use a component that needs them.
|
|
119
|
+
|
|
120
|
+
### 4. Import and use components
|
|
121
|
+
|
|
122
|
+
```jsx
|
|
123
|
+
import { ConfirmModal, Button } from '@stokr/components-library'
|
|
124
|
+
|
|
125
|
+
function MyPage() {
|
|
126
|
+
const [open, setOpen] = useState(false)
|
|
127
|
+
return (
|
|
128
|
+
<>
|
|
129
|
+
<Button onClick={() => setOpen(true)}>Open</Button>
|
|
130
|
+
<ConfirmModal isOpen={open} onClose={() => setOpen(false)} onConfirm={() => {}} title="Confirm?" />
|
|
131
|
+
</>
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Configuration
|
|
139
|
+
|
|
140
|
+
### Runtime config (required when consuming as npm package) {#runtime-config}
|
|
141
|
+
|
|
142
|
+
Since v3.0.16, the library uses a **runtime config** system. When this package is consumed by an external Vite app, `import.meta.env` values are baked at **library build time** and do not reflect the consuming app's `.env` file. Pass a `config` prop to `<AuthProvider>` so API URLs, Firebase credentials, and cookie domain are resolved from **your** environment:
|
|
143
|
+
|
|
144
|
+
```jsx
|
|
145
|
+
import { AuthProvider } from '@stokr/components-library'
|
|
146
|
+
|
|
147
|
+
function App() {
|
|
148
|
+
return (
|
|
149
|
+
<AuthProvider
|
|
150
|
+
config={{
|
|
151
|
+
apiUrl: import.meta.env.VITE_API_URL,
|
|
152
|
+
baseUrlPublic: import.meta.env.VITE_BASE_URL_PUBLIC,
|
|
153
|
+
cookieDomain: import.meta.env.VITE_COOKIE_DOMAIN,
|
|
154
|
+
websiteDomain: import.meta.env.VITE_WEBSITE_DOMAIN,
|
|
155
|
+
photoApiUrl: import.meta.env.VITE_PHOTO_API_URL,
|
|
156
|
+
firebase: {
|
|
157
|
+
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
|
|
158
|
+
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
|
|
159
|
+
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
|
|
160
|
+
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
|
|
161
|
+
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
|
|
162
|
+
appId: import.meta.env.VITE_FIREBASE_APP_ID,
|
|
163
|
+
measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID,
|
|
164
|
+
},
|
|
165
|
+
}}>
|
|
166
|
+
{/* your app */}
|
|
167
|
+
</AuthProvider>
|
|
168
|
+
)
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
| Prop key | Env variable it replaces | Purpose |
|
|
173
|
+
| -------------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
174
|
+
| `apiUrl` | `VITE_API_URL` | Backend API base URL |
|
|
175
|
+
| `baseUrlPublic` | `VITE_BASE_URL_PUBLIC` | Public (no-auth) API base URL |
|
|
176
|
+
| `cookieDomain` | `VITE_COOKIE_DOMAIN` | Domain attribute for auth cookies |
|
|
177
|
+
| `websiteDomain` | `VITE_WEBSITE_DOMAIN` | Platform domain (redirects, links) |
|
|
178
|
+
| `photoApiUrl` | `VITE_PHOTO_API_URL` | Photo upload / avatar API URL |
|
|
179
|
+
| `firebase` | `VITE_FIREBASE_*` | Full Firebase config object |
|
|
180
|
+
| `routingMode` | `VITE_ROUTING_MODE` | Set to `path` for single-origin app URLs (see below). |
|
|
181
|
+
| `appUrlPaths` | — | Optional object overriding first path segments in path mode (e.g. `{ onboarding: '/signup', dashboard: '/app' }`). |
|
|
182
|
+
| `surfaceRoutingMode` | — | Optional per-surface `'path'` / `'subdomain'` overrides for incremental URL migration (see [below](#incremental-url-migration-surfaceRoutingMode)). |
|
|
183
|
+
|
|
184
|
+
> **Why is this needed?** With the old CRA / `react-scripts` build, Webpack re-processed library code through the consuming app's build pipeline, so the app's `.env` values were injected automatically. Vite treats npm packages as pre-built — `import.meta.env` values in the compiled library are frozen at library build time. The `config` prop passes them at runtime instead.
|
|
185
|
+
|
|
186
|
+
If you also need config values **before** `<AuthProvider>` mounts (e.g. for analytics init), you can call `configure()` directly:
|
|
187
|
+
|
|
188
|
+
```js
|
|
189
|
+
import { configure } from '@stokr/components-library'
|
|
190
|
+
|
|
191
|
+
configure({
|
|
192
|
+
apiUrl: import.meta.env.VITE_API_URL,
|
|
193
|
+
cookieDomain: import.meta.env.VITE_COOKIE_DOMAIN,
|
|
194
|
+
// ...
|
|
195
|
+
})
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
After `configure()` / `<AuthProvider config>`, the library may log a **one-time `console.warn`** listing any **`VITE_*`** variables that are still missing (no override and no env fallback). Fix your `.env` or extend the `config` object until the list is empty.
|
|
199
|
+
|
|
200
|
+
### Path-based URLs vs subdomains {#path-based-urls-vs-subdomains}
|
|
201
|
+
|
|
202
|
+
By default the library builds **subdomain** links (`https://dashboard.{websiteDomain}`, `https://signup.{websiteDomain}/welcome`, `https://admin.{websiteDomain}`, etc.), matching historical STOKR hosting.
|
|
203
|
+
|
|
204
|
+
To switch to **one origin + path prefixes** (for example `https://example.com/dashboard`, `https://example.com/signin/welcome`, `https://example.com/admin`), pass **`routingMode: 'path'`** (or `VITE_ROUTING_MODE=path`) and optionally **`appUrlPaths`** overrides. The public origin for path mode is always **`https://{websiteDomain}`** (same as **`getPlatformURL()`**).
|
|
205
|
+
|
|
206
|
+
```jsx
|
|
207
|
+
<AuthProvider
|
|
208
|
+
config={{
|
|
209
|
+
apiUrl: import.meta.env.VITE_API_URL,
|
|
210
|
+
websiteDomain: import.meta.env.VITE_WEBSITE_DOMAIN,
|
|
211
|
+
routingMode: 'path',
|
|
212
|
+
appUrlPaths: {
|
|
213
|
+
onboarding: '/signin', // flows that used https://signup.{domain}
|
|
214
|
+
registerEntry: '/signup', // CTA from login; default in code is /signup
|
|
215
|
+
dashboard: '/dashboard',
|
|
216
|
+
admin: '/admin',
|
|
217
|
+
},
|
|
218
|
+
firebase: { /* … */ },
|
|
219
|
+
/* …other keys */
|
|
220
|
+
}}>
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**Analytics and backoffice** always use legacy subdomains **`https://analytics.{websiteDomain}`** and **`https://backoffice.{websiteDomain}`**, even in path mode. They are implemented in **`src/utils/app-urls-analytics-backoffice.js`** and re-exported from **`app-urls.js`** (`getAnalyticsIngestUrl`, `getBackofficeAppUrl`); they are not driven by **`appUrlPaths`**.
|
|
224
|
+
|
|
225
|
+
#### Incremental URL migration (`surfaceRoutingMode`) {#incremental-url-migration-surfaceRoutingMode}
|
|
226
|
+
|
|
227
|
+
You do not have to flip every surface at once.
|
|
228
|
+
|
|
229
|
+
- **Global default:** `routingMode: 'path'` means “use path URLs for every surface that supports it”, unless overridden. Leaving `routingMode` unset (or not `'path'`) keeps **subdomain** URLs by default.
|
|
230
|
+
- **Per-surface override:** pass **`surfaceRoutingMode`** on `configure()` / `<AuthProvider config>`. Each key is one of **`onboarding`**, **`dashboard`**, **`admin`**, **`registerEntry`**, **`investorRoot`** (see **`SURFACE_ROUTING_PATH_KEYS`** on the package entry). Each value is **`'path'`** or **`'subdomain'`**. Any surface **omitted** from the object follows the global **`routingMode`**.
|
|
231
|
+
|
|
232
|
+
Examples:
|
|
233
|
+
|
|
234
|
+
1. **Path everywhere except admin** (admin still `https://admin.{domain}` until infra is ready):
|
|
235
|
+
|
|
236
|
+
```js
|
|
237
|
+
configure({
|
|
238
|
+
websiteDomain: 'example.com',
|
|
239
|
+
routingMode: 'path',
|
|
240
|
+
appUrlPaths: { dashboard: '/dashboard', onboarding: '/signin', registerEntry: '/signup', admin: '/admin' },
|
|
241
|
+
surfaceRoutingMode: { admin: 'subdomain' },
|
|
242
|
+
})
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
2. **Subdomains by default, dashboard and admin on path** (e.g. first rollout):
|
|
246
|
+
|
|
247
|
+
```js
|
|
248
|
+
configure({
|
|
249
|
+
websiteDomain: 'example.com',
|
|
250
|
+
appUrlPaths: { dashboard: '/dashboard', admin: '/admin' },
|
|
251
|
+
surfaceRoutingMode: { dashboard: 'path', admin: 'path' },
|
|
252
|
+
})
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
In host UI or guards, use **`isPathForSurface('dashboard')`** / **`isPathForSurface('admin')`** (exported from **`@stokr/components-library`**) so behaviour matches **`resolveAppHref`**.
|
|
256
|
+
|
|
257
|
+
##### Worked example (no script)
|
|
258
|
+
|
|
259
|
+
Assume **`websiteDomain: 'acme.com'`** and default **`appUrlPaths`** (among others: **`dashboard`** → **`/dashboard`**, **`admin`** → **`/admin`**).
|
|
260
|
+
|
|
261
|
+
**A — Full path mode** (every surface that supports paths uses **`https://acme.com`** + prefix):
|
|
262
|
+
|
|
263
|
+
```js
|
|
264
|
+
import { configure, resolveAppHref, isPathForSurface, AppSurface } from '@stokr/components-library'
|
|
265
|
+
|
|
266
|
+
configure({ websiteDomain: 'acme.com', routingMode: 'path' })
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
| Call | Result |
|
|
270
|
+
| ---------------------------------------------------- | -------------------------------------- |
|
|
271
|
+
| `resolveAppHref(AppSurface.DASHBOARD, '')` | `https://acme.com/dashboard` |
|
|
272
|
+
| `resolveAppHref(AppSurface.DASHBOARD, '/checklist')` | `https://acme.com/dashboard/checklist` |
|
|
273
|
+
| `resolveAppHref(AppSurface.ADMIN, '')` | `https://acme.com/admin` |
|
|
274
|
+
| `isPathForSurface('dashboard')` | `true` |
|
|
275
|
+
| `isPathForSurface('admin')` | `true` |
|
|
276
|
+
|
|
277
|
+
**B — Path mode, but admin stays on subdomain** until infra is ready:
|
|
278
|
+
|
|
279
|
+
```js
|
|
280
|
+
configure({
|
|
281
|
+
websiteDomain: 'acme.com',
|
|
282
|
+
routingMode: 'path',
|
|
283
|
+
surfaceRoutingMode: { admin: 'subdomain' },
|
|
284
|
+
})
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
| Call | Result |
|
|
288
|
+
| ---------------------------------------------------- | -------------------------------------------------- |
|
|
289
|
+
| `resolveAppHref(AppSurface.DASHBOARD, '/checklist')` | `https://acme.com/dashboard/checklist` (unchanged) |
|
|
290
|
+
| `resolveAppHref(AppSurface.ADMIN, '')` | `https://admin.acme.com` |
|
|
291
|
+
| `isPathForSurface('admin')` | `false` |
|
|
292
|
+
|
|
293
|
+
**C — Global default is still subdomain; dashboard and admin use path** (incremental first step):
|
|
294
|
+
|
|
295
|
+
```js
|
|
296
|
+
configure({
|
|
297
|
+
websiteDomain: 'acme.com',
|
|
298
|
+
surfaceRoutingMode: { dashboard: 'path', admin: 'path' },
|
|
299
|
+
})
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
(`routingMode` is not **`'path'`**, so any surface **not** listed in **`surfaceRoutingMode`** keeps subdomain URLs.)
|
|
303
|
+
|
|
304
|
+
| Call | Result |
|
|
305
|
+
| ------------------------------------------ | ---------------------------- |
|
|
306
|
+
| `resolveAppHref(AppSurface.DASHBOARD, '')` | `https://acme.com/dashboard` |
|
|
307
|
+
| `resolveAppHref(AppSurface.ADMIN, '')` | `https://acme.com/admin` |
|
|
308
|
+
| `isPathForSurface('dashboard')` | `true` |
|
|
309
|
+
| `isPathForSurface('admin')` | `true` |
|
|
310
|
+
|
|
311
|
+
**Rule of thumb:** for each routable surface, the code checks **`surfaceRoutingMode[surfaceKey]`** first (`'path'` or `'subdomain'`). If that key is **omitted**, it falls back to the global flag **`routingMode === 'path'`**. **`resolveAppHref`** and **`isPathForSurface`** use the same logic.
|
|
312
|
+
|
|
313
|
+
Readable routing API (recommended):
|
|
314
|
+
|
|
315
|
+
- **`AppSurface`** / **`AppRoute`** — named surfaces and path suffixes (`src/routing/app-routes.js`).
|
|
316
|
+
- **`resolveAppHref(surface, path)`** — one function that returns the absolute URL for any surface + suffix.
|
|
317
|
+
- **`isPathForSurface(key)`** / **`SURFACE_ROUTING_PATH_KEYS`** — align host code with per-surface path vs subdomain resolution when using **`surfaceRoutingMode`**.
|
|
318
|
+
- **`navigateApp(navigate, surface, path)`** / **`navigateToHref(navigate, url)`** — use the `navigate` function from `react-router-dom` when the target is **same-origin** (SPA transition); otherwise they fall back to `location.assign` (e.g. `admin.` / `signup.` subdomains).
|
|
319
|
+
- **`RouterWrapper`** — optional root helper: mounts `BrowserRouter` only when the tree is not already under a Router (same-origin SPA navigation without nesting two browser routers).
|
|
320
|
+
|
|
321
|
+
Legacy helpers (`buildDashboardUrl`, `getAdminAppUrl`, …) remain on **`./utils/app-urls`** for compatibility.
|
|
322
|
+
|
|
323
|
+
**Authentication-only HTTP** — backend routes under `auth/*` (e.g. forgot password) are exposed as **`authenticationApi.post(segment, body)`** from `src/api/authenticationApi.js` (also re-exported from the package entry). The default axios instance is the **general API client** for all authenticated backend calls, not auth-only.
|
|
324
|
+
|
|
325
|
+
### Reading config with `getConfig()` {#reading-config-with-getconfig}
|
|
326
|
+
|
|
327
|
+
In your app (or in code next to the library), read the same resolved values the package uses:
|
|
328
|
+
|
|
329
|
+
```js
|
|
330
|
+
import { getConfig } from '@stokr/components-library'
|
|
331
|
+
|
|
332
|
+
const api = getConfig('apiUrl')
|
|
333
|
+
const domain = getConfig('websiteDomain')
|
|
334
|
+
const firebaseOptions = getConfig('firebase') // override object or env-built fallback
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Supported keys: `apiUrl`, `baseUrlPublic`, `cookieDomain`, `websiteDomain`, `photoApiUrl`, `routingMode`, `appUrlPaths`, `surfaceRoutingMode`, `firebase`. Resolution order is always **explicit `configure()` / `AuthProvider` `config`** first, then **`import.meta.env`** in the consuming Vite app (where a `VITE_*` mapping exists).
|
|
338
|
+
|
|
339
|
+
**Marketing site origin** — the old `platformDomain` / `platformURL` exports were removed. Use **`getPlatformURL()`** for `https://{websiteDomain}`, or **`getConfig('websiteDomain')`** for the bare host (e.g. `"example.com"`). Both read the same runtime config after **`configure()`** / **`AuthProvider`**.
|
|
340
|
+
|
|
341
|
+
```js
|
|
342
|
+
import { getConfig, getPlatformURL } from '@stokr/components-library'
|
|
343
|
+
|
|
344
|
+
const host = getConfig('websiteDomain') // e.g. "example.com"
|
|
345
|
+
const origin = getPlatformURL() // e.g. "https://example.com"
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
**Footer link groups** — if you previously imported the static `footerGroups` from `FooterLayout`, import **`getFooterGroups`** instead (same package entry as other footer exports). It returns fresh URLs using the current `getPlatformURL()`.
|
|
349
|
+
|
|
350
|
+
### Ionicons
|
|
351
|
+
|
|
352
|
+
Components such as **Modal**, **ConfirmModal**, **BackButton**, **InfoIcon**, **Select**, **MainMenu**, and **RegisterLiquidSteps** use [Ionicons](http://ionicons.com/). You can enable them in three ways:
|
|
353
|
+
|
|
354
|
+
| Approach | When to use |
|
|
355
|
+
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
356
|
+
| **Global injection** | Render `<IoniconsStyles />` once at app root. Full icon set, singleton. |
|
|
357
|
+
| **No setup** | Don’t render anything; styles inject on first use of an icon component. |
|
|
358
|
+
| **CSS import** | Prefer loading via CSS: `import '@stokr/components-library/styles.css'` or `import '@stokr/components-library/ionicons.css'`. |
|
|
359
|
+
|
|
360
|
+
**Global injection example:**
|
|
361
|
+
|
|
362
|
+
```jsx
|
|
363
|
+
import { IoniconsStyles } from '@stokr/components-library'
|
|
364
|
+
|
|
365
|
+
function App() {
|
|
366
|
+
return (
|
|
367
|
+
<>
|
|
368
|
+
<IoniconsStyles />
|
|
369
|
+
{/* your routes, layout, etc. */}
|
|
370
|
+
</>
|
|
371
|
+
)
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
If you use **Layout**, **GlobalStyle**, or need **Open Sans**, import the full styles once:
|
|
376
|
+
|
|
377
|
+
```js
|
|
378
|
+
import '@stokr/components-library/styles.css'
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### React Router
|
|
382
|
+
|
|
383
|
+
Any component that uses `useNavigate()` or routing must be rendered inside a `Router` from `react-router-dom` (e.g. `BrowserRouter`), or under **`RouterWrapper`** so a router exists when the host does not provide one. Components wrapped with **`withRouter`** receive `navigate` from `useNavigate()` when inside a Router; outside a Router, `navigate` throws with a message to add `BrowserRouter` or `RouterWrapper`. See [How to start – step 2](#2-wrap-your-app-with-a-router-if-you-use-routing).
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## Troubleshooting
|
|
388
|
+
|
|
389
|
+
### "useNavigate() may be used only in the context of a \<Router\> component"
|
|
390
|
+
|
|
391
|
+
Wrap your app with a Router, or use **`RouterWrapper`** at the root when you are not already inside a host `BrowserRouter`:
|
|
392
|
+
|
|
393
|
+
```jsx
|
|
394
|
+
import { BrowserRouter } from 'react-router-dom'
|
|
395
|
+
|
|
396
|
+
root.render(
|
|
397
|
+
<BrowserRouter>
|
|
398
|
+
<App />
|
|
399
|
+
</BrowserRouter>,
|
|
400
|
+
)
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
```jsx
|
|
404
|
+
import { RouterWrapper } from '@stokr/components-library'
|
|
405
|
+
|
|
406
|
+
root.render(
|
|
407
|
+
<RouterWrapper>
|
|
408
|
+
<App />
|
|
409
|
+
</RouterWrapper>,
|
|
410
|
+
)
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
Install the peer dependency: `npm install react-router-dom`
|
|
414
|
+
|
|
415
|
+
### "Invalid hook call" / "Cannot read properties of null (reading 'use')"
|
|
416
|
+
|
|
417
|
+
Your app and the library must use the **same** React instance.
|
|
418
|
+
|
|
419
|
+
1. Install peer dependencies:
|
|
420
|
+
`npm install react react-dom styled-components`
|
|
421
|
+
|
|
422
|
+
2. **Vite apps** – add dedupe in `vite.config.js` or `vite.config.ts`:
|
|
423
|
+
|
|
424
|
+
```js
|
|
425
|
+
export default defineConfig({
|
|
426
|
+
resolve: {
|
|
427
|
+
dedupe: ['react', 'react-dom', 'styled-components'],
|
|
428
|
+
},
|
|
429
|
+
// ...rest of config
|
|
430
|
+
})
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
3. Reinstall or refresh the library after updating (e.g. `npm install` or clear cache and reinstall).
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
## Development & publishing
|
|
438
|
+
|
|
439
|
+
### Run Storybook
|
|
440
|
+
|
|
441
|
+
```bash
|
|
442
|
+
npm run storybook
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
Use **Story Source** for consumption examples and **Viewport** for different screen sizes.
|
|
446
|
+
|
|
447
|
+
### Build for distribution
|
|
448
|
+
|
|
449
|
+
```bash
|
|
450
|
+
npm run build:dist
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
This runs `vite build` and copies static assets to `dist/`.
|
|
454
|
+
|
|
455
|
+
### Publish a new version
|
|
456
|
+
|
|
457
|
+
1. Commit your changes.
|
|
458
|
+
2. Update [CHANGELOG.md](CHANGELOG.md) – add a new `# vX.Y.Z` section at the top with the list of changes.
|
|
459
|
+
3. Bump the version: `npm version <version>` (e.g. `npm version 3.0.7`).
|
|
460
|
+
4. (ensure you are authenticated) Run `npm login` to log first on NPM package (only needed one time a day)
|
|
461
|
+
5. Run `npm run pub` (will first run `npm run build:dist`).
|
|
462
|
+
|
|
463
|
+
Consumers can see what changed in each release in [CHANGELOG.md](CHANGELOG.md).
|
|
464
|
+
|
|
465
|
+
### Reference
|
|
466
|
+
|
|
467
|
+
- [How to publish a React component library](https://medium.com/better-programming/how-to-publish-a-react-component-library-c89a07566770)
|