From e80598d9cc5252b9abf0904676acd22fa012cbb1 Mon Sep 17 00:00:00 2001 From: Caleb Jacob Date: Mon, 12 Aug 2024 14:25:54 -0600 Subject: [PATCH] Implement to remove hard requirement / peer dep on next js --- README.md | 33 +++++- package.json | 3 +- pnpm-lock.yaml | 198 -------------------------------- src/components/Article.tsx | 4 +- src/components/Button.tsx | 3 +- src/components/Card.tsx | 3 +- src/components/CookiePrompt.tsx | 4 +- src/components/Dropdown.tsx | 6 +- src/components/Table.tsx | 3 +- src/components/Tabs.tsx | 12 +- src/context/PagodaUi.tsx | 25 ++++ src/index.ts | 5 + 12 files changed, 80 insertions(+), 219 deletions(-) create mode 100644 src/context/PagodaUi.tsx diff --git a/README.md b/README.md index 8b98aae..82e7611 100644 --- a/README.md +++ b/README.md @@ -6,18 +6,16 @@ A React component library that implements the official design system of NEAR and **React 18** -**Next JS >=13** - Some of our components rely on `next/link` and hooks like `router.push()`. We'll look into refactoring the library soon to remove the Next JS requirement so that our library can be used within any React framework. - **Zustand 4** - Our `openToast()` method is able to work in any context due to relying on a Zustand global store. ## Installation & Setup ```bash -pnpm add zustand next +pnpm add zustand pnpm add @near-pagoda/ui ``` -In your `_app.tsx` file, you'll need to import the following CSS files: +In your `_app.tsx` file, import the following CSS files in order: ```tsx import '@near-pagoda/ui/globals.css'; @@ -25,6 +23,33 @@ import '@near-pagoda/ui/theme.css'; import '@near-pagoda/ui/lib.css'; ``` +Wrap your application with the `` to pass in your framework's `` component and router methods. You'll also want to include the `` component to display toasts when calling `openToast()`: + +```tsx +import Link from 'next/link'; +import { useRouter } from 'next/router'; +import { PagodaUiProvider, Toaster } from '@near-pagoda/ui'; + +... + +const router = useRouter(); + +... + + + ... + + +``` + +Why is `` needed? Some of our components render anchor tags or dynamically change the current route. This provider allows our library to support any React framework (Vanilla/Vite, Next JS, etc) by passing in your router's components. + ## Documentation Please refer to `README.md` files in `src/components` for examples and documentation of components. diff --git a/package.json b/package.json index e1535fa..2422a26 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@near-pagoda/ui", - "version": "0.3.1", + "version": "1.0.0", "description": "A React component library that implements the official NEAR design system.", "license": "MIT", "repository": { @@ -57,7 +57,6 @@ } }, "peerDependencies": { - "next": ">=13", "react": "^18", "react-dom": "^18", "zustand": "^4" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f9e3c96..e79b10e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,9 +38,6 @@ importers: lodash-es: specifier: ^4.17.21 version: 4.17.21 - next: - specifier: '>=13' - version: 13.5.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8) react: specifier: ^18 version: 18.3.1 @@ -463,66 +460,9 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - '@next/env@13.5.6': - resolution: {integrity: sha512-Yac/bV5sBGkkEXmAX5FWPS9Mmo2rthrOPRQQNfycJPkjUAUclomCPH7QFVCDQ4Mp2k2K1SSM6m0zrxYrOwtFQw==} - '@next/eslint-plugin-next@14.2.5': resolution: {integrity: sha512-LY3btOpPh+OTIpviNojDpUdIbHW9j0JBYBjsIp8IxtDFfYFyORvw3yNq6N231FVqQA7n7lwaf7xHbVJlA1ED7g==} - '@next/swc-darwin-arm64@13.5.6': - resolution: {integrity: sha512-5nvXMzKtZfvcu4BhtV0KH1oGv4XEW+B+jOfmBdpFI3C7FrB/MfujRpWYSBBO64+qbW8pkZiSyQv9eiwnn5VIQA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@next/swc-darwin-x64@13.5.6': - resolution: {integrity: sha512-6cgBfxg98oOCSr4BckWjLLgiVwlL3vlLj8hXg2b+nDgm4bC/qVXXLfpLB9FHdoDu4057hzywbxKvmYGmi7yUzA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@next/swc-linux-arm64-gnu@13.5.6': - resolution: {integrity: sha512-txagBbj1e1w47YQjcKgSU4rRVQ7uF29YpnlHV5xuVUsgCUf2FmyfJ3CPjZUvpIeXCJAoMCFAoGnbtX86BK7+sg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-arm64-musl@13.5.6': - resolution: {integrity: sha512-cGd+H8amifT86ZldVJtAKDxUqeFyLWW+v2NlBULnLAdWsiuuN8TuhVBt8ZNpCqcAuoruoSWynvMWixTFcroq+Q==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-x64-gnu@13.5.6': - resolution: {integrity: sha512-Mc2b4xiIWKXIhBy2NBTwOxGD3nHLmq4keFk+d4/WL5fMsB8XdJRdtUlL87SqVCTSaf1BRuQQf1HvXZcy+rq3Nw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-linux-x64-musl@13.5.6': - resolution: {integrity: sha512-CFHvP9Qz98NruJiUnCe61O6GveKKHpJLloXbDSWRhqhkJdZD2zU5hG+gtVJR//tyW897izuHpM6Gtf6+sNgJPQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-win32-arm64-msvc@13.5.6': - resolution: {integrity: sha512-aFv1ejfkbS7PUa1qVPwzDHjQWQtknzAZWGTKYIAaS4NMtBlk3VyA6AYn593pqNanlicewqyl2jUhQAaFV/qXsg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@next/swc-win32-ia32-msvc@13.5.6': - resolution: {integrity: sha512-XqqpHgEIlBHvzwG8sp/JXMFkLAfGLqkbVsyN+/Ih1mR8INb6YCc2x/Mbwi6hsAgUnqQztz8cvEbHJUbSl7RHDg==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] - - '@next/swc-win32-x64-msvc@13.5.6': - resolution: {integrity: sha512-Cqfe1YmOS7k+5mGu92nl5ULkzpKuxJrP3+4AEuPmrpFZ3BHxTY3TnHmU1On3bFmFFs6FbTcdF58CCUProGpIGQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1037,9 +977,6 @@ packages: '@rushstack/eslint-patch@1.10.3': resolution: {integrity: sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg==} - '@swc/helpers@0.5.2': - resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==} - '@testing-library/dom@10.4.0': resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} engines: {node: '>=18'} @@ -1315,10 +1252,6 @@ packages: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} - busboy@1.6.0: - resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} - engines: {node: '>=10.16.0'} - cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -1361,9 +1294,6 @@ packages: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} - client-only@0.0.1: - resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -1916,9 +1846,6 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - glob-to-regexp@0.4.1: - resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.3.10: resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} engines: {node: '>=16 || 14 >=14.17'} @@ -2373,21 +2300,6 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - next@13.5.6: - resolution: {integrity: sha512-Y2wTcTbO4WwEsVb4A8VSnOsG1I9ok+h74q0ZdxkwM3EODqrs4pasq7O0iUxbcS9VtWMicG7f3+HAj0r1+NtKSw==} - engines: {node: '>=16.14.0'} - hasBin: true - peerDependencies: - '@opentelemetry/api': ^1.1.0 - react: ^18.2.0 - react-dom: ^18.2.0 - sass: ^1.3.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - sass: - optional: true - node-releases@2.0.18: resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} @@ -2929,10 +2841,6 @@ packages: postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} - engines: {node: ^10 || ^12 || >=14} - postcss@8.4.40: resolution: {integrity: sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==} engines: {node: ^10 || ^12 || >=14} @@ -3230,10 +3138,6 @@ packages: resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} engines: {node: '>= 0.4'} - streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} - string-hash@1.1.3: resolution: {integrity: sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==} @@ -3289,19 +3193,6 @@ packages: style-inject@0.3.0: resolution: {integrity: sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==} - styled-jsx@5.1.1: - resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} - engines: {node: '>= 12.0.0'} - peerDependencies: - '@babel/core': '*' - babel-plugin-macros: '*' - react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' - peerDependenciesMeta: - '@babel/core': - optional: true - babel-plugin-macros: - optional: true - stylehacks@5.1.1: resolution: {integrity: sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==} engines: {node: ^10 || ^12 || >=14.0} @@ -3524,10 +3415,6 @@ packages: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} - watchpack@2.4.0: - resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==} - engines: {node: '>=10.13.0'} - webidl-conversions@7.0.0: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} @@ -3893,39 +3780,10 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 - '@next/env@13.5.6': {} - '@next/eslint-plugin-next@14.2.5': dependencies: glob: 10.3.10 - '@next/swc-darwin-arm64@13.5.6': - optional: true - - '@next/swc-darwin-x64@13.5.6': - optional: true - - '@next/swc-linux-arm64-gnu@13.5.6': - optional: true - - '@next/swc-linux-arm64-musl@13.5.6': - optional: true - - '@next/swc-linux-x64-gnu@13.5.6': - optional: true - - '@next/swc-linux-x64-musl@13.5.6': - optional: true - - '@next/swc-win32-arm64-msvc@13.5.6': - optional: true - - '@next/swc-win32-ia32-msvc@13.5.6': - optional: true - - '@next/swc-win32-x64-msvc@13.5.6': - optional: true - '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -4414,10 +4272,6 @@ snapshots: '@rushstack/eslint-patch@1.10.3': {} - '@swc/helpers@0.5.2': - dependencies: - tslib: 2.6.3 - '@testing-library/dom@10.4.0': dependencies: '@babel/code-frame': 7.24.7 @@ -4742,10 +4596,6 @@ snapshots: builtin-modules@3.3.0: {} - busboy@1.6.0: - dependencies: - streamsearch: 1.1.0 - cac@6.7.14: {} call-bind@1.0.7: @@ -4802,8 +4652,6 @@ snapshots: clean-stack@2.2.0: {} - client-only@0.0.1: {} - cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -5571,8 +5419,6 @@ snapshots: dependencies: is-glob: 4.0.3 - glob-to-regexp@0.4.1: {} - glob@10.3.10: dependencies: foreground-child: 3.2.1 @@ -6015,32 +5861,6 @@ snapshots: natural-compare@1.4.0: {} - next@13.5.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8): - dependencies: - '@next/env': 13.5.6 - '@swc/helpers': 0.5.2 - busboy: 1.6.0 - caniuse-lite: 1.0.30001643 - postcss: 8.4.31 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - styled-jsx: 5.1.1(react@18.3.1) - watchpack: 2.4.0 - optionalDependencies: - '@next/swc-darwin-arm64': 13.5.6 - '@next/swc-darwin-x64': 13.5.6 - '@next/swc-linux-arm64-gnu': 13.5.6 - '@next/swc-linux-arm64-musl': 13.5.6 - '@next/swc-linux-x64-gnu': 13.5.6 - '@next/swc-linux-x64-musl': 13.5.6 - '@next/swc-win32-arm64-msvc': 13.5.6 - '@next/swc-win32-ia32-msvc': 13.5.6 - '@next/swc-win32-x64-msvc': 13.5.6 - sass: 1.77.8 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - node-releases@2.0.18: {} normalize-path@3.0.0: {} @@ -6572,12 +6392,6 @@ snapshots: postcss-value-parser@4.2.0: {} - postcss@8.4.31: - dependencies: - nanoid: 3.3.7 - picocolors: 1.0.1 - source-map-js: 1.2.0 - postcss@8.4.40: dependencies: nanoid: 3.3.7 @@ -6892,8 +6706,6 @@ snapshots: dependencies: internal-slot: 1.0.7 - streamsearch@1.1.0: {} - string-hash@1.1.3: {} string-width@4.2.3: @@ -6968,11 +6780,6 @@ snapshots: style-inject@0.3.0: {} - styled-jsx@5.1.1(react@18.3.1): - dependencies: - client-only: 0.0.1 - react: 18.3.1 - stylehacks@5.1.1(postcss@8.4.40): dependencies: browserslist: 4.23.2 @@ -7202,11 +7009,6 @@ snapshots: dependencies: xml-name-validator: 5.0.0 - watchpack@2.4.0: - dependencies: - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - webidl-conversions@7.0.0: {} whatwg-encoding@3.1.1: diff --git a/src/components/Article.tsx b/src/components/Article.tsx index 4d445d5..eec6146 100644 --- a/src/components/Article.tsx +++ b/src/components/Article.tsx @@ -1,6 +1,6 @@ -import Link from 'next/link'; import { ComponentProps, ReactNode } from 'react'; +import { usePagodaUi } from '../context/PagodaUi'; import s from './Article.module.scss'; type Props = { @@ -12,6 +12,8 @@ type Props = { }; export const Article = ({ alt, src, children, ...props }: Props) => { + const { Link } = usePagodaUi(); + return (
diff --git a/src/components/Button.tsx b/src/components/Button.tsx index 4403e37..ff347a1 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -1,7 +1,7 @@ -import Link from 'next/link'; import type { ComponentPropsWithRef, ReactElement } from 'react'; import { forwardRef } from 'react'; +import { usePagodaUi } from '../context/PagodaUi'; import s from './Button.module.scss'; type Fill = 'solid' | 'outline' | 'ghost'; @@ -40,6 +40,7 @@ export const Button = forwardRef( }, ref, ) => { + const { Link } = usePagodaUi(); const conditionalAttributes: Record = href ? { href, diff --git a/src/components/Card.tsx b/src/components/Card.tsx index aabc8a4..55ce37f 100644 --- a/src/components/Card.tsx +++ b/src/components/Card.tsx @@ -1,6 +1,6 @@ -import Link from 'next/link'; import { type ComponentPropsWithRef, forwardRef } from 'react'; +import { usePagodaUi } from '../context/PagodaUi'; import { ThemeColor } from '../utils/types'; import s from './Card.module.scss'; @@ -15,6 +15,7 @@ type Props = ComponentPropsWithRef<'div'> & { export const Card = forwardRef( ({ background = 'white', border = 'white', className = '', gap, padding, style, ...props }, ref) => { + const { Link } = usePagodaUi(); const Element: any = props.href ? Link : 'div'; return ( diff --git a/src/components/CookiePrompt.tsx b/src/components/CookiePrompt.tsx index 741fb6c..c46c53e 100644 --- a/src/components/CookiePrompt.tsx +++ b/src/components/CookiePrompt.tsx @@ -1,5 +1,4 @@ -import Link from 'next/link'; - +import { usePagodaUi } from '../context/PagodaUi'; import { useCookiePreferences } from '../hooks/cookies'; import { Button } from './Button'; import s from './CookiePrompt.module.scss'; @@ -11,6 +10,7 @@ type Props = { export const CookiePrompt = ({ cookiePolicyUrl = '/cookies' }: Props) => { const { cookiesPreference, setCookiesPreference } = useCookiePreferences(); + const { Link } = usePagodaUi(); if (cookiesPreference) return null; diff --git a/src/components/Dropdown.tsx b/src/components/Dropdown.tsx index aff637f..4310a9a 100644 --- a/src/components/Dropdown.tsx +++ b/src/components/Dropdown.tsx @@ -1,9 +1,9 @@ import { CaretDown } from '@phosphor-icons/react'; import * as Primitive from '@radix-ui/react-dropdown-menu'; -import { useRouter } from 'next/router'; import type { ComponentProps, MouseEventHandler, ReactNode } from 'react'; import { forwardRef } from 'react'; +import { usePagodaUi } from '../context/PagodaUi'; import s from './Dropdown.module.scss'; import { SvgIcon } from './SvgIcon'; import { Text } from './Text'; @@ -43,14 +43,14 @@ export const Item = forwardRef< HTMLDivElement, ComponentProps & { external?: boolean; href?: string } >(({ external, href, ...props }, ref) => { - const router = useRouter(); + const { routerPush } = usePagodaUi(); const onClick: MouseEventHandler = (event) => { if (href) { if (event.metaKey || external) { window.open(href, '_blank'); } else { - router.push(href); + routerPush(href); } } }; diff --git a/src/components/Table.tsx b/src/components/Table.tsx index 90a78c3..bb20f22 100644 --- a/src/components/Table.tsx +++ b/src/components/Table.tsx @@ -1,8 +1,8 @@ import { CaretCircleDown, CaretCircleUp } from '@phosphor-icons/react'; -import Link from 'next/link'; import type { ComponentPropsWithRef, HTMLAttributeAnchorTarget, KeyboardEventHandler, ReactNode } from 'react'; import { forwardRef } from 'react'; +import { usePagodaUi } from '../context/PagodaUi'; import { Flex } from './Flex'; import { Placeholder } from './Placeholder'; import { SvgIcon } from './SvgIcon'; @@ -142,6 +142,7 @@ export const Cell = forwardRef( const isButton = !!props.onClick && !href; const role = isButton ? 'button' : undefined; const tabIndex = isButton ? (disabled ? -1 : 0) : undefined; + const { Link } = usePagodaUi(); const onKeyDown: KeyboardEventHandler = (event) => { if (event.key === 'Enter') { diff --git a/src/components/Tabs.tsx b/src/components/Tabs.tsx index 46d4015..07104b7 100644 --- a/src/components/Tabs.tsx +++ b/src/components/Tabs.tsx @@ -1,9 +1,9 @@ import * as Primitive from '@radix-ui/react-tabs'; -import { useRouter } from 'next/router'; import type { ComponentProps, ReactElement } from 'react'; import { forwardRef } from 'react'; import { useEffect, useRef } from 'react'; +import { usePagodaUi } from '../context/PagodaUi'; import { mergeRefs } from '../utils/merge-refs'; import s from './Tabs.module.scss'; @@ -39,13 +39,13 @@ Content.displayName = 'Content'; export const Trigger = forwardRef(({ children, href, iconLeft, ...props }, ref) => { const elementRef = useRef(null); - const router = useRouter(); + const { routerPush, routerPrefetch } = usePagodaUi(); useEffect(() => { if (href) { - router.prefetch(href); + routerPrefetch(href); } - }, [href, router]); + }, [href, routerPrefetch]); useEffect(() => { function onClick(event: MouseEvent) { @@ -53,7 +53,7 @@ export const Trigger = forwardRef(({ children, if (event.metaKey || event.ctrlKey) { window.open(href, '_blank'); } else { - router.push(href); + routerPush(href); } } } @@ -64,7 +64,7 @@ export const Trigger = forwardRef(({ children, return () => { el?.removeEventListener('click', onClick); }; - }, [href, router]); + }, [href, routerPush]); return ( diff --git a/src/context/PagodaUi.tsx b/src/context/PagodaUi.tsx new file mode 100644 index 0000000..e0f92b9 --- /dev/null +++ b/src/context/PagodaUi.tsx @@ -0,0 +1,25 @@ +import { type ComponentProps, createContext, type ReactNode, useContext } from 'react'; + +type PagodaUi = { + routerPrefetch: (path: string) => any; + routerPush: (path: string) => any; + Link: (props: { + children: ReactNode; + className?: string; + href: string; + target?: ComponentProps<'a'>['target']; + }) => ReactNode; +}; + +export const PagodaUiContext = createContext(null); + +export function usePagodaUi() { + const pagodaUi = useContext(PagodaUiContext); + + if (!pagodaUi) + throw new Error( + 'Pagoda UI context was not found within usePagodaUi(). Make sure to wrap your application with ', + ); + + return pagodaUi; +} diff --git a/src/index.ts b/src/index.ts index 3756145..c420945 100644 --- a/src/index.ts +++ b/src/index.ts @@ -50,3 +50,8 @@ export * from './utils/merge-refs'; export * from './utils/number'; export * from './utils/types'; export * from './utils/unreachable'; + +// Contexts + +import { PagodaUiContext } from './context/PagodaUi'; +export const PagodaUiProvider = PagodaUiContext.Provider;