Skip to content

Commit

Permalink
chore: WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
stipsan committed Nov 26, 2024
1 parent 0f6d429 commit c8fbf95
Show file tree
Hide file tree
Showing 14 changed files with 314 additions and 176 deletions.
2 changes: 2 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ public-hoist-pattern[]=sanity
; This is needed for prettier to be able to use the plugin specified by the `@sanity/prettier-config` preset
public-hoist-pattern[]=prettier-plugin-packagejson

public-hoist-pattern[]=@million/lint

prefer-workspace-packages = true
link-workspace-packages = deep
1 change: 1 addition & 0 deletions dev/test-studio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"react-compiler-runtime": "0.0.0-experimental-dc8bd44-20241121",
"react-dom": "^18.3.1",
"react-refractor": "^2.1.6",
"react-scan": "^0.0.29",
"refractor": "^3.6.0",
"rxjs": "^7.8.0",
"sanity": "workspace:*",
Expand Down
23 changes: 15 additions & 8 deletions dev/test-studio/sanity.cli.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import path from 'node:path'

import MillionLint from '@million/lint'
import {defineCliConfig} from 'sanity/cli'
import {type UserConfig} from 'vite'

Expand All @@ -12,19 +13,25 @@ export default defineCliConfig({
// Can be overriden by:
// A) `SANITY_STUDIO_REACT_STRICT_MODE=false pnpm dev`
// B) creating a `.env` file locally that sets the same env variable as above
reactStrictMode: true,
reactCompiler: {target: '18'},
// reactStrictMode: true,
// reactCompiler: {target: '18'},
vite(viteConfig: UserConfig): UserConfig {
const reactProductionProfiling = process.env.REACT_PRODUCTION_PROFILING === 'true'

return {
...viteConfig,
// plugins: [
// MillionLint.vite({
// telemetry: false,
// }),
// ...(viteConfig.plugins || []),
// ],
plugins: [
MillionLint.vite({
telemetry: false,

// dev: 'debug',
// stats: {
// captures: 1,
// components: 1,
// },
}),
...(viteConfig.plugins || []),
],
optimizeDeps: {
...viteConfig.optimizeDeps,
include: ['react/jsx-runtime'],
Expand Down
14 changes: 14 additions & 0 deletions dev/test-studio/sanity.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// eslint-disable-next-line import/no-extraneous-dependencies, simple-import-sort/imports
// import {scan} from 'react-scan' // import this BEFORE react

import {assist} from '@sanity/assist'
import {googleMapsInput} from '@sanity/google-maps-input'
import {BookIcon} from '@sanity/icons'
Expand Down Expand Up @@ -359,3 +362,14 @@ export default defineConfig([
basePath: '/presentation',
},
]) as WorkspaceOptions[]

// if (typeof window !== 'undefined') {
// scan({
// enabled: true,
// log: true, // logs render info to console (default: false)
// renderCountThreshold: 10,
// maxRenders: 20,
// report: true,
// includeChildren: true,
// })
// }
Empty file added diff.patch
Empty file.
2 changes: 1 addition & 1 deletion packages/sanity/src/_internal/cli/server/getEntryModule.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const entryModule = `
// This file is auto-generated on 'sanity dev'
// Modifications to this file is automatically discarded
import {renderStudio} from "sanity"
import studioConfig from %STUDIO_CONFIG_LOCATION%
import {renderStudio} from "sanity"
renderStudio(
document.getElementById("sanity"),
Expand Down
10 changes: 8 additions & 2 deletions packages/sanity/src/_singletons/context/HoveredFieldContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import {createContext} from 'sanity/_createContext'

/** @internal */
export interface HoveredFieldContextValue {
hoveredStack: string[]
store: {
subscribe: (onStoreCallback: () => void) => () => void
getSnapshot: () => string[]
}
onMouseEnter: (path: Path) => void
onMouseLeave: (path: Path) => void
}
Expand All @@ -12,7 +15,10 @@ export interface HoveredFieldContextValue {
export const HoveredFieldContext = createContext<HoveredFieldContextValue>(
'sanity/_singletons/context/hovered-field',
{
hoveredStack: [],
store: {
subscribe: () => () => undefined,
getSnapshot: () => [],
},
onMouseEnter: () => undefined,
onMouseLeave: () => undefined,
},
Expand Down
65 changes: 40 additions & 25 deletions packages/sanity/src/core/form/field/HoveredFieldProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,61 @@
import {type Path} from '@sanity/types'
import {memo, type PropsWithChildren, useCallback, useMemo, useState} from 'react'
import {memo, type PropsWithChildren, useCallback, useMemo, useRef, useState} from 'react'
import {HoveredFieldContext, type HoveredFieldContextValue} from 'sanity/_singletons'

import {pathToString} from '../../field'

/** @internal */
export const HoveredFieldProvider = memo(function HoveredFieldProvider(props: PropsWithChildren) {
const {children} = props
const [hoveredStack, setHoveredStack] = useState<string[]>([])

const handleMouseEnter = useCallback((path: Path) => {
const pathString = pathToString(path)

setHoveredStack((prev) => {
if (prev.includes(pathString)) {
return prev
const [listeners] = useState(() => new Set<() => void>())
const hoveredStackRef = useRef<string[]>([])

const handleMouseEnter = useCallback(
(path: Path) => {
const pathString = pathToString(path)
if (!hoveredStackRef.current.includes(pathString)) {
hoveredStackRef.current = [pathString, ...hoveredStackRef.current]
for (const listener of listeners) {
listener()
}
}
},
[listeners],
)

return [pathString, ...prev]
})
}, [])

const handleMouseLeave = useCallback((path: Path) => {
const pathString = pathToString(path)

setHoveredStack((prev) => {
if (prev.includes(pathString)) {
// eslint-disable-next-line max-nested-callbacks
return prev.filter((item) => item !== pathString)
const handleMouseLeave = useCallback(
(path: Path) => {
const pathString = pathToString(path)
if (hoveredStackRef.current.includes(pathString)) {
hoveredStackRef.current = hoveredStackRef.current.filter((item) => item !== pathString)
for (const listener of listeners) {
listener()
}
}
},
[listeners],
)

return prev
})
}, [])
const store = useMemo(
() => ({
subscribe: (onStoreChange: () => void) => {
listeners.add(onStoreChange)
return () => {
listeners.delete(onStoreChange)
}
},
getSnapshot: () => hoveredStackRef.current,
}),
[listeners],
)

const context: HoveredFieldContextValue = useMemo(
() => ({
hoveredStack,
store,
onMouseEnter: handleMouseEnter,
onMouseLeave: handleMouseLeave,
}),
[handleMouseEnter, handleMouseLeave, hoveredStack],
[handleMouseEnter, handleMouseLeave, store],
)

return <HoveredFieldContext.Provider value={context}>{children}</HoveredFieldContext.Provider>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {type Path} from '@sanity/types'
import {memo, type PropsWithChildren, useCallback, useMemo} from 'react'
import {memo, type PropsWithChildren, useCallback, useMemo, useSyncExternalStore} from 'react'
import {FieldActionsContext, type FieldActionsContextValue} from 'sanity/_singletons'

import {type DocumentFieldActionNode} from '../../../config'
Expand All @@ -18,10 +18,16 @@ export const FieldActionsProvider = memo(function FieldActionsProvider(
props: FieldActionsProviderProps,
) {
const {actions, children, path, focused} = props
const {onMouseEnter: onFieldMouseEnter, onMouseLeave: onFieldMouseLeave} = useHoveredField()

const hoveredPath = useHoveredField().hoveredStack[0]
const hovered = supportsTouch || (hoveredPath ? pathToString(path) === hoveredPath : false)
const {
onMouseEnter: onFieldMouseEnter,
onMouseLeave: onFieldMouseLeave,
store: hoveredStore,
} = useHoveredField()

const hovered = useSyncExternalStore(hoveredStore.subscribe, () => {
const [hoveredPath] = hoveredStore.getSnapshot()
return supportsTouch || (hoveredPath ? pathToString(path) === hoveredPath : false)
})

const handleMouseEnter = useCallback(() => {
onFieldMouseEnter(path)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function SearchWrapper({

const {
dispatch,
searchCommandList,
searchCommandListRef,
setOnClose,
state: {result},
} = useSearchState()
Expand All @@ -31,9 +31,24 @@ export function SearchWrapper({
* Store top-most search result scroll index on close
*/
const handleClose = useCallback(() => {
dispatch({index: searchCommandList?.getTopIndex() ?? -1, type: 'LAST_ACTIVE_INDEX_SET'})
dispatch({
index: searchCommandListRef.current?.getTopIndex() ?? -1,
type: 'LAST_ACTIVE_INDEX_SET',
})
onClose()
}, [dispatch, onClose, searchCommandList])
}, [dispatch, onClose, searchCommandListRef])
useEffect(() => {
handleClose && console.count('handleClose changed')
}, [handleClose])
useEffect(() => {
dispatch && console.count('dispatch changed')
}, [dispatch])
useEffect(() => {
onClose && console.count('onClose changed')
}, [onClose])
useEffect(() => {
searchCommandListRef && console.count('searchCommandListRef changed')
}, [searchCommandListRef])

/**
* Bind hotkeys to open action
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Card, Flex} from '@sanity/ui'
import {memo, useCallback} from 'react'
import {memo, useCallback, useEffect} from 'react'
import {styled} from 'styled-components'

import {CommandList, type CommandListRenderItemCallback} from '../../../../../../components'
Expand Down Expand Up @@ -64,6 +64,10 @@ export const SearchResults = memo(function SearchResults({
dispatch({type: 'PAGE_INCREMENT'})
}, [dispatch])

// useEffect(() => {
// onClose && console.count('onClose changed')
// }, [onClose])

const renderItem = useCallback<CommandListRenderItemCallback<WeightedHit>>(
(item) => {
return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {type Dispatch, type SetStateAction} from 'react'
import {type Dispatch, type RefObject, type SetStateAction} from 'react'

import {type CommandListHandle} from '../../../../../../components/commandList/types'
import {type SearchAction, type SearchReducerState} from './reducer'
Expand All @@ -11,6 +11,7 @@ export interface SearchContextValue {
onClose: (() => void) | null
searchCommandList: CommandListHandle | null
setSearchCommandList: Dispatch<SetStateAction<CommandListHandle | null>>
searchCommandListRef: RefObject<CommandListHandle | null>
setOnClose: (onClose: () => void) => void
state: SearchReducerState
}
Loading

0 comments on commit c8fbf95

Please sign in to comment.