open-index/open-npm huggingface dataset:
npm package: @kaliber/html-to-portable-text
Description: A plugin for converting html to portableText
Latest version: 3.0.2

# Kaliber HTML to portableText plugin
A plugin for converting html to portableText

## Usage
`htmlToPortableText(html, overrides = {})`

```js
const htmlToPortableText = require('@kaliber/html-to-portable-text')

const portableText = processHTML('<p><h1>This</strong><em>is HTML</em></p>')

function processHTML(html) {
  return removeUndefinedValues(htmlToPortableText(html, { h1: 'heading', h2: 'subheading' }))
}

function removeUndefinedValues(o) {
  return JSON.parse(JSON.stringify(o))
}
```

## Development

```
> yarn
> yarn link
> yarn watch
```

```
yarn link @kaliber/html-to-portable-text
```

## Publish

```
yarn publish
git push
git push --tags
```
---
![](https://media.giphy.com/media/C6JQPEUsZUyVq/giphy.gif)

## Disclaimer
This library is intended for internal use, we provide __no__ support, use at your own risk. It does not import React, but expects it to be provided, which [@kaliber/build](https://kaliberjs.github.io/build/) can handle for you.

This library is not transpiled.
npm package: @kaliber/mo-compiler
Description: Compile PO files to MO files.
Latest version: 0.0.2

## Installation

`yarn add @kaliber/mo-compiler`

## How to use

Run the command `compile-po`, followed by the path to the folder containing the .po files. E.g.: `compile-po path/to/translations`.

## Publish

To publish a new version:

```
>> cd library
>> yarn publish
>> git push
>> git push --tags
```
npm package: @kaliber/pack
Latest version: 0.0.2

Opinionated package to compile libraries using Babel.

```
yarn add @kaliber/pack --dev
```

`package.json`
```
  "scripts": {
    "build": "kaliber-pack",
    "watch": "kaliber-pack --watch",
    "prepublishOnly": "kaliber-pack"
  },
```
npm package: @kaliber/pagination
Description: Generate an array with page numbers, with null values to indicate gaps
Latest version: 1.0.1

# Pagination
Generate an array with page numbers, with null values to indicate gaps.

## Motivation
Whenever you need this, there's probably a deeper issue with the design you're implementing. Nevertheless: when you must add pagination to your application, it's nice to have something ready on the shelf. 

## Installation

```
yarn add @kaliber/pagination
```

## Usage
Be sure to checkout the /example folder, it has an accessible example. `getPagination` only provides the bare bones data needed to render a pagination. It's up to you to make sure it's accessible. If you're not sure how, check out the example folder for an implementation based on this article: [Accessible Pagination
](https://www.a11ymatters.com/pattern/pagination/).

```jsx
import { getPagination } from '@kaliber/pagination'

function Component({ currentPage, maxPages }) {
  const pagination = getPagination({ 
    current: currentPage, 
    max: maxPages, 
    padding: 2 
  })
  
  return (
    <nav>
      {pagination.map(x => x
        ? <a href={`?page=${x}`}>{x}</a>
        : <span>…</span>
      )}
    </nav>
  )
}
```

**🚨 Gotcha**: This library is designed to output a static number of pagination items. You should keep that in mind when displaying arrows alongside the pagination: don't hide them, but disable them instead.

# Reference
`getPagination` accepts 1 option object as argument, with 3 required properties:

| Argument   | Type | Description |
|---|---|---|
| `current` | `number` | The current page |
| `max` | `number` | The maximum number of pages |
| `padding` | `number` | A positive integer, which states at least how many numbers there  should be next to the current number. There could be shown more numbers, if any gaps can be swapped with numbers to continue the number sequence |

_Example: a padding of 1_
```
1 ... 4 5 6 ... 12
^     ^   ^     ^
|     |   |     |
|     |   |     Always shown
|     Padding of 1
Always shown
```

The function returns an array with gaps denoted by a `null` value:

```js
console.log(getPagination({ current: 5, max: 11, padding: 2 })) 
// => [1, null, 3, 4, 5, 6, 7, null, 11]
```

```js
console.log(getPagination({ current: 2, max: 11, padding: 2 })) 
// => [1, 2, 3, 4, 5, 6, 7, null, 11]
```

```js
console.log(getPagination({ current: 2, max: 5, padding: 1 })) 
// => [1, 2, 3, 4, 5]
```

---

![](https://media.giphy.com/media/3o6MbdZPdSUE0FE4zC/giphy.gif)

## Disclaimer
This library is intended for internal use, we provide __no__ support, use at your own risk. It does not import React, but expects it to be provided, which [@kaliber/build](https://kaliberjs.github.io/build/) can handle for you.

This library is not transpiled.
npm package: @kaliber/safe-json-stringify
Description: Returns a safe stringified version of a given string
Latest version: 2.0.1

# Safe JSON stringify
Returns a safe stringified version of a given string

## Motivation
Solves potential XSS vulnerabilities when using JSON.stringify() inside dangerouslySetInnerHtml={}

## Installation

```
yarn add @kaliber/safe-json-stringify
```

## Usage
```jsx
import { safeJsonStringify }  from '@kaliber/safe-json-stringify'

const content =  {"title":"Woooppppss","content":"</script><script>alert('gotcha!')</script>"}

export default function Component() {
  return <div dangerouslySetInnerHTML={{__html: safeJsonStringify(content)}}/>
}

```

## Releasing a new version
Because this library is used in both the node runtime and webpack environment, the library is precompiled using [kaliberjs/pack](https://github.com/kaliberjs/pack). When releasing a new version, do not forget to execute `yarn build` before running `yarn publish`. This should be done because the yarn publish command uses your local files to upload to the npm registry.

## Disclaimer
This library is intended for internal use, we provide __no__ support, use at your own risk. It does not import React, but expects it to be provided, which [@kaliber/build](https://kaliberjs.github.io/build/) can handle for you.

This library is not transpiled.
npm package: @kaliber/safe-url
Description: Returns a safe url of the given string
Latest version: 1.0.0

# Safe-url
Returns a safe url of the given string

## Motivation
Solves potential XSS vulnerabilities when `javascript:` is used as a protocol.

## Installation

```
yarn add @kaliber/safe-url
```

## Usage
This function should be used when you want to navigate a user to a other url especially when you take the value form the url. A use case would be to check a returnUrl.

### Basic usage
```js
import { safeUrl } from '@kaliber/safe-url'

const { returnUrl } = req.query // useQueryString()

// Allowed protocols
window.location.href = safeUrl(returnUrl) // returnUrl = 'https://kaliber.net'

// This throws a error
window.location.href = safeUrl(returnUrl) // returnUrl =  'javascript:confirm(document.domain)'
```

### allowedHostsList
```js
import { safeUrl } from '@kaliber/safe-url'

safeUrl('https://npm.com/', { allowedHostsList: ['kaliber.net'] }) // throws a error
safeUrl('https://kaliber.net/', { allowedHostsList: ['kaliber.net'] }) // returns the given url.
```

## Disclaimer
This library is intended for internal use, we provide __no__ support, use at your own risk. It does not import React, but expects it to be provided, which [@kaliber/build](https://kaliberjs.github.io/build/) can handle for you.

This library is not transpiled.
npm package: @kaliber/sanity-plugin-duplicate
Description: Adds a (usable) duplicate to sanity
Author: Kaliber Machinery
Latest version: 2.0.4

# Sanity plugin duplicate
Replaces the default duplicate function of Sanity and allows for the schema to determine how
to handle duplication of specific fields.

## Installation

```
> yarn add @kaliber/sanity-plugin-duplicate
```

_`config/default.js`_

```js
{
  kaliber: [
    compileWithBabel: [
      /@kaliber\/sanity-plugin-duplicate/,
      ...
    ],
    ...
  ],
  ...
}
```

_`admin/sanity.config.js`_

```js
defineConfig({
    ...

    plugins: [
      preview({ reportError }),
      ...
    ],
})
```

Signatures of `reportError`:

```ts
(e: Error) => void
```

## Additional setup

Customize duplication can be done by setting the Kaliber `duplicate` option.

```js
import { clear } from '@kaliber/sanity-plugin-duplicate'

export const page = {
  type: 'document',
  name: 'page',
  title: 'Page',
  ...
  fields: [
    {
      title: 'My Field',
      name: 'myField',
      type: 'string',
      ...
      options: {
        kaliber: {
          duplicate: clear,
          ...
        },
        ...
      }
    }
  ]
```

The `duplicate` option allows for the following values:

* A regular value, this value is used in the duplication
* The `clear` symbol, the field is cleared (removed) during duplication
* A function, the function is called with the current value to generate a new value

Common example for things like titles:

```
  options: {
    kaliber: {
      duplicate(previousValue) {
        return `${previousValue} (copy)`
      }
    }
  }
```

---

## Development

```
> yarn
> yarn link
```

```
project/> yarn link @kaliber/sanity-plugin-duplicate
project/> yarn add @kaliber/sanity-plugin-duplicate@link:./node_modules/@kaliber/sanity-plugin-duplicate
```

## Publish

```
yarn publish
git push
git push --tags
```

---

![](https://media.giphy.com/media/3oriOfWPE8r5YeK3lK/giphy.gif)

## Disclaimer
This library is intended for internal use, we provide __no__ support, use at your own risk.
npm package: @kaliber/sanity-plugin-multi-language
Description: Document level translations.
Latest version: 4.4.0

# Kaliber Sanity Multi Language Plugin

Document level translations.

## Installation

```
> yarn add @kaliber/sanity-plugin-multi-language
```

## Usage

`sanity.config.js`

```js
import { addFields as addMultiLanguageFields } from '@kaliber/sanity-plugin-multi-language'

defineConfig({
  plugins: [
    deskTool({
      defaultDocumentNode: (S, context) => {
        const getClient = context.getClient.bind(context)

        const views = [
          S.view.form(),
          typeHasLanguage(context) && S.view
            .component(Translations)
            .options({ multiLanguage, reportError })
            .title('Translations'),

        ].filter(Boolean)

        return S.document().views(views)
      }
    }),
  ],
  schema: {
      types: (prev, context) => prev
        .concat(schemaTypes)
        .map(addMultiLanguageFields({ multiLanguage: clientConfig.multiLanguage, reportError })),
    },
})
```


`schema/documents/page.js`

```js
export const page = {
  type: 'document',
  name: 'page',
  title: 'Page',
  options: {
    kaliber: {
      multiLanguage: true,
      ...
    },
    ...
  },
  ...
}
```

### Custom Document ID Generator

By default, new translations are created with a random UUID (`drafts.{uuid}`). You can customize this behavior by providing a `multiLanguageNewDocumentId` function in your schema options:
```js
export const page = {
  type: 'document',
  name: 'page',
  title: 'Page',
  options: {
    kaliber: {
      multiLanguage: true,
      multiLanguageNewDocumentId: ({ currentId, currentLanguage, newLanguage }) => {
        // Example: Replace language code in the document ID
        return currentId.replace(new RegExp(`_${currentLanguage}$`), `_${newLanguage}`)
      }
    }
  },
  ...
}
```

**Parameters:**
- `currentId` - The ID of the source document
- `currentLanguage` - The language code of the source document
- `newLanguage` - The language code for the new translation

**Returns:** A string to be used as the new document ID

This is useful when you want predictable IDs based on language codes, making it easier to find related translations programmatically.

### Config
_config.multiLanguage_
```js
{
  defaultLanguage: 'nl',
  languages: {
    nl: {
      title: 'Dutch',
      adjective: 'dutch',
      language: 'nl',
      icu: 'nl_NL'
    },
    en: {
      title: 'English',
      adjective: 'english',
      language: 'en',
      icu: 'en_US'
    }
  },
}
```

## Development

In this plugin:
```
> yarn
> yarn link
```

In your project:
```
> yarn link @kaliber/sanity-plugin-multi-language
```

## Publish

```
yarn publish
git push
git push --tags
```
---
![](https://media.giphy.com/media/3orif0Pxk3I4WQj46k/giphy.gif)
npm package: @kaliber/sanity-plugin-nav-extend
Description: Extends the nav bar of Sanity Studio
Author: Kaliber Machinery
Latest version: 1.1.0

# Sanity plugin nav extend
Extends the nav bar of Sanity Studio

## Installation

```
> yarn add @kaliber/sanity-plugin-nav-extend
```

_`config/default.js`_

```js
{
  kaliber: [
    compileWithBabel: [
      /@kaliber\/sanity-plugin-nav-extend/,
      ...
    ],
    ...
  ],
  ...
}
```

_`admin/sanity.config.js`_

Minimal version

```js
defineConfig({
    ...

    plugins: [
      sanityPluginNavExtend({ clientConfig, reportError }),
      ...
    ],
})
```

Showing a context switch (e.g. language switch)

```js
defineConfig({
    ...

    plugins: [
      sanityPluginNavExtend({
        contextSwitch: {
          profileKey: 'language',
          schemaType: '', // optionally overwrite schema type, default 'profile'
          options: Object.values(clientConfig.multiLanguage.languages).map(
            ({ flagIcon, title, language }) => ({
              id: language,
              label: title,
              icon: <Flag country={flagIcon} />,
            })
          ),
          defaultValue: clientConfig.multiLanguage.defaultLanguage,
        },
        clientConfig,
        reportError
      }),
      ...
    ],
})
```

---

## Development

```
> yarn
> yarn link
```

```
project/> yarn link @kaliber/sanity-plugin-nav-extend
project/> yarn add @kaliber/sanity-plugin-nav-extend@link:./node_modules/@kaliber/sanity-plugin-nav-extend
```

## Publish

```
yarn publish
git push
git push --tags
```

---

## Disclaimer
This library is intended for internal use, we provide __no__ support, use at your own risk.
npm package: @kaliber/sanity-plugin-preview
Description: Adds a (p)review document action to Sanity
Author: Kaliber Machinery
Latest version: 2.0.2

# Sanity plugin preview
Adds (p)review document actions to Sanity.

## Installation

```
> cd admin
> yarn add @kaliber/sanity-plugin-preview
```

_`admin/sanity.json`_

```json
{
  "plugins": [
    "@kaliber/sanity-plugin-preview",
    ...
  ],
  ...
}
```

## Prerequisites
This plugin expects your project to:

- Handle the `/${documentPath}?preview=${previewSecret}` route at the front office using `@kaliber/sanity-preview`.
- Implement the `part:@kaliber/resolve-production-url` part at the back office.
- Add the document actions to the default document actions, by implementing the `part:@sanity/base/document-actions/resolver` part.

Check `kaliber-sanity-template` for a concrete example.

### Implementing the `part:@kaliber/resolve-production-url` part

Create a file called `resolveProductionUrl.js` in your sanity folder. It should export an async function `resolveProductionUrl`, that returns the url to the given document tacking on the `queryString` given:

```js
import qs from 'query-string' 

export async function resolveProductionUrl(document, { queryString = undefined } = {}) {
  // ... fetch path based on document

  return [
    path,
    queryString && qs.stringify(queryString)
  ].filter(Boolean).join('?')
}
```

Next, add it to the parts array in your `sanity.json` file: 

```json
{
  "implements": "part:@kaliber/resolve-production-url",
  "path": "./resolveProductionUrl.js"
}
```

### Adding the custom document actions

To add the actual document actions, you have to add them to the default document actions. To do this, in your sanity folder create a file called `resolveDocumentActions.js` and add the following:

```js
import defaultResolve from 'part:@sanity/base/document-actions'
import { DocumentActionProductionPreview, DocumentActionProductionReview } from '@kaliber/sanity-plugin-preview'

export default function resolveDocumentActions(props) {
  return [...defaultResolve(props), DocumentActionProductionPreview, DocumentActionProductionReview]
}
```

Then add the `part:@sanity/base/document-actions/resolver` part to the parts array in `sanity.json`:

```json
{
  "implements": "part:@sanity/base/document-actions/resolver",
  "path": "./resolveDocumentActions.js"
}
```

---

## Development

```
> yarn
> yarn link
> yarn watch
```

```
project/admin/> yarn link @kaliber/sanity-plugin-preview
```

## Publish

```
yarn publish
git push
git push --tags
```

---

![](https://media.giphy.com/media/3oriOfWPE8r5YeK3lK/giphy.gif)

## Disclaimer
This library is intended for internal use, we provide __no__ support, use at your own risk.
npm package: @kaliber/sanity-plugin-seo
Description: Yoast SEO Analysis.
Latest version: 3.0.0

# Kaliber Sanity SEO Plugin

Yoast SEO Analysis.

## Installation

```
> yarn add @kaliber/sanity-plugin-seo
```

`sanity.config.js`

```js
import { sanityPluginSeo, SeoAnalysis, typeHasSeo } from '@kaliber/sanity-plugin-seo'

defineConfig({
  ...

  plugins: [
    deskTool({
      defaultDocumentNode: (S, context) => {
        const getClient = context.getClient.bind(context)

        const views = [
          S.view.form(),
          typeHasSeo(context) && S.view
            .component(SeoAnalysis)
            .options({ multiLanguage, resolvePublishedUrl, resolvePreviewUrl, getClient, reportError })
            .title('SEO'),
        ].filter(Boolean)

        return S.document().views(views)
      },
      ...
    }),
    sanityPluginSeo(),
    ...
  ]
})
```

## Configuration

### Custom Share Image Field

By default, the plugin uses the standard Sanity `image` type with an alt text field for the share image. You can customize this to use a custom image type (e.g., `klbrImage`) or modify the field schema:

```js
sanityPluginSeo({
  shareImageField: {
    title: 'Share image',
    name: 'shareImage',
    type: 'klbrImage', // Use your custom image type
    // No alt field needed for klbrImage
  }
})
```

You can also extend the default field definition to customize specific properties:

```js
import { sanityPluginSeo, defaultShareImageField } from '@kaliber/sanity-plugin-seo'

sanityPluginSeo({
  shareImageField: {
    ...defaultShareImageField,
    fields: [] // Remove the alt text field while keeping other defaults
  }
})
```

## Usage

`schema/documents/pagina.js`

```js
export const pagina = {
  type: 'document',
  name: 'pagina',
  title: 'Pagina',
  fields: [
    {
      title: 'SEO',
      name: 'seo',
      type: 'seo'
    },
    ...
  ],
}
```

## Development

```
> yarn
> yarn link
```

```
project/> yarn link @kaliber/sanity-plugin-seo
```

## Publish

```
yarn publish
git push
git push --tags
```
npm package: @kaliber/stylelint-plugin
Description: This Stylelint plugin enforces Kaliber's code conventions, helping maintain consistency across projects.
Latest version: 1.0.3

# @kaliber/stylelint-plugin

This Stylelint plugin enforces Kaliber's code conventions, helping maintain consistency across projects.

## Usage

To use this plugin in your project, create an `.stylelintrc` file with the following content:

```json
{
  "ignoreFiles": ["node_modules/**/*", "**/*.js", "**/*.svg", "**/*.md"],
  "extends": "./node_modules/@kaliber/stylelint-plugin/.stylelintrc"
}
```

## Publishing a new version

To publish a new version, run the following commands:

```sh
>> yarn publish
>> git push
>> git push --tags
```
npm package: @kaliber/typekit-loader
Description: A short description
Author: Kaliber Machinery
Latest version: 1.0.3

<!-- # BEFORE YOU PUBLISH
- Read [Libraries van Kaliber](https://docs.google.com/document/d/1FrJi-xWtKkbocyMVK5A5_hupjl5E4gD4rDvATDlxWyc/edit#heading=h.bb3md3gyf493).
- Make sure your example works.
- Make sure your package.json is correct. Have you change the library title?
- Update the bin/postInstall script. It should refer to your library.
- Update the `<title>` tag in `index.html.js`.
- Remove 'BEFORE YOU PUBLISH' and 'PUBLISHING' from this document.

# PUBLISHING
- Make sure you are added to the kaliber organization on NPM
- run `yarn publish`
- Enter a correct version, we adhere to semantic versioning (semver)
- run `git push`
- run `git push --tags`
- Send everybody an email to introduce them to your library! -->

# typekit-loader
Parse Adobe TypeKit font-face `css` files server-side to have more control over them client-side.

## Motivation
TypeKit is a pain to load, and usually managed by a client (thus loading too many fonts).

## Installation

```
yarn add @kaliber/typekit-loader
```

## Usage
A few steps are required for setup:

#### Add `typekit` key to your `default.js`.
You can leave `fontNames` out if you want to use _all_ fonts in the `css` file.
```jsx
typekit: {
  cssUrl: 'https://use.typekit.net/YOUR_TYPEKIT_ID.css',
  fontNames: ['font-family-name', 'other-font-family-name']
}
```

#### Add `requestHandler` to your `app` in `routeMap`.
```jsx
function getRouteData() {
  return {
    app: {
      // ... other code
      fetch: {
        fonts: requestHandlers => requestHandlers.getFonts,
        // ... other requestHandlers
      }
    }
  }
}
```

#### Add `getFonts` to your `app` in `requestHandlers`.
```jsx
import { getFonts } from '@kaliber/typekit-loader'

export const requestHandlers = {
  // ... other domains
  app: {
    // ... other routes
    async getFonts() {
      return getFonts(config.typekit)
    },
  }
}
```

#### Add `TypeKitFontsScript` to your `head`.
```jsx
import { TypeKitFontsScript } from '@kaliber/typekit-loader'

<TypeKitFontsScript fontfaceObjects={data?.fonts?.stylesheet || []} cssUrl={config.typekit.cssUrl} />
```

#### (Optionally) Add `TypeKitFontsPreloaders` to your `head`.
```jsx
import { TypeKitFontsPreloaders } from '@kaliber/typekit-loader'

<TypeKitFontsPreloaders fontfaceUrls={data?.fonts?.urls || []} />
```

#### Add fallback to your 500 page.
```jsx
import { TypeKitFontsFallback } from '@kaliber/typekit-loader'

<TypeKitFontsFallback cssUrl={config.typekit.cssUrl} />
```

## Pro-tip
Generate a fallback font through e.g. https://screenspan.net/fallback and add that to a `fonts.css` in your project.

## Disclaimer
This library is intended for internal use, we provide __no__ support, use at your own risk. It does not import React, but expects it to be provided, which [@kaliber/build](https://kaliberjs.github.io/build/) can handle for you.

This library is not transpiled.
npm package: @kaliber/use-element-size
Description: Determines the width and height in pixels of an element through ResizeObserver
Latest version: 4.0.4

# useElementSize
Read the height and width of an element

## Motivation
Determines the width and height (in pixels) of an element through [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver). This is more performant and easier to use than listening to a `resize` event and reading the element's size through `getBoundingClientRect` or `getComputedStyle`, which run on the main thread and can trash layout. Note that the hook is only updated when the element's size changes, not when the window's size changes.

## Box sizing
This library reports the [border-box](https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing) size, which includes the elements padding and border.

## Installation

```
yarn add @kaliber/use-element-size
```

## Usage
### Basic
```jsx
import { useElementSize }  from '@kaliber/use-element-size'

function Component() {
  const { size: { width, height }, ref: elementRef } = useElementSize()
  return <div ref={elementRef}>{width}px × {height}px</div>
}
```
### Animate height
```css
.component {
  overflow: hidden;
  transition: height 0.5s;
}
```
```jsx
import { useElementSize } from '@kaliber/use-element-size'

export function Expand({ children, expanded }) {
  const { size: { height }, ref: innerRef } = useElementSize()

  return (
    <div 
      className={styles.component} 
      style={{ height: expanded ? height + 'px' : '0px' }}
    >
      <div ref={innerRef}>
        {children}
      </div>
    </div>
  )
}
```

![](https://media.giphy.com/media/GFFZmiHkm6h9u/source.gif)

## Disclaimer
This library is intended for internal use, we provide __no__ support, use at your own risk. It does not import React, but expects it to be provided, which [@kaliber/build](https://kaliberjs.github.io/build/) can handle for you.

This library is not transpiled.
npm package: @kaliber/use-global-page-state
Description: Module based state that allows communication between different client React 'islands' on the same page
Latest version: 1.0.0

# @kaliber/use-global-page-state
Module based state that allows communication between different client React 'islands' on the same page.

## Motivation
With @kaliber/build it has become easy to serve a React page component server side and only mount components client side when they contain interactivity. The downside of this, is that these interactive parts live on theire own isolated islands: they can't easily communicate. This library introduces the `useGlobalPageState` hook, which works comparable to React's `useState`, but syncs state between uses of this hook that provide the same id.

## Installation

```
yarn add @kaliber/use-global-page-state
```

## Usage

*Home.js*
```jsx
import { ServerSideComponent } from '/features/pageOnly/ServerSideComponent'
import ClientSideComponentA from '/features/pageOnly/ClientSideComponentA.universal'
import ClientSideComponentB from '/features/pageOnly/ClientSideComponentB.universal'

export function Home() {
  return (
    <main>
      <ClientSideComponentA />
      <ServerSideComponent />
      <ClientSideComponentB />
    </main>
  )
}
```

*ClientSideComponentA.js*
```jsx
import { useGlobalPageState } from '@kaliber/use-global-page-state'

export function ClientSideComponentA() {
  const [state, setState] = useGlobalPageState('unique-id')
  return (
    <section>
      {/* ... */}
    </section>
  )
}
```

*ClientSideComponentB.js*
```jsx
import { useGlobalPageState } from '@kaliber/use-global-page-state'

export function ClientSideComponentA() {
  const [state, setState] = useGlobalPageState('unique-id')
  return (
    <section>
      {/* ... */}
    </section>
  )
}
```

---

![](https://media.giphy.com/media/find-a-good-gif/giphy.gif)

## Disclaimer
This library is intended for internal use, we provide __no__ support, use at your own risk. It does not import React, but expects it to be provided, which [@kaliber/build](https://kaliberjs.github.io/build/) can handle for you.

This library is not transpiled.
npm package: @kaliber/use-is-ie11
Description: Detects if a browser is IE11
Latest version: 1.0.6

# useIsIe11

Detects if a browser is IE11.

## Motivation
In case you need to detect whether a browser is Internet Explorer 11. Doesn't use UA sniffing, but feature detection.

## Installation

```
yarn add @kaliber/use-is-ie11
```

## Usage
```jsx
import { useIsIe11 } from 'use-is-ie11'

function Component() {
  const isIe11 = useIsIe11()
  return isIe11 ? '😞' : '😎'
}
```

![](https://media.giphy.com/media/yqtpq8rqqXBh6/giphy.gif)

## Disclaimer
This library is intended for internal use, we provide __no__ support, use at your own risk. It does not import React, but expects it to be provided, which [@kaliber/build](https://kaliberjs.github.io/build/) can handle for you.

This library is not transpiled.
npm package: @kaliber/use-is-in-viewport
Description: Returns whether an element intersects with a parent element, using the IntersectionObserver
Latest version: 1.1.1

# useIsInViewport
Check whether an element is currently (or was at some time) visible inside the viewport

## Motivation
Reports wether an element is visible inside the viewport using the [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). This is more performant and easier to use than listening to `scroll` and `resize` events and measuring the current offset using `getBoundingClientRect`. 

## Polyfill
The `IntersectionObserver` is [supported by most current browsers](https://caniuse.com/#search=intersectionobserver). If you need wider support, there is a [polyfill](https://www.npmjs.com/package/intersection-observer) available through polyfill.io.

Using @kaliberjs/build, you can add the following argument to the `polyfill()` call.
```
{polyfill(['default', 'IntersectionObserver'])}
```

Without, you can manually add the following script to your page (or include it in your build):
```
https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver
```

## Installation

```
yarn add @kaliber/use-is-in-viewport
```

## Usage
```jsx
function Component() {
  const { ref: isInViewportRef, isInViewport } = useIsInViewport({ rootMargin: '-10%' })
  const { ref: wasInViewportRef, wasInViewport } = useWasInViewport({ rootMargin: '-10%' })

  return (
    <div>
      <div ref={isInViewportRef}>
        {isInViewport 
          ? 'Is in viewport'  
          : 'Is not in viewport'}
      </div>

      <div ref={wasInViewportRef} >
        {wasInViewport 
          ? 'Has been in viewport' 
          : 'Has not yet been in viewport'}
      </div>
    </div>
  )
}
```

The `useIsInViewport` hook also returns wether an element has been in the viewport in the past (`wasInViewport`). The main difference with the dedicated `useWasInViewport` hook is that the IntersectionObserver doesn't get cleaned up, since the hook still has to track wether the element is currently in the viewport. This can be useful if you want to pause an expensive operation, but also want the element to have a reveal animation.

```jsx
function Component() {
  const { ref: elementRef, isInViewport, wasInViewport } = useIsInViewport()

  return (
    <div>
      <div ref={elementRef} className={cx(wasInViewport && styles.isRevealed)}>
        {isInViewport ? 'Is in viewport' : 'Is not in viewport'}
      </div>
    </div>
  )
}
```

![](https://media.giphy.com/media/12FLhMHdanoLJK/giphy.gif)

## Disclaimer
This library is intended for internal use, we provide __no__ support, use at your own risk. It does not import React, but expects it to be provided, which [@kaliber/build](https://kaliberjs.github.io/build/) can handle for you.

This library is not transpiled.
npm package: @kaliber/use-is-mounted-ref
Description: Returns a ref with a current value of true if mounted
Latest version: 1.0.2

# useIsMountedRef
Returns a ref with a `current` value of true when a component is mounted.

## Motivation
Useful when working with server side rendering. Comparable to `componentDidMount` in a class-based component. Does __not__ trigger a rerender.

Another use-case is to check if a component is still mounted after calling an async function.

## Installation

```
yarn add @kaliber/use-is-mounted-ref
```

## Usage
```jsx
import { useIsMountedRef } from '@kaliber/use-is-mounted-ref'

function Component() {
  const [state, setState] = React.useState('⬇️')
  const isMountedRef = useIsMountedRef()

  // Use it to check if a component is still mounted after calling an async function.
  React.useEffect(
    () => {
      async function doSomethingAync() {
        try {
          await someAsyncFunction()
        } catch (err) {
          console.error(err)
          if (isMountedRef.current) setState('⚠️')
        }
        if (isMountedRef.current) setState('⬆️')
      }
      doSomethingAync()
    },
    [isMountedRef]
  )

  return (
    <>
      <div style={{ fontSize: '5em' }}>{state}</div>
    </>
  )
}

function someAsyncFunction() {
  return new Promise(resolve => { window.setTimeout(resolve, 1000) })
}
```

![](https://media.giphy.com/media/9SgOeNxFAh8Hu/giphy.gif)

## Disclaimer
This library is intended for internal use, we provide __no__ support, use at your own risk. It does not import React, but expects it to be provided, which [@kaliber/build](https://kaliberjs.github.io/build/) can handle for you.

This library is not transpiled.
npm package: @kaliber/use-media-query
Description: A hook that makes it easy to use a media query in React
Latest version: 1.1.1

# @kaliber/use-media-query
A hook that makes it easy to use a media query in React.

## Motivation
Sometimes it's useful to render a different version of a component on different media. For instance: a navigation component can have wildly different implementations for mobile and desktop. This hook gives you the power to use media queries to trigger this behavior.

## Installation

```
yarn add @kaliber/use-media-query
```

Add the library to your `compileWithBabel` array:

__`config/default.js`__
```js
module.exports = {
  kaliber: {
    compileWithBabel: [/@kaliber\/use-media-query/]
  }
}
```

### Supporting older browsers
To support older browsers you will need to add some polyfills. When polyfilling for IE11 using polyfill.io, you need:

- `matchMedia`
- `MediaQueryList.prototype.addEventListener`
- `MediaQueryList.prototype.removeEventListener`

## Usage

```jsx
import { useMediaQuery } from '@kaliber/use-media-query'

function Component() {
  const showDesktopNavigation = useMediaQuery('screen and (min-width: 48em)')

  return (
    <div className={styles.component}>
      <header className={styles.header}>
        {showDesktopNavigation
          ? <HeaderDesktop items={menuItems} />
          : <HeaderMobile items={menuItems} />
        }
      </header>
    </div>
  )
}
```

Please do refer to the example in the `/example` folder to see how you can avoid CLS and displaying the wrong menu for a frame.

### Default values

`useMediaQuery` only returns a non-null value after the first render, because the first render there's no information about the media query available yet. If you need a default value, you can add one using the __nullish coalescing operator__:

```js
const showDesktopNavigation = useMediaQuery('screen and (min-width: 48em)') ?? true
```

### Indeterminate

If you want to display a waiting state while you wait for `useMediaQuery` to update, you can explicitly test against `null`:

```js
function Component() {
  const isViewportMd = useMediaQuery('screen and (min-width: 48em)')
  const indeterminate = isViewportMd === null

  return (
    <div className={styles.component}>
      <header className={cx(styles.header, indeterminate && styles.indeterminate)}>
        {/* ... */}
      </header>
    </div>
  )
}
```

---

![](https://media.giphy.com/media/3yjYqt6EosROH9ZwFX/giphy.gif)

## Disclaimer
This library is intended for internal use, we provide __no__ support, use at your own risk. It does not import React, but expects it to be provided, which [@kaliber/build](https://kaliberjs.github.io/build/) can handle for you.

This library is not transpiled.
npm package: @kaliber/use-observed-ref
Description: This is an internal library to facilitate the use of Observers in hooks.
Latest version: 1.0.0

# useObservedRef
This is an internal library to facilitate the use of Observers in hooks

## Installation
You typically don't use this library directly.

## Usage
```jsx
import { useObservedRef } from './use-observed-ref'

export function useObserver() { 
  const [state, setState] = React.useState(null)
  const createObserver = React.useCallback(
    () => {
      // @ts-ignore
      return new window.Observer(([entry]) => {
        setState(entry)
      })
    },
    []
  );

  const reset = React.useCallback(() => { setState(null) }, [])
  const ref = useObservedRef({ createObserver, reset, disabled: false })

  return { state, ref }
}
```

You can use the disabled option if you want to disable the Observer entirely after a successful callback. E.g.: you want to test if something enters the viewport, but don't to know when it leaves again.

![](https://media.giphy.com/media/3orieUe6ejxSFxYCXe/giphy.gif)

## Disclaimer
This library is intended for internal use, we provide __no__ support, use at your own risk. It does not import React, but expects it to be provided, which [@kaliber/build](https://kaliberjs.github.io/build/) can handle for you.

This library is not transpiled.
npm package: @kaliber/use-render-on-mount
Description: Returns a boolean indicating whether a component is mounted, so you can render on mount.
Latest version: 1.0.4

# useRenderOnMount
Returns a boolean indicating whether a component is mounted, so you can render on mount.

## Motivation
In some cases you don't want to render a component universally, but rather only on the client. This hook provides a boolean indicating whether a component is mounted, which you can use to conditionally render the component. 

When the boolean is flipped, a re-render happens so you can update your UI accordingly.


## Installation

```
yarn add @kaliber/use-render-on-mount
```

## Usage
```jsx
import { useRenderOnMount } from '@kaliber/use-render-on-mount'

function Component() {
  const isMounted = useRenderOnMount()
  return isMounted && '😎'
}
```

![](https://media.giphy.com/media/U5IUJHu2LGueEeU2Yz/giphy.gif)

## Disclaimer
This library is intended for internal use, we provide __no__ support, use at your own risk. It does not import React, but expects it to be provided, which [@kaliber/build](https://kaliberjs.github.io/build/) can handle for you.

This library is not transpiled.
npm package: @kaliber/use-scroll-velocity
Description: A helper library to track the users scroll velocity
Latest version: 1.0.1

# useScrollVelocity
A library that returns an immutable value that signifies the users scroll velocity.

It returns a positive float on down scroll and a negative float on up scroll behavior.
The returned value is lerped, the lerp speed is `0.1` by default but can be overwritten by passing the `lerpSpeed` prop, if you need additional smoothing functionality you should either use your own function or use it in conjunction with ThreeJS Math utils like lerp.

Example with built in lerp:
```js
const scrollVelocity = useScrollVelocity({ lerpSpeed: 0.3 })
```

Example with ThreeJS Math util:
```js
const meshRef = React.useRef()
const lerpSpeed = 0.3
const scrollVelocity = useScrollVelocity()

const THREELerp = THREE.MathUtils.lerp(
    meshRef.current.material.uniforms.uScrollVelocity.value,
    scrollVelocity.current,
    lerpSpeed
)
```

## Motivation
Creating animations that react to the speed of which the user scrolls can be a bit tricky. Most libraries that give this kind of functionality require you to install their entire package. This package tries to solve this by returning an immutable value that serves a singular purpose. 

## Installation

```
yarn add @kaliber/use-scroll-velocity
```

## Usage

```jsx
import { useScrollVelocity } from '@kaliber/use-scroll-velocity'

function R3FComponent() {
    const scrollVelocity = useScrollVelocity()
    const meshRef = React.useRef()

    useFrame(() => {
        const normalizedVelocity = scrollVelocity.current * 0.01
        meshRef.current.rotation.z += normalizedVelocity
    })

    return <mesh ref={meshRef}><boxMesh /></mesh>
}
```

# Reference
This library is mainly used as an immutable state reference for ThreeJS / R3F. 

![](https://media4.giphy.com/media/v1.Y2lkPTc5MGI3NjExMHhxNjBhaGo5bDJ0bmJoMGVsdmk1MzhvcDBoOHh3M2NxeHhhZzIwNiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/pjOTiMEkFKlN8lQXOT/giphy.gif)

## Disclaimer
This library is intended for internal use, we provide __no__ support, use at your own risk. It does not import React, but expects it to be provided, which [@kaliber/build](https://kaliberjs.github.io/build/) can handle for you.

This library is not transpiled.
npm package: @kalidao/hooks
Description: React Hooks for Ethereum
Author: ivelin.eth
Latest version: 0.0.5

Kali Hooks is a Rect Hooks library that aims to simplify development of Kali DAO based web3 apps. Kali Hooks extends the [wagmi hooks](https://github.com/wagmi-dev/wagmi) library and follows the wagmi best practices.

To learn more [see docs](https://github.com/kalidao/hooks#readme).