Skip to content

Commit c83baa8

Browse files
committed
feat: use react compiler
1 parent 353332a commit c83baa8

File tree

12 files changed

+228
-269
lines changed

12 files changed

+228
-269
lines changed

.eslintrc.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ module.exports = {
9090
'react/prop-types': 'off',
9191
'react-hooks/exhaustive-deps': 'error', // Checks effect dependencies
9292
'react-hooks/rules-of-hooks': 'error', // Checks rules of Hooks
93-
'react-compiler/react-compiler': 'warn', // Set to error once existing warnings are fixed
93+
'react-compiler/react-compiler': 'error',
9494
'react/no-unescaped-entities': 'off',
9595
'no-restricted-imports': [
9696
'error',

.github/workflows/main.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jobs:
3838
- run: pnpm install
3939
- name: Register Problem Matcher for ESLint that handles -f compact and shows warnings and errors inline on PRs
4040
run: echo "::add-matcher::.github/eslint-compact.json"
41-
- run: "pnpm lint -f compact --rule 'no-warning-comments: [off]' --max-warnings 6"
41+
- run: "pnpm lint -f compact --rule 'no-warning-comments: [off]' --max-warnings 0"
4242

4343
test:
4444
needs: [build]

package.config.ts

+19-1
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,23 @@ export default defineConfig({
1515
},
1616
tsconfig: 'tsconfig.dist.json',
1717
babel: {reactCompiler: true},
18-
reactCompilerOptions: {target: '18'},
18+
reactCompilerOptions: {
19+
target: '18',
20+
logger: {
21+
logEvent(filename, event) {
22+
/* eslint-disable no-console */
23+
if (event.kind === 'CompileError') {
24+
console.group(`[${filename}] ${event.kind}`)
25+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
26+
const {reason, description, severity, loc, suggestions} = event.detail as any
27+
28+
console.error(`[${severity}] ${reason}`)
29+
console.log(`${filename}:${loc.start?.line}:${loc.start?.column} ${description}`)
30+
console.log(suggestions)
31+
32+
console.groupEnd()
33+
}
34+
},
35+
},
36+
},
1937
})

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sanity/ui",
3-
"version": "2.8.21",
3+
"version": "2.9.0-canary.6",
44
"keywords": [
55
"sanity",
66
"ui",

src/core/components/breadcrumbs/breadcrumbs.tsx

+35-47
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,4 @@
1-
import {
2-
Children,
3-
forwardRef,
4-
Fragment,
5-
isValidElement,
6-
useCallback,
7-
useMemo,
8-
useRef,
9-
useState,
10-
} from 'react'
1+
import {Children, forwardRef, Fragment, isValidElement, useCallback, useRef, useState} from 'react'
112
import {useArrayProp, useClickOutsideEvent} from '../../hooks'
123
import {Box, Popover, Stack, Text} from '../../primitives'
134
import {ExpandButton, Root} from './breadcrumbs.styles'
@@ -39,46 +30,43 @@ export const Breadcrumbs = forwardRef(function Breadcrumbs(
3930

4031
useClickOutsideEvent(collapse, () => [expandElementRef.current, popoverElementRef.current])
4132

42-
const rawItems = useMemo(() => Children.toArray(children).filter(isValidElement), [children])
33+
const rawItems = Children.toArray(children).filter(isValidElement)
4334

44-
const items = useMemo(() => {
45-
const len = rawItems.length
35+
let items = rawItems
36+
const len = rawItems.length
4637

47-
if (maxLength && len > maxLength) {
48-
const beforeLength = Math.ceil(maxLength / 2)
49-
const afterLength = Math.floor(maxLength / 2)
38+
if (maxLength && rawItems.length > maxLength) {
39+
const beforeLength = Math.ceil(maxLength / 2)
40+
const afterLength = Math.floor(maxLength / 2)
5041

51-
return [
52-
...rawItems.slice(0, beforeLength - 1),
53-
<Popover
54-
constrainSize
55-
content={
56-
<Stack as="ol" overflow="auto" padding={space} space={space}>
57-
{rawItems.slice(beforeLength - 1, len - afterLength)}
58-
</Stack>
59-
}
60-
key="button"
61-
open={open}
62-
placement="top"
63-
portal
64-
ref={popoverElementRef}
65-
>
66-
<ExpandButton
67-
fontSize={1}
68-
mode="bleed"
69-
onClick={open ? collapse : expand}
70-
padding={1}
71-
ref={expandElementRef}
72-
selected={open}
73-
text="…"
74-
/>
75-
</Popover>,
76-
...rawItems.slice(len - afterLength),
77-
]
78-
}
79-
80-
return rawItems
81-
}, [collapse, expand, maxLength, open, rawItems, space])
42+
items = [
43+
...rawItems.slice(0, beforeLength - 1),
44+
<Popover
45+
constrainSize
46+
content={
47+
<Stack as="ol" overflow="auto" padding={space} space={space}>
48+
{rawItems.slice(beforeLength - 1, len - afterLength)}
49+
</Stack>
50+
}
51+
key="button"
52+
open={open}
53+
placement="top"
54+
portal
55+
ref={popoverElementRef}
56+
>
57+
<ExpandButton
58+
fontSize={1}
59+
mode="bleed"
60+
onClick={open ? collapse : expand}
61+
padding={1}
62+
ref={expandElementRef}
63+
selected={open}
64+
text="…"
65+
/>
66+
</Popover>,
67+
...rawItems.slice(len - afterLength),
68+
]
69+
}
8270

8371
return (
8472
<Root data-ui="Breadcrumbs" {...restProps} ref={ref}>

src/core/components/menu/useMenuController.ts

+18-21
Original file line numberDiff line numberDiff line change
@@ -36,31 +36,28 @@ export function useMenuController(props: {
3636
activeIndexRef.current = nextActiveIndex
3737
}, [])
3838

39-
const mount = useCallback(
40-
(element: HTMLElement | null, selected?: boolean): (() => void) => {
41-
if (!element) return () => undefined
39+
const mount = (element: HTMLElement | null, selected?: boolean): (() => void) => {
40+
if (!element) return () => undefined
4241

43-
if (elementsRef.current.indexOf(element) === -1) {
44-
elementsRef.current.push(element)
45-
_sortElements(rootElementRef.current, elementsRef.current)
46-
}
42+
if (elementsRef.current.indexOf(element) === -1) {
43+
elementsRef.current.push(element)
44+
_sortElements(rootElementRef.current, elementsRef.current)
45+
}
4746

48-
if (selected) {
49-
const selectedIndex = elementsRef.current.indexOf(element)
47+
if (selected) {
48+
const selectedIndex = elementsRef.current.indexOf(element)
5049

51-
setActiveIndex(selectedIndex)
52-
}
50+
setActiveIndex(selectedIndex)
51+
}
5352

54-
return () => {
55-
const idx = elementsRef.current.indexOf(element)
53+
return () => {
54+
const idx = elementsRef.current.indexOf(element)
5655

57-
if (idx > -1) {
58-
elementsRef.current.splice(idx, 1)
59-
}
56+
if (idx > -1) {
57+
elementsRef.current.splice(idx, 1)
6058
}
61-
},
62-
[rootElementRef, setActiveIndex],
63-
)
59+
}
60+
}
6461

6562
const handleKeyDown = useCallback(
6663
(event: React.KeyboardEvent<HTMLDivElement>) => {
@@ -170,15 +167,15 @@ export function useMenuController(props: {
170167
[setActiveIndex],
171168
)
172169

173-
const handleItemMouseLeave = useCallback(() => {
170+
const handleItemMouseLeave = () => {
174171
// Set the active index to -2 to deactivate all menu items
175172
// when the user moves the mouse away from the menu item.
176173
// We avoid using -1 because it would focus the first menu item,
177174
// which would be incorrect when the user hovers over a gap
178175
// between two menu items or a menu divider.
179176
setActiveIndex(-2)
180177
rootElementRef.current?.focus()
181-
}, [rootElementRef, setActiveIndex])
178+
}
182179

183180
// Set focus on the currently active element
184181
useEffect(() => {

src/core/components/tree/treeItem.tsx

+18-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {ToggleArrowRightIcon} from '@sanity/icons'
22
import {ThemeFontWeightKey} from '@sanity/ui/theme'
3-
import {memo, useCallback, useEffect, useId, useMemo, useRef} from 'react'
3+
import {memo, useCallback, useEffect, useId, useMemo, useRef, useState} from 'react'
44
import {styled} from 'styled-components'
55
import {Box, BoxProps, Flex, Text} from '../../primitives'
66
import {
@@ -64,18 +64,21 @@ export const TreeItem = memo(function TreeItem(
6464
weight,
6565
...restProps
6666
} = props
67-
const rootRef = useRef<HTMLLIElement | null>(null)
67+
const [rootElement, setRootElement] = useState<HTMLLIElement | null>(null)
6868
const treeitemRef = useRef<HTMLDivElement | null>(null)
6969
const tree = useTree()
7070
const {path, registerItem, setExpanded, setFocusedElement} = tree
7171
const _id = useId()
7272
const id = idProp || _id
73-
const itemPath = useMemo(() => path.concat([id || '']), [id, path])
74-
const itemKey = itemPath.join('/')
73+
const [itemPath, itemKey] = useMemo(() => {
74+
const result = path.concat([id || ''])
75+
76+
return [result, result.join('/')]
77+
}, [id, path])
7578
const itemState = tree.state[itemKey]
76-
const focused = tree.focusedElement === rootRef.current
79+
const focused = tree.focusedElement === rootElement
7780
const expanded = itemState?.expanded === undefined ? expandedProp : itemState?.expanded || false
78-
const tabIndex = tree.focusedElement && tree.focusedElement === rootRef.current ? 0 : -1
81+
const tabIndex = tree.focusedElement && tree.focusedElement === rootElement ? 0 : -1
7982
const contextValue = useMemo(
8083
() => ({...tree, level: tree.level + 1, path: itemPath}),
8184
[itemPath, tree],
@@ -94,28 +97,28 @@ export const TreeItem = memo(function TreeItem(
9497
) {
9598
event.stopPropagation()
9699
setExpanded(itemKey, !expanded)
97-
setFocusedElement(rootRef.current)
100+
setFocusedElement(rootElement)
98101
}
99102
},
100-
[expanded, itemKey, onClick, setExpanded, setFocusedElement],
103+
[expanded, itemKey, onClick, rootElement, setExpanded, setFocusedElement],
101104
)
102105

103106
const handleKeyDown = useCallback(
104107
(event: React.KeyboardEvent<HTMLElement>) => {
105108
if (focused && event.key === 'Enter') {
106-
const el = treeitemRef.current || rootRef.current
109+
const el = treeitemRef.current || rootElement
107110

108111
el?.click()
109112
}
110113
},
111-
[focused],
114+
[focused, rootElement],
112115
)
113116

114117
useEffect(() => {
115-
if (!rootRef.current) return
118+
if (!rootElement) return
116119

117-
return registerItem(rootRef.current, itemPath.join('/'), expanded, selected)
118-
}, [expanded, itemPath, registerItem, selected])
120+
return registerItem(rootElement, itemPath.join('/'), expanded, selected)
121+
}, [expanded, itemPath, registerItem, rootElement, selected])
119122

120123
const content = (
121124
<Flex padding={padding}>
@@ -154,7 +157,7 @@ export const TreeItem = memo(function TreeItem(
154157
data-ui="TreeItem"
155158
{...restProps}
156159
onClick={handleClick}
157-
ref={rootRef}
160+
ref={setRootElement}
158161
role="none"
159162
>
160163
<TreeItemBox
@@ -187,7 +190,7 @@ export const TreeItem = memo(function TreeItem(
187190
aria-expanded={expanded}
188191
onClick={handleClick}
189192
onKeyDown={handleKeyDown}
190-
ref={rootRef}
193+
ref={setRootElement}
191194
role="treeitem"
192195
tabIndex={tabIndex}
193196
>

src/core/hooks/useMatchMedia.ts

+12-22
Original file line numberDiff line numberDiff line change
@@ -11,34 +11,24 @@ export function useMatchMedia(
1111
mediaQueryString: `(${string})`,
1212
getServerSnapshot?: () => boolean,
1313
): boolean {
14+
/**
15+
* `subscribe` and `getSnapshot` are only called on the client and both need access to the same `matchMedia` instance
16+
* we don't want to eagerly instantiate it to ensure it's only created when actually used
17+
*/
18+
const cachedMatchMedia = useMemo(
19+
() => (typeof window === 'undefined' ? null : window.matchMedia(mediaQueryString)),
20+
[mediaQueryString],
21+
)
1422
const {subscribe, getSnapshot} = useMemo(() => {
15-
/**
16-
* `subscribe` and `getSnapshot` are only called on the client and both need access to the same `matchMedia` instance
17-
* we don't want to eagerly instantiate it to ensure it's only created when actually used
18-
*/
19-
let MEDIA_QUERY_CACHE: MediaQueryList | undefined
20-
21-
const getMatchMedia = (): MediaQueryList => {
22-
if (!MEDIA_QUERY_CACHE) {
23-
// As this function is only called during `subscribe` and `getSnapshot`, we can assume that the
24-
// the `window` global is available and we're in a browser environment
25-
MEDIA_QUERY_CACHE = window.matchMedia(mediaQueryString)
26-
}
27-
28-
return MEDIA_QUERY_CACHE
29-
}
30-
3123
return {
3224
subscribe: (onStoreChange: () => void): (() => void) => {
33-
const matchMedia = getMatchMedia()
34-
35-
matchMedia.addEventListener('change', onStoreChange)
25+
cachedMatchMedia!.addEventListener('change', onStoreChange)
3626

37-
return () => matchMedia.removeEventListener('change', onStoreChange)
27+
return () => cachedMatchMedia!.removeEventListener('change', onStoreChange)
3828
},
39-
getSnapshot: () => getMatchMedia().matches,
29+
getSnapshot: () => cachedMatchMedia!.matches,
4030
}
41-
}, [mediaQueryString])
31+
}, [cachedMatchMedia])
4232

4333
useDebugValue(mediaQueryString)
4434

0 commit comments

Comments
 (0)