Skip to content

Commit e36d439

Browse files
✨ implement linked tabs
1 parent 347526e commit e36d439

12 files changed

+182
-64
lines changed

docs/components/linked-tabs.tsx

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { Tabs } from 'nextra/components';
2+
import React, { ReactNode } from 'react';
3+
import { useTabContext } from './tab-context';
4+
5+
interface LinkedTabsProps {
6+
id: string;
7+
items: string[];
8+
children: ReactNode;
9+
}
10+
11+
export const LinkedTabs: React.FC<LinkedTabsProps> = ({
12+
id,
13+
items,
14+
children,
15+
}) => {
16+
const { selectedTabs, setSelectedTab } = useTabContext();
17+
const selectedTab = selectedTabs[id] || items[0];
18+
19+
const index = items.indexOf(selectedTab);
20+
const selectedIndex = index !== -1 ? index : 0;
21+
22+
return (
23+
<Tabs
24+
items={items}
25+
selectedIndex={selectedIndex}
26+
onChange={(index: number) => setSelectedTab(id, items[index])}
27+
>
28+
{children}
29+
</Tabs>
30+
);
31+
};

docs/components/tab-context.tsx

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import {
2+
createContext,
3+
useContext,
4+
useState,
5+
useEffect,
6+
ReactNode,
7+
} from 'react';
8+
9+
interface TabContextType {
10+
selectedTabs: { [key: string]: string };
11+
setSelectedTab: (id: string, tab: string) => void;
12+
}
13+
14+
const TabContext = createContext<TabContextType>({
15+
selectedTabs: {},
16+
setSelectedTab: () => {},
17+
});
18+
19+
export const useTabContext = () => useContext(TabContext);
20+
21+
interface TabProviderProps {
22+
children: ReactNode;
23+
}
24+
25+
export const TabProvider: React.FC<TabProviderProps> = ({ children }) => {
26+
const [selectedTabs, setSelectedTabs] = useState<{ [key: string]: string }>(
27+
{},
28+
);
29+
30+
useEffect(() => {
31+
if (typeof window !== 'undefined') {
32+
const storedTabs = localStorage.getItem('selectedTabs');
33+
if (storedTabs) {
34+
try {
35+
const parsedTabs = JSON.parse(storedTabs) as {
36+
[key: string]: string;
37+
};
38+
setSelectedTabs(parsedTabs);
39+
} catch (error) {
40+
console.error(
41+
'Failed to parse selectedTabs from localStorage',
42+
error,
43+
);
44+
}
45+
}
46+
}
47+
}, []);
48+
49+
useEffect(() => {
50+
if (typeof window !== 'undefined') {
51+
localStorage.setItem('selectedTabs', JSON.stringify(selectedTabs));
52+
}
53+
}, [selectedTabs]);
54+
55+
const setSelectedTab = (id: string, tab: string) => {
56+
setSelectedTabs((prev) => ({
57+
...prev,
58+
[id]: tab,
59+
}));
60+
};
61+
62+
return (
63+
<TabContext.Provider value={{ selectedTabs, setSelectedTab }}>
64+
{children}
65+
</TabContext.Provider>
66+
);
67+
};

docs/pages/_app.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
import { TabProvider } from '@/components/tab-context';
12
import { Analytics } from '@vercel/analytics/react';
23
import type { AppProps } from 'next/app';
34

45
function MyApp({ Component, pageProps }: AppProps) {
56
return (
6-
<>
7+
<TabProvider>
78
<Component {...pageProps} />
89
<Analytics />
9-
</>
10+
</TabProvider>
1011
);
1112
}
1213

docs/pages/postgrest/custom-cache-updates.mdx

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Callout, Tabs } from 'nextra/components';
2+
import { LinkedTabs } from '@/components/linked-tabs';
23

34
# Custom Cache Updates
45

@@ -8,7 +9,7 @@ Sometimes, you will find yourself writing custom cache updates. The library expo
89

910
Delete a postgrest entity from the cache. Note that you have to pass a value for all primary keys in the input.
1011

11-
<Tabs items={['SWR', 'React Query']}>
12+
<LinkedTabs items={['SWR', 'React Query']} id="data-fetcher">
1213
<Tabs.Tab>
1314
```tsx
1415
import { useDeleteItem } from "@supabase-cache-helpers/postgrest-swr";
@@ -43,13 +44,13 @@ Delete a postgrest entity from the cache. Note that you have to pass a value for
4344
```
4445

4546
</Tabs.Tab>
46-
</Tabs>
47+
</LinkedTabs>
4748

4849
## `useUpsertItem`
4950

5051
Upsert a postgrest entity into the cache. Note that you have to pass a value for all primary keys in the input.
5152

52-
<Tabs items={['SWR', 'React Query']}>
53+
<LinkedTabs items={['SWR', 'React Query']} id="data-fetcher">
5354
<Tabs.Tab>
5455
```tsx
5556
import { useUpsertItem } from "@supabase-cache-helpers/postgrest-swr";
@@ -84,4 +85,4 @@ Upsert a postgrest entity into the cache. Note that you have to pass a value for
8485
```
8586

8687
</Tabs.Tab>
87-
</Tabs>
88+
</LinkedTabs>

docs/pages/postgrest/getting-started.mdx

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Callout, Tabs } from 'nextra/components';
2+
import { LinkedTabs } from '@/components/linked-tabs';
23

34
# Getting Started
45

@@ -12,16 +13,16 @@ pnpm add @supabase-cache-helpers/postgrest-swr
1213

1314
If your package manager does not install peer dependencies automatically, you will need to install them, too.
1415

15-
<Tabs items={["SWR", "React Query"]}>
16+
<LinkedTabs items={['SWR', 'React Query']} id="data-fetcher">
1617
<Tabs.Tab>`pnpm add swr react @supabase/postgrest-js`</Tabs.Tab>
1718
<Tabs.Tab>`pnpm add @tanstack/react-query react @supabase/postgrest-js`</Tabs.Tab>
18-
</Tabs>
19+
</LinkedTabs>
1920

2021
## Quick Start
2122

2223
Import [`useQuery`](./queries#usequery) and define a simple query. The cache key is automatically created from the query. You can pass the SWR- and React Query-native options as a second argument. For pagination and infinite scroll queries, use [`useInfiniteOffsetPaginationQuery`](./queries#useinfiniteoffsetpaginationquery), [`useOffsetInfiniteScrollQuery`](./queries#useoffsetinfinitescrollquery) and [`useCursorInfiniteScrollQuery`](./queries#usecursorinfinitescrollquery).
2324

24-
<Tabs items={['SWR', 'React Query']}>
25+
<LinkedTabs items={['SWR', 'React Query']} id="data-fetcher">
2526
<Tabs.Tab>
2627
```tsx
2728
import { useQuery } from "@supabase-cache-helpers/postgrest-swr";
@@ -75,11 +76,11 @@ Import [`useQuery`](./queries#usequery) and define a simple query. The cache key
7576
```
7677

7778
</Tabs.Tab>
78-
</Tabs>
79+
</LinkedTabs>
7980

8081
Somewhere in your app, import [`useInsertMutation`](./mutations#useinsertmutation) and define a mutation. For the automatic cache population to work, you need to pass the primary key(s) of the relation as a second argument. To return data from the mutation, pass a `.select('...')` string as the third argument. Pass `null` to skip. The fourth argument is the SWR- and React Query-native `options` object. The mutation will automatically update the query cache of the contact query defined above. Other operations are supported with [`useUpsertMutation`](./mutations#useupsertmutation), [`useUpdateMutation`](./mutations#useupdatemutation) and [`useDeleteMutation`](./mutations#usedeletemutation).
8182

82-
<Tabs items={['SWR', 'React Query']}>
83+
<LinkedTabs items={['SWR', 'React Query']} id="data-fetcher">
8384
<Tabs.Tab>
8485
```tsx
8586
import { useInsertMutation } from "@supabase-cache-helpers/postgrest-swr";
@@ -126,13 +127,13 @@ Somewhere in your app, import [`useInsertMutation`](./mutations#useinsertmutatio
126127
```
127128

128129
</Tabs.Tab>
129-
</Tabs>
130+
</LinkedTabs>
130131

131132
To subscribe to changes, import [`useSubscription`](./subscriptions#usesubscription) and define a subscription. Use any channel name, and define the subscription as you know it from the Supabase client. For the automatic cache population to work, you need to pass the primary key(s) of the relation. You can pass the SWR and React Query-native mutation options.
132133

133134
The query cache will automatically be updated when new data comes in. If you use [computed / virtual columns](https://postgrest.org/en/stable/api.html?highlight=computed%20columns#computed-virtual-columns) or relations, you can use [`useSubscriptionQuery`](./subscriptions#usesubscriptionquery) to fetch the entity from `PostgREST` before populating the cache with it.
134135

135-
<Tabs items={['SWR', 'React Query']}>
136+
<LinkedTabs items={['SWR', 'React Query']} id="data-fetcher">
136137
<Tabs.Tab>
137138
```tsx
138139
import { useSubscription } from "@supabase-cache-helpers/postgrest-swr";
@@ -185,4 +186,4 @@ The query cache will automatically be updated when new data comes in. If you use
185186
```
186187

187188
</Tabs.Tab>
188-
</Tabs>
189+
</LinkedTabs>

docs/pages/postgrest/mutations.mdx

+17-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Callout, Tabs } from 'nextra/components';
2+
import { LinkedTabs } from '@/components/linked-tabs';
23

34
# Mutations
45

@@ -66,7 +67,9 @@ declare type PostgrestMutatorOpts<Type> = {
6667

6768
Insert entities. Will also update the count if applicable. Note that hook requires the user to define the primary keys of the relation, because the items are upserted to the cache to prevent duplicates, e.g. if a subscription is used in parallel.
6869

69-
<Tabs items={['SWR', 'React Query']}>
70+
<LinkedTabs items={['SWR', 'React Query']}
71+
id="data-fetcher"
72+
>
7073
<Tabs.Tab>
7174
```tsx
7275
import { useInsertMutation } from '@supabase-cache-helpers/postgrest-swr'
@@ -115,13 +118,15 @@ Insert entities. Will also update the count if applicable. Note that hook requir
115118
```
116119
117120
</Tabs.Tab>
118-
</Tabs>
121+
</LinkedTabs>
119122
120123
## `useUpdateMutation`
121124
122125
Update an entity. Requires the primary keys to be defined explicitly.
123126
124-
<Tabs items={['SWR', 'React Query']}>
127+
<LinkedTabs items={['SWR', 'React Query']}
128+
id="data-fetcher"
129+
>
125130
<Tabs.Tab>
126131
```tsx
127132
import { useUpdateMutation } from '@supabase-cache-helpers/postgrest-swr'
@@ -170,13 +175,15 @@ Update an entity. Requires the primary keys to be defined explicitly.
170175
```
171176
172177
</Tabs.Tab>
173-
</Tabs>
178+
</LinkedTabs>
174179
175180
## `useUpsertMutation`
176181
177182
Upsert entities. Requires the primary keys to be defined explicitly. Will also increment the count if an item is inserted.
178183
179-
<Tabs items={['SWR', 'React Query']}>
184+
<LinkedTabs items={['SWR', 'React Query']}
185+
id="data-fetcher"
186+
>
180187
<Tabs.Tab>
181188
```tsx
182189
import { useUpsertMutation } from '@supabase-cache-helpers/postgrest-swr'
@@ -225,13 +232,15 @@ Upsert entities. Requires the primary keys to be defined explicitly. Will also i
225232
```
226233
227234
</Tabs.Tab>
228-
</Tabs>
235+
</LinkedTabs>
229236
230237
## `useDeleteMutation`
231238
232239
Delete an item by primary key(s). Requires the primary keys to be defined explicitly. Will also update the count of the queries.
233240
234-
<Tabs items={['SWR', 'React Query']}>
241+
<LinkedTabs items={['SWR', 'React Query']}
242+
id="data-fetcher"
243+
>
235244
<Tabs.Tab>
236245
```tsx
237246
import { useDeleteMutation } from '@supabase-cache-helpers/postgrest-swr'
@@ -280,4 +289,4 @@ Delete an item by primary key(s). Requires the primary keys to be defined explic
280289
```
281290
282291
</Tabs.Tab>
283-
</Tabs>
292+
</LinkedTabs>

0 commit comments

Comments
 (0)