Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/long-crews-join.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@ultraviolet/ui": major
---

⚠️ Breaking changes:

`ThemeRegistry` is no longer available in this package. You can import it by adding `@ultraviolet/nextjs` package to your project. The component is the same only the import changes.
5 changes: 5 additions & 0 deletions .changeset/true-ducks-deny.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ultraviolet/nextjs": major
---

New package and component ThemeRegistry for next compatibility
2 changes: 1 addition & 1 deletion examples/next-app-router/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Metadata } from 'next'
import './globals.css'
import { ThemeRegistry } from '@ultraviolet/nextjs'
import { consoleLightTheme } from '@ultraviolet/themes'
import { ThemeRegistry } from '@ultraviolet/ui'
import { ReactNode } from 'react'
import { GlobalStyles } from './GlobalStyles'

Expand Down
1 change: 1 addition & 0 deletions examples/next-app-router/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@ultraviolet/fonts": "workspace:*",
"@ultraviolet/form": "workspace:*",
"@ultraviolet/icons": "workspace:*",
"@ultraviolet/nextjs": "workspace:*",
"@ultraviolet/ui": "workspace:*",
"next": "15.3.4",
"react": "19.1.0",
Expand Down
3 changes: 3 additions & 0 deletions packages/nextjs/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/*
!/dist/**/*.js
*.test.js
78 changes: 78 additions & 0 deletions packages/nextjs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Ultraviolet NextJS

[![npm version](https://badge.fury.io/js/%40ultraviolet%2Fnextjs.svg)](https://badge.fury.io/js/%40ultraviolet%2Fui)

Ultraviolet JS is a utility package to make Ultraviolet UI work with NextJS. This package will guide you through the integration of Ultraviolet UI with Next.js [App Router](https://nextjs.org/docs/app).

### Get Started

```sh
pnpm add @ultraviolet/nextjs @ultraviolet/ui @ultraviolet/themes @emotion/react @emotion/styled @emotion/cache
```

In you NextJS project you can implement the following:

```tsx
// app/layout.tsx
import { consoleLightTheme } from '@ultraviolet/themes'
import { ThemeRegistry } from '@ultraviolet/nextjs'
import { Button } from '@ultraviolet/ui'
import { ReactNode } from 'react'

export default function RootLayout({
children,
}: Readonly<{
children: ReactNode
}>) {
return (
<html lang="en">
<body>
<ThemeRegistry theme={consoleLightTheme}>
{children}
<Button variant="primary">Click Me</Button>
</ThemeRegistry>
</body>
</html>
)
}
```

### Limitations

- **Fonts**: Ultraviolet UI uses custom fonts that need to be imported separately. Make sure to import the fonts CSS file in your project's entry point:
```sh
pnpm add @ultraviolet/fonts
```

then in you `GlobalStyle` file:

```tsx
"use client"

import '@ultraviolet/fonts/fonts.css'
```

- **Styled Components**: in order to customize an emotion component, you need to import the `styled` function from `@emotion/styled` and use it to create your styled components. Emotion is not yet compatible with server components, so you need to use the `styled` function in a client component. Example:

```tsx
"use client"

import { styled } from '@emotion/styled'

const Button = styled.button`
background-color: #0070f3;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
`
```

## Documentation

Checkout our [documentation website](https://storybook.ultraviolet.scaleway.com/).

## Contributing

📝 You can participate in the development and [start contributing](/CONTRIBUTING.md) to it.
71 changes: 71 additions & 0 deletions packages/nextjs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
"name": "@ultraviolet/nextjs",
"version": "0.0.1",
"description": "Ultraviolet NextJS utility package",
"homepage": "https://github.com/scaleway/ultraviolet#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/scaleway/ultraviolet.git",
"directory": "packages/nextjs"
},
"scripts": {
"type:generate": "tsc --declaration -p tsconfig.build.json",
"watch": "pnpm run '/^watch:.*/'",
"watch:build": "vite build --config vite.config.ts --watch",
"build": "vite build --config vite.config.ts && pnpm run type:generate",
"build:profile": "npx vite-bundle-visualizer -c vite.config.ts",
"typecheck": "tsc --noEmit",
"lintpublish": "publint"
},
"keywords": [
"react",
"reactjs",
"ui",
"nextjs"
],
"license": "Apache-2.0",
"publishConfig": {
"access": "public"
},
"engines": {
"node": ">=18.x",
"pnpm": ">=9.x"
},
"os": [
"darwin",
"linux"
],
"sideEffects": false,
"type": "module",
"files": [
"dist/"
],
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"main": "./dist/index.cjs",
"exports": {
".": {
"types": "./dist/index.d.ts",
"require": "./dist/index.cjs",
"default": "./dist/index.js"
}
},
"peerDependencies": {
"@emotion/cache": "11.14.0",
"@emotion/react": "11.14.0",
"@emotion/styled": "11.14.0",
"@ultraviolet/ui": "workspace:*",
"next": "15.x",
"react": "18.x || 19.x",
"react-dom": "18.x || 19.x"
},
"devDependencies": {
"@emotion/cache": "11.14.0",
"@emotion/react": "11.14.0",
"@emotion/styled": "11.14.0",
"@ultraviolet/ui": "workspace:*",
"next": "15.3.4",
"react": "19.1.0",
"react-dom": "19.1.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type ThemeRegistryProps = {
* ThemeRegistry is a component that provides a theme to its children.
* This solution is provided to work with Next.js app router.
*/
export default function ThemeRegistry({ children, theme }: ThemeRegistryProps) {
export const ThemeRegistry = ({ children, theme }: ThemeRegistryProps) => {
const [{ cache, flush }] = useState(() => {
const localCache = createCache({ key: 'uv' })
localCache.compat = true
Expand Down
1 change: 1 addition & 0 deletions packages/nextjs/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ThemeRegistry } from './ThemeRegistry'
18 changes: 18 additions & 0 deletions packages/nextjs/tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": false,
"emitDeclarationOnly": true,
"rootDir": "src",
"outDir": "dist"
},
"exclude": [
"*.config.ts",
"*.setup.ts",
"**/__tests__",
"**/__mocks__",
"**/__stories__",
"src/**/*.test.tsx",
"vitest.setup.ts"
]
}
8 changes: 8 additions & 0 deletions packages/nextjs/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": "."
},
"include": ["src", "../../global.d.ts"],
"exclude": ["node_modules", "coverage", "dist"]
}
4 changes: 4 additions & 0 deletions packages/nextjs/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { defineConfig } from 'vite'
import { defaultConfig } from '../../vite.config'

export default defineConfig(defaultConfig)
2 changes: 0 additions & 2 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@
"react-dom": "19.1.0"
},
"dependencies": {
"@emotion/cache": "11.14.0",
"@emotion/serialize": "1.3.3",
"@nivo/bar": "0.89.1",
"@nivo/core": "0.89.1",
Expand All @@ -94,7 +93,6 @@
"@ultraviolet/icons": "workspace:*",
"@ultraviolet/themes": "workspace:*",
"deepmerge": "4.3.1",
"next": "15.3.4",
"react-toastify": "11.0.5",
"react-use-clipboard": "1.0.9"
}
Expand Down
86 changes: 5 additions & 81 deletions packages/ui/src/__stories__/Guides/NextIntegration.mdx
Original file line number Diff line number Diff line change
@@ -1,84 +1,8 @@
import { Meta } from '@storybook/blocks'
import { Markdown, Meta } from '@storybook/blocks'
import Readme from '../../../../nextjs/README.md?raw'

<Meta title="Guides/Next Integration" />

# Next Integration

Learn how to use Ultraviolet UI with Next.js.

## App Router

This section will guide you through the integration of Ultraviolet UI with Next.js [App Router](https://nextjs.org/docs/app).

### Install dependencies

Start by installing Ultraviolet dependencies and emotion dependencies.

```sh
pnpm add @ultraviolet/ui @ultraviolet/themes @emotion/react @emotion/styled
```

### Configuration

Inside `app/layout.tsx`, import the `ThemeRegistry` from `@ultraviolet/ui` and wrap your app with it.

```tsx
// app/layout.tsx
import { consoleLightTheme } from '@ultraviolet/themes'
import { ThemeRegistry } from '@ultraviolet/ui'
import { ReactNode } from 'react'

export default function RootLayout({
children,
}: Readonly<{
children: ReactNode
}>) {
return (
<html lang="en">
<body>
<ThemeRegistry theme={consoleLightTheme}>
{children}
</ThemeRegistry>
</body>
</html>
)
}
```

`ThemeRegistry` component is responsible for providing the theme context to all components within the app.
This component has been specially made to work seamlessly with Next.js's App Router.

### Limitations

- **Fonts**: Ultraviolet UI uses custom fonts that need to be imported separately. Make sure to import the fonts CSS file in your project's entry point:
```sh
pnpm add @ultraviolet/fonts
```

then in you `GlobalStyle` file:
```tsx
"use client"

import '@ultraviolet/fonts/fonts.css'
```

- **Styled Components**: in order to customize an emotion component, you need to import the `styled` function from `@emotion/styled` and use it to create your styled components. Emotion is not yet compatible with server components, so you need to use the `styled` function in a client component. Example:
```tsx
"use client"

import { styled } from '@emotion/styled'

const Button = styled.button`
background-color: #0070f3;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
`
```

### Examples

In order to help you integrate Ultraviolet UI with Next.js, we've prepared an example available on GitHub:
[https://github.com/scaleway/ultraviolet/tree/main/examples/next-app-router](https://github.com/scaleway/ultraviolet/tree/main/examples/next-app-router)
<Markdown>
{Readme}
</Markdown>
1 change: 0 additions & 1 deletion packages/ui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ export {
darkTheme,
default as theme,
extendTheme,
ThemeRegistry,
} from './theme'
export type { SCWUITheme, UltravioletUITheme } from './theme'
export {
Expand Down
2 changes: 0 additions & 2 deletions packages/ui/src/theme/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { consoleDarkTheme, consoleLightTheme } from '@ultraviolet/themes'
import deepmerge from 'deepmerge'
import ThemeRegistry from './ThemeRegistry'

export type ScreenSize = keyof typeof consoleLightTheme.breakpoints

Expand Down Expand Up @@ -66,7 +65,6 @@ export {
SENTIMENTS,
SENTIMENTS_WITHOUT_NEUTRAL,
typography,
ThemeRegistry,
}

export default consoleLightTheme
Loading
Loading