@sanity/ui 2.0.0-alpha.2 → 2.0.0-alpha.21

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.
Files changed (96) hide show
  1. package/dist/index.cjs.mjs +28 -0
  2. package/dist/index.d.ts +476 -12
  3. package/dist/index.esm.js +1326 -524
  4. package/dist/index.esm.js.map +1 -1
  5. package/dist/index.js +1353 -523
  6. package/dist/index.js.map +1 -1
  7. package/package.json +6 -8
  8. package/src/components/autocomplete/autocomplete.tsx +6 -0
  9. package/src/components/dialog/constants.ts +4 -0
  10. package/src/components/dialog/dialog.tsx +79 -15
  11. package/src/components/hotkeys/hotkeys.tsx +2 -0
  12. package/src/components/menu/menu.tsx +2 -0
  13. package/src/components/menu/menuButton.tsx +2 -0
  14. package/src/components/menu/menuGroup.tsx +22 -23
  15. package/src/components/menu/menuItem.tsx +29 -35
  16. package/src/components/tab/tab.tsx +4 -1
  17. package/src/components/toast/toast.tsx +4 -0
  18. package/src/primitives/_selectable/style.ts +2 -1
  19. package/src/primitives/avatar/avatar.tsx +16 -9
  20. package/src/primitives/avatar/avatarCounter.tsx +3 -3
  21. package/src/primitives/avatar/styles.ts +1 -1
  22. package/src/primitives/badge/badge.tsx +7 -3
  23. package/src/primitives/box/box.tsx +3 -0
  24. package/src/primitives/button/__workshop__/sanityUploadButton.tsx +2 -1
  25. package/src/primitives/button/button.tsx +7 -3
  26. package/src/primitives/button/styles.ts +9 -2
  27. package/src/primitives/card/card.tsx +4 -0
  28. package/src/primitives/card/styles.ts +2 -0
  29. package/src/primitives/checkbox/checkbox.tsx +2 -0
  30. package/src/primitives/code/code.tsx +1 -0
  31. package/src/primitives/container/container.tsx +2 -0
  32. package/src/primitives/flex/flex.tsx +2 -0
  33. package/src/primitives/grid/grid.tsx +2 -0
  34. package/src/primitives/heading/heading.tsx +2 -0
  35. package/src/primitives/inline/inline.tsx +3 -0
  36. package/src/primitives/kbd/kbd.tsx +2 -0
  37. package/src/primitives/label/label.tsx +2 -0
  38. package/src/primitives/popover/popover.tsx +6 -1
  39. package/src/primitives/radio/radio.tsx +2 -0
  40. package/src/primitives/select/select.tsx +2 -0
  41. package/src/primitives/select/styles.ts +2 -0
  42. package/src/primitives/spinner/spinner.tsx +2 -0
  43. package/src/primitives/stack/stack.tsx +2 -0
  44. package/src/primitives/switch/switch.tsx +4 -0
  45. package/src/primitives/text/text.tsx +3 -0
  46. package/src/primitives/textArea/textArea.tsx +4 -1
  47. package/src/primitives/textInput/textInput.tsx +10 -1
  48. package/src/primitives/tooltip/__workshop__/customPortal.tsx +99 -0
  49. package/src/primitives/tooltip/__workshop__/index.ts +15 -0
  50. package/src/primitives/tooltip/__workshop__/overflowingBoundary.tsx +73 -0
  51. package/src/primitives/tooltip/__workshop__/resizableBoundary.tsx +85 -0
  52. package/src/primitives/tooltip/constants.ts +1 -0
  53. package/src/primitives/tooltip/tooltip.test.tsx +192 -0
  54. package/src/primitives/tooltip/tooltip.tsx +109 -33
  55. package/src/primitives/types.ts +4 -0
  56. package/src/styles/input/textInputStyle.ts +11 -6
  57. package/src/theme/_internal/__workshop__/build/story.tsx +288 -0
  58. package/src/theme/_internal/__workshop__/build/theme.ts +3 -0
  59. package/src/theme/_internal/__workshop__/index.ts +14 -0
  60. package/src/theme/_internal/build/buildTheme.test.ts +78 -0
  61. package/src/theme/_internal/build/buildTheme.ts +16 -0
  62. package/src/theme/_internal/build/colorTheme/buildColorTheme.test.ts +185 -0
  63. package/src/theme/_internal/build/colorTheme/buildColorTheme.ts +164 -0
  64. package/src/theme/_internal/build/colorTheme/renderColorTheme.ts +242 -0
  65. package/src/theme/_internal/build/colorTheme/resolveColorTokens.ts +121 -0
  66. package/src/theme/_internal/build/defaults/colorPalette.ts +8 -0
  67. package/src/theme/_internal/build/defaults/colorTokens.ts +147 -0
  68. package/src/theme/_internal/build/helpers.ts +65 -0
  69. package/src/theme/_internal/build/index.ts +1 -0
  70. package/src/theme/_internal/config/helpers.ts +47 -0
  71. package/src/theme/_internal/config/index.ts +3 -0
  72. package/src/theme/_internal/config/token/index.ts +2 -0
  73. package/src/theme/_internal/config/token/parseTokenKey.test.ts +72 -0
  74. package/src/theme/_internal/config/token/parseTokenKey.ts +88 -0
  75. package/src/theme/_internal/config/token/parseTokenValue.test.ts +45 -0
  76. package/src/theme/_internal/config/token/parseTokenValue.ts +123 -0
  77. package/src/theme/_internal/config/types.ts +137 -0
  78. package/src/theme/_internal/constants.ts +48 -0
  79. package/src/theme/_internal/helpers.ts +19 -0
  80. package/src/theme/_internal/index.ts +5 -0
  81. package/src/theme/_internal/types.ts +91 -0
  82. package/src/theme/index.ts +1 -0
  83. package/src/theme/lib/color-fns/blend/multiply.ts +2 -2
  84. package/src/theme/lib/color-fns/blend/screen.ts +2 -2
  85. package/src/theme/lib/color-fns/convert.ts +15 -1
  86. package/src/theme/lib/color-fns/parse.ts +7 -3
  87. package/src/theme/lib/color-fns/types.ts +11 -0
  88. package/src/theme/lib/theme/avatar.ts +2 -0
  89. package/src/theme/lib/theme/color/_legacy/createColorTheme.ts +7 -0
  90. package/src/theme/lib/theme/color/_legacy/index.ts +1 -0
  91. package/src/theme/lib/theme/color/_legacy/legacyColor.ts +3997 -0
  92. package/src/theme/studioTheme/color.ts +98 -82
  93. package/src/theme/studioTheme/helpers.ts +15 -1
  94. package/src/theme/studioTheme/theme.ts +5 -5
  95. package/src/theme/studioTheme/tints.ts +244 -84
  96. 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
- -webkit-appearance: none;
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 & ThemeProps
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
@@ -29,6 +29,8 @@ export function cardBaseStyle(props: CardStyleProps & ThemeProps): ReturnType<ty
29
29
  font: inherit;
30
30
  text-align: inherit;
31
31
  border: 0;
32
+ width: -moz-available;
33
+ width: -webkit-fill-available;
32
34
  width: stretch;
33
35
  }
34
36
 
@@ -16,6 +16,8 @@ const Root = styled.div(checkboxBaseStyles)
16
16
  const Input = styled.input(inputElementStyles)
17
17
 
18
18
  /**
19
+ * Checkboxes allow the user to select one or more items from a set.
20
+ *
19
21
  * @public
20
22
  */
21
23
  export const Checkbox = forwardRef(function Checkbox(
@@ -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
@@ -17,6 +17,8 @@ const Root = styled(Box)<ResponsiveWidthStyleProps>(
17
17
  )
18
18
 
19
19
  /**
20
+ * The `Container` component wraps content layout in a defined set of widths.
21
+ *
20
22
  * @public
21
23
  */
22
24
  export const Container = forwardRef(function Container(
@@ -26,6 +26,8 @@ const Root = styled(Box)<FlexItemStyleProps & ResponsiveFlexStyleProps>(
26
26
  )
27
27
 
28
28
  /**
29
+ * The `Flex` component is a wrapper component for flexible elements (`Box`, `Card` and `Flex`).
30
+ *
29
31
  * @public
30
32
  */
31
33
  export const Flex = forwardRef(function Flex(
@@ -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(
@@ -43,6 +43,8 @@ const SpanWithTextOverflow = styled.span`
43
43
  `
44
44
 
45
45
  /**
46
+ * Typographic headings.
47
+ *
46
48
  * @public
47
49
  */
48
50
  export const Heading = forwardRef(function Heading(
@@ -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(
@@ -30,6 +30,8 @@ function kbdStyle() {
30
30
  const Root = styled.kbd<ResponsiveRadiusStyleProps>(responsiveRadiusStyle, kbdStyle)
31
31
 
32
32
  /**
33
+ * Used to define some text as keyboard input.
34
+ *
33
35
  * @public
34
36
  */
35
37
  export const KBD = forwardRef(function KBD(
@@ -40,6 +40,8 @@ const SpanWithTextOverflow = styled.span`
40
40
  `
41
41
 
42
42
  /**
43
+ * Typographic labels.
44
+ *
43
45
  * @public
44
46
  */
45
47
  export const Label = forwardRef(function Label(
@@ -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
- /** @public */
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 &
@@ -14,6 +14,8 @@ const Root = styled.div(radioBaseStyle)
14
14
  const Input = styled.input(inputElementStyle)
15
15
 
16
16
  /**
17
+ * The `Radio` component allows the user to select one option from a set.
18
+ *
17
19
  * @public
18
20
  */
19
21
  export const Radio = forwardRef(function Radio(
@@ -30,6 +30,8 @@ const Input = styled.select<{
30
30
  const IconBox = styled(Box)(selectStyle.iconBox)
31
31
 
32
32
  /**
33
+ * The `Select` component provides control of options.
34
+ *
33
35
  * @public
34
36
  */
35
37
  export const Select = forwardRef(function Select(
@@ -13,6 +13,8 @@ import {CSSObject} from '../../types/styled'
13
13
  function rootStyle(): ReturnType<typeof css> {
14
14
  return css`
15
15
  position: relative;
16
+ width: -moz-available;
17
+ width: -webkit-fill-available;
16
18
  width: stretch;
17
19
 
18
20
  &:not([hidden]) {
@@ -28,6 +28,8 @@ const Root = styled(Text)`
28
28
  `
29
29
 
30
30
  /**
31
+ * Indicate that something is loading for an indeterminate amount of time.
32
+ *
31
33
  * @public
32
34
  */
33
35
  export const Spinner = forwardRef(function Spinner(
@@ -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 = 1,
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 = 1,
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,
@@ -0,0 +1,99 @@
1
+ import {
2
+ BoundaryElementProvider,
3
+ Button,
4
+ Card,
5
+ Flex,
6
+ Portal,
7
+ PortalProvider,
8
+ Stack,
9
+ Text,
10
+ Tooltip,
11
+ } from '@sanity/ui'
12
+ import {useBoolean, useSelect, useText} from '@sanity/ui-workshop'
13
+ import {useState} from 'react'
14
+ import {WORKSHOP_PLACEMENT_OPTIONS} from '../../../__workshop__/constants'
15
+
16
+ const PORTAL_OPTIONS = {
17
+ '(true)': true,
18
+ '(false)': false,
19
+ portal1: 'portal1',
20
+ }
21
+
22
+ export default function CustomPortalStory() {
23
+ const content = useText(
24
+ 'Content',
25
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut mollis consectetur malesuada. Sed lobortis est dolor, eget imperdiet velit placerat et. Aenean posuere mi non aliquet iaculis. Donec fermentum pulvinar purus at sagittis. Ut tincidunt massa odio, sed finibus justo ullamcorper id. Nam venenatis justo non ligula elementum cursus. Pellentesque laoreet justo in mollis sagittis. In lacinia ornare ultrices. Suspendisse potenti.',
26
+ )
27
+ const placement = useSelect('Placement', WORKSHOP_PLACEMENT_OPTIONS, 'top')
28
+ const portal = useSelect('Portal', PORTAL_OPTIONS, undefined, 'Props')
29
+ const useBoundaryElement = useBoolean('Use boundary element', true)
30
+
31
+ const [portal1Element, setPortal1Element] = useState<HTMLDivElement | null>(null)
32
+ const [boundaryElement, setBoundaryElement] = useState<HTMLDivElement | null>(null)
33
+
34
+ return (
35
+ <PortalProvider
36
+ __unstable_elements={{
37
+ portal1: portal1Element,
38
+ }}
39
+ >
40
+ <Flex align="center" height="fill" justify="center">
41
+ <BoundaryElementProvider element={useBoundaryElement ? boundaryElement : null}>
42
+ <Card
43
+ border
44
+ padding={4}
45
+ ref={setBoundaryElement}
46
+ style={{
47
+ height: 'calc(100vh - 100px)',
48
+ position: 'relative',
49
+ width: '500px',
50
+ }}
51
+ >
52
+ <Text>Boundary element</Text>
53
+ <Flex align="center" height="fill" justify="center">
54
+ <Flex justify="center">
55
+ <Stack space={2}>
56
+ <Tooltip
57
+ boundaryElement={useBoundaryElement ? boundaryElement : null}
58
+ content={<Text size={1}>{content}</Text>}
59
+ padding={2}
60
+ placement={placement}
61
+ portal={portal}
62
+ >
63
+ <Button mode="bleed" text="Tooltip" />
64
+ </Tooltip>
65
+ </Stack>
66
+ </Flex>
67
+ </Flex>
68
+ </Card>
69
+ </BoundaryElementProvider>
70
+ </Flex>
71
+
72
+ <Card
73
+ border
74
+ margin={4}
75
+ padding={4}
76
+ ref={setPortal1Element}
77
+ style={{
78
+ left: 0,
79
+ position: 'absolute',
80
+ top: 0,
81
+ width: '175px',
82
+ }}
83
+ tone="critical"
84
+ />
85
+
86
+ <Portal __unstable_name="portal1">
87
+ <Stack space={4}>
88
+ <Text size={1} weight="medium">
89
+ Portal 1 content
90
+ </Text>
91
+ <Text size={1}>
92
+ The tooltip's max-width should not exceed this container's width (minus padding) if it's
93
+ set to use this portal
94
+ </Text>
95
+ </Stack>
96
+ </Portal>
97
+ </PortalProvider>
98
+ )
99
+ }
@@ -10,5 +10,20 @@ export default defineScope({
10
10
  title: 'Props',
11
11
  component: lazy(() => import('./props')),
12
12
  },
13
+ {
14
+ name: 'resizableBoundary',
15
+ title: 'Resizable Boundary',
16
+ component: lazy(() => import('./resizableBoundary')),
17
+ },
18
+ {
19
+ name: 'overflowBoundary',
20
+ title: 'Overflowing Boundary',
21
+ component: lazy(() => import('./overflowingBoundary')),
22
+ },
23
+ {
24
+ name: 'customPortalStory',
25
+ title: 'Custom Portal',
26
+ component: lazy(() => import('./customPortal')),
27
+ },
13
28
  ],
14
29
  })
@@ -0,0 +1,73 @@
1
+ import {BoundaryElementProvider, Button, Card, Code, Flex, Stack, Text, Tooltip} from '@sanity/ui'
2
+ import {useBoolean, useSelect, useText} from '@sanity/ui-workshop'
3
+ import {useCallback, useState} from 'react'
4
+ import {WORKSHOP_PLACEMENT_OPTIONS} from '../../../__workshop__/constants'
5
+
6
+ export default function OverflowingBoundaryStory() {
7
+ const content = useText(
8
+ 'Content',
9
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut mollis consectetur malesuada. Sed lobortis est dolor, eget imperdiet velit placerat et. Aenean posuere mi non aliquet iaculis. Donec fermentum pulvinar purus at sagittis. Ut tincidunt massa odio, sed finibus justo ullamcorper id. Nam venenatis justo non ligula elementum cursus. Pellentesque laoreet justo in mollis sagittis. In lacinia ornare ultrices. Suspendisse potenti.',
10
+ )
11
+ const placement = useSelect('Placement', WORKSHOP_PLACEMENT_OPTIONS, 'top')
12
+ const portal = useBoolean('Portal', false)
13
+ const useBoundaryElement = useBoolean('Use boundary element', true)
14
+
15
+ const [boundaryElement, setBoundaryElement] = useState<HTMLDivElement | null>(null)
16
+ const [buttonsVisible, setButtonsVisible] = useState(true)
17
+
18
+ const handleHideButtons = useCallback(() => {
19
+ setButtonsVisible(false)
20
+ }, [])
21
+
22
+ const handleShowButtons = useCallback(() => {
23
+ setButtonsVisible(true)
24
+ }, [])
25
+
26
+ return (
27
+ <Flex align="center" height="fill" justify="center" style={{height: '200vh'}}>
28
+ <BoundaryElementProvider element={useBoundaryElement ? boundaryElement : null}>
29
+ <Card
30
+ border
31
+ ref={setBoundaryElement}
32
+ style={{
33
+ height: 'calc(100vh - 100px)',
34
+ overflow: 'hidden',
35
+ position: 'relative',
36
+ resize: 'both',
37
+ width: '500px',
38
+ }}
39
+ >
40
+ <Flex align="center" height="fill" justify="center">
41
+ <Flex justify="center">
42
+ <Stack space={2}>
43
+ <Code size={1}>Placement: {placement}</Code>
44
+ <Button
45
+ disabled={buttonsVisible}
46
+ fontSize={1}
47
+ onClick={handleShowButtons}
48
+ text="Show buttons"
49
+ />
50
+ </Stack>
51
+ </Flex>
52
+ </Flex>
53
+
54
+ {buttonsVisible && (
55
+ <Tooltip
56
+ content={<Text size={1}>{content}</Text>}
57
+ padding={2}
58
+ placement={placement}
59
+ portal={portal}
60
+ >
61
+ <Button
62
+ mode="bleed"
63
+ onClick={handleHideButtons}
64
+ style={{position: 'absolute', top: 10, right: 10}}
65
+ text="Tooltip"
66
+ />
67
+ </Tooltip>
68
+ )}
69
+ </Card>
70
+ </BoundaryElementProvider>
71
+ </Flex>
72
+ )
73
+ }
@@ -0,0 +1,85 @@
1
+ import {BoundaryElementProvider, Button, Card, Code, Flex, Text, Tooltip} from '@sanity/ui'
2
+ import {useBoolean, useSelect, useText} from '@sanity/ui-workshop'
3
+ import {useState} from 'react'
4
+ import {WORKSHOP_PLACEMENT_OPTIONS} from '../../../__workshop__/constants'
5
+
6
+ export default function ResizableBoundaryStory() {
7
+ const content = useText(
8
+ 'Content',
9
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut mollis consectetur malesuada. Sed lobortis est dolor, eget imperdiet velit placerat et. Aenean posuere mi non aliquet iaculis. Donec fermentum pulvinar purus at sagittis. Ut tincidunt massa odio, sed finibus justo ullamcorper id. Nam venenatis justo non ligula elementum cursus. Pellentesque laoreet justo in mollis sagittis. In lacinia ornare ultrices. Suspendisse potenti.',
10
+ )
11
+ const placement = useSelect('Placement', WORKSHOP_PLACEMENT_OPTIONS, 'right')
12
+ const portal = useBoolean('Portal', true)
13
+ const useBoundaryElement = useBoolean('Use boundary element', true)
14
+
15
+ const [boundaryElement, setBoundaryElement] = useState<HTMLDivElement | null>(null)
16
+
17
+ return (
18
+ <Flex align="center" height="fill" justify="center">
19
+ <BoundaryElementProvider element={useBoundaryElement ? boundaryElement : null}>
20
+ <Card
21
+ border
22
+ ref={setBoundaryElement}
23
+ style={{
24
+ height: 'calc(100vh - 100px)',
25
+ overflow: 'hidden',
26
+ position: 'relative',
27
+ resize: 'both',
28
+ width: '500px',
29
+ }}
30
+ >
31
+ <Flex align="center" height="fill" justify="center">
32
+ <Flex justify="center">
33
+ <Code size={1}>Placement: {placement}</Code>
34
+ </Flex>
35
+ </Flex>
36
+
37
+ <Tooltip
38
+ content={<Text size={1}>{content}</Text>}
39
+ padding={2}
40
+ placement={placement}
41
+ portal={portal}
42
+ >
43
+ <Button mode="bleed" style={{position: 'absolute', top: 10, left: 10}} text="Tooltip" />
44
+ </Tooltip>
45
+ <Tooltip
46
+ content={<Text size={1}>{content}</Text>}
47
+ padding={2}
48
+ placement={placement}
49
+ portal={portal}
50
+ >
51
+ <Button
52
+ mode="bleed"
53
+ style={{position: 'absolute', top: 10, right: 10}}
54
+ text="Tooltip"
55
+ />
56
+ </Tooltip>
57
+ <Tooltip
58
+ content={<Text size={1}>{content}</Text>}
59
+ padding={2}
60
+ placement={placement}
61
+ portal={portal}
62
+ >
63
+ <Button
64
+ mode="bleed"
65
+ style={{position: 'absolute', bottom: 10, left: 10}}
66
+ text="Tooltip"
67
+ />
68
+ </Tooltip>
69
+ <Tooltip
70
+ content={<Text size={1}>{content}</Text>}
71
+ padding={2}
72
+ placement={placement}
73
+ portal={portal}
74
+ >
75
+ <Button
76
+ mode="bleed"
77
+ style={{position: 'absolute', bottom: 10, right: 10}}
78
+ text="Tooltip"
79
+ />
80
+ </Tooltip>
81
+ </Card>
82
+ </BoundaryElementProvider>
83
+ </Flex>
84
+ )
85
+ }