@sanity/ui 3.1.14 → 3.3.0
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/_chunks-cjs/_visual-editing.js +323 -292
- package/dist/_chunks-cjs/_visual-editing.js.map +1 -1
- package/dist/_chunks-es/_visual-editing.mjs +323 -292
- package/dist/_chunks-es/_visual-editing.mjs.map +1 -1
- package/dist/_visual-editing.d.mts +195 -76
- package/dist/_visual-editing.d.ts +195 -76
- package/dist/index.d.mts +308 -140
- package/dist/index.d.ts +308 -140
- package/dist/index.js +97 -93
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +97 -93
- package/dist/index.mjs.map +1 -1
- package/dist/theme.d.mts +10 -4
- package/dist/theme.d.ts +10 -4
- package/package.json +1 -1
- package/src/core/components/autocomplete/autocomplete.tsx +1 -1
- package/src/core/components/autocomplete/types.ts +2 -2
- package/src/core/components/breadcrumbs/breadcrumbs.test.tsx +51 -0
- package/src/core/components/breadcrumbs/breadcrumbs.tsx +7 -3
- package/src/core/components/hotkeys/hotkeys.test.tsx +42 -0
- package/src/core/components/hotkeys/hotkeys.tsx +7 -3
- package/src/core/components/menu/__workshop__/asComponent.tsx +1 -1
- package/src/core/components/menu/menu.spacing.test.tsx +63 -0
- package/src/core/components/menu/menu.tsx +8 -2
- package/src/core/components/menu/menuDivider.ts +16 -5
- package/src/core/components/menu/menuGroup.spacing.test.tsx +63 -0
- package/src/core/components/menu/menuGroup.tsx +22 -8
- package/src/core/components/menu/menuItem.spacing.test.tsx +59 -0
- package/src/core/components/menu/menuItem.tsx +25 -8
- package/src/core/components/skeleton/skeleton.tsx +2 -2
- package/src/core/components/tab/tabList.test.tsx +48 -0
- package/src/core/components/tab/tabList.tsx +2 -2
- package/src/core/components/tab/tabPanel.tsx +2 -2
- package/src/core/components/toast/styles.ts +2 -2
- package/src/core/components/tree/__workshop__/basic.perf.ts +1 -1
- package/src/core/components/tree/__workshop__/tabFromElement.tsx +1 -1
- package/src/core/components/tree/tree.test.tsx +55 -0
- package/src/core/components/tree/tree.tsx +19 -10
- package/src/core/components/tree/treeGroup.tsx +3 -3
- package/src/core/components/tree/treeItem.test.tsx +65 -0
- package/src/core/components/tree/treeItem.tsx +11 -4
- package/src/core/components/tree/types.ts +4 -0
- package/src/core/primitives/avatar/avatar.tsx +19 -11
- package/src/core/primitives/badge/badge.tsx +20 -12
- package/src/core/primitives/box/__workshop__/asComponent.tsx +31 -0
- package/src/core/primitives/box/__workshop__/index.ts +5 -0
- package/src/core/primitives/box/box.test.tsx +142 -0
- package/src/core/primitives/box/box.tsx +41 -18
- package/src/core/primitives/button/__workshop__/disabled.tsx +2 -2
- package/src/core/primitives/button/__workshop__/sanityUploadButton.tsx +1 -1
- package/src/core/primitives/button/__workshop__/uploadButton.tsx +1 -1
- package/src/core/primitives/button/button.test.tsx +41 -3
- package/src/core/primitives/button/button.tsx +36 -12
- package/src/core/primitives/card/__workshop__/asComponent.tsx +1 -1
- package/src/core/primitives/card/card.tsx +24 -13
- package/src/core/primitives/code/code.tsx +16 -7
- package/src/core/primitives/container/container.tsx +23 -10
- package/src/core/primitives/flex/flex.tsx +21 -11
- package/src/core/primitives/grid/grid.test.tsx +80 -0
- package/src/core/primitives/grid/grid.tsx +39 -13
- package/src/core/primitives/heading/heading.tsx +19 -11
- package/src/core/primitives/inline/inline.test.tsx +51 -0
- package/src/core/primitives/inline/inline.tsx +28 -12
- package/src/core/primitives/kbd/kbd.tsx +19 -11
- package/src/core/primitives/label/label.tsx +19 -11
- package/src/core/primitives/popover/__workshop__/SidePanelStory.tsx +1 -1
- package/src/core/primitives/select/select.test.tsx +52 -0
- package/src/core/primitives/select/select.tsx +8 -2
- package/src/core/primitives/stack/stack.test.tsx +57 -0
- package/src/core/primitives/stack/stack.tsx +27 -13
- package/src/core/primitives/text/text.tsx +19 -11
- package/src/core/primitives/textInput/textInput.test.tsx +48 -0
- package/src/core/primitives/textInput/textInput.tsx +9 -4
- package/src/core/primitives/types.ts +33 -0
- package/src/core/types/component.ts +32 -0
- package/src/core/types/index.ts +1 -0
- package/src/core/utils/virtualList/virtualList.tsx +2 -2
- package/src/theme/system/css.ts +10 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {forwardRef, useEffect, useState} from 'react'
|
|
2
2
|
import {styled} from 'styled-components'
|
|
3
3
|
|
|
4
|
-
import {Box,
|
|
4
|
+
import {Box, BoxOwnProps, ResponsiveRadiusProps} from '../../primitives'
|
|
5
5
|
import {_getArrayProp} from '../../styles'
|
|
6
6
|
import {responsiveRadiusStyle, ResponsiveRadiusStyleProps} from '../../styles/internal'
|
|
7
7
|
import {skeletonStyle} from './styles'
|
|
@@ -14,7 +14,7 @@ const StyledSkeleton = styled(Box)<
|
|
|
14
14
|
* This API might change. DO NOT USE IN PRODUCTION.
|
|
15
15
|
* @beta
|
|
16
16
|
*/
|
|
17
|
-
export interface SkeletonProps extends ResponsiveRadiusProps, Omit<
|
|
17
|
+
export interface SkeletonProps extends ResponsiveRadiusProps, Omit<BoxOwnProps, 'children'> {
|
|
18
18
|
animated?: boolean
|
|
19
19
|
delay?: number
|
|
20
20
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** @jest-environment jsdom */
|
|
2
|
+
|
|
3
|
+
import {render} from '../../../../test'
|
|
4
|
+
import {inlineSpaceStyle} from '../../primitives/inline/styles'
|
|
5
|
+
import {Tab} from './tab'
|
|
6
|
+
import {TabList} from './tabList'
|
|
7
|
+
|
|
8
|
+
jest.mock('../../primitives/inline/styles', () => {
|
|
9
|
+
const actual = jest.requireActual('../../primitives/inline/styles')
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
...actual,
|
|
13
|
+
inlineSpaceStyle: jest.fn(actual.inlineSpaceStyle),
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
describe('components/tabList', () => {
|
|
18
|
+
const mockedInlineSpaceStyle = jest.mocked(inlineSpaceStyle)
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
mockedInlineSpaceStyle.mockClear()
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
function renderTabList(
|
|
25
|
+
props: Partial<React.ComponentProps<typeof TabList>> = {},
|
|
26
|
+
): ReturnType<typeof render> {
|
|
27
|
+
return render(
|
|
28
|
+
<TabList {...props}>
|
|
29
|
+
<Tab aria-controls="tab-panel-a" id="tab-a" label="Tab A" />
|
|
30
|
+
<Tab aria-controls="tab-panel-b" id="tab-b" label="Tab B" />
|
|
31
|
+
</TabList>,
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
it('should support `space` and `gap` with the same behavior', () => {
|
|
36
|
+
renderTabList({space: 2})
|
|
37
|
+
expect(mockedInlineSpaceStyle).toHaveBeenCalledWith(expect.objectContaining({$space: [2]}))
|
|
38
|
+
|
|
39
|
+
mockedInlineSpaceStyle.mockClear()
|
|
40
|
+
renderTabList({gap: 2})
|
|
41
|
+
expect(mockedInlineSpaceStyle).toHaveBeenCalledWith(expect.objectContaining({$space: [2]}))
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('should prefer `gap` over `space` when both are provided', () => {
|
|
45
|
+
renderTabList({gap: 3, space: 1})
|
|
46
|
+
expect(mockedInlineSpaceStyle).toHaveBeenCalledWith(expect.objectContaining({$space: [3]}))
|
|
47
|
+
})
|
|
48
|
+
})
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {Children, cloneElement, forwardRef, isValidElement, useCallback, useState} from 'react'
|
|
2
2
|
import {styled} from 'styled-components'
|
|
3
3
|
|
|
4
|
-
import {Inline,
|
|
4
|
+
import {Inline, InlineOwnProps} from '../../primitives'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @public
|
|
8
8
|
*/
|
|
9
|
-
export interface TabListProps extends Omit<
|
|
9
|
+
export interface TabListProps extends Omit<InlineOwnProps, 'height'> {
|
|
10
10
|
children: Array<React.JSX.Element | null | undefined | false>
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {forwardRef} from 'react'
|
|
2
2
|
|
|
3
|
-
import {Box,
|
|
3
|
+
import {Box, BoxOwnProps} from '../../primitives'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @public
|
|
7
7
|
*/
|
|
8
|
-
export interface TabPanelProps extends
|
|
8
|
+
export interface TabPanelProps extends BoxOwnProps {
|
|
9
9
|
/**
|
|
10
10
|
* The `id` of the correlating `Tab` component.
|
|
11
11
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {getTheme_v2, ThemeColorStateToneKey} from '@sanity/ui/theme'
|
|
2
2
|
import {styled} from 'styled-components'
|
|
3
3
|
|
|
4
|
-
import {Card, Flex} from '../../primitives'
|
|
4
|
+
import {Card, type CardProps, Flex} from '../../primitives'
|
|
5
5
|
import type {ButtonTone} from '../../types'
|
|
6
6
|
|
|
7
7
|
const LOADING_BAR_HEIGHT = 2
|
|
@@ -61,7 +61,7 @@ export const LoadingBarMask = styled(Card)`
|
|
|
61
61
|
z-index: 1;
|
|
62
62
|
`
|
|
63
63
|
|
|
64
|
-
type LoadingBarProgressProps = Omit<
|
|
64
|
+
type LoadingBarProgressProps = Omit<CardProps, 'tone'> & {
|
|
65
65
|
tone: ThemeColorStateToneKey
|
|
66
66
|
}
|
|
67
67
|
export const LoadingBarProgress = styled<React.ComponentType<LoadingBarProgressProps>>(Card)`
|
|
@@ -9,7 +9,7 @@ function test<ElementType = unknown>(
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export const perfTests = [
|
|
12
|
-
test('Toggle tree groups', async ({target}: {target:
|
|
12
|
+
test('Toggle tree groups', async ({target}: {target: HTMLUListElement}) => {
|
|
13
13
|
const apples = await findByTestId(target, 'apples')
|
|
14
14
|
const oranges = await findByTestId(target, 'oranges')
|
|
15
15
|
|
|
@@ -19,7 +19,7 @@ export default function BasicStory() {
|
|
|
19
19
|
if (testid) setId(testid)
|
|
20
20
|
}, [])
|
|
21
21
|
|
|
22
|
-
const handleFocus = useCallback((event: React.FocusEvent<
|
|
22
|
+
const handleFocus = useCallback((event: React.FocusEvent<HTMLElement>) => {
|
|
23
23
|
const elementFocus = event.target.getAttribute('data-testid')
|
|
24
24
|
if (elementFocus) setFocus(elementFocus)
|
|
25
25
|
}, [])
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** @jest-environment jsdom */
|
|
2
|
+
|
|
3
|
+
import {render} from '../../../../test'
|
|
4
|
+
import {Stack} from '../../primitives'
|
|
5
|
+
import {Tree} from './tree'
|
|
6
|
+
import {TreeItem} from './treeItem'
|
|
7
|
+
|
|
8
|
+
jest.mock('../../primitives', () => {
|
|
9
|
+
const actual = jest.requireActual('../../primitives')
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
...actual,
|
|
13
|
+
Stack: jest.fn((props: Record<string, unknown>) => (actual.Stack as any).render(props, null)),
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
describe('components/tree spacing', () => {
|
|
18
|
+
const mockedStack = jest.mocked(Stack)
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
mockedStack.mockClear()
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('should support `space` and `gap` with the same behavior', () => {
|
|
25
|
+
render(
|
|
26
|
+
<Tree space={2}>
|
|
27
|
+
<TreeItem text="Item 1" />
|
|
28
|
+
</Tree>,
|
|
29
|
+
)
|
|
30
|
+
expect(mockedStack.mock.calls.map(([props]) => props)).toContainEqual(
|
|
31
|
+
expect.objectContaining({gap: 2}),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
mockedStack.mockClear()
|
|
35
|
+
render(
|
|
36
|
+
<Tree gap={2}>
|
|
37
|
+
<TreeItem text="Item 1" />
|
|
38
|
+
</Tree>,
|
|
39
|
+
)
|
|
40
|
+
expect(mockedStack.mock.calls.map(([props]) => props)).toContainEqual(
|
|
41
|
+
expect.objectContaining({gap: 2}),
|
|
42
|
+
)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('should prefer `gap` over `space` when both are provided', () => {
|
|
46
|
+
render(
|
|
47
|
+
<Tree gap={3} space={1}>
|
|
48
|
+
<TreeItem text="Item 1" />
|
|
49
|
+
</Tree>,
|
|
50
|
+
)
|
|
51
|
+
const propsList = mockedStack.mock.calls.map(([props]) => props)
|
|
52
|
+
expect(propsList).toContainEqual(expect.objectContaining({gap: 3}))
|
|
53
|
+
expect(propsList).not.toContainEqual(expect.objectContaining({gap: 1}))
|
|
54
|
+
})
|
|
55
|
+
})
|
|
@@ -18,6 +18,10 @@ import {TreeContextValue, TreeState} from './types'
|
|
|
18
18
|
* @beta
|
|
19
19
|
*/
|
|
20
20
|
export interface TreeProps {
|
|
21
|
+
gap?: number | number[]
|
|
22
|
+
/**
|
|
23
|
+
* @deprecated Use `gap` instead. `space` will be removed in v4.
|
|
24
|
+
*/
|
|
21
25
|
space?: number | number[]
|
|
22
26
|
}
|
|
23
27
|
|
|
@@ -27,11 +31,12 @@ export interface TreeProps {
|
|
|
27
31
|
*/
|
|
28
32
|
export const Tree = forwardRef(function Tree(
|
|
29
33
|
props: TreeProps &
|
|
30
|
-
Omit<React.HTMLProps<
|
|
31
|
-
forwardedRef: React.ForwardedRef<
|
|
34
|
+
Omit<React.HTMLProps<HTMLUListElement>, 'align' | 'as' | 'height' | 'ref' | 'role' | 'wrap'>,
|
|
35
|
+
forwardedRef: React.ForwardedRef<HTMLUListElement>,
|
|
32
36
|
): React.JSX.Element {
|
|
33
|
-
const {children, space = 1, onFocus, ...restProps} = props
|
|
34
|
-
const
|
|
37
|
+
const {children, gap, space: deprecated_space = 1, onFocus, ...restProps} = props
|
|
38
|
+
const spacing = gap === undefined ? deprecated_space : gap
|
|
39
|
+
const ref = useRef<HTMLUListElement | null>(null)
|
|
35
40
|
const [focusedElement, setFocusedElement] = useState<HTMLElement | null>(null)
|
|
36
41
|
const focusedElementRef = useRef(focusedElement)
|
|
37
42
|
const path: string[] = useMemo(() => [], [])
|
|
@@ -39,7 +44,10 @@ export const Tree = forwardRef(function Tree(
|
|
|
39
44
|
const [state, setState] = useState<TreeState>({})
|
|
40
45
|
const stateRef = useRef(state)
|
|
41
46
|
|
|
42
|
-
useImperativeHandle<
|
|
47
|
+
useImperativeHandle<HTMLUListElement | null, HTMLUListElement | null>(
|
|
48
|
+
forwardedRef,
|
|
49
|
+
() => ref.current,
|
|
50
|
+
)
|
|
43
51
|
|
|
44
52
|
useEffect(() => {
|
|
45
53
|
focusedElementRef.current = focusedElement
|
|
@@ -89,14 +97,15 @@ export const Tree = forwardRef(function Tree(
|
|
|
89
97
|
registerItem,
|
|
90
98
|
setExpanded,
|
|
91
99
|
setFocusedElement,
|
|
92
|
-
|
|
100
|
+
gap: spacing,
|
|
101
|
+
space: spacing,
|
|
93
102
|
state,
|
|
94
103
|
}),
|
|
95
|
-
[focusedElement, itemElements, path, registerItem, setExpanded,
|
|
104
|
+
[focusedElement, itemElements, path, registerItem, setExpanded, spacing, state],
|
|
96
105
|
)
|
|
97
106
|
|
|
98
107
|
const handleKeyDown = useCallback(
|
|
99
|
-
(event: React.KeyboardEvent<
|
|
108
|
+
(event: React.KeyboardEvent<HTMLUListElement>) => {
|
|
100
109
|
if (!focusedElementRef.current) return
|
|
101
110
|
|
|
102
111
|
if (event.key === 'ArrowDown') {
|
|
@@ -193,7 +202,7 @@ export const Tree = forwardRef(function Tree(
|
|
|
193
202
|
)
|
|
194
203
|
|
|
195
204
|
const handleFocus = useCallback(
|
|
196
|
-
(event: React.FocusEvent<
|
|
205
|
+
(event: React.FocusEvent<HTMLUListElement>) => {
|
|
197
206
|
setFocusedElement(event.target)
|
|
198
207
|
|
|
199
208
|
// Call the element's `focus` handler
|
|
@@ -221,7 +230,7 @@ export const Tree = forwardRef(function Tree(
|
|
|
221
230
|
onKeyDown={handleKeyDown}
|
|
222
231
|
ref={ref}
|
|
223
232
|
role="tree"
|
|
224
|
-
|
|
233
|
+
gap={spacing}
|
|
225
234
|
>
|
|
226
235
|
{children}
|
|
227
236
|
</Stack>
|
|
@@ -7,7 +7,7 @@ export interface TreeGroupProps {
|
|
|
7
7
|
|
|
8
8
|
export function TreeGroup(
|
|
9
9
|
props: TreeGroupProps &
|
|
10
|
-
Omit<React.HTMLProps<
|
|
10
|
+
Omit<React.HTMLProps<HTMLUListElement>, 'as' | 'height' | 'ref' | 'role' | 'wrap'>,
|
|
11
11
|
): React.JSX.Element {
|
|
12
12
|
const {children, expanded = false, ...restProps} = props
|
|
13
13
|
const tree = useTree()
|
|
@@ -18,9 +18,9 @@ export function TreeGroup(
|
|
|
18
18
|
data-ui="TreeGroup"
|
|
19
19
|
{...restProps}
|
|
20
20
|
hidden={!expanded}
|
|
21
|
-
marginTop={tree.
|
|
21
|
+
marginTop={tree.gap}
|
|
22
22
|
role="group"
|
|
23
|
-
|
|
23
|
+
gap={tree.gap}
|
|
24
24
|
>
|
|
25
25
|
{children}
|
|
26
26
|
</Stack>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/** @jest-environment jsdom */
|
|
2
|
+
|
|
3
|
+
import {render} from '../../../../test'
|
|
4
|
+
import {Box} from '../../primitives'
|
|
5
|
+
import {TreeContext} from './treeContext'
|
|
6
|
+
import {TreeItem} from './treeItem'
|
|
7
|
+
import {TreeContextValue, TreeState} from './types'
|
|
8
|
+
|
|
9
|
+
jest.mock('../../primitives', () => {
|
|
10
|
+
const actual = jest.requireActual('../../primitives')
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
...actual,
|
|
14
|
+
Box: jest.fn((props: Record<string, unknown>) => (actual.Box as any).render(props, null)),
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
const treeContextValue: TreeContextValue = {
|
|
19
|
+
version: 0.0,
|
|
20
|
+
focusedElement: null,
|
|
21
|
+
gap: 1,
|
|
22
|
+
level: 0,
|
|
23
|
+
path: [],
|
|
24
|
+
registerItem: () => () => undefined,
|
|
25
|
+
setExpanded: () => undefined,
|
|
26
|
+
setFocusedElement: () => undefined,
|
|
27
|
+
space: 1,
|
|
28
|
+
state: {} as TreeState,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function renderTreeItem(props: Partial<React.ComponentProps<typeof TreeItem>> = {}) {
|
|
32
|
+
return render(
|
|
33
|
+
<TreeContext.Provider value={treeContextValue}>
|
|
34
|
+
<TreeItem text="Item" {...props} />
|
|
35
|
+
</TreeContext.Provider>,
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
describe('components/treeItem spacing', () => {
|
|
40
|
+
const mockedBox = jest.mocked(Box)
|
|
41
|
+
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
mockedBox.mockClear()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('should support `space` and `gap` with the same behavior', () => {
|
|
47
|
+
renderTreeItem({space: 2})
|
|
48
|
+
expect(mockedBox.mock.calls.map(([props]) => props)).toContainEqual(
|
|
49
|
+
expect.objectContaining({marginRight: 2}),
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
mockedBox.mockClear()
|
|
53
|
+
renderTreeItem({gap: 2})
|
|
54
|
+
expect(mockedBox.mock.calls.map(([props]) => props)).toContainEqual(
|
|
55
|
+
expect.objectContaining({marginRight: 2}),
|
|
56
|
+
)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('should prefer `gap` over `space` when both are provided', () => {
|
|
60
|
+
renderTreeItem({gap: 3, space: 1})
|
|
61
|
+
const propsList = mockedBox.mock.calls.map(([props]) => props)
|
|
62
|
+
expect(propsList).toContainEqual(expect.objectContaining({marginRight: 3}))
|
|
63
|
+
expect(propsList).not.toContainEqual(expect.objectContaining({marginRight: 1}))
|
|
64
|
+
})
|
|
65
|
+
})
|
|
@@ -3,7 +3,8 @@ import {ThemeFontWeightKey} from '@sanity/ui/theme'
|
|
|
3
3
|
import {startTransition, useCallback, useEffect, useId, useMemo, useRef, useState} from 'react'
|
|
4
4
|
import {styled} from 'styled-components'
|
|
5
5
|
|
|
6
|
-
import {Box,
|
|
6
|
+
import {Box, Flex, Text} from '../../primitives'
|
|
7
|
+
import {ElementType} from '../../types'
|
|
7
8
|
import {
|
|
8
9
|
treeItemBoxStyle,
|
|
9
10
|
TreeItemBoxStyleProps,
|
|
@@ -24,8 +25,12 @@ export interface TreeItemProps {
|
|
|
24
25
|
/**
|
|
25
26
|
* Allows passing a custom element type to the link component
|
|
26
27
|
*/
|
|
27
|
-
linkAs?:
|
|
28
|
+
linkAs?: ElementType
|
|
28
29
|
padding?: number | number[]
|
|
30
|
+
gap?: number | number[]
|
|
31
|
+
/**
|
|
32
|
+
* @deprecated Use `gap` instead. `space` will be removed in v4.
|
|
33
|
+
*/
|
|
29
34
|
space?: number | number[]
|
|
30
35
|
text?: React.ReactNode
|
|
31
36
|
weight?: ThemeFontWeightKey
|
|
@@ -60,11 +65,13 @@ export function TreeItem(
|
|
|
60
65
|
onClick,
|
|
61
66
|
padding = 2,
|
|
62
67
|
selected = false,
|
|
63
|
-
|
|
68
|
+
gap,
|
|
69
|
+
space: deprecated_space = 2,
|
|
64
70
|
text,
|
|
65
71
|
weight,
|
|
66
72
|
...restProps
|
|
67
73
|
} = props
|
|
74
|
+
const spacing = gap === undefined ? deprecated_space : gap
|
|
68
75
|
const [rootElement, _setRootElement] = useState<HTMLLIElement | null>(null)
|
|
69
76
|
/**
|
|
70
77
|
* The startTransition wrapper here is to avoid an issue when on React 18 where this error can happen:
|
|
@@ -133,7 +140,7 @@ export function TreeItem(
|
|
|
133
140
|
const content = (
|
|
134
141
|
<Flex padding={padding}>
|
|
135
142
|
<Box
|
|
136
|
-
marginRight={
|
|
143
|
+
marginRight={spacing}
|
|
137
144
|
style={{
|
|
138
145
|
visibility: IconComponent || children ? 'visible' : 'hidden',
|
|
139
146
|
pointerEvents: 'none',
|
|
@@ -16,6 +16,10 @@ export interface TreeContextValue {
|
|
|
16
16
|
registerItem: (element: HTMLElement, path: string, expanded: boolean, selected: boolean) => void
|
|
17
17
|
setExpanded: (path: string, expanded: boolean) => void
|
|
18
18
|
setFocusedElement: (focusedElement: HTMLElement | null) => void
|
|
19
|
+
gap: number | number[]
|
|
20
|
+
/**
|
|
21
|
+
* @deprecated Use `gap` instead. `space` will be removed in v4.
|
|
22
|
+
*/
|
|
19
23
|
space: number | number[]
|
|
20
24
|
state: TreeState
|
|
21
25
|
}
|
|
@@ -5,19 +5,18 @@ import {styled} from 'styled-components'
|
|
|
5
5
|
|
|
6
6
|
import {_getArrayProp} from '../../styles'
|
|
7
7
|
import {useTheme_v2} from '../../theme'
|
|
8
|
-
import {AvatarPosition, AvatarSize, AvatarStatus} from '../../types'
|
|
8
|
+
import {AvatarPosition, AvatarSize, AvatarStatus, ElementType, Props} from '../../types'
|
|
9
9
|
import {Label} from '../label'
|
|
10
10
|
import {avatarStyle, responsiveAvatarSizeStyle} from './styles'
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* @public
|
|
14
14
|
*/
|
|
15
|
-
export interface
|
|
15
|
+
export interface AvatarOwnProps {
|
|
16
16
|
/** @beta */
|
|
17
17
|
__unstable_hideInnerStroke?: boolean
|
|
18
18
|
animateArrowFrom?: AvatarPosition
|
|
19
19
|
arrowPosition?: AvatarPosition
|
|
20
|
-
as?: React.ElementType | keyof React.JSX.IntrinsicElements
|
|
21
20
|
color?: ThemeColorAvatarColorKey
|
|
22
21
|
initials?: string
|
|
23
22
|
onImageLoadError?: (event: Error) => void
|
|
@@ -31,6 +30,11 @@ export interface AvatarProps {
|
|
|
31
30
|
title?: string
|
|
32
31
|
}
|
|
33
32
|
|
|
33
|
+
/**
|
|
34
|
+
* @public
|
|
35
|
+
*/
|
|
36
|
+
export type AvatarProps<E extends ElementType = 'div'> = Props<AvatarOwnProps, E>
|
|
37
|
+
|
|
34
38
|
const StyledAvatar = styled.div<{$color: ThemeColorAvatarColorKey; $size: AvatarSize[]}>(
|
|
35
39
|
responsiveAvatarSizeStyle,
|
|
36
40
|
avatarStyle.root,
|
|
@@ -50,13 +54,8 @@ const InitialsLabel = styled(Label)({
|
|
|
50
54
|
|
|
51
55
|
const AvatarImage = styled.svg(avatarStyle.image)
|
|
52
56
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
*
|
|
56
|
-
* @public
|
|
57
|
-
*/
|
|
58
|
-
export const Avatar = forwardRef(function Avatar(
|
|
59
|
-
props: AvatarProps & Omit<React.HTMLProps<HTMLDivElement>, 'as' | 'ref'>,
|
|
57
|
+
const AvatarComponent = forwardRef(function Avatar(
|
|
58
|
+
props: AvatarOwnProps & {as?: ElementType} & Omit<React.HTMLProps<HTMLDivElement>, 'as' | 'ref'>,
|
|
60
59
|
ref: React.ForwardedRef<HTMLDivElement>,
|
|
61
60
|
) {
|
|
62
61
|
const {
|
|
@@ -189,4 +188,13 @@ export const Avatar = forwardRef(function Avatar(
|
|
|
189
188
|
</StyledAvatar>
|
|
190
189
|
)
|
|
191
190
|
})
|
|
192
|
-
|
|
191
|
+
AvatarComponent.displayName = 'ForwardRef(Avatar)'
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Avatars are used to represent people and other agents (e.g. bots).
|
|
195
|
+
*
|
|
196
|
+
* @public
|
|
197
|
+
*/
|
|
198
|
+
export const Avatar = AvatarComponent as unknown as <E extends ElementType = 'div'>(
|
|
199
|
+
props: AvatarProps<E>,
|
|
200
|
+
) => React.JSX.Element
|
|
@@ -3,8 +3,8 @@ import {styled} from 'styled-components'
|
|
|
3
3
|
|
|
4
4
|
import {_getArrayProp} from '../../styles'
|
|
5
5
|
import {responsiveRadiusStyle, ResponsiveRadiusStyleProps} from '../../styles/internal'
|
|
6
|
-
import {BadgeMode, BadgeTone} from '../../types'
|
|
7
|
-
import {Box,
|
|
6
|
+
import {BadgeMode, BadgeTone, ElementType, Props} from '../../types'
|
|
7
|
+
import {Box, BoxOwnProps} from '../box'
|
|
8
8
|
import {Text} from '../text'
|
|
9
9
|
import {ResponsiveRadiusProps} from '../types'
|
|
10
10
|
import {badgeStyle} from './styles'
|
|
@@ -13,26 +13,25 @@ import {BadgeStyleProps} from './types'
|
|
|
13
13
|
/**
|
|
14
14
|
* @public
|
|
15
15
|
*/
|
|
16
|
-
export interface
|
|
17
|
-
as?: React.ElementType | keyof React.JSX.IntrinsicElements
|
|
16
|
+
export interface BadgeOwnProps extends BoxOwnProps, ResponsiveRadiusProps {
|
|
18
17
|
fontSize?: number | number[]
|
|
19
18
|
/** @deprecated No longer used. */
|
|
20
19
|
mode?: BadgeMode
|
|
21
20
|
tone?: BadgeTone
|
|
22
21
|
}
|
|
23
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
export type BadgeProps<E extends ElementType = 'div'> = Props<BadgeOwnProps, E>
|
|
27
|
+
|
|
24
28
|
const StyledBadge = styled(Box)<BadgeStyleProps & ResponsiveRadiusStyleProps>(
|
|
25
29
|
responsiveRadiusStyle,
|
|
26
30
|
badgeStyle,
|
|
27
31
|
)
|
|
28
32
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
*
|
|
32
|
-
* @public
|
|
33
|
-
*/
|
|
34
|
-
export const Badge = forwardRef(function Badge(
|
|
35
|
-
props: BadgeProps & React.HTMLProps<HTMLDivElement>,
|
|
33
|
+
const BadgeComponent = forwardRef(function Badge(
|
|
34
|
+
props: BadgeOwnProps & {as?: ElementType} & React.HTMLProps<HTMLDivElement>,
|
|
36
35
|
ref,
|
|
37
36
|
) {
|
|
38
37
|
const {
|
|
@@ -59,4 +58,13 @@ export const Badge = forwardRef(function Badge(
|
|
|
59
58
|
</StyledBadge>
|
|
60
59
|
)
|
|
61
60
|
})
|
|
62
|
-
|
|
61
|
+
BadgeComponent.displayName = 'ForwardRef(Badge)'
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Badges are used to tag resources.
|
|
65
|
+
*
|
|
66
|
+
* @public
|
|
67
|
+
*/
|
|
68
|
+
export const Badge = BadgeComponent as unknown as <E extends ElementType = 'div'>(
|
|
69
|
+
props: BadgeProps<E>,
|
|
70
|
+
) => React.JSX.Element
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {Box, Flex, Text} from '@sanity/ui'
|
|
2
|
+
import {forwardRef} from 'react'
|
|
3
|
+
|
|
4
|
+
// A custom component with its own props. When passed to `Box`'s `as` prop, these props are
|
|
5
|
+
// inferred on `Box` itself: `href` is required and `target` is optional, and unknown props
|
|
6
|
+
// are rejected by the type checker.
|
|
7
|
+
const Link = forwardRef(function Link(
|
|
8
|
+
props: {href: string; target?: string} & Omit<
|
|
9
|
+
React.HTMLProps<HTMLAnchorElement>,
|
|
10
|
+
'as' | 'href' | 'target'
|
|
11
|
+
>,
|
|
12
|
+
ref: React.ForwardedRef<HTMLAnchorElement>,
|
|
13
|
+
): React.JSX.Element {
|
|
14
|
+
const {children, ...restProps} = props
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<a {...restProps} ref={ref}>
|
|
18
|
+
{children}
|
|
19
|
+
</a>
|
|
20
|
+
)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
export default function AsComponentStory() {
|
|
24
|
+
return (
|
|
25
|
+
<Flex align="center" height="fill" justify="center">
|
|
26
|
+
<Box as={Link} href="/" padding={4} target="_new">
|
|
27
|
+
<Text size={1}>As component</Text>
|
|
28
|
+
</Box>
|
|
29
|
+
</Flex>
|
|
30
|
+
)
|
|
31
|
+
}
|