@sanity/ui 3.1.13 → 3.2.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 +276 -252
- package/dist/_chunks-cjs/_visual-editing.js.map +1 -1
- package/dist/_chunks-es/_visual-editing.mjs +276 -252
- package/dist/_chunks-es/_visual-editing.mjs.map +1 -1
- package/dist/_visual-editing.d.mts +66 -1
- package/dist/_visual-editing.d.ts +66 -1
- package/dist/index.d.mts +86 -1
- package/dist/index.d.ts +86 -1
- 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/package.json +1 -1
- 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/menu.spacing.test.tsx +63 -0
- package/src/core/components/menu/menu.tsx +8 -2
- package/src/core/components/menu/menuGroup.spacing.test.tsx +69 -0
- package/src/core/components/menu/menuGroup.tsx +8 -2
- package/src/core/components/menu/menuItem.spacing.test.tsx +59 -0
- package/src/core/components/menu/menuItem.tsx +8 -2
- package/src/core/components/tab/tabList.test.tsx +48 -0
- package/src/core/components/tree/tree.test.tsx +55 -0
- package/src/core/components/tree/tree.tsx +10 -4
- package/src/core/components/tree/treeGroup.tsx +2 -2
- package/src/core/components/tree/treeItem.test.tsx +65 -0
- package/src/core/components/tree/treeItem.tsx +8 -2
- package/src/core/components/tree/types.ts +4 -0
- package/src/core/hooks/useDelayed.test.ts +20 -0
- package/src/core/hooks/useDelayedState.ts +9 -1
- package/src/core/primitives/box/box.test.tsx +134 -0
- package/src/core/primitives/box/box.tsx +18 -6
- package/src/core/primitives/button/button.test.tsx +38 -0
- package/src/core/primitives/button/button.tsx +8 -3
- package/src/core/primitives/grid/grid.test.tsx +78 -0
- package/src/core/primitives/grid/grid.tsx +17 -4
- package/src/core/primitives/inline/inline.test.tsx +51 -0
- package/src/core/primitives/inline/inline.tsx +9 -3
- 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 +7 -2
- package/src/core/primitives/textInput/textInput.test.tsx +48 -0
- package/src/core/primitives/textInput/textInput.tsx +7 -2
- package/src/core/primitives/types.ts +33 -0
package/package.json
CHANGED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** @jest-environment jsdom */
|
|
2
|
+
|
|
3
|
+
import {render} from '../../../../test'
|
|
4
|
+
import {Box} from '../../primitives'
|
|
5
|
+
import {Breadcrumbs} from './breadcrumbs'
|
|
6
|
+
|
|
7
|
+
jest.mock('../../primitives', () => {
|
|
8
|
+
const actual = jest.requireActual('../../primitives')
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
...actual,
|
|
12
|
+
Box: jest.fn((props: Record<string, unknown>) => (actual.Box as any).render(props, null)),
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
function renderBreadcrumbs(props: Partial<React.ComponentProps<typeof Breadcrumbs>> = {}) {
|
|
17
|
+
return render(
|
|
18
|
+
<Breadcrumbs {...props}>
|
|
19
|
+
<span>Root</span>
|
|
20
|
+
<span>Section</span>
|
|
21
|
+
</Breadcrumbs>,
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
describe('components/breadcrumbs spacing', () => {
|
|
26
|
+
const mockedBox = jest.mocked(Box)
|
|
27
|
+
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
mockedBox.mockClear()
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('should support `space` and `gap` with the same behavior', () => {
|
|
33
|
+
renderBreadcrumbs({space: 2})
|
|
34
|
+
expect(mockedBox.mock.calls.map(([props]) => props)).toContainEqual(
|
|
35
|
+
expect.objectContaining({paddingX: [2]}),
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
mockedBox.mockClear()
|
|
39
|
+
renderBreadcrumbs({gap: 2})
|
|
40
|
+
expect(mockedBox.mock.calls.map(([props]) => props)).toContainEqual(
|
|
41
|
+
expect.objectContaining({paddingX: [2]}),
|
|
42
|
+
)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('should prefer `gap` over `space` when both are provided', () => {
|
|
46
|
+
renderBreadcrumbs({gap: 3, space: 1})
|
|
47
|
+
const propsList = mockedBox.mock.calls.map(([props]) => props)
|
|
48
|
+
expect(propsList).toContainEqual(expect.objectContaining({paddingX: [3]}))
|
|
49
|
+
expect(propsList).not.toContainEqual(expect.objectContaining({paddingX: [1]}))
|
|
50
|
+
})
|
|
51
|
+
})
|
|
@@ -20,6 +20,10 @@ import {ExpandButton, StyledBreadcrumbs} from './breadcrumbs.styles'
|
|
|
20
20
|
export interface BreadcrumbsProps {
|
|
21
21
|
maxLength?: number
|
|
22
22
|
separator?: React.ReactNode
|
|
23
|
+
gap?: number | number[]
|
|
24
|
+
/**
|
|
25
|
+
* @deprecated Use `gap` instead. `space` will be removed in v4.
|
|
26
|
+
*/
|
|
23
27
|
space?: number | number[]
|
|
24
28
|
}
|
|
25
29
|
|
|
@@ -30,8 +34,8 @@ export const Breadcrumbs = forwardRef(function Breadcrumbs(
|
|
|
30
34
|
props: BreadcrumbsProps & Omit<React.HTMLProps<HTMLOListElement>, 'as' | 'ref' | 'type'>,
|
|
31
35
|
ref: React.ForwardedRef<HTMLOListElement>,
|
|
32
36
|
) {
|
|
33
|
-
const {children, maxLength, separator, space:
|
|
34
|
-
const space = _getArrayProp(
|
|
37
|
+
const {children, gap, maxLength, separator, space: deprecated_space = 2, ...restProps} = props
|
|
38
|
+
const space = _getArrayProp(gap === undefined ? deprecated_space : gap)
|
|
35
39
|
const [open, setOpen] = useState(false)
|
|
36
40
|
const expandElementRef = useRef<HTMLButtonElement | null>(null)
|
|
37
41
|
const popoverElementRef = useRef<HTMLDivElement | null>(null)
|
|
@@ -101,7 +105,7 @@ function useItems({
|
|
|
101
105
|
<Popover
|
|
102
106
|
constrainSize
|
|
103
107
|
content={
|
|
104
|
-
<Stack as="ol" overflow="auto" padding={space}
|
|
108
|
+
<Stack as="ol" overflow="auto" padding={space} gap={space}>
|
|
105
109
|
{rawItems.slice(beforeLength - 1, len - afterLength)}
|
|
106
110
|
</Stack>
|
|
107
111
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** @jest-environment jsdom */
|
|
2
|
+
|
|
3
|
+
import {render} from '../../../../test'
|
|
4
|
+
import {Inline} from '../../primitives'
|
|
5
|
+
import {Hotkeys} from './hotkeys'
|
|
6
|
+
|
|
7
|
+
jest.mock('../../primitives', () => {
|
|
8
|
+
const actual = jest.requireActual('../../primitives')
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
...actual,
|
|
12
|
+
Inline: jest.fn((props: Record<string, unknown>) => (actual.Inline as any).render(props, null)),
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
describe('components/hotkeys spacing', () => {
|
|
17
|
+
const mockedInline = jest.mocked(Inline)
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
mockedInline.mockClear()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('should support `space` and `gap` with the same behavior', () => {
|
|
24
|
+
render(<Hotkeys keys={['Ctrl', 'S']} space={2} />)
|
|
25
|
+
expect(mockedInline.mock.calls.map(([props]) => props)).toContainEqual(
|
|
26
|
+
expect.objectContaining({gap: [2]}),
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
mockedInline.mockClear()
|
|
30
|
+
render(<Hotkeys gap={2} keys={['Ctrl', 'S']} />)
|
|
31
|
+
expect(mockedInline.mock.calls.map(([props]) => props)).toContainEqual(
|
|
32
|
+
expect.objectContaining({gap: [2]}),
|
|
33
|
+
)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('should prefer `gap` over `space` when both are provided', () => {
|
|
37
|
+
render(<Hotkeys gap={3} keys={['Ctrl', 'S']} space={1} />)
|
|
38
|
+
const propsList = mockedInline.mock.calls.map(([props]) => props)
|
|
39
|
+
expect(propsList).toContainEqual(expect.objectContaining({gap: [3]}))
|
|
40
|
+
expect(propsList).not.toContainEqual(expect.objectContaining({gap: [1]}))
|
|
41
|
+
})
|
|
42
|
+
})
|
|
@@ -10,8 +10,12 @@ import {Radius} from '../../types'
|
|
|
10
10
|
*/
|
|
11
11
|
export interface HotkeysProps {
|
|
12
12
|
fontSize?: number | number[]
|
|
13
|
+
gap?: number | number[]
|
|
13
14
|
padding?: number | number[]
|
|
14
15
|
radius?: Radius | Radius[]
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated Use `gap` instead. `space` will be removed in v4.
|
|
18
|
+
*/
|
|
15
19
|
space?: number | number[]
|
|
16
20
|
keys?: string[]
|
|
17
21
|
}
|
|
@@ -40,8 +44,8 @@ export const Hotkeys = forwardRef(function Hotkeys(
|
|
|
40
44
|
props: HotkeysProps & Omit<React.HTMLProps<HTMLElement>, 'as' | 'ref' | 'size'>,
|
|
41
45
|
ref: React.Ref<HTMLElement>,
|
|
42
46
|
) {
|
|
43
|
-
const {fontSize, keys, padding, radius, space:
|
|
44
|
-
const
|
|
47
|
+
const {fontSize, gap, keys, padding, radius, space: deprecated_space = 0.5, ...restProps} = props
|
|
48
|
+
const spacing = _getArrayProp(gap === undefined ? deprecated_space : gap)
|
|
45
49
|
|
|
46
50
|
if (!keys || keys.length === 0) {
|
|
47
51
|
return <></>
|
|
@@ -49,7 +53,7 @@ export const Hotkeys = forwardRef(function Hotkeys(
|
|
|
49
53
|
|
|
50
54
|
return (
|
|
51
55
|
<StyledHotkeys data-ui="Hotkeys" {...restProps} ref={ref}>
|
|
52
|
-
<Inline as="span"
|
|
56
|
+
<Inline as="span" gap={spacing}>
|
|
53
57
|
{keys.map((key, i) => (
|
|
54
58
|
<Key fontSize={fontSize} key={i} padding={padding} radius={radius}>
|
|
55
59
|
{key}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/** @jest-environment jsdom */
|
|
2
|
+
|
|
3
|
+
import {render} from '../../../../test'
|
|
4
|
+
import {Stack} from '../../primitives'
|
|
5
|
+
import {Menu} from './menu'
|
|
6
|
+
|
|
7
|
+
jest.mock('../../primitives', () => {
|
|
8
|
+
const actual = jest.requireActual('../../primitives')
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
...actual,
|
|
12
|
+
Stack: jest.fn((props: Record<string, unknown>) => (actual.Stack as any).render(props, null)),
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
jest.mock('../../utils', () => {
|
|
17
|
+
const actual = jest.requireActual('../../utils')
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
...actual,
|
|
21
|
+
useLayer: () => ({isTopLayer: true}),
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
describe('components/menu spacing', () => {
|
|
26
|
+
const mockedStack = jest.mocked(Stack)
|
|
27
|
+
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
mockedStack.mockClear()
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('should support `space` and `gap` with the same behavior', () => {
|
|
33
|
+
render(
|
|
34
|
+
<Menu space={2}>
|
|
35
|
+
<div>Item</div>
|
|
36
|
+
</Menu>,
|
|
37
|
+
)
|
|
38
|
+
expect(mockedStack.mock.calls.map(([props]) => props)).toContainEqual(
|
|
39
|
+
expect.objectContaining({gap: 2}),
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
mockedStack.mockClear()
|
|
43
|
+
render(
|
|
44
|
+
<Menu gap={2}>
|
|
45
|
+
<div>Item</div>
|
|
46
|
+
</Menu>,
|
|
47
|
+
)
|
|
48
|
+
expect(mockedStack.mock.calls.map(([props]) => props)).toContainEqual(
|
|
49
|
+
expect.objectContaining({gap: 2}),
|
|
50
|
+
)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('should prefer `gap` over `space` when both are provided', () => {
|
|
54
|
+
render(
|
|
55
|
+
<Menu gap={3} space={1}>
|
|
56
|
+
<div>Item</div>
|
|
57
|
+
</Menu>,
|
|
58
|
+
)
|
|
59
|
+
const propsList = mockedStack.mock.calls.map(([props]) => props)
|
|
60
|
+
expect(propsList).toContainEqual(expect.objectContaining({gap: 3}))
|
|
61
|
+
expect(propsList).not.toContainEqual(expect.objectContaining({gap: 1}))
|
|
62
|
+
})
|
|
63
|
+
})
|
|
@@ -27,6 +27,10 @@ export interface MenuProps extends ResponsivePaddingProps {
|
|
|
27
27
|
'originElement'?: HTMLElement | null
|
|
28
28
|
'registerElement'?: (el: HTMLElement) => () => void
|
|
29
29
|
'shouldFocus'?: 'first' | 'last' | null
|
|
30
|
+
'gap'?: number | number[]
|
|
31
|
+
/**
|
|
32
|
+
* @deprecated Use `gap` instead. `space` will be removed in v4.
|
|
33
|
+
*/
|
|
30
34
|
'space'?: number | number[]
|
|
31
35
|
'aria-labelledby'?: string
|
|
32
36
|
'onBlurCapture'?: (event: FocusEvent) => void
|
|
@@ -61,9 +65,11 @@ export const Menu = forwardRef(function Menu(
|
|
|
61
65
|
padding = 1,
|
|
62
66
|
registerElement,
|
|
63
67
|
shouldFocus: _shouldFocus,
|
|
64
|
-
|
|
68
|
+
gap,
|
|
69
|
+
space: deprecated_space = 1,
|
|
65
70
|
...restProps
|
|
66
71
|
} = props
|
|
72
|
+
const spacing = gap === undefined ? deprecated_space : gap
|
|
67
73
|
const shouldFocus =
|
|
68
74
|
_shouldFocus ?? ((props.focusFirst && 'first') || (props.focusLast && 'last') || null)
|
|
69
75
|
|
|
@@ -164,7 +170,7 @@ export const Menu = forwardRef(function Menu(
|
|
|
164
170
|
role="menu"
|
|
165
171
|
tabIndex={-1}
|
|
166
172
|
>
|
|
167
|
-
<Stack
|
|
173
|
+
<Stack gap={spacing}>{children}</Stack>
|
|
168
174
|
</StyledMenu>
|
|
169
175
|
</MenuContext.Provider>
|
|
170
176
|
)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** @jest-environment jsdom */
|
|
2
|
+
|
|
3
|
+
import {render} from '../../../../test'
|
|
4
|
+
import {Flex} from '../../primitives'
|
|
5
|
+
import {MenuContext, MenuContextValue} from './menuContext'
|
|
6
|
+
import {MenuGroup} from './menuGroup'
|
|
7
|
+
import {MenuItem} from './menuItem'
|
|
8
|
+
|
|
9
|
+
jest.mock('../../primitives', () => {
|
|
10
|
+
const actual = jest.requireActual('../../primitives')
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
...actual,
|
|
14
|
+
Flex: jest.fn((props: Record<string, unknown>) => (actual.Flex as any).render(props, null)),
|
|
15
|
+
Popover: jest.fn(
|
|
16
|
+
({
|
|
17
|
+
children,
|
|
18
|
+
}: {
|
|
19
|
+
children?: React.ReactNode
|
|
20
|
+
}) => children,
|
|
21
|
+
),
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const menuContextValue: MenuContextValue = {
|
|
26
|
+
version: 2,
|
|
27
|
+
activeElement: null,
|
|
28
|
+
mount: () => () => undefined,
|
|
29
|
+
onItemMouseEnter: () => undefined,
|
|
30
|
+
onItemMouseLeave: () => undefined,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function renderMenuGroup(props: Partial<React.ComponentProps<typeof MenuGroup>> = {}) {
|
|
34
|
+
return render(
|
|
35
|
+
<MenuContext.Provider value={menuContextValue}>
|
|
36
|
+
<MenuGroup id="menu-group" text="Menu group" {...props}>
|
|
37
|
+
<MenuItem id="submenu-item" text="Submenu item" />
|
|
38
|
+
</MenuGroup>
|
|
39
|
+
</MenuContext.Provider>,
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
describe('components/menuGroup spacing', () => {
|
|
44
|
+
const mockedFlex = jest.mocked(Flex)
|
|
45
|
+
|
|
46
|
+
beforeEach(() => {
|
|
47
|
+
mockedFlex.mockClear()
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('should support `space` and `gap` with the same behavior', () => {
|
|
51
|
+
renderMenuGroup({space: 2})
|
|
52
|
+
expect(mockedFlex.mock.calls.map(([props]) => props)).toContainEqual(
|
|
53
|
+
expect.objectContaining({gap: 2}),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
mockedFlex.mockClear()
|
|
57
|
+
renderMenuGroup({gap: 2})
|
|
58
|
+
expect(mockedFlex.mock.calls.map(([props]) => props)).toContainEqual(
|
|
59
|
+
expect.objectContaining({gap: 2}),
|
|
60
|
+
)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('should prefer `gap` over `space` when both are provided', () => {
|
|
64
|
+
renderMenuGroup({gap: 3, space: 1})
|
|
65
|
+
const propsList = mockedFlex.mock.calls.map(([props]) => props)
|
|
66
|
+
expect(propsList).toContainEqual(expect.objectContaining({gap: 3}))
|
|
67
|
+
expect(propsList).not.toContainEqual(expect.objectContaining({gap: 1}))
|
|
68
|
+
})
|
|
69
|
+
})
|
|
@@ -31,6 +31,10 @@ export interface MenuGroupProps {
|
|
|
31
31
|
padding?: number | number[]
|
|
32
32
|
popover?: Omit<PopoverProps, 'content' | 'open'>
|
|
33
33
|
radius?: Radius | Radius[]
|
|
34
|
+
gap?: number | number[]
|
|
35
|
+
/**
|
|
36
|
+
* @deprecated Use `gap` instead. `space` will be removed in v4.
|
|
37
|
+
*/
|
|
34
38
|
space?: number | number[]
|
|
35
39
|
text: React.ReactNode
|
|
36
40
|
tone?: SelectableTone
|
|
@@ -53,11 +57,13 @@ export function MenuGroup(
|
|
|
53
57
|
padding = 3,
|
|
54
58
|
popover,
|
|
55
59
|
radius = 2,
|
|
56
|
-
|
|
60
|
+
gap,
|
|
61
|
+
space: deprecated_space = 3,
|
|
57
62
|
text,
|
|
58
63
|
tone = 'default',
|
|
59
64
|
...restProps
|
|
60
65
|
} = props
|
|
66
|
+
const spacing = gap === undefined ? deprecated_space : gap
|
|
61
67
|
const menu = useMenu()
|
|
62
68
|
const {scheme} = useRootTheme()
|
|
63
69
|
const {
|
|
@@ -193,7 +199,7 @@ export function MenuGroup(
|
|
|
193
199
|
tabIndex={-1}
|
|
194
200
|
type={as === 'button' ? 'button' : undefined}
|
|
195
201
|
>
|
|
196
|
-
<Flex gap={
|
|
202
|
+
<Flex gap={spacing} padding={padding}>
|
|
197
203
|
{IconComponent && (
|
|
198
204
|
<Text size={fontSize}>
|
|
199
205
|
{isValidElement(IconComponent) && IconComponent}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** @jest-environment jsdom */
|
|
2
|
+
|
|
3
|
+
import {render} from '../../../../test'
|
|
4
|
+
import {Flex} from '../../primitives'
|
|
5
|
+
import {MenuContext, MenuContextValue} from './menuContext'
|
|
6
|
+
import {MenuItem} from './menuItem'
|
|
7
|
+
|
|
8
|
+
jest.mock('../../primitives', () => {
|
|
9
|
+
const actual = jest.requireActual('../../primitives')
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
...actual,
|
|
13
|
+
Flex: jest.fn((props: Record<string, unknown>) => (actual.Flex as any).render(props, null)),
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const menuContextValue: MenuContextValue = {
|
|
18
|
+
version: 2,
|
|
19
|
+
activeElement: null,
|
|
20
|
+
mount: () => () => undefined,
|
|
21
|
+
onItemMouseEnter: () => undefined,
|
|
22
|
+
onItemMouseLeave: () => undefined,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function renderMenuItem(props: Partial<React.ComponentProps<typeof MenuItem>> = {}) {
|
|
26
|
+
return render(
|
|
27
|
+
<MenuContext.Provider value={menuContextValue}>
|
|
28
|
+
<MenuItem id="menu-item" text="Menu item" {...props} />
|
|
29
|
+
</MenuContext.Provider>,
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe('components/menuItem spacing', () => {
|
|
34
|
+
const mockedFlex = jest.mocked(Flex)
|
|
35
|
+
|
|
36
|
+
beforeEach(() => {
|
|
37
|
+
mockedFlex.mockClear()
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('should support `space` and `gap` with the same behavior', () => {
|
|
41
|
+
renderMenuItem({space: 2})
|
|
42
|
+
expect(mockedFlex.mock.calls.map(([props]) => props)).toContainEqual(
|
|
43
|
+
expect.objectContaining({gap: 2}),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
mockedFlex.mockClear()
|
|
47
|
+
renderMenuItem({gap: 2})
|
|
48
|
+
expect(mockedFlex.mock.calls.map(([props]) => props)).toContainEqual(
|
|
49
|
+
expect.objectContaining({gap: 2}),
|
|
50
|
+
)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('should prefer `gap` over `space` when both are provided', () => {
|
|
54
|
+
renderMenuItem({gap: 3, space: 1})
|
|
55
|
+
const propsList = mockedFlex.mock.calls.map(([props]) => props)
|
|
56
|
+
expect(propsList).toContainEqual(expect.objectContaining({gap: 3}))
|
|
57
|
+
expect(propsList).not.toContainEqual(expect.objectContaining({gap: 1}))
|
|
58
|
+
})
|
|
59
|
+
})
|
|
@@ -30,6 +30,10 @@ export interface MenuItemProps extends ResponsivePaddingProps, ResponsiveRadiusP
|
|
|
30
30
|
iconRight?: React.ElementType | React.ReactNode
|
|
31
31
|
pressed?: boolean
|
|
32
32
|
selected?: boolean
|
|
33
|
+
gap?: number | number[]
|
|
34
|
+
/**
|
|
35
|
+
* @deprecated Use `gap` instead. `space` will be removed in v4.
|
|
36
|
+
*/
|
|
33
37
|
space?: number | number[]
|
|
34
38
|
text?: React.ReactNode
|
|
35
39
|
tone?: SelectableTone
|
|
@@ -62,11 +66,13 @@ export const MenuItem = forwardRef(function MenuItem(
|
|
|
62
66
|
pressed,
|
|
63
67
|
radius = 2,
|
|
64
68
|
selected: selectedProp,
|
|
65
|
-
|
|
69
|
+
gap,
|
|
70
|
+
space: deprecated_space = 3,
|
|
66
71
|
text,
|
|
67
72
|
tone = 'default',
|
|
68
73
|
...restProps
|
|
69
74
|
} = props
|
|
75
|
+
const spacing = gap === undefined ? deprecated_space : gap
|
|
70
76
|
const {scheme} = useRootTheme()
|
|
71
77
|
const menu = useMenu()
|
|
72
78
|
const {
|
|
@@ -137,7 +143,7 @@ export const MenuItem = forwardRef(function MenuItem(
|
|
|
137
143
|
type={as === 'button' ? 'button' : undefined}
|
|
138
144
|
>
|
|
139
145
|
{(IconComponent || text || IconRightComponent) && (
|
|
140
|
-
<Flex as="span" gap={
|
|
146
|
+
<Flex as="span" gap={spacing} align="center" {...paddingProps}>
|
|
141
147
|
{IconComponent && (
|
|
142
148
|
<Text size={fontSize}>
|
|
143
149
|
{isValidElement(IconComponent) && IconComponent}
|
|
@@ -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
|
+
})
|
|
@@ -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
|
|
|
@@ -30,7 +34,8 @@ export const Tree = forwardRef(function Tree(
|
|
|
30
34
|
Omit<React.HTMLProps<HTMLDivElement>, 'align' | 'as' | 'height' | 'ref' | 'role' | 'wrap'>,
|
|
31
35
|
forwardedRef: React.ForwardedRef<HTMLDivElement>,
|
|
32
36
|
): React.JSX.Element {
|
|
33
|
-
const {children, space = 1, onFocus, ...restProps} = props
|
|
37
|
+
const {children, gap, space: deprecated_space = 1, onFocus, ...restProps} = props
|
|
38
|
+
const spacing = gap === undefined ? deprecated_space : gap
|
|
34
39
|
const ref = useRef<HTMLDivElement | null>(null)
|
|
35
40
|
const [focusedElement, setFocusedElement] = useState<HTMLElement | null>(null)
|
|
36
41
|
const focusedElementRef = useRef(focusedElement)
|
|
@@ -89,10 +94,11 @@ export const Tree = forwardRef(function Tree(
|
|
|
89
94
|
registerItem,
|
|
90
95
|
setExpanded,
|
|
91
96
|
setFocusedElement,
|
|
92
|
-
|
|
97
|
+
gap: spacing,
|
|
98
|
+
space: spacing,
|
|
93
99
|
state,
|
|
94
100
|
}),
|
|
95
|
-
[focusedElement, itemElements, path, registerItem, setExpanded,
|
|
101
|
+
[focusedElement, itemElements, path, registerItem, setExpanded, spacing, state],
|
|
96
102
|
)
|
|
97
103
|
|
|
98
104
|
const handleKeyDown = useCallback(
|
|
@@ -221,7 +227,7 @@ export const Tree = forwardRef(function Tree(
|
|
|
221
227
|
onKeyDown={handleKeyDown}
|
|
222
228
|
ref={ref}
|
|
223
229
|
role="tree"
|
|
224
|
-
|
|
230
|
+
gap={spacing}
|
|
225
231
|
>
|
|
226
232
|
{children}
|
|
227
233
|
</Stack>
|