npm package: @stokr/components-library
Description: STOKR - Components Library
Author: Bilal Hodzic
Latest version: 3.0.20

# @stokr/components-library

React component library for STOKR applications. Includes modals, forms, buttons, tables, and shared styles.

## Table of contents

- [Installation](#installation)
- [How to start](#how-to-start)
- [Configuration](#configuration)
  - [Runtime config (npm consumers)](#runtime-config)
  - [Ionicons](#ionicons)
  - [React Router](#react-router)
- [Troubleshooting](#troubleshooting)
- [Development & publishing](#development--publishing)

---

## Installation

```bash
npm install @stokr/components-library
```

**Peer dependencies** (install in your app if not already present):

```bash
npm install react react-dom styled-components react-router-dom
```

- **React** 18 or 19
- **styled-components** 6.x
- **react-router-dom** 6.x (required if you use routing-dependent components)

---

## How to start

### 1. Install the package and peers

```bash
npm install @stokr/components-library react react-dom styled-components react-router-dom
```

### 2. Wrap your app with a Router (if you use routing)

Components that use navigation (e.g. `MainMenu`, `LearnMore`, `HeaderHo`) must live inside a React Router:

```jsx
// main.jsx or App.jsx
import { BrowserRouter } from 'react-router-dom'
import App from './App'

root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
)
```

### 3. (Optional) Add Ionicons for icons

If you use **Modal**, **ConfirmModal**, **BackButton**, **Select**, **InfoIcon**, etc., add the icon styles once at the root:

```jsx
import { IoniconsStyles } from '@stokr/components-library'

function App() {
  return (
    <>
      <IoniconsStyles />
      {/* your app */}
    </>
  )
}
```

You can skip this; the library will inject icon styles when you first use a component that needs them.

### 4. Import and use components

```jsx
import { ConfirmModal, Button } from '@stokr/components-library'

function MyPage() {
  const [open, setOpen] = useState(false)
  return (
    <>
      <Button onClick={() => setOpen(true)}>Open</Button>
      <ConfirmModal isOpen={open} onClose={() => setOpen(false)} onConfirm={() => {}} title="Confirm?" />
    </>
  )
}
```

---

## Configuration

### Runtime config (required when consuming as npm package) {#runtime-config}

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:

```jsx
import { AuthProvider } from '@stokr/components-library'

function App() {
  return (
    <AuthProvider
      config={{
        apiUrl: import.meta.env.VITE_API_URL,
        baseUrlPublic: import.meta.env.VITE_BASE_URL_PUBLIC,
        cookieDomain: import.meta.env.VITE_COOKIE_DOMAIN,
        websiteDomain: import.meta.env.VITE_WEBSITE_DOMAIN,
        photoApiUrl: import.meta.env.VITE_PHOTO_API_URL,
        firebase: {
          apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
          authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
          projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
          storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
          messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
          appId: import.meta.env.VITE_FIREBASE_APP_ID,
          measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID,
        },
      }}>
      {/* your app */}
    </AuthProvider>
  )
}
```

| Prop key        | Env variable it replaces | Purpose                            |
| --------------- | ------------------------ | ---------------------------------- |
| `apiUrl`        | `VITE_API_URL`           | Backend API base URL               |
| `baseUrlPublic` | `VITE_BASE_URL_PUBLIC`   | Public (no-auth) API base URL      |
| `cookieDomain`  | `VITE_COOKIE_DOMAIN`     | Domain attribute for auth cookies  |
| `websiteDomain` | `VITE_WEBSITE_DOMAIN`    | Platform domain (redirects, links) |
| `photoApiUrl`   | `VITE_PHOTO_API_URL`     | Photo upload / avatar API URL      |
| `firebase`      | `VITE_FIREBASE_*`        | Full Firebase config object        |

> **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.

If you also need config values **before** `<AuthProvider>` mounts (e.g. for analytics init), you can call `configure()` directly:

```js
import { configure } from '@stokr/components-library'

configure({
  apiUrl: import.meta.env.VITE_API_URL,
  cookieDomain: import.meta.env.VITE_COOKIE_DOMAIN,
  // ...
})
```

### Ionicons

Components such as **Modal**, **ConfirmModal**, **BackButton**, **InfoIcon**, **Select**, **MainMenu**, and **RegisterLiquidSteps** use [Ionicons](http://ionicons.com/). You can enable them in three ways:

| Approach             | When to use                                                                                                                   |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **Global injection** | Render `<IoniconsStyles />` once at app root. Full icon set, singleton.                                                       |
| **No setup**         | Don’t render anything; styles inject on first use of an icon component.                                                       |
| **CSS import**       | Prefer loading via CSS: `import '@stokr/components-library/styles.css'` or `import '@stokr/components-library/ionicons.css'`. |

**Global injection example:**

```jsx
import { IoniconsStyles } from '@stokr/components-library'

function App() {
  return (
    <>
      <IoniconsStyles />
      {/* your routes, layout, etc. */}
    </>
  )
}
```

If you use **Layout**, **GlobalStyle**, or need **Open Sans**, import the full styles once:

```js
import '@stokr/components-library/styles.css'
```

### React Router

Any component that uses `useNavigate()` or routing must be rendered inside a `Router` from `react-router-dom` (e.g. `BrowserRouter`). See [How to start – step 2](#2-wrap-your-app-with-a-router-if-you-use-routing).

---

## Troubleshooting

### "useNavigate() may be used only in the context of a \<Router\> component"

Wrap your app with a Router:

```jsx
import { BrowserRouter } from 'react-router-dom'

root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
)
```

Install the peer dependency: `npm install react-router-dom`

### "Invalid hook call" / "Cannot read properties of null (reading 'use')"

Your app and the library must use the **same** React instance.

1. Install peer dependencies:  
   `npm install react react-dom styled-components`

2. **Vite apps** – add dedupe in `vite.config.js` or `vite.config.ts`:

   ```js
   export default defineConfig({
     resolve: {
       dedupe: ['react', 'react-dom', 'styled-components'],
     },
     // ...rest of config
   })
   ```

3. Reinstall or refresh the library after updating (e.g. `npm install` or clear cache and reinstall).

---

## Development & publishing

### Run Storybook

```bash
npm run storybook
```

Use **Story Source** for consumption examples and **Viewport** for different screen sizes.

### Build for distribution

```bash
npm run build:dist
```

This runs `vite build` and copies static assets to `dist/`.

### Publish a new version

1. Commit your changes.
2. Update [CHANGELOG.md](CHANGELOG.md) – add a new `# vX.Y.Z` section at the top with the list of changes.
3. Bump the version: `npm version <version>` (e.g. `npm version 3.0.7`).
4. (ensure you are authenticated) Run `npm login` to log first on NPM package (only needed one time a day)
5. Run `npm run pub` (will first run `npm run build:dist`).

Consumers can see what changed in each release in [CHANGELOG.md](CHANGELOG.md).

### Reference

- [How to publish a React component library](https://medium.com/better-programming/how-to-publish-a-react-component-library-c89a07566770)