-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove dependency to reach-ui
#1002
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@ag.ds-next/react': minor | ||
--- | ||
|
||
Removed dependency to Reach UI as it is no longer being maintained. The logic from `@reach/auto-id` has been forked and copied into the repo. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// The contents of this file has been copied from https://github.com/reach/reach-ui/blob/dev/packages/utils/src/can-use-dom.ts | ||
|
||
export function canUseDOM() { | ||
return !!( | ||
typeof window !== 'undefined' && | ||
window.document && | ||
window.document.createElement | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { useId } from './useId'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// The contents of this file has been copied from https://github.com/reach/reach-ui/blob/dev/packages/auto-id/__tests__/auto-id.test.tsx | ||
|
||
import { render, cleanup } from '../../../../../../test-utils'; | ||
import { useId } from './useId'; | ||
|
||
afterEach(cleanup); | ||
|
||
describe('useId', () => { | ||
it('should generate a unique ID value', () => { | ||
function Comp() { | ||
const justNull = null; | ||
const randId = useId(justNull); | ||
const randId2 = useId(); | ||
return ( | ||
<div> | ||
<div id={randId}>Wow</div> | ||
<div id={randId2}>Ok</div> | ||
</div> | ||
); | ||
} | ||
const { getByText } = render(<Comp />); | ||
const id1 = getByText('Wow').id; | ||
const id2 = getByText('Ok').id; | ||
expect(id2).not.toEqual(id1); | ||
}); | ||
|
||
it('uses a fallback ID', () => { | ||
function Comp() { | ||
const newId = useId('awesome'); | ||
return <div id={newId}>Ok</div>; | ||
} | ||
const { getByText } = render(<Comp />); | ||
expect(getByText('Ok').id).toEqual('awesome'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/** | ||
* This file use to just be a simple re-export of `useId` from @reach/auto-id | ||
* We can not just use `useId` from React as we need to provide support for React 16, 17 and 18 | ||
* | ||
* As Reach is no longer being maintained and does not support React 18, the contents of this file have been copied from: | ||
* https://github.com/reach/reach-ui/blob/dev/packages/auto-id/src/reach-auto-id.ts | ||
* | ||
* See Github issue: https://github.com/reach/reach-ui/issues/972 | ||
*/ | ||
|
||
/** | ||
* Welcome to @reach/auto-id! | ||
* Let's see if we can make sense of why this hook exists and its | ||
* implementation. | ||
* | ||
* Some background: | ||
* 1. Accessibility APIs rely heavily on element IDs | ||
* 2. Requiring developers to put IDs on every element in Reach UI is both | ||
* cumbersome and error-prone | ||
* 3. With a component model, we can generate IDs for them! | ||
* | ||
* Solution 1: Generate random IDs. | ||
* | ||
* This works great as long as you don't server render your app. When React (in | ||
* the client) tries to reuse the markup from the server, the IDs won't match | ||
* and React will then recreate the entire DOM tree. | ||
* | ||
* Solution 2: Increment an integer | ||
* | ||
* This sounds great. Since we're rendering the exact same tree on the server | ||
* and client, we can increment a counter and get a deterministic result between | ||
* client and server. Also, JS integers can go up to nine-quadrillion. I'm | ||
* pretty sure the tab will be closed before an app never needs | ||
* 10 quadrillion IDs! | ||
* | ||
* Problem solved, right? | ||
* | ||
* Ah, but there's a catch! React's concurrent rendering makes this approach | ||
* non-deterministic. While the client and server will end up with the same | ||
* elements in the end, depending on suspense boundaries (and possibly some user | ||
* input during the initial render) the incrementing integers won't always match | ||
* up. | ||
* | ||
* Solution 3: Don't use IDs at all on the server; patch after first render. | ||
* | ||
* What we've done here is solution 2 with some tricks. With this approach, the | ||
* ID returned is an empty string on the first render. This way the server and | ||
* client have the same markup no matter how wild the concurrent rendering may | ||
* have gotten. | ||
* | ||
* After the render, we patch up the components with an incremented ID. This | ||
* causes a double render on any components with `useId`. Shouldn't be a problem | ||
* since the components using this hook should be small, and we're only updating | ||
* the ID attribute on the DOM, nothing big is happening. | ||
* | ||
* It doesn't have to be an incremented number, though--we could do generate | ||
* random strings instead, but incrementing a number is probably the cheapest | ||
* thing we can do. | ||
* | ||
* Additionally, we only do this patchup on the very first client render ever. | ||
* Any calls to `useId` that happen dynamically in the client will be | ||
* populated immediately with a value. So, we only get the double render after | ||
* server hydration and never again, SO BACK OFF ALRIGHT? | ||
*/ | ||
|
||
/* eslint-disable react-hooks/rules-of-hooks */ | ||
|
||
import * as React from 'react'; | ||
import { useIsomorphicLayoutEffect as useLayoutEffect } from './useIsomorphicLayoutEffect'; | ||
|
||
let serverHandoffComplete = false; | ||
let id = 0; | ||
function genId() { | ||
return ++id; | ||
} | ||
|
||
// Workaround for https://github.com/webpack/webpack/issues/14814 | ||
// https://github.com/eps1lon/material-ui/blob/8d5f135b4d7a58253a99ab56dce4ac8de61f5dc1/packages/mui-utils/src/useId.ts#L21 | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const maybeReactUseId: undefined | (() => string) = (React as any)[ | ||
'useId'.toString() | ||
]; | ||
|
||
/** | ||
* useId | ||
* | ||
* Autogenerate IDs to facilitate WAI-ARIA and server rendering. | ||
* | ||
* Note: The returned ID will initially be `null` and will update after a | ||
* component mounts. Users may need to supply their own ID if they need | ||
* consistent values for SSR. | ||
* | ||
* @see Docs https://reach.tech/auto-id | ||
*/ | ||
function useId(idFromProps: string): string; | ||
function useId(idFromProps: number): number; | ||
function useId(idFromProps: string | number): string | number; | ||
function useId(idFromProps: string | undefined | null): string | undefined; | ||
function useId(idFromProps: number | undefined | null): number | undefined; | ||
function useId( | ||
idFromProps: string | number | undefined | null | ||
): string | number | undefined; | ||
function useId(): string | undefined; | ||
|
||
function useId(providedId?: number | string | undefined | null) { | ||
if (maybeReactUseId !== undefined) { | ||
const generatedId = maybeReactUseId(); | ||
return providedId ?? generatedId; | ||
} | ||
|
||
// If this instance isn't part of the initial render, we don't have to do the | ||
// double render/patch-up dance. We can just generate the ID and return it. | ||
const initialId = providedId ?? (serverHandoffComplete ? genId() : null); | ||
const [id, setId] = React.useState(initialId); | ||
|
||
useLayoutEffect(() => { | ||
if (id === null) { | ||
// Patch the ID after render. We do this in `useLayoutEffect` to avoid any | ||
// rendering flicker, though it'll make the first render slower (unlikely | ||
// to matter, but you're welcome to measure your app and let us know if | ||
// it's a problem). | ||
setId(genId()); | ||
} | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, []); | ||
|
||
React.useEffect(() => { | ||
if (serverHandoffComplete === false) { | ||
// Flag all future uses of `useId` to skip the update dance. This is in | ||
// `useEffect` because it goes after `useLayoutEffect`, ensuring we don't | ||
// accidentally bail out of the patch-up dance prematurely. | ||
serverHandoffComplete = true; | ||
} | ||
}, []); | ||
|
||
return providedId ?? id ?? undefined; | ||
} | ||
|
||
export { useId }; |
32 changes: 32 additions & 0 deletions
32
packages/react/src/core/utils/useId/useIsomorphicLayoutEffect.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// The contents of this file has been copied from https://github.com/reach/reach-ui/blob/dev/packages/utils/src/use-isomorphic-layout-effect.ts | ||
|
||
import { useEffect, useLayoutEffect } from 'react'; | ||
import { canUseDOM } from './canUseDom'; | ||
|
||
/** | ||
* React currently throws a warning when using useLayoutEffect on the server. To | ||
* get around it, we can conditionally useEffect on the server (no-op) and | ||
* useLayoutEffect in the browser. We occasionally need useLayoutEffect to | ||
* ensure we don't get a render flash for certain operations, but we may also | ||
* need affected components to render on the server. One example is when setting | ||
* a component's descendants to retrieve their index values. | ||
* | ||
* Important to note that using this hook as an escape hatch will break the | ||
* eslint dependency warnings unless you rename the import to `useLayoutEffect`. | ||
* Use sparingly only when the effect won't effect the rendered HTML to avoid | ||
* any server/client mismatch. | ||
* | ||
* If a useLayoutEffect is needed and the result would create a mismatch, it's | ||
* likely that the component in question shouldn't be rendered on the server at | ||
* all, so a better approach would be to lazily render those in a parent | ||
* component after client-side hydration. | ||
* | ||
* https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85 | ||
* https://github.com/reduxjs/react-redux/blob/master/src/utils/useIsomorphicLayoutEffect.js | ||
* | ||
* @param effect | ||
* @param deps | ||
*/ | ||
export const useIsomorphicLayoutEffect = canUseDOM() | ||
? useLayoutEffect | ||
: useEffect; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2253,18 +2253,6 @@ | |
resolved "https://registry.yarnpkg.com/@preconstruct/next/-/next-4.0.0.tgz#4d9c64ed68bb7cdc72d35d79d1dbe26ba2cae61e" | ||
integrity sha512-vSrc8wFQgBErU7dKTKSQtr/DLWPHcN9jMoiWOAQodB1+B4Kpqqry6QhGYoRm0DQU5gNL+Rcp+Xb350O1E/gjsg== | ||
|
||
"@reach/auto-id@^0.18.0": | ||
version "0.18.0" | ||
resolved "https://registry.yarnpkg.com/@reach/auto-id/-/auto-id-0.18.0.tgz#4b97085cd1cf1360a9bedc6e9c78e97824014f0d" | ||
integrity sha512-XwY1IwhM7mkHZFghhjiqjQ6dstbOdpbFLdggeke75u8/8icT8uEHLbovFUgzKjy9qPvYwZIB87rLiR8WdtOXCg== | ||
dependencies: | ||
"@reach/utils" "0.18.0" | ||
|
||
"@reach/[email protected]": | ||
version "0.18.0" | ||
resolved "https://registry.yarnpkg.com/@reach/utils/-/utils-0.18.0.tgz#4f3cebe093dd436eeaff633809bf0f68f4f9d2ee" | ||
integrity sha512-KdVMdpTgDyK8FzdKO9SCpiibuy/kbv3pwgfXshTI6tEcQT1OOwj7BAksnzGC0rPz0UholwC+AgkqEl3EJX3M1A== | ||
|
||
"@react-spring/animated@~9.4.5": | ||
version "9.4.5" | ||
resolved "https://registry.yarnpkg.com/@react-spring/animated/-/animated-9.4.5.tgz#dd9921c716a4f4a3ed29491e0c0c9f8ca0eb1a54" | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have an
any
warning here. Is that going to annoy us going forward?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point, I've just added an
eslint-disable-next-line @typescript-eslint/no-explicit-any
above this line