@sanity/ui 2.9.0-canary.2 → 2.9.0-canary.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +12 -10
- package/dist/index.d.ts +12 -10
- package/dist/index.esm.js +332 -142
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +331 -141
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +332 -142
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/core/components/breadcrumbs/breadcrumbs.tsx +35 -47
- package/src/core/components/menu/menu.tsx +12 -10
- package/src/core/components/menu/menuButton.tsx +14 -36
- package/src/core/components/tab/tabList.tsx +3 -11
- package/src/core/components/toast/toastProvider.tsx +5 -6
- package/src/core/components/toast/toastState.ts +6 -0
- package/src/core/components/tree/treeItem.tsx +5 -2
- package/src/core/constants.ts +1 -1
- package/src/core/primitives/popover/popover.tsx +4 -7
- package/src/core/utils/elementQuery/elementQuery.tsx +14 -16
- package/src/core/utils/layer/layerProvider.tsx +1 -1
package/package.json
CHANGED
|
@@ -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'
|
|
11
2
|
import {useArrayProp, useClickOutsideEvent} from '../../hooks'
|
|
12
3
|
import {Box, Popover, Stack, Text} from '../../primitives'
|
|
13
4
|
import {ExpandButton, Root} from './breadcrumbs.styles'
|
|
@@ -39,46 +30,43 @@ export const Breadcrumbs = forwardRef(function Breadcrumbs(
|
|
|
39
30
|
|
|
40
31
|
useClickOutsideEvent(collapse, () => [expandElementRef.current, popoverElementRef.current])
|
|
41
32
|
|
|
42
|
-
const rawItems =
|
|
33
|
+
const rawItems = Children.toArray(children).filter(isValidElement)
|
|
43
34
|
|
|
44
|
-
|
|
45
|
-
|
|
35
|
+
let items = rawItems
|
|
36
|
+
const len = rawItems.length
|
|
46
37
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
38
|
+
if (maxLength && rawItems.length > maxLength) {
|
|
39
|
+
const beforeLength = Math.ceil(maxLength / 2)
|
|
40
|
+
const afterLength = Math.floor(maxLength / 2)
|
|
50
41
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
+
}
|
|
82
70
|
|
|
83
71
|
return (
|
|
84
72
|
<Root data-ui="Breadcrumbs" {...restProps} ref={ref}>
|
|
@@ -14,19 +14,21 @@ export interface MenuProps extends ResponsivePaddingProps {
|
|
|
14
14
|
/**
|
|
15
15
|
* @deprecated Use `shouldFocus="first"` instead.
|
|
16
16
|
*/
|
|
17
|
-
focusFirst?: boolean
|
|
17
|
+
'focusFirst'?: boolean
|
|
18
18
|
/**
|
|
19
19
|
* @deprecated Use `shouldFocus="last"` instead.
|
|
20
20
|
*/
|
|
21
|
-
focusLast?: boolean
|
|
22
|
-
onClickOutside?: (event: MouseEvent) => void
|
|
23
|
-
onEscape?: () => void
|
|
24
|
-
onItemClick?: () => void
|
|
25
|
-
onItemSelect?: (index: number) => void
|
|
26
|
-
originElement?: HTMLElement | null
|
|
27
|
-
registerElement?: (el: HTMLElement) => () => void
|
|
28
|
-
shouldFocus?: 'first' | 'last' | null
|
|
29
|
-
space?: number | number[]
|
|
21
|
+
'focusLast'?: boolean
|
|
22
|
+
'onClickOutside'?: (event: MouseEvent) => void
|
|
23
|
+
'onEscape'?: () => void
|
|
24
|
+
'onItemClick'?: () => void
|
|
25
|
+
'onItemSelect'?: (index: number) => void
|
|
26
|
+
'originElement'?: HTMLElement | null
|
|
27
|
+
'registerElement'?: (el: HTMLElement) => () => void
|
|
28
|
+
'shouldFocus'?: 'first' | 'last' | null
|
|
29
|
+
'space'?: number | number[]
|
|
30
|
+
'aria-labelledby'?: string
|
|
31
|
+
'onBlurCapture'?: (event: FocusEvent) => void
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
const Root = styled(Box)`
|
|
@@ -169,7 +169,7 @@ export const MenuButton = forwardRef(function MenuButton(
|
|
|
169
169
|
}, [buttonElement, disableRestoreFocusOnClose])
|
|
170
170
|
|
|
171
171
|
const handleBlur = useCallback(
|
|
172
|
-
(event:
|
|
172
|
+
(event: FocusEvent) => {
|
|
173
173
|
const target = event.relatedTarget
|
|
174
174
|
|
|
175
175
|
if (!(target instanceof Node)) {
|
|
@@ -199,32 +199,19 @@ export const MenuButton = forwardRef(function MenuButton(
|
|
|
199
199
|
return () => setChildMenuElements((els) => els.filter((_el) => _el !== el))
|
|
200
200
|
}, [])
|
|
201
201
|
|
|
202
|
-
const menuProps: MenuProps =
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}),
|
|
213
|
-
[
|
|
214
|
-
buttonElement,
|
|
215
|
-
handleMenuClickOutside,
|
|
216
|
-
handleMenuEscape,
|
|
217
|
-
handleItemClick,
|
|
218
|
-
id,
|
|
219
|
-
handleBlur,
|
|
220
|
-
registerElement,
|
|
221
|
-
shouldFocus,
|
|
222
|
-
],
|
|
223
|
-
)
|
|
202
|
+
const menuProps: MenuProps = {
|
|
203
|
+
'aria-labelledby': id,
|
|
204
|
+
'onBlurCapture': handleBlur,
|
|
205
|
+
'onClickOutside': handleMenuClickOutside,
|
|
206
|
+
'onEscape': handleMenuEscape,
|
|
207
|
+
'onItemClick': handleItemClick,
|
|
208
|
+
'originElement': buttonElement,
|
|
209
|
+
registerElement,
|
|
210
|
+
shouldFocus,
|
|
211
|
+
}
|
|
224
212
|
|
|
225
213
|
const menu = menuProp && cloneElement(menuProp, menuProps)
|
|
226
214
|
|
|
227
|
-
const ref = useRef<HTMLButtonElement | null>(null)
|
|
228
215
|
const button = useMemo(
|
|
229
216
|
() =>
|
|
230
217
|
buttonProp &&
|
|
@@ -236,7 +223,7 @@ export const MenuButton = forwardRef(function MenuButton(
|
|
|
236
223
|
'onMouseDown': handleMouseDown,
|
|
237
224
|
'aria-haspopup': true,
|
|
238
225
|
'aria-expanded': open,
|
|
239
|
-
'ref':
|
|
226
|
+
'ref': setButtonElement,
|
|
240
227
|
'selected': buttonProp.props.selected ?? open,
|
|
241
228
|
}),
|
|
242
229
|
[buttonProp, handleButtonClick, handleButtonKeyDown, handleMouseDown, id, open],
|
|
@@ -245,19 +232,10 @@ export const MenuButton = forwardRef(function MenuButton(
|
|
|
245
232
|
// Forward button ref to parent
|
|
246
233
|
useImperativeHandle<HTMLButtonElement | null, HTMLButtonElement | null>(
|
|
247
234
|
forwardedRef,
|
|
248
|
-
() =>
|
|
235
|
+
() => buttonElement,
|
|
236
|
+
[buttonElement],
|
|
249
237
|
)
|
|
250
238
|
|
|
251
|
-
// If there's a button then we need to set the reference element to the cloned button ref
|
|
252
|
-
// and if button changes we make sure to update or remove the reference element.
|
|
253
|
-
useEffect(() => {
|
|
254
|
-
if (!button) return undefined
|
|
255
|
-
|
|
256
|
-
setButtonElement(ref.current)
|
|
257
|
-
|
|
258
|
-
return () => setButtonElement(null)
|
|
259
|
-
}, [button])
|
|
260
|
-
|
|
261
239
|
const popoverProps: MenuButtonProps['popover'] = useMemo(
|
|
262
240
|
() => ({
|
|
263
241
|
boundaryElement: deprecated_boundaryElement,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {cloneElement, forwardRef, useCallback,
|
|
1
|
+
import {cloneElement, forwardRef, useCallback, useState, Children, isValidElement} from 'react'
|
|
2
2
|
import {styled} from 'styled-components'
|
|
3
3
|
import {Inline, InlineProps} from '../../primitives'
|
|
4
4
|
|
|
@@ -9,10 +9,6 @@ export interface TabListProps extends Omit<InlineProps, 'as' | 'height'> {
|
|
|
9
9
|
children: Array<React.ReactElement | null | undefined | false>
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
function _isReactElement(node: unknown): node is React.ReactElement {
|
|
13
|
-
return Boolean(node)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
12
|
//Limits the width of tabs in tablist
|
|
17
13
|
const CustomInline = styled(Inline)`
|
|
18
14
|
& > div {
|
|
@@ -33,22 +29,18 @@ export const TabList = forwardRef(function TabList(
|
|
|
33
29
|
const {children: childrenProp, ...restProps} = props
|
|
34
30
|
const [focusedIndex, setFocusedIndex] = useState(-1)
|
|
35
31
|
|
|
36
|
-
const children =
|
|
32
|
+
const children: React.ReactElement[] = Children.toArray(childrenProp).filter(isValidElement)
|
|
37
33
|
|
|
38
34
|
const tabs = children.map((child, childIndex) =>
|
|
39
35
|
cloneElement(child, {
|
|
40
36
|
focused: focusedIndex === childIndex,
|
|
41
37
|
key: childIndex,
|
|
42
|
-
onFocus: () =>
|
|
38
|
+
onFocus: () => setFocusedIndex(childIndex),
|
|
43
39
|
}),
|
|
44
40
|
)
|
|
45
41
|
|
|
46
42
|
const numTabs = tabs.length
|
|
47
43
|
|
|
48
|
-
const handleTabFocus = useCallback((tabIdx: number) => {
|
|
49
|
-
setFocusedIndex(tabIdx)
|
|
50
|
-
}, [])
|
|
51
|
-
|
|
52
44
|
const handleKeyDown = useCallback(
|
|
53
45
|
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
|
54
46
|
if (event.key === 'ArrowLeft') {
|
|
@@ -8,6 +8,7 @@ import {Box} from '../../primitives'
|
|
|
8
8
|
import {Layer} from '../../utils'
|
|
9
9
|
import {Toast} from './toast'
|
|
10
10
|
import {ToastContext} from './toastContext'
|
|
11
|
+
import {generateToastId} from './toastState'
|
|
11
12
|
import {ToastContextValue, ToastParams} from './types'
|
|
12
13
|
|
|
13
14
|
type ToastState = {
|
|
@@ -45,8 +46,6 @@ const ToastContainer = styled.div`
|
|
|
45
46
|
width: 100%;
|
|
46
47
|
`
|
|
47
48
|
|
|
48
|
-
let toastId = 0
|
|
49
|
-
|
|
50
49
|
/**
|
|
51
50
|
* @public
|
|
52
51
|
*/
|
|
@@ -60,20 +59,20 @@ export function ToastProvider(props: ToastProviderProps): React.ReactElement {
|
|
|
60
59
|
() => ({
|
|
61
60
|
initial: {
|
|
62
61
|
opacity: 0,
|
|
63
|
-
[POPOVER_MOTION_CONTENT_OPACITY_PROPERTY
|
|
62
|
+
[POPOVER_MOTION_CONTENT_OPACITY_PROPERTY]: 0,
|
|
64
63
|
y: 32,
|
|
65
64
|
scale: 0.25,
|
|
66
65
|
willChange: 'transform',
|
|
67
66
|
},
|
|
68
67
|
animate: {
|
|
69
68
|
opacity: [0, 1, 1],
|
|
70
|
-
[POPOVER_MOTION_CONTENT_OPACITY_PROPERTY
|
|
69
|
+
[POPOVER_MOTION_CONTENT_OPACITY_PROPERTY]: [0, 0, 1],
|
|
71
70
|
y: 0,
|
|
72
71
|
scale: 1,
|
|
73
72
|
},
|
|
74
73
|
exit: {
|
|
75
74
|
opacity: [1, 1, 0],
|
|
76
|
-
[POPOVER_MOTION_CONTENT_OPACITY_PROPERTY
|
|
75
|
+
[POPOVER_MOTION_CONTENT_OPACITY_PROPERTY]: [1, 0, 0],
|
|
77
76
|
scale: 0.5,
|
|
78
77
|
transition: prefersReducedMotion ? {duration: 0} : {duration: 0.2},
|
|
79
78
|
},
|
|
@@ -86,7 +85,7 @@ export function ToastProvider(props: ToastProviderProps): React.ReactElement {
|
|
|
86
85
|
// Wrap setState in startTransition to allow React to give input state updates higher priority
|
|
87
86
|
const setState: typeof _setState = (state) => startTransition(() => _setState(state))
|
|
88
87
|
|
|
89
|
-
const id = params.id ||
|
|
88
|
+
const id = params.id || generateToastId()
|
|
90
89
|
const duration = params.duration || 5000
|
|
91
90
|
|
|
92
91
|
const dismiss = () => {
|
|
@@ -70,8 +70,11 @@ export const TreeItem = memo(function TreeItem(
|
|
|
70
70
|
const {path, registerItem, setExpanded, setFocusedElement} = tree
|
|
71
71
|
const _id = useId()
|
|
72
72
|
const id = idProp || _id
|
|
73
|
-
const itemPath = useMemo(() =>
|
|
74
|
-
|
|
73
|
+
const [itemPath, itemKey] = useMemo(() => {
|
|
74
|
+
const result = path.concat([id || ''])
|
|
75
|
+
|
|
76
|
+
return [result, result.join('/')]
|
|
77
|
+
}, [id, path])
|
|
75
78
|
const itemState = tree.state[itemKey]
|
|
76
79
|
const focused = tree.focusedElement === rootElement
|
|
77
80
|
const expanded = itemState?.expanded === undefined ? expandedProp : itemState?.expanded || false
|
package/src/core/constants.ts
CHANGED
|
@@ -13,7 +13,7 @@ export const EMPTY_RECORD: Record<string, never> = {}
|
|
|
13
13
|
/**
|
|
14
14
|
* @internal
|
|
15
15
|
*/
|
|
16
|
-
export const POPOVER_MOTION_CONTENT_OPACITY_PROPERTY = '--motion-content-opacity'
|
|
16
|
+
export const POPOVER_MOTION_CONTENT_OPACITY_PROPERTY = '--motion-content-opacity' as string
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Shared `framer-motion` variants used by `Popover` and `Tooltip` components.
|
|
@@ -171,7 +171,7 @@ export const Popover = memo(
|
|
|
171
171
|
const widthArrayProp = useArrayProp(widthProp)
|
|
172
172
|
const zOffset = useArrayProp(zOffsetProp)
|
|
173
173
|
const ref = useRef<HTMLDivElement | null>(null)
|
|
174
|
-
const
|
|
174
|
+
const [arrowElement, setArrowElement] = useState<HTMLDivElement | null>(null)
|
|
175
175
|
const rootBoundary: RootBoundary = 'viewport'
|
|
176
176
|
|
|
177
177
|
useImperativeHandle<HTMLDivElement | null, HTMLDivElement | null>(
|
|
@@ -299,7 +299,7 @@ export const Popover = memo(
|
|
|
299
299
|
if (arrowProp) {
|
|
300
300
|
ret.push(
|
|
301
301
|
arrow({
|
|
302
|
-
element:
|
|
302
|
+
element: arrowElement,
|
|
303
303
|
padding: DEFAULT_POPOVER_PADDING,
|
|
304
304
|
}),
|
|
305
305
|
)
|
|
@@ -322,6 +322,7 @@ export const Popover = memo(
|
|
|
322
322
|
return ret
|
|
323
323
|
}, [
|
|
324
324
|
animate,
|
|
325
|
+
arrowElement,
|
|
325
326
|
arrowProp,
|
|
326
327
|
constrainSize,
|
|
327
328
|
fallbackPlacements,
|
|
@@ -346,10 +347,6 @@ export const Popover = memo(
|
|
|
346
347
|
const originX = middlewareData['@sanity/ui/origin']?.originX
|
|
347
348
|
const originY = middlewareData['@sanity/ui/origin']?.originY
|
|
348
349
|
|
|
349
|
-
const setArrow = useCallback((arrowEl: HTMLDivElement | null) => {
|
|
350
|
-
arrowRef.current = arrowEl
|
|
351
|
-
}, [])
|
|
352
|
-
|
|
353
350
|
const setFloating = useCallback(
|
|
354
351
|
(node: HTMLDivElement | null) => {
|
|
355
352
|
ref.current = node
|
|
@@ -393,7 +390,7 @@ export const Popover = memo(
|
|
|
393
390
|
__unstable_margins={margins}
|
|
394
391
|
animate={animate}
|
|
395
392
|
arrow={arrowProp}
|
|
396
|
-
arrowRef={
|
|
393
|
+
arrowRef={setArrowElement}
|
|
397
394
|
arrowX={arrowX}
|
|
398
395
|
arrowY={arrowY}
|
|
399
396
|
hidden={referenceHidden}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {forwardRef,
|
|
1
|
+
import {forwardRef, useImperativeHandle, useMemo, useState} from 'react'
|
|
2
2
|
import {useElementSize} from '../../hooks'
|
|
3
3
|
import {useTheme_v2} from '../../theme'
|
|
4
4
|
import {findMaxBreakpoints, findMinBreakpoints} from './helpers'
|
|
@@ -24,29 +24,27 @@ export const ElementQuery = forwardRef(function ElementQuery(
|
|
|
24
24
|
const {children, media: _media, ...restProps} = props
|
|
25
25
|
const media = _media ?? theme.media
|
|
26
26
|
|
|
27
|
-
const ref = useRef<HTMLDivElement | null>(null)
|
|
28
27
|
const [element, setElement] = useState<HTMLDivElement | null>(null)
|
|
29
28
|
const elementSize = useElementSize(element)
|
|
30
29
|
const width = useMemo(() => elementSize?.border.width ?? window.innerWidth, [elementSize])
|
|
31
30
|
|
|
32
|
-
const max = useMemo(() =>
|
|
33
|
-
|
|
31
|
+
const max = useMemo(() => {
|
|
32
|
+
const eq = findMaxBreakpoints(media, width)
|
|
34
33
|
|
|
35
|
-
|
|
34
|
+
return eq.length ? eq.join(' ') : undefined
|
|
35
|
+
}, [media, width])
|
|
36
|
+
const min = useMemo(() => {
|
|
37
|
+
const eq = findMinBreakpoints(media, width)
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
return eq.length ? eq.join(' ') : undefined
|
|
40
|
+
}, [media, width])
|
|
41
|
+
|
|
42
|
+
useImperativeHandle<HTMLDivElement | null, HTMLDivElement | null>(forwardedRef, () => element, [
|
|
43
|
+
element,
|
|
44
|
+
])
|
|
41
45
|
|
|
42
46
|
return (
|
|
43
|
-
<div
|
|
44
|
-
data-ui="ElementQuery"
|
|
45
|
-
{...restProps}
|
|
46
|
-
data-eq-max={max.length ? max.join(' ') : undefined}
|
|
47
|
-
data-eq-min={min.length ? min.join(' ') : undefined}
|
|
48
|
-
ref={setRef}
|
|
49
|
-
>
|
|
47
|
+
<div data-ui="ElementQuery" {...restProps} data-eq-max={max} data-eq-min={min} ref={setElement}>
|
|
50
48
|
{children}
|
|
51
49
|
</div>
|
|
52
50
|
)
|