@sanity/ui 2.0.0-alpha.2 → 2.0.0-alpha.20
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.cjs.mjs +28 -0
- package/dist/index.d.ts +476 -12
- package/dist/index.esm.js +1281 -503
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1309 -503
- package/dist/index.js.map +1 -1
- package/package.json +6 -8
- package/src/components/autocomplete/autocomplete.tsx +6 -0
- package/src/components/dialog/constants.ts +4 -0
- package/src/components/dialog/dialog.tsx +79 -15
- package/src/components/hotkeys/hotkeys.tsx +2 -0
- package/src/components/menu/menu.tsx +2 -0
- package/src/components/menu/menuButton.tsx +2 -0
- package/src/components/menu/menuGroup.tsx +22 -23
- package/src/components/menu/menuItem.tsx +29 -35
- package/src/components/tab/tab.tsx +4 -1
- package/src/components/toast/toast.tsx +4 -0
- package/src/primitives/_selectable/style.ts +2 -1
- package/src/primitives/avatar/avatar.tsx +16 -9
- package/src/primitives/avatar/avatarCounter.tsx +3 -3
- package/src/primitives/avatar/styles.ts +1 -1
- package/src/primitives/badge/badge.tsx +7 -3
- package/src/primitives/box/box.tsx +3 -0
- package/src/primitives/button/__workshop__/sanityUploadButton.tsx +2 -1
- package/src/primitives/button/button.tsx +7 -3
- package/src/primitives/button/styles.ts +9 -2
- package/src/primitives/card/card.tsx +4 -0
- package/src/primitives/card/styles.ts +2 -0
- package/src/primitives/checkbox/checkbox.tsx +2 -0
- package/src/primitives/code/code.tsx +1 -0
- package/src/primitives/container/container.tsx +2 -0
- package/src/primitives/flex/flex.tsx +2 -0
- package/src/primitives/grid/grid.tsx +2 -0
- package/src/primitives/heading/heading.tsx +2 -0
- package/src/primitives/inline/inline.tsx +3 -0
- package/src/primitives/kbd/kbd.tsx +2 -0
- package/src/primitives/label/label.tsx +2 -0
- package/src/primitives/popover/popover.tsx +6 -1
- package/src/primitives/radio/radio.tsx +2 -0
- package/src/primitives/select/select.tsx +2 -0
- package/src/primitives/select/styles.ts +2 -0
- package/src/primitives/spinner/spinner.tsx +2 -0
- package/src/primitives/stack/stack.tsx +2 -0
- package/src/primitives/switch/switch.tsx +4 -0
- package/src/primitives/text/text.tsx +3 -0
- package/src/primitives/textArea/textArea.tsx +4 -1
- package/src/primitives/textInput/textInput.tsx +10 -1
- package/src/primitives/tooltip/tooltip.test.tsx +67 -0
- package/src/primitives/tooltip/tooltip.tsx +28 -5
- package/src/primitives/types.ts +4 -0
- package/src/styles/input/textInputStyle.ts +11 -6
- package/src/theme/_internal/__workshop__/build/story.tsx +288 -0
- package/src/theme/_internal/__workshop__/build/theme.ts +3 -0
- package/src/theme/_internal/__workshop__/index.ts +14 -0
- package/src/theme/_internal/build/buildTheme.test.ts +78 -0
- package/src/theme/_internal/build/buildTheme.ts +16 -0
- package/src/theme/_internal/build/colorTheme/buildColorTheme.test.ts +185 -0
- package/src/theme/_internal/build/colorTheme/buildColorTheme.ts +164 -0
- package/src/theme/_internal/build/colorTheme/renderColorTheme.ts +242 -0
- package/src/theme/_internal/build/colorTheme/resolveColorTokens.ts +121 -0
- package/src/theme/_internal/build/defaults/colorPalette.ts +8 -0
- package/src/theme/_internal/build/defaults/colorTokens.ts +147 -0
- package/src/theme/_internal/build/helpers.ts +65 -0
- package/src/theme/_internal/build/index.ts +1 -0
- package/src/theme/_internal/config/helpers.ts +47 -0
- package/src/theme/_internal/config/index.ts +3 -0
- package/src/theme/_internal/config/token/index.ts +2 -0
- package/src/theme/_internal/config/token/parseTokenKey.test.ts +72 -0
- package/src/theme/_internal/config/token/parseTokenKey.ts +88 -0
- package/src/theme/_internal/config/token/parseTokenValue.test.ts +45 -0
- package/src/theme/_internal/config/token/parseTokenValue.ts +123 -0
- package/src/theme/_internal/config/types.ts +137 -0
- package/src/theme/_internal/constants.ts +48 -0
- package/src/theme/_internal/helpers.ts +19 -0
- package/src/theme/_internal/index.ts +5 -0
- package/src/theme/_internal/types.ts +91 -0
- package/src/theme/index.ts +1 -0
- package/src/theme/lib/color-fns/blend/multiply.ts +2 -2
- package/src/theme/lib/color-fns/blend/screen.ts +2 -2
- package/src/theme/lib/color-fns/convert.ts +15 -1
- package/src/theme/lib/color-fns/parse.ts +7 -3
- package/src/theme/lib/color-fns/types.ts +11 -0
- package/src/theme/lib/theme/avatar.ts +2 -0
- package/src/theme/lib/theme/color/_legacy/createColorTheme.ts +7 -0
- package/src/theme/lib/theme/color/_legacy/index.ts +1 -0
- package/src/theme/lib/theme/color/_legacy/legacyColor.ts +3997 -0
- package/src/theme/studioTheme/color.ts +98 -82
- package/src/theme/studioTheme/helpers.ts +15 -1
- package/src/theme/studioTheme/theme.ts +5 -5
- package/src/theme/studioTheme/tints.ts +244 -84
- package/src/types/button.ts +5 -0
|
@@ -4,7 +4,7 @@ import styled from 'styled-components'
|
|
|
4
4
|
|
|
5
5
|
const SanityUploadButton = styled(Button).attrs({forwardedAs: 'label'})`
|
|
6
6
|
& input {
|
|
7
|
-
|
|
7
|
+
appearance: none;
|
|
8
8
|
overflow: hidden;
|
|
9
9
|
overflow: clip;
|
|
10
10
|
top: 0;
|
|
@@ -14,6 +14,7 @@ const SanityUploadButton = styled(Button).attrs({forwardedAs: 'label'})`
|
|
|
14
14
|
opacity: 0;
|
|
15
15
|
position: absolute;
|
|
16
16
|
max-width: 0;
|
|
17
|
+
width: -webkit-fill-available;
|
|
17
18
|
width: stretch;
|
|
18
19
|
}
|
|
19
20
|
|
|
@@ -5,7 +5,7 @@ import {useArrayProp} from '../../hooks'
|
|
|
5
5
|
import {ThemeProps} from '../../styles'
|
|
6
6
|
import {responsiveRadiusStyle, ResponsiveRadiusStyleProps} from '../../styles/internal'
|
|
7
7
|
import {useTheme} from '../../theme'
|
|
8
|
-
import {ButtonMode, ButtonTextAlign, ButtonTone, FlexJustify} from '../../types'
|
|
8
|
+
import {ButtonMode, ButtonTextAlign, ButtonTone, ButtonWidth, FlexJustify} from '../../types'
|
|
9
9
|
import {Box} from '../box'
|
|
10
10
|
import {Flex} from '../flex'
|
|
11
11
|
import {Spinner} from '../spinner'
|
|
@@ -34,10 +34,12 @@ export interface ButtonProps extends ResponsivePaddingProps, ResponsiveRadiusPro
|
|
|
34
34
|
text?: React.ReactNode
|
|
35
35
|
tone?: ButtonTone
|
|
36
36
|
type?: 'button' | 'reset' | 'submit'
|
|
37
|
+
width?: ButtonWidth
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
const Root = styled.button<
|
|
40
|
-
{$mode: ButtonMode; $tone: ButtonTone} & ResponsiveRadiusStyleProps &
|
|
41
|
+
{$mode: ButtonMode; $tone: ButtonTone; $width?: ButtonWidth} & ResponsiveRadiusStyleProps &
|
|
42
|
+
ThemeProps
|
|
41
43
|
>(responsiveRadiusStyle, buttonBaseStyles, buttonColorStyles)
|
|
42
44
|
|
|
43
45
|
const LoadingBox = styled.div`
|
|
@@ -59,7 +61,7 @@ const LoadingBox = styled.div`
|
|
|
59
61
|
* @public
|
|
60
62
|
*/
|
|
61
63
|
export const Button = forwardRef(function Button(
|
|
62
|
-
props: ButtonProps & Omit<React.HTMLProps<HTMLButtonElement>, 'as'>,
|
|
64
|
+
props: ButtonProps & Omit<React.HTMLProps<HTMLButtonElement>, 'as' | 'width'>,
|
|
63
65
|
ref: React.ForwardedRef<HTMLButtonElement>,
|
|
64
66
|
) {
|
|
65
67
|
const {
|
|
@@ -86,6 +88,7 @@ export const Button = forwardRef(function Button(
|
|
|
86
88
|
tone = 'default',
|
|
87
89
|
type = 'button',
|
|
88
90
|
muted = false,
|
|
91
|
+
width,
|
|
89
92
|
...restProps
|
|
90
93
|
} = props
|
|
91
94
|
|
|
@@ -128,6 +131,7 @@ export const Button = forwardRef(function Button(
|
|
|
128
131
|
disabled={Boolean(loading || disabled)}
|
|
129
132
|
ref={ref}
|
|
130
133
|
type={type}
|
|
134
|
+
$width={width}
|
|
131
135
|
>
|
|
132
136
|
{Boolean(loading) && (
|
|
133
137
|
<LoadingBox>
|
|
@@ -2,13 +2,13 @@ import {css} from 'styled-components'
|
|
|
2
2
|
import {ThemeProps} from '../../styles'
|
|
3
3
|
import {_colorVarsStyle} from '../../styles/colorVars'
|
|
4
4
|
import {focusRingBorderStyle, focusRingStyle} from '../../styles/internal'
|
|
5
|
-
import {ButtonMode, ButtonTone} from '../../types'
|
|
5
|
+
import {ButtonMode, ButtonTone, ButtonWidth} from '../../types'
|
|
6
6
|
import {CSSObject} from '../../types/styled'
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @internal
|
|
10
10
|
*/
|
|
11
|
-
export function buttonBaseStyles(): ReturnType<typeof css> {
|
|
11
|
+
export function buttonBaseStyles({$width}: {$width?: ButtonWidth}): ReturnType<typeof css> {
|
|
12
12
|
return css`
|
|
13
13
|
-webkit-font-smoothing: inherit;
|
|
14
14
|
appearance: none;
|
|
@@ -27,6 +27,13 @@ export function buttonBaseStyles(): ReturnType<typeof css> {
|
|
|
27
27
|
text-align: left;
|
|
28
28
|
position: relative;
|
|
29
29
|
|
|
30
|
+
${$width === 'fill' &&
|
|
31
|
+
css`
|
|
32
|
+
width: -moz-available;
|
|
33
|
+
width: -webkit-fill-available;
|
|
34
|
+
width: stretch;
|
|
35
|
+
`}
|
|
36
|
+
|
|
30
37
|
& > span {
|
|
31
38
|
display: block;
|
|
32
39
|
flex: 1;
|
|
@@ -48,6 +48,9 @@ const Root = styled(Box)<
|
|
|
48
48
|
>(responsiveBorderStyle, responsiveRadiusStyle, responsiveShadowStyle, cardStyle)
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
|
+
* The `Card` component acts much like a `Box`, but with a background and foreground color.
|
|
52
|
+
* Components within a `Card` inherit its colors.
|
|
53
|
+
*
|
|
51
54
|
* @public
|
|
52
55
|
*/
|
|
53
56
|
export const Card = forwardRef(function Card(
|
|
@@ -76,6 +79,7 @@ export const Card = forwardRef(function Card(
|
|
|
76
79
|
const rootTheme = useRootTheme()
|
|
77
80
|
const tone = toneProp === 'inherit' ? rootTheme.tone : toneProp
|
|
78
81
|
|
|
82
|
+
// TODO: Consider adding the wrapper approach for nested cards in which the tones are not changing, avoid unnecessary ThemeColorProvider
|
|
79
83
|
return (
|
|
80
84
|
<ThemeColorProvider scheme={scheme} tone={tone}>
|
|
81
85
|
<Root
|
|
@@ -11,6 +11,7 @@ import {codeBaseStyle} from './styles'
|
|
|
11
11
|
*/
|
|
12
12
|
export interface CodeProps {
|
|
13
13
|
as?: React.ElementType | keyof JSX.IntrinsicElements
|
|
14
|
+
/** Define the language to use for syntax highlighting. */
|
|
14
15
|
language?: string
|
|
15
16
|
size?: number | number[]
|
|
16
17
|
weight?: string
|
|
@@ -13,6 +13,8 @@ export interface GridProps extends Omit<BoxProps, 'display'>, ResponsiveGridProp
|
|
|
13
13
|
const Root = styled(Box)<ResponsiveGridStyleProps>(responsiveGridStyle)
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
+
* The `Grid` component is for building 2-dimensional layers (based on CSS grid).
|
|
17
|
+
*
|
|
16
18
|
* @public
|
|
17
19
|
*/
|
|
18
20
|
export const Grid = forwardRef(function Grid(
|
|
@@ -10,12 +10,15 @@ import {ResponsiveInlineSpaceStyleProps} from './types'
|
|
|
10
10
|
* @public
|
|
11
11
|
*/
|
|
12
12
|
export interface InlineProps extends Omit<BoxProps, 'display'> {
|
|
13
|
+
/** The spacing between children. */
|
|
13
14
|
space?: number | number[]
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
const Root = styled(Box)<ResponsiveInlineSpaceStyleProps>(inlineBaseStyle, inlineSpaceStyle)
|
|
17
18
|
|
|
18
19
|
/**
|
|
20
|
+
* The `Inline` component is a layout utility for aligning and spacing items horizontally.
|
|
21
|
+
*
|
|
19
22
|
* @public
|
|
20
23
|
*/
|
|
21
24
|
export const Inline = forwardRef(function Inline(
|
|
@@ -59,6 +59,7 @@ export interface PopoverProps
|
|
|
59
59
|
overflow?: BoxOverflow
|
|
60
60
|
padding?: number | number[]
|
|
61
61
|
placement?: Placement
|
|
62
|
+
/** Whether or not to render the popover in a portal element. */
|
|
62
63
|
portal?: boolean | string
|
|
63
64
|
preventOverflow?: boolean
|
|
64
65
|
referenceBoundary?: HTMLElement | null
|
|
@@ -72,7 +73,11 @@ export interface PopoverProps
|
|
|
72
73
|
width?: PopoverWidth | PopoverWidth[]
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
/**
|
|
76
|
+
/**
|
|
77
|
+
* The `Popover` component is used to display some content on top of another.
|
|
78
|
+
*
|
|
79
|
+
* @public
|
|
80
|
+
*/
|
|
76
81
|
export const Popover = memo(
|
|
77
82
|
forwardRef(function Popover(
|
|
78
83
|
props: PopoverProps &
|
|
@@ -15,6 +15,8 @@ export interface StackProps extends BoxProps {
|
|
|
15
15
|
const Root = styled(Box)<ResponsiveStackSpaceStyleProps>(stackBaseStyle, responsiveStackSpaceStyle)
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
+
* The `Stack` component is used to place elements on top of each other.
|
|
19
|
+
*
|
|
18
20
|
* @public
|
|
19
21
|
*/
|
|
20
22
|
export const Stack = forwardRef(function Stack(
|
|
@@ -23,6 +23,10 @@ const Track = styled.span(switchTrackStyles)
|
|
|
23
23
|
const Thumb = styled.span<{$checked?: boolean; $indeterminate?: boolean}>(switchThumbStyles)
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
+
* The `Switch` component allows the user to toggle a setting on and off.
|
|
27
|
+
*
|
|
28
|
+
* Extends all properties of an `<input type="checkbox" />` element, except type.
|
|
29
|
+
*
|
|
26
30
|
* @public
|
|
27
31
|
*/
|
|
28
32
|
export const Switch = forwardRef(function Switch(
|
|
@@ -17,6 +17,7 @@ export interface TextProps {
|
|
|
17
17
|
accent?: boolean
|
|
18
18
|
align?: TextAlign | TextAlign[]
|
|
19
19
|
as?: React.ElementType | keyof JSX.IntrinsicElements
|
|
20
|
+
/** When `true` the text color will be muted. */
|
|
20
21
|
muted?: boolean
|
|
21
22
|
size?: number | number[]
|
|
22
23
|
/**
|
|
@@ -43,6 +44,8 @@ const SpanWithTextOverflow = styled.span`
|
|
|
43
44
|
`
|
|
44
45
|
|
|
45
46
|
/**
|
|
47
|
+
* The `Text` component is an agile, themed typographic element.
|
|
48
|
+
*
|
|
46
49
|
* @public
|
|
47
50
|
*/
|
|
48
51
|
export const Text = forwardRef(function Text(
|
|
@@ -48,6 +48,9 @@ const Presentation = styled.div<ResponsiveRadiusStyleProps & TextInputRepresenta
|
|
|
48
48
|
)
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
|
+
* A multiline text input.
|
|
52
|
+
*
|
|
53
|
+
|
|
51
54
|
* @public
|
|
52
55
|
*/
|
|
53
56
|
export const TextArea = forwardRef(function TextArea(
|
|
@@ -60,7 +63,7 @@ export const TextArea = forwardRef(function TextArea(
|
|
|
60
63
|
disabled = false,
|
|
61
64
|
fontSize = 2,
|
|
62
65
|
padding = 3,
|
|
63
|
-
radius =
|
|
66
|
+
radius = 2,
|
|
64
67
|
weight,
|
|
65
68
|
...restProps
|
|
66
69
|
} = props
|
|
@@ -50,6 +50,10 @@ export type TextInputType =
|
|
|
50
50
|
* @public
|
|
51
51
|
*/
|
|
52
52
|
export interface TextInputProps {
|
|
53
|
+
/**
|
|
54
|
+
* @beta
|
|
55
|
+
*/
|
|
56
|
+
__unstable_disableFocusRing?: boolean
|
|
53
57
|
border?: boolean
|
|
54
58
|
/**
|
|
55
59
|
* @beta
|
|
@@ -140,6 +144,8 @@ const TextInputClearButton = styled(Button)({
|
|
|
140
144
|
})
|
|
141
145
|
|
|
142
146
|
/**
|
|
147
|
+
* Single line text input.
|
|
148
|
+
*
|
|
143
149
|
* @public
|
|
144
150
|
*/
|
|
145
151
|
export const TextInput = forwardRef(function TextInput(
|
|
@@ -147,6 +153,7 @@ export const TextInput = forwardRef(function TextInput(
|
|
|
147
153
|
forwardedRef: React.Ref<HTMLInputElement>,
|
|
148
154
|
) {
|
|
149
155
|
const {
|
|
156
|
+
__unstable_disableFocusRing,
|
|
150
157
|
border = true,
|
|
151
158
|
clearButton,
|
|
152
159
|
disabled = false,
|
|
@@ -156,7 +163,7 @@ export const TextInput = forwardRef(function TextInput(
|
|
|
156
163
|
onClear,
|
|
157
164
|
padding: paddingProp = 3,
|
|
158
165
|
prefix,
|
|
159
|
-
radius: radiusProp =
|
|
166
|
+
radius: radiusProp = 2,
|
|
160
167
|
readOnly,
|
|
161
168
|
space: spaceProp = 3,
|
|
162
169
|
suffix,
|
|
@@ -219,6 +226,7 @@ export const TextInput = forwardRef(function TextInput(
|
|
|
219
226
|
() => (
|
|
220
227
|
<Presentation
|
|
221
228
|
$hasPrefix={$hasPrefix}
|
|
229
|
+
$unstableDisableFocusRing={__unstable_disableFocusRing}
|
|
222
230
|
$hasSuffix={$hasSuffix}
|
|
223
231
|
$radius={radius}
|
|
224
232
|
$scheme={rootTheme.scheme}
|
|
@@ -247,6 +255,7 @@ export const TextInput = forwardRef(function TextInput(
|
|
|
247
255
|
</Presentation>
|
|
248
256
|
),
|
|
249
257
|
[
|
|
258
|
+
__unstable_disableFocusRing,
|
|
250
259
|
border,
|
|
251
260
|
fontSize,
|
|
252
261
|
icon,
|
|
@@ -275,4 +275,71 @@ describe('Tooltip', () => {
|
|
|
275
275
|
jest.clearAllMocks()
|
|
276
276
|
})
|
|
277
277
|
})
|
|
278
|
+
describe('Closing the <Tooltip /> with the Escape key', () => {
|
|
279
|
+
it('Standalone tooltip closes immediately with Escape key', () => {
|
|
280
|
+
const delay = 150
|
|
281
|
+
|
|
282
|
+
jest.useFakeTimers()
|
|
283
|
+
|
|
284
|
+
render(
|
|
285
|
+
<Tooltip
|
|
286
|
+
content={<Text size={1}>{'Tooltip content'}</Text>}
|
|
287
|
+
placement={'top'}
|
|
288
|
+
delay={delay}
|
|
289
|
+
>
|
|
290
|
+
<Button mode="bleed" text="Hover me" />
|
|
291
|
+
</Tooltip>,
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
const button = screen.getByText('Hover me')
|
|
295
|
+
|
|
296
|
+
// Validate tooltip content is not rendered
|
|
297
|
+
expect(screen.queryByText('Tooltip content')).not.toBeInTheDocument()
|
|
298
|
+
fireEvent.focus(button)
|
|
299
|
+
act(() => jest.advanceTimersByTime(delay))
|
|
300
|
+
|
|
301
|
+
// Validate tooltip content is rendered
|
|
302
|
+
screen.getByText('Tooltip content')
|
|
303
|
+
|
|
304
|
+
act(() => {
|
|
305
|
+
fireEvent.keyDown(button, {key: 'Escape', code: 'Escape'})
|
|
306
|
+
})
|
|
307
|
+
// Validate tooltip content is not rendered anymore
|
|
308
|
+
expect(screen.queryByText('Tooltip content')).not.toBeInTheDocument()
|
|
309
|
+
})
|
|
310
|
+
it('With <TooltipDelayGroupProvider /> closes immediately with Escape key', () => {
|
|
311
|
+
const delay = 150
|
|
312
|
+
|
|
313
|
+
jest.useFakeTimers()
|
|
314
|
+
|
|
315
|
+
render(
|
|
316
|
+
<TooltipDelayGroupProvider delay={{close: delay}}>
|
|
317
|
+
<Tooltip
|
|
318
|
+
content={<Text size={1}>{'Tooltip content'}</Text>}
|
|
319
|
+
placement={'top'}
|
|
320
|
+
delay={{close: delay}}
|
|
321
|
+
>
|
|
322
|
+
<Button mode="bleed" text="Hover me" />
|
|
323
|
+
</Tooltip>
|
|
324
|
+
</TooltipDelayGroupProvider>,
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
const button = screen.getByText('Hover me')
|
|
328
|
+
|
|
329
|
+
// Validate tooltip content is not rendered
|
|
330
|
+
expect(screen.queryByText('Tooltip content')).not.toBeInTheDocument()
|
|
331
|
+
fireEvent.focus(button)
|
|
332
|
+
|
|
333
|
+
act(() => jest.advanceTimersByTime(delay))
|
|
334
|
+
|
|
335
|
+
// Validate tooltip content is rendered
|
|
336
|
+
screen.getByText('Tooltip content')
|
|
337
|
+
|
|
338
|
+
act(() => {
|
|
339
|
+
fireEvent.keyDown(button, {key: 'Escape', code: 'Escape'})
|
|
340
|
+
})
|
|
341
|
+
// Validate tooltip content is not rendered anymore
|
|
342
|
+
expect(screen.queryByText('Tooltip content')).not.toBeInTheDocument()
|
|
343
|
+
})
|
|
344
|
+
})
|
|
278
345
|
})
|
|
@@ -48,6 +48,7 @@ export interface TooltipProps extends Omit<LayerProps, 'as'> {
|
|
|
48
48
|
fallbackPlacements?: Placement[]
|
|
49
49
|
padding?: number | number[]
|
|
50
50
|
placement?: Placement
|
|
51
|
+
/** Whether or not to render the tooltip in a portal element. */
|
|
51
52
|
portal?: boolean | string
|
|
52
53
|
scheme?: ThemeColorSchemeKey
|
|
53
54
|
shadow?: number | number[]
|
|
@@ -66,6 +67,8 @@ const Root = styled(Layer)`
|
|
|
66
67
|
`
|
|
67
68
|
|
|
68
69
|
/**
|
|
70
|
+
* Tooltips display information when hovering, focusing or tapping.
|
|
71
|
+
*
|
|
69
72
|
* @public
|
|
70
73
|
*/
|
|
71
74
|
export const Tooltip = forwardRef(function Tooltip(
|
|
@@ -177,23 +180,27 @@ export const Tooltip = forwardRef(function Tooltip(
|
|
|
177
180
|
const closeDelay = isInsideGroup ? delayGroupContext.closeDelay : closeDelayProp
|
|
178
181
|
|
|
179
182
|
const handleIsOpenChange = useCallback(
|
|
180
|
-
(open: boolean) => {
|
|
183
|
+
(open: boolean, immediate?: boolean) => {
|
|
181
184
|
if (isInsideGroup) {
|
|
182
185
|
// When it's inside a group, the open or close status will be handled by the group.
|
|
183
186
|
if (open) {
|
|
184
|
-
|
|
185
|
-
|
|
187
|
+
const groupedOpenDelay = immediate ? 0 : openDelay
|
|
188
|
+
|
|
189
|
+
delayGroupContext.setIsGroupActive(open, groupedOpenDelay)
|
|
190
|
+
delayGroupContext.setOpenTooltipId(tooltipId, groupedOpenDelay)
|
|
186
191
|
} else {
|
|
187
192
|
const minimumGroupDeactivateDelay = 200 // We should provide some delay to allow the user to reach the next tooltip.
|
|
188
193
|
const groupDeactivateDelay =
|
|
189
194
|
closeDelay > minimumGroupDeactivateDelay ? closeDelay : minimumGroupDeactivateDelay
|
|
190
195
|
|
|
191
196
|
delayGroupContext.setIsGroupActive(open, groupDeactivateDelay)
|
|
192
|
-
delayGroupContext.setOpenTooltipId(null, closeDelay)
|
|
197
|
+
delayGroupContext.setOpenTooltipId(null, immediate ? 0 : closeDelay)
|
|
193
198
|
}
|
|
194
199
|
} else {
|
|
200
|
+
const standaloneDelay = immediate ? 0 : open ? openDelay : closeDelay
|
|
201
|
+
|
|
195
202
|
// When it's not inside a group, the open or close status will be handled by the tooltip itself.
|
|
196
|
-
setIsOpen(open,
|
|
203
|
+
setIsOpen(open, standaloneDelay)
|
|
197
204
|
}
|
|
198
205
|
},
|
|
199
206
|
[isInsideGroup, delayGroupContext, openDelay, tooltipId, closeDelay, setIsOpen],
|
|
@@ -243,6 +250,22 @@ export const Tooltip = forwardRef(function Tooltip(
|
|
|
243
250
|
// Update reference
|
|
244
251
|
useEffect(() => refs.setReference(referenceElement), [referenceElement, refs])
|
|
245
252
|
|
|
253
|
+
useEffect(() => {
|
|
254
|
+
// If the user clicks on escape key, close the tooltip.
|
|
255
|
+
if (!showTooltip) return
|
|
256
|
+
|
|
257
|
+
function handleWindowKeyDown(event: KeyboardEvent) {
|
|
258
|
+
if (event.key === 'Escape') {
|
|
259
|
+
handleIsOpenChange(false, true)
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
window.addEventListener('keydown', handleWindowKeyDown)
|
|
264
|
+
|
|
265
|
+
return () => {
|
|
266
|
+
window.removeEventListener('keydown', handleWindowKeyDown)
|
|
267
|
+
}
|
|
268
|
+
}, [handleIsOpenChange, showTooltip])
|
|
246
269
|
const setArrow = useCallback(
|
|
247
270
|
(arrowEl: HTMLDivElement | null) => {
|
|
248
271
|
arrowRef.current = arrowEl
|
package/src/primitives/types.ts
CHANGED
|
@@ -55,6 +55,7 @@ export interface ResponsiveFlexProps {
|
|
|
55
55
|
* @public
|
|
56
56
|
*/
|
|
57
57
|
export interface ResponsiveFlexItemProps {
|
|
58
|
+
/** Sets the flex CSS attribute. The property is responsive. */
|
|
58
59
|
flex?: FlexValue | FlexValue[]
|
|
59
60
|
}
|
|
60
61
|
|
|
@@ -88,8 +89,11 @@ export interface ResponsiveGridItemProps {
|
|
|
88
89
|
* @public
|
|
89
90
|
*/
|
|
90
91
|
export interface ResponsiveMarginProps {
|
|
92
|
+
/** Applies margins to all sides. The property is responsive. */
|
|
91
93
|
margin?: number | number[]
|
|
94
|
+
/** Applies margins to the left and right sides. The property is responsive. */
|
|
92
95
|
marginX?: number | number[]
|
|
96
|
+
/** Applies margins to the top and bottom sides. The property is responsive. */
|
|
93
97
|
marginY?: number | number[]
|
|
94
98
|
marginTop?: number | number[]
|
|
95
99
|
marginRight?: number | number[]
|
|
@@ -24,6 +24,7 @@ export interface TextInputRepresentationStyleProps {
|
|
|
24
24
|
$hasSuffix?: boolean
|
|
25
25
|
$scheme: ThemeColorSchemeKey
|
|
26
26
|
$tone: CardTone
|
|
27
|
+
$unstableDisableFocusRing?: boolean
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
const ROOT_STYLE = css`
|
|
@@ -129,7 +130,7 @@ export function textInputFontSizeStyle(props: TextInputInputStyleProps & ThemePr
|
|
|
129
130
|
export function textInputRepresentationStyle(
|
|
130
131
|
props: TextInputRepresentationStyleProps & ThemeProps,
|
|
131
132
|
): ReturnType<typeof css> {
|
|
132
|
-
const {$hasPrefix, $hasSuffix, $scheme, $tone, theme} = props
|
|
133
|
+
const {$hasPrefix, $hasSuffix, $scheme, $tone, $unstableDisableFocusRing, theme} = props
|
|
133
134
|
const {input} = theme.sanity
|
|
134
135
|
const {focusRing} = input.text
|
|
135
136
|
const color = theme.sanity.color.input
|
|
@@ -182,14 +183,18 @@ export function textInputRepresentationStyle(
|
|
|
182
183
|
/* focused */
|
|
183
184
|
*:not(:disabled):focus + & {
|
|
184
185
|
&[data-border] {
|
|
185
|
-
--input-box-shadow: ${
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
--input-box-shadow: ${$unstableDisableFocusRing
|
|
187
|
+
? undefined
|
|
188
|
+
: focusRingStyle({
|
|
189
|
+
border: {color: color.default.enabled.border, width: input.border.width},
|
|
190
|
+
focusRing,
|
|
191
|
+
})};
|
|
189
192
|
}
|
|
190
193
|
|
|
191
194
|
&:not([data-border]) {
|
|
192
|
-
--input-box-shadow: ${
|
|
195
|
+
--input-box-shadow: ${$unstableDisableFocusRing
|
|
196
|
+
? undefined
|
|
197
|
+
: focusRingStyle({focusRing})};
|
|
193
198
|
}
|
|
194
199
|
}
|
|
195
200
|
|