From 0c50cf00a69d9c846af58173b6147d95860cbc4a Mon Sep 17 00:00:00 2001 From: Cody Olsen Date: Mon, 11 Nov 2024 23:05:32 +0100 Subject: [PATCH] fix(performance): improve `useArrayProp` memoization --- .eslintrc.js | 13 -------- .github/workflows/main.yml | 2 +- package.json | 2 +- .../components/autocomplete/autocomplete.tsx | 2 +- .../components/breadcrumbs/breadcrumbs.tsx | 3 +- src/core/components/dialog/dialog.tsx | 8 ++--- src/core/components/hotkeys/hotkeys.tsx | 2 +- src/core/components/menu/menuGroup.tsx | 2 +- src/core/components/menu/menuItem.tsx | 2 +- src/core/components/skeleton/skeleton.tsx | 2 +- src/core/components/skeleton/textSkeleton.tsx | 2 +- src/core/hooks/index.ts | 2 +- src/core/hooks/useArrayProp.ts | 14 +++++---- src/core/hooks/useArrayPropLegacy.ts | 30 +++++++++++++++++++ src/core/primitives/avatar/avatar.tsx | 2 +- src/core/primitives/avatar/avatarCounter.tsx | 2 +- src/core/primitives/avatar/avatarStack.tsx | 2 +- src/core/primitives/badge/badge.tsx | 2 +- src/core/primitives/box/box.tsx | 2 +- src/core/primitives/button/button.tsx | 2 +- src/core/primitives/card/card.tsx | 2 +- src/core/primitives/code/code.tsx | 2 +- src/core/primitives/container/container.tsx | 2 +- src/core/primitives/flex/flex.tsx | 2 +- src/core/primitives/grid/grid.tsx | 2 +- src/core/primitives/heading/heading.tsx | 2 +- src/core/primitives/inline/inline.tsx | 2 +- src/core/primitives/kbd/kbd.tsx | 2 +- src/core/primitives/label/label.tsx | 2 +- src/core/primitives/popover/popover.tsx | 3 +- src/core/primitives/select/select.tsx | 3 +- src/core/primitives/stack/stack.tsx | 2 +- src/core/primitives/text/text.tsx | 2 +- src/core/primitives/textArea/textArea.tsx | 3 +- src/core/primitives/textInput/textInput.tsx | 3 +- src/core/primitives/tooltip/tooltip.tsx | 3 +- src/core/styles/helpers.ts | 4 +-- src/core/utils/layer/layerProvider.tsx | 3 +- src/core/utils/portal/portalProvider.tsx | 18 ++++++----- 39 files changed, 92 insertions(+), 68 deletions(-) create mode 100644 src/core/hooks/useArrayPropLegacy.ts diff --git a/.eslintrc.js b/.eslintrc.js index 127f563e7..7d53fd00f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -36,8 +36,6 @@ module.exports = { ], rules: { '@typescript-eslint/explicit-module-boundary-types': 'error', - '@typescript-eslint/interface-name-prefix': 'off', - '@typescript-eslint/member-delimiter-style': 'off', '@typescript-eslint/no-empty-interface': 'off', 'boundaries/element-types': [ 'error', @@ -76,17 +74,6 @@ module.exports = { ], 'no-console': 'error', 'no-warning-comments': ['warn', {location: 'start', terms: ['todo', '@todo', 'fixme']}], - 'padding-line-between-statements': [ - 'warn', - {blankLine: 'always', prev: '*', next: 'block'}, - {blankLine: 'always', prev: '*', next: 'block-like'}, - {blankLine: 'always', prev: 'const', next: 'expression'}, - {blankLine: 'always', prev: 'let', next: 'expression'}, - {blankLine: 'always', prev: 'var', next: 'expression'}, - {blankLine: 'always', prev: 'block', next: '*'}, - {blankLine: 'always', prev: 'block-like', next: '*'}, - {blankLine: 'always', prev: '*', next: 'return'}, - ], 'react/prop-types': 'off', 'react-hooks/exhaustive-deps': 'error', // Checks effect dependencies 'react-hooks/rules-of-hooks': 'error', // Checks rules of Hooks diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 44f3a78f4..ca2251ae4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -38,7 +38,7 @@ jobs: - run: pnpm install - name: Register Problem Matcher for ESLint that handles -f compact and shows warnings and errors inline on PRs run: echo "::add-matcher::.github/eslint-compact.json" - - run: "pnpm lint -f compact --rule 'no-warning-comments: [off]' --max-warnings 33" + - run: "pnpm lint -f compact --rule 'no-warning-comments: [off]' --max-warnings 27" test: needs: [build] diff --git a/package.json b/package.json index 26104242e..7e2719351 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sanity/ui", - "version": "2.8.23", + "version": "2.8.24-canary.2", "keywords": [ "sanity", "ui", diff --git a/src/core/components/autocomplete/autocomplete.tsx b/src/core/components/autocomplete/autocomplete.tsx index 9677cc5d9..ff9310bbc 100644 --- a/src/core/components/autocomplete/autocomplete.tsx +++ b/src/core/components/autocomplete/autocomplete.tsx @@ -20,7 +20,7 @@ import { } from 'react' import {EMPTY_ARRAY, EMPTY_RECORD} from '../../constants' import {_hasFocus, _raf, focusFirstDescendant} from '../../helpers' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import { Box, BoxProps, diff --git a/src/core/components/breadcrumbs/breadcrumbs.tsx b/src/core/components/breadcrumbs/breadcrumbs.tsx index 4a184e444..a6e97bde8 100644 --- a/src/core/components/breadcrumbs/breadcrumbs.tsx +++ b/src/core/components/breadcrumbs/breadcrumbs.tsx @@ -8,7 +8,8 @@ import { useRef, useState, } from 'react' -import {useArrayProp, useClickOutsideEvent} from '../../hooks' +import {useClickOutsideEvent} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {Box, Popover, Stack, Text} from '../../primitives' import {ExpandButton, Root} from './breadcrumbs.styles' diff --git a/src/core/components/dialog/dialog.tsx b/src/core/components/dialog/dialog.tsx index 83bd88d2d..5e133d0b1 100644 --- a/src/core/components/dialog/dialog.tsx +++ b/src/core/components/dialog/dialog.tsx @@ -8,12 +8,8 @@ import { focusLastDescendant, isHTMLElement, } from '../../helpers' -import { - useArrayProp, - useClickOutsideEvent, - useGlobalKeyDown, - usePrefersReducedMotion, -} from '../../hooks' +import {useClickOutsideEvent, useGlobalKeyDown, usePrefersReducedMotion} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {Box, Button, Card, Container, Flex, Text} from '../../primitives' import {ResponsivePaddingProps, ResponsiveWidthProps} from '../../primitives/types' import {responsivePaddingStyle, ResponsivePaddingStyleProps} from '../../styles/internal' diff --git a/src/core/components/hotkeys/hotkeys.tsx b/src/core/components/hotkeys/hotkeys.tsx index a669ec9e7..b5d98d7ef 100644 --- a/src/core/components/hotkeys/hotkeys.tsx +++ b/src/core/components/hotkeys/hotkeys.tsx @@ -1,6 +1,6 @@ import {forwardRef} from 'react' import {styled} from 'styled-components' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {Inline, KBD} from '../../primitives' import {Radius} from '../../types' diff --git a/src/core/components/menu/menuGroup.tsx b/src/core/components/menu/menuGroup.tsx index 99abd4258..9950c9ef5 100644 --- a/src/core/components/menu/menuGroup.tsx +++ b/src/core/components/menu/menuGroup.tsx @@ -1,7 +1,7 @@ import {ChevronRightIcon} from '@sanity/icons' import {isValidElement, useCallback, useEffect, useState} from 'react' import {isValidElementType} from 'react-is' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {Box, Flex, Popover, PopoverProps, Text} from '../../primitives' import {Selectable} from '../../primitives/_selectable' import {useRootTheme} from '../../theme' diff --git a/src/core/components/menu/menuItem.tsx b/src/core/components/menu/menuItem.tsx index d1abcf69e..19149e9d9 100644 --- a/src/core/components/menu/menuItem.tsx +++ b/src/core/components/menu/menuItem.tsx @@ -9,7 +9,7 @@ import { useState, } from 'react' import {isValidElementType} from 'react-is' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {Box, Flex, Text} from '../../primitives' import {Selectable} from '../../primitives/_selectable' import {ResponsivePaddingProps, ResponsiveRadiusProps} from '../../primitives/types' diff --git a/src/core/components/skeleton/skeleton.tsx b/src/core/components/skeleton/skeleton.tsx index 3fc17a745..2e44b2dd8 100644 --- a/src/core/components/skeleton/skeleton.tsx +++ b/src/core/components/skeleton/skeleton.tsx @@ -1,6 +1,6 @@ import {forwardRef, useEffect, useState} from 'react' import {styled} from 'styled-components' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {Box} from '../../primitives' import {BoxProps, ResponsiveRadiusProps} from '../../primitives' import {responsiveRadiusStyle, ResponsiveRadiusStyleProps} from '../../styles/internal' diff --git a/src/core/components/skeleton/textSkeleton.tsx b/src/core/components/skeleton/textSkeleton.tsx index 9c7819de5..6ee7fa838 100644 --- a/src/core/components/skeleton/textSkeleton.tsx +++ b/src/core/components/skeleton/textSkeleton.tsx @@ -1,7 +1,7 @@ import {ThemeFontKey, getTheme_v2} from '@sanity/ui/theme' import {forwardRef} from 'react' import {styled} from 'styled-components' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {ThemeProps, _responsive} from '../../styles' import {Skeleton, SkeletonProps} from './skeleton' diff --git a/src/core/hooks/index.ts b/src/core/hooks/index.ts index f04844380..e11cdde69 100644 --- a/src/core/hooks/index.ts +++ b/src/core/hooks/index.ts @@ -1,4 +1,4 @@ -export * from './useArrayProp' +export * from './useArrayPropLegacy' export * from './useClickOutside' export * from './useClickOutsideEvent' export * from './useCustomValidity' diff --git a/src/core/hooks/useArrayProp.ts b/src/core/hooks/useArrayProp.ts index fe6855d1e..490afdcb9 100644 --- a/src/core/hooks/useArrayProp.ts +++ b/src/core/hooks/useArrayProp.ts @@ -10,21 +10,23 @@ export type ArrayPropPrimitive = string | number | boolean | undefined | null */ export function useArrayProp( val: T | T[] | undefined, - defaultVal?: T[], ): T[] { const [[cachedVal, cachedHash], setCache] = useState<[T[], string]>(() => [ - _getArrayProp(val, defaultVal), - JSON.stringify(val ?? defaultVal), + _getArrayProp(val), + JSON.stringify(val), ]) + let result = cachedVal - const hash = JSON.stringify(val ?? defaultVal) + const hash = JSON.stringify(val) if (hash !== cachedHash) { + const current = _getArrayProp(val) // If the cached hash has changed, update the cache right away. // Calling setState during render is fine in this case, and preferred over a useEffect loop // https://19.react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes - setCache([_getArrayProp(val, defaultVal), hash]) + setCache([current, hash]) + result = current } - return cachedVal + return result } diff --git a/src/core/hooks/useArrayPropLegacy.ts b/src/core/hooks/useArrayPropLegacy.ts new file mode 100644 index 000000000..42b8756e0 --- /dev/null +++ b/src/core/hooks/useArrayPropLegacy.ts @@ -0,0 +1,30 @@ +import {useArrayProp as useArrayPropHook, type ArrayPropPrimitive} from './useArrayProp' + +export type {ArrayPropPrimitive} + +/** + * This API might change. DO NOT USE IN PRODUCTION. + * @beta + */ +export function useArrayProp( + val: T | T[] | undefined, +): T[] +/** + * This API might change. DO NOT USE IN PRODUCTION. + * @beta + * @deprecated - use `useArrayProp(value ?? defaultValue)` instead of `useArrayProp(value, defaultValue)` + */ +export function useArrayProp( + val: T | T[] | undefined, + defaultVal: T[], +): T[] +/** + * This API might change. DO NOT USE IN PRODUCTION. + * @beta + */ +export function useArrayProp( + val: T | T[] | undefined, + defaultVal?: T[], +): T[] { + return useArrayPropHook(val ?? defaultVal) +} diff --git a/src/core/primitives/avatar/avatar.tsx b/src/core/primitives/avatar/avatar.tsx index 8fdc8dedc..81c8e02f4 100644 --- a/src/core/primitives/avatar/avatar.tsx +++ b/src/core/primitives/avatar/avatar.tsx @@ -2,7 +2,7 @@ import {ThemeColorAvatarColorKey} from '@sanity/ui/theme' import {forwardRef, useCallback, useEffect, useId, useMemo, useState} from 'react' import ReactIs from 'react-is' import {styled} from 'styled-components' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {useTheme_v2} from '../../theme' import {AvatarPosition, AvatarSize, AvatarStatus} from '../../types' import {Label} from '../label' diff --git a/src/core/primitives/avatar/avatarCounter.tsx b/src/core/primitives/avatar/avatarCounter.tsx index c4d792057..f762e1dc8 100644 --- a/src/core/primitives/avatar/avatarCounter.tsx +++ b/src/core/primitives/avatar/avatarCounter.tsx @@ -2,7 +2,7 @@ import {getTheme_v2} from '@sanity/ui/theme' import {forwardRef, useMemo} from 'react' import {styled, css} from 'styled-components' import {EMPTY_RECORD} from '../../constants' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {rem, _responsive, ThemeProps} from '../../styles' import {AvatarSize} from '../../types' import {Label} from '../label' diff --git a/src/core/primitives/avatar/avatarStack.tsx b/src/core/primitives/avatar/avatarStack.tsx index dada7effa..2521447aa 100644 --- a/src/core/primitives/avatar/avatarStack.tsx +++ b/src/core/primitives/avatar/avatarStack.tsx @@ -2,7 +2,7 @@ import {getTheme_v2} from '@sanity/ui/theme' import {Children, cloneElement, forwardRef, isValidElement} from 'react' import {styled, css} from 'styled-components' import {EMPTY_RECORD} from '../../constants' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {rem, _responsive, ThemeProps} from '../../styles' import {AvatarSize} from '../../types' import {AvatarCounter} from './avatarCounter' diff --git a/src/core/primitives/badge/badge.tsx b/src/core/primitives/badge/badge.tsx index cef7a9768..dfe24806f 100644 --- a/src/core/primitives/badge/badge.tsx +++ b/src/core/primitives/badge/badge.tsx @@ -1,6 +1,6 @@ import {forwardRef} from 'react' import {styled} from 'styled-components' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {responsiveRadiusStyle, ResponsiveRadiusStyleProps} from '../../styles/internal' import {BadgeMode, BadgeTone} from '../../types' import {Box, BoxProps} from '../box' diff --git a/src/core/primitives/box/box.tsx b/src/core/primitives/box/box.tsx index d8c7f0f2e..a3470cbc1 100644 --- a/src/core/primitives/box/box.tsx +++ b/src/core/primitives/box/box.tsx @@ -1,6 +1,6 @@ import {forwardRef} from 'react' import {styled} from 'styled-components' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import { boxStyle, flexItemStyle, diff --git a/src/core/primitives/button/button.tsx b/src/core/primitives/button/button.tsx index 96e684cf7..196bf90f7 100644 --- a/src/core/primitives/button/button.tsx +++ b/src/core/primitives/button/button.tsx @@ -1,7 +1,7 @@ import {forwardRef, isValidElement, useMemo} from 'react' import {isValidElementType} from 'react-is' import {styled} from 'styled-components' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {ThemeProps} from '../../styles' import {responsiveRadiusStyle, ResponsiveRadiusStyleProps} from '../../styles/internal' import {useTheme_v2} from '../../theme' diff --git a/src/core/primitives/card/card.tsx b/src/core/primitives/card/card.tsx index 0cdeba018..a1e5ad863 100644 --- a/src/core/primitives/card/card.tsx +++ b/src/core/primitives/card/card.tsx @@ -2,7 +2,7 @@ import {ThemeColorSchemeKey} from '@sanity/ui/theme' import {forwardRef} from 'react' import {isValidElementType} from 'react-is' import {styled} from 'styled-components' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import { responsiveBorderStyle, ResponsiveBorderStyleProps, diff --git a/src/core/primitives/code/code.tsx b/src/core/primitives/code/code.tsx index a102ccfff..d954fda61 100644 --- a/src/core/primitives/code/code.tsx +++ b/src/core/primitives/code/code.tsx @@ -2,7 +2,7 @@ import {forwardRef} from 'react' import Refractor from 'react-refractor' import {styled} from 'styled-components' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {responsiveCodeFontStyle, ResponsiveFontStyleProps} from '../../styles/internal' import {codeBaseStyle} from './styles' diff --git a/src/core/primitives/container/container.tsx b/src/core/primitives/container/container.tsx index 97b6c5d9c..531a7e181 100644 --- a/src/core/primitives/container/container.tsx +++ b/src/core/primitives/container/container.tsx @@ -1,6 +1,6 @@ import {forwardRef} from 'react' import {styled} from 'styled-components' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {Box, BoxProps} from '../box' import {ResponsiveWidthProps} from '../types' import {containerBaseStyle, responsiveContainerWidthStyle} from './styles' diff --git a/src/core/primitives/flex/flex.tsx b/src/core/primitives/flex/flex.tsx index 286d885ce..ccc2a703e 100644 --- a/src/core/primitives/flex/flex.tsx +++ b/src/core/primitives/flex/flex.tsx @@ -1,6 +1,6 @@ import {forwardRef} from 'react' import {styled} from 'styled-components' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import { flexItemStyle, FlexItemStyleProps, diff --git a/src/core/primitives/grid/grid.tsx b/src/core/primitives/grid/grid.tsx index 17f6fd1d5..561984cb3 100644 --- a/src/core/primitives/grid/grid.tsx +++ b/src/core/primitives/grid/grid.tsx @@ -1,6 +1,6 @@ import {forwardRef} from 'react' import {styled} from 'styled-components' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {responsiveGridStyle, ResponsiveGridStyleProps} from '../../styles/internal' import {Box, BoxProps} from '../box' import {ResponsiveGridProps} from '../types' diff --git a/src/core/primitives/heading/heading.tsx b/src/core/primitives/heading/heading.tsx index c5d2eecd1..2e5b4b338 100644 --- a/src/core/primitives/heading/heading.tsx +++ b/src/core/primitives/heading/heading.tsx @@ -1,7 +1,7 @@ import {ThemeFontWeightKey} from '@sanity/ui/theme' import {forwardRef} from 'react' import {styled} from 'styled-components' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import { ResponsiveFontStyleProps, responsiveHeadingFont, diff --git a/src/core/primitives/inline/inline.tsx b/src/core/primitives/inline/inline.tsx index 3a0d5f60c..20c3bee96 100644 --- a/src/core/primitives/inline/inline.tsx +++ b/src/core/primitives/inline/inline.tsx @@ -1,6 +1,6 @@ import {forwardRef, useMemo, Children} from 'react' import {styled} from 'styled-components' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {Box, BoxProps} from '../box' import {inlineBaseStyle, inlineSpaceStyle} from './styles' import {ResponsiveInlineSpaceStyleProps} from './types' diff --git a/src/core/primitives/kbd/kbd.tsx b/src/core/primitives/kbd/kbd.tsx index d645374a3..5d3f003a3 100644 --- a/src/core/primitives/kbd/kbd.tsx +++ b/src/core/primitives/kbd/kbd.tsx @@ -1,6 +1,6 @@ import {forwardRef} from 'react' import {styled, css} from 'styled-components' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {responsiveRadiusStyle, ResponsiveRadiusStyleProps} from '../../styles/internal' import {Radius} from '../../types' import {Box} from '../box' diff --git a/src/core/primitives/label/label.tsx b/src/core/primitives/label/label.tsx index cdfc5ec32..73c593836 100644 --- a/src/core/primitives/label/label.tsx +++ b/src/core/primitives/label/label.tsx @@ -1,7 +1,7 @@ import {ThemeFontWeightKey} from '@sanity/ui/theme' import {forwardRef} from 'react' import {styled} from 'styled-components' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {responsiveLabelFont, responsiveTextAlignStyle} from '../../styles/internal' import {TextAlign} from '../../types' import {labelBaseStyle} from './styles' diff --git a/src/core/primitives/popover/popover.tsx b/src/core/primitives/popover/popover.tsx index 64bbbc65d..d538a5a44 100644 --- a/src/core/primitives/popover/popover.tsx +++ b/src/core/primitives/popover/popover.tsx @@ -24,7 +24,8 @@ import { useMemo, useRef, } from 'react' -import {useArrayProp, useElementSize, useMediaIndex, usePrefersReducedMotion} from '../../hooks' +import {useElementSize, useMediaIndex, usePrefersReducedMotion} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {origin} from '../../middleware/origin' import {useTheme_v2} from '../../theme' import {BoxOverflow, CardTone, Placement, PopoverMargins} from '../../types' diff --git a/src/core/primitives/select/select.tsx b/src/core/primitives/select/select.tsx index 037946b01..a7cdbca7e 100644 --- a/src/core/primitives/select/select.tsx +++ b/src/core/primitives/select/select.tsx @@ -1,7 +1,8 @@ import {ChevronDownIcon} from '@sanity/icons' import {forwardRef, useImperativeHandle, useRef} from 'react' import {styled} from 'styled-components' -import {useCustomValidity, useArrayProp} from '../../hooks' +import {useCustomValidity} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {Radius} from '../../types' import {Box} from '../box' import {Text} from '../text' diff --git a/src/core/primitives/stack/stack.tsx b/src/core/primitives/stack/stack.tsx index cf9724a9e..ad1902ffb 100644 --- a/src/core/primitives/stack/stack.tsx +++ b/src/core/primitives/stack/stack.tsx @@ -1,6 +1,6 @@ import {forwardRef} from 'react' import {styled} from 'styled-components' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {Box, BoxProps} from '../box' import {stackBaseStyle, responsiveStackSpaceStyle, ResponsiveStackSpaceStyleProps} from './styles' diff --git a/src/core/primitives/text/text.tsx b/src/core/primitives/text/text.tsx index 09acafd76..4299833fd 100644 --- a/src/core/primitives/text/text.tsx +++ b/src/core/primitives/text/text.tsx @@ -1,7 +1,7 @@ import {ThemeFontWeightKey} from '@sanity/ui/theme' import {forwardRef} from 'react' import {styled} from 'styled-components' -import {useArrayProp} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import { ResponsiveFontStyleProps, responsiveTextAlignStyle, diff --git a/src/core/primitives/textArea/textArea.tsx b/src/core/primitives/textArea/textArea.tsx index 9cfb10597..43ffbeb43 100644 --- a/src/core/primitives/textArea/textArea.tsx +++ b/src/core/primitives/textArea/textArea.tsx @@ -1,7 +1,8 @@ import {ThemeFontWeightKey} from '@sanity/ui/theme' import {forwardRef, useImperativeHandle, useRef} from 'react' import {styled} from 'styled-components' -import {useCustomValidity, useArrayProp} from '../../hooks' +import {useCustomValidity} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import { responsiveInputPaddingStyle, responsiveRadiusStyle, diff --git a/src/core/primitives/textInput/textInput.tsx b/src/core/primitives/textInput/textInput.tsx index 9a8acd18a..e1c54786c 100644 --- a/src/core/primitives/textInput/textInput.tsx +++ b/src/core/primitives/textInput/textInput.tsx @@ -4,7 +4,8 @@ import {forwardRef, isValidElement, useCallback, useImperativeHandle, useMemo, u import {isValidElementType} from 'react-is' import {styled} from 'styled-components' import {EMPTY_RECORD} from '../../constants' -import {useArrayProp, useCustomValidity} from '../../hooks' +import {useCustomValidity} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import { responsiveRadiusStyle, ResponsiveRadiusStyleProps, diff --git a/src/core/primitives/tooltip/tooltip.tsx b/src/core/primitives/tooltip/tooltip.tsx index 7f3a916f0..8ff417997 100644 --- a/src/core/primitives/tooltip/tooltip.tsx +++ b/src/core/primitives/tooltip/tooltip.tsx @@ -25,7 +25,8 @@ import { } from 'react' import {styled} from 'styled-components' import {useEffectEvent} from 'use-effect-event' -import {useArrayProp, usePrefersReducedMotion} from '../../hooks' +import {usePrefersReducedMotion} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {useDelayedState} from '../../hooks/useDelayedState' import {origin} from '../../middleware/origin' import {useTheme_v2} from '../../theme' diff --git a/src/core/styles/helpers.ts b/src/core/styles/helpers.ts index 15abf6c96..542c5feab 100644 --- a/src/core/styles/helpers.ts +++ b/src/core/styles/helpers.ts @@ -42,8 +42,8 @@ export function _responsive( /** * @internal */ -export function _getArrayProp(val: T | T[] | undefined, defaultVal?: T[]): T[] { - if (val === undefined) return defaultVal || EMPTY_ARRAY +export function _getArrayProp(val: T | T[] | undefined): T[] { + if (val === undefined) return EMPTY_ARRAY return Array.isArray(val) ? val : [val] } diff --git a/src/core/utils/layer/layerProvider.tsx b/src/core/utils/layer/layerProvider.tsx index 8795ce4a9..119ea306e 100644 --- a/src/core/utils/layer/layerProvider.tsx +++ b/src/core/utils/layer/layerProvider.tsx @@ -1,5 +1,6 @@ import {useCallback, useContext, useEffect, useMemo, useState} from 'react' -import {useMediaIndex, useArrayProp} from '../../hooks' +import {useMediaIndex} from '../../hooks' +import {useArrayProp} from '../../hooks/useArrayProp' import {getLayerContext} from './getLayerContext' import {LayerContext} from './layerContext' import {LayerContextValue} from './types' diff --git a/src/core/utils/portal/portalProvider.tsx b/src/core/utils/portal/portalProvider.tsx index 41918f7d2..8da64159c 100644 --- a/src/core/utils/portal/portalProvider.tsx +++ b/src/core/utils/portal/portalProvider.tsx @@ -1,4 +1,4 @@ -import {useMemo, useRef, useSyncExternalStore} from 'react' +import {useMemo, useState, useSyncExternalStore} from 'react' import {PortalContext} from './portalContext' import {PortalContextValue} from './types' @@ -22,8 +22,8 @@ export interface PortalProviderProps { * @public */ export function PortalProvider(props: PortalProviderProps): React.ReactElement { - const {boundaryElement, children, element, __unstable_elements: elementsProp} = props - const elements = useUnique(elementsProp) + const {boundaryElement, children, element} = props + const elements = useUnique(props.__unstable_elements) const fallbackElement = useSyncExternalStore( emptySubscribe, () => document.body, @@ -51,16 +51,18 @@ const emptySubscribe = () => () => {} * equality comparison (eg by identity), and only goes one level deep. */ function useUnique(value: ValueType): ValueType { - const valueRef = useRef(value) + const [cachedValue, setCachedValue] = useState(value) + let result = cachedValue - if (!_isEqual(valueRef.current, value)) { - valueRef.current = value + if (!isEqual(cachedValue, value)) { + setCachedValue(value) + result = value } - return valueRef.current + return result } -function _isEqual(objA: Comparable, objB: Comparable): boolean { +function isEqual(objA: Comparable, objB: Comparable): boolean { if (!objA || !objB) { return objA === objB }