Skip to content

Commit 7605741

Browse files
committed
feat: sync variables to url
1 parent 05cc859 commit 7605741

18 files changed

Lines changed: 371 additions & 134 deletions

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"yaml": "^2.8.2"
3838
},
3939
"peerDependencies": {
40+
"nuqs": "^2.0.0",
4041
"react": "^18.0.0 || ^19.0.0",
4142
"react-dom": "^18.0.0 || ^19.0.0"
4243
},
@@ -49,6 +50,7 @@
4950
"@vitejs/plugin-react": "^5.1.4",
5051
"@vitest/coverage-v8": "^4.0.18",
5152
"jsdom": "^28.1.0",
53+
"nuqs": "^2.0.0",
5254
"typescript": "^5.9.3",
5355
"vite": "^6.3.5",
5456
"vitest": "^4.0.18"

pnpm-lock.yaml

Lines changed: 34 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Dashboard.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1+
import { useMemo } from 'react'
12
import { DashboardRenderer } from './components/DashboardRenderer'
23
import { DashboardProvider } from './context/DashboardContext'
4+
import { extractVariableDefs } from './extractVariableDefs'
35
import type { ComponentDef, FileLoader } from './types'
46
import './styles.css'
57

68
export function Dashboard({ definition, fileLoader }: { definition: ComponentDef; fileLoader?: FileLoader }) {
9+
const variableDefs = useMemo(() => extractVariableDefs(definition), [definition])
10+
711
return (
8-
<DashboardProvider fileLoader={fileLoader}>
12+
<DashboardProvider fileLoader={fileLoader} variableDefs={variableDefs}>
913
<DashboardRenderer definition={definition} />
1014
</DashboardProvider>
1115
)

src/components/DashboardRenderer.test.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import '@testing-library/jest-dom'
22
import { render, screen } from '@testing-library/react'
3+
import { NuqsTestingAdapter } from 'nuqs/adapters/testing'
34
import { DashboardProvider } from '../context/DashboardContext'
45
import { DashboardRenderer } from './DashboardRenderer'
56

67
describe('DashboardRenderer', () => {
78
it('renders unknown component error for unrecognized component type', () => {
89
render(
9-
<DashboardProvider>
10-
<DashboardRenderer definition={{ component: 'nonexistent' }} />
11-
</DashboardProvider>,
10+
<NuqsTestingAdapter>
11+
<DashboardProvider>
12+
<DashboardRenderer definition={{ component: 'nonexistent' }} />
13+
</DashboardProvider>
14+
</NuqsTestingAdapter>,
1215
)
1316

1417
expect(screen.getByText('Unknown component: nonexistent')).toBeInTheDocument()
@@ -17,9 +20,11 @@ describe('DashboardRenderer', () => {
1720

1821
it('renders a text component correctly', () => {
1922
render(
20-
<DashboardProvider>
21-
<DashboardRenderer definition={{ component: 'text', args: { tagName: 'p' }, data: 'hello' }} />
22-
</DashboardProvider>,
23+
<NuqsTestingAdapter>
24+
<DashboardProvider>
25+
<DashboardRenderer definition={{ component: 'text', args: { tagName: 'p' }, data: 'hello' }} />
26+
</DashboardProvider>
27+
</NuqsTestingAdapter>,
2328
)
2429

2530
expect(screen.getByText('hello')).toBeInTheDocument()

src/components/board/Board.test.tsx

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,34 @@
11
import '@testing-library/jest-dom'
22
import { render, screen } from '@testing-library/react'
3+
import { NuqsTestingAdapter } from 'nuqs/adapters/testing'
34
import { DashboardProvider } from '../../context/DashboardContext'
45
import { Board } from './Board'
56

67
describe('Board', () => {
78
it('renders ds--board container', () => {
89
const { container } = render(
9-
<DashboardProvider>
10-
<Board data={[]} />
11-
</DashboardProvider>,
10+
<NuqsTestingAdapter>
11+
<DashboardProvider>
12+
<Board data={[]} />
13+
</DashboardProvider>
14+
</NuqsTestingAdapter>,
1215
)
1316

1417
expect(container.querySelector('.ds--board')).toBeInTheDocument()
1518
})
1619

1720
it('renders children', () => {
1821
render(
19-
<DashboardProvider>
20-
<Board
21-
data={[
22-
{ component: 'text', args: { tagName: 'p' }, data: 'board child one' },
23-
{ component: 'text', args: { tagName: 'p' }, data: 'board child two' },
24-
]}
25-
/>
26-
</DashboardProvider>,
22+
<NuqsTestingAdapter>
23+
<DashboardProvider>
24+
<Board
25+
data={[
26+
{ component: 'text', args: { tagName: 'p' }, data: 'board child one' },
27+
{ component: 'text', args: { tagName: 'p' }, data: 'board child two' },
28+
]}
29+
/>
30+
</DashboardProvider>
31+
</NuqsTestingAdapter>,
2732
)
2833

2934
expect(screen.getByText('board child one')).toBeInTheDocument()

src/components/chart/Chart.test.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import '@testing-library/jest-dom'
22
import { render } from '@testing-library/react'
3+
import { NuqsTestingAdapter } from 'nuqs/adapters/testing'
34
import { DashboardProvider } from '../../context/DashboardContext'
45
import { Chart } from './Chart'
56

67
describe('Chart', () => {
78
it('renders ds--chart container', () => {
89
const { container } = render(
9-
<DashboardProvider>
10-
<Chart args={{ type: 'bar' }} data={[]} />
11-
</DashboardProvider>,
10+
<NuqsTestingAdapter>
11+
<DashboardProvider>
12+
<Chart args={{ type: 'bar' }} data={[]} />
13+
</DashboardProvider>
14+
</NuqsTestingAdapter>,
1215
)
1316

1417
expect(container.querySelector('.ds--chart')).toBeInTheDocument()
@@ -17,9 +20,11 @@ describe('Chart', () => {
1720
it('throws when type is missing', () => {
1821
expect(() =>
1922
render(
20-
<DashboardProvider>
21-
<Chart args={{}} data={[]} />
22-
</DashboardProvider>,
23+
<NuqsTestingAdapter>
24+
<DashboardProvider>
25+
<Chart args={{}} data={[]} />
26+
</DashboardProvider>
27+
</NuqsTestingAdapter>,
2328
),
2429
).toThrow()
2530
})

src/components/columns/Columns.test.tsx

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,35 @@
11
import '@testing-library/jest-dom'
22
import { render, screen } from '@testing-library/react'
3+
import { NuqsTestingAdapter } from 'nuqs/adapters/testing'
34
import { DashboardProvider } from '../../context/DashboardContext'
45
import { Columns } from './Columns'
56

67
describe('Columns', () => {
78
it('renders ds--columns container', () => {
89
const { container } = render(
9-
<DashboardProvider>
10-
<Columns args={{}} data={[]} />
11-
</DashboardProvider>,
10+
<NuqsTestingAdapter>
11+
<DashboardProvider>
12+
<Columns args={{}} data={[]} />
13+
</DashboardProvider>
14+
</NuqsTestingAdapter>,
1215
)
1316

1417
expect(container.querySelector('.ds--columns')).toBeInTheDocument()
1518
})
1619

1720
it('renders children in ds--column divs', () => {
1821
render(
19-
<DashboardProvider>
20-
<Columns
21-
args={{}}
22-
data={[
23-
{ component: 'text', args: { tagName: 'p' }, data: 'col one' },
24-
{ component: 'text', args: { tagName: 'p' }, data: 'col two' },
25-
]}
26-
/>
27-
</DashboardProvider>,
22+
<NuqsTestingAdapter>
23+
<DashboardProvider>
24+
<Columns
25+
args={{}}
26+
data={[
27+
{ component: 'text', args: { tagName: 'p' }, data: 'col one' },
28+
{ component: 'text', args: { tagName: 'p' }, data: 'col two' },
29+
]}
30+
/>
31+
</DashboardProvider>
32+
</NuqsTestingAdapter>,
2833
)
2934

3035
expect(screen.getByText('col one')).toBeInTheDocument()
@@ -36,9 +41,11 @@ describe('Columns', () => {
3641

3742
it('uses default column count of 2', () => {
3843
const { container } = render(
39-
<DashboardProvider>
40-
<Columns args={{}} data={[]} />
41-
</DashboardProvider>,
44+
<NuqsTestingAdapter>
45+
<DashboardProvider>
46+
<Columns args={{}} data={[]} />
47+
</DashboardProvider>
48+
</NuqsTestingAdapter>,
4249
)
4350

4451
const columnsEl = container.querySelector('.ds--columns')

src/components/dropdown/Dropdown.test.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import '@testing-library/jest-dom'
22
import { render, screen } from '@testing-library/react'
3+
import { NuqsTestingAdapter } from 'nuqs/adapters/testing'
34
import { DashboardProvider } from '../../context/DashboardContext'
45
import { Dropdown } from './Dropdown'
56

@@ -19,9 +20,11 @@ describe('Dropdown', () => {
1920
]
2021

2122
render(
22-
<DashboardProvider>
23-
<Dropdown args={{ variable: 'color', default: 'a' }} data={options} />
24-
</DashboardProvider>,
23+
<NuqsTestingAdapter>
24+
<DashboardProvider variableDefs={[{ name: 'color', defaultValue: 'a' }]}>
25+
<Dropdown args={{ variable: 'color', default: 'a' }} data={options} />
26+
</DashboardProvider>
27+
</NuqsTestingAdapter>,
2528
)
2629

2730
expect(screen.getByRole('combobox')).toBeInTheDocument()
@@ -32,9 +35,11 @@ describe('Dropdown', () => {
3235
it('throws when variable arg is missing', () => {
3336
expect(() =>
3437
render(
35-
<DashboardProvider>
36-
<Dropdown args={{ default: 'a' }} data={[]} />
37-
</DashboardProvider>,
38+
<NuqsTestingAdapter>
39+
<DashboardProvider>
40+
<Dropdown args={{ default: 'a' }} data={[]} />
41+
</DashboardProvider>
42+
</NuqsTestingAdapter>,
3843
),
3944
).toThrow()
4045
})

src/components/root/Root.test.tsx

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,35 @@
11
import '@testing-library/jest-dom'
22
import { render, screen } from '@testing-library/react'
3+
import { NuqsTestingAdapter } from 'nuqs/adapters/testing'
34
import { DashboardProvider } from '../../context/DashboardContext'
45
import { Root } from './Root'
56

67
describe('Root', () => {
78
it('sets document.title', () => {
89
render(
9-
<DashboardProvider>
10-
<Root args={{ title: 'My Dashboard' }} data={[]} />
11-
</DashboardProvider>,
10+
<NuqsTestingAdapter>
11+
<DashboardProvider>
12+
<Root args={{ title: 'My Dashboard' }} data={[]} />
13+
</DashboardProvider>
14+
</NuqsTestingAdapter>,
1215
)
1316

1417
expect(document.title).toBe('My Dashboard')
1518
})
1619

1720
it('renders children in ds--wrapper divs', () => {
1821
render(
19-
<DashboardProvider>
20-
<Root
21-
args={{ title: 'Test' }}
22-
data={[
23-
{ component: 'text', args: { tagName: 'p' }, data: 'child one' },
24-
{ component: 'text', args: { tagName: 'p' }, data: 'child two' },
25-
]}
26-
/>
27-
</DashboardProvider>,
22+
<NuqsTestingAdapter>
23+
<DashboardProvider>
24+
<Root
25+
args={{ title: 'Test' }}
26+
data={[
27+
{ component: 'text', args: { tagName: 'p' }, data: 'child one' },
28+
{ component: 'text', args: { tagName: 'p' }, data: 'child two' },
29+
]}
30+
/>
31+
</DashboardProvider>
32+
</NuqsTestingAdapter>,
2833
)
2934

3035
expect(screen.getByText('child one')).toBeInTheDocument()
@@ -37,9 +42,11 @@ describe('Root', () => {
3742
it('throws when title is missing', () => {
3843
expect(() =>
3944
render(
40-
<DashboardProvider>
41-
<Root args={{}} data={[]} />
42-
</DashboardProvider>,
45+
<NuqsTestingAdapter>
46+
<DashboardProvider>
47+
<Root args={{}} data={[]} />
48+
</DashboardProvider>
49+
</NuqsTestingAdapter>,
4350
),
4451
).toThrow()
4552
})

0 commit comments

Comments
 (0)