@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.
Files changed (78) hide show
  1. package/dist/_chunks-cjs/_visual-editing.js +323 -292
  2. package/dist/_chunks-cjs/_visual-editing.js.map +1 -1
  3. package/dist/_chunks-es/_visual-editing.mjs +323 -292
  4. package/dist/_chunks-es/_visual-editing.mjs.map +1 -1
  5. package/dist/_visual-editing.d.mts +195 -76
  6. package/dist/_visual-editing.d.ts +195 -76
  7. package/dist/index.d.mts +308 -140
  8. package/dist/index.d.ts +308 -140
  9. package/dist/index.js +97 -93
  10. package/dist/index.js.map +1 -1
  11. package/dist/index.mjs +97 -93
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/theme.d.mts +10 -4
  14. package/dist/theme.d.ts +10 -4
  15. package/package.json +1 -1
  16. package/src/core/components/autocomplete/autocomplete.tsx +1 -1
  17. package/src/core/components/autocomplete/types.ts +2 -2
  18. package/src/core/components/breadcrumbs/breadcrumbs.test.tsx +51 -0
  19. package/src/core/components/breadcrumbs/breadcrumbs.tsx +7 -3
  20. package/src/core/components/hotkeys/hotkeys.test.tsx +42 -0
  21. package/src/core/components/hotkeys/hotkeys.tsx +7 -3
  22. package/src/core/components/menu/__workshop__/asComponent.tsx +1 -1
  23. package/src/core/components/menu/menu.spacing.test.tsx +63 -0
  24. package/src/core/components/menu/menu.tsx +8 -2
  25. package/src/core/components/menu/menuDivider.ts +16 -5
  26. package/src/core/components/menu/menuGroup.spacing.test.tsx +63 -0
  27. package/src/core/components/menu/menuGroup.tsx +22 -8
  28. package/src/core/components/menu/menuItem.spacing.test.tsx +59 -0
  29. package/src/core/components/menu/menuItem.tsx +25 -8
  30. package/src/core/components/skeleton/skeleton.tsx +2 -2
  31. package/src/core/components/tab/tabList.test.tsx +48 -0
  32. package/src/core/components/tab/tabList.tsx +2 -2
  33. package/src/core/components/tab/tabPanel.tsx +2 -2
  34. package/src/core/components/toast/styles.ts +2 -2
  35. package/src/core/components/tree/__workshop__/basic.perf.ts +1 -1
  36. package/src/core/components/tree/__workshop__/tabFromElement.tsx +1 -1
  37. package/src/core/components/tree/tree.test.tsx +55 -0
  38. package/src/core/components/tree/tree.tsx +19 -10
  39. package/src/core/components/tree/treeGroup.tsx +3 -3
  40. package/src/core/components/tree/treeItem.test.tsx +65 -0
  41. package/src/core/components/tree/treeItem.tsx +11 -4
  42. package/src/core/components/tree/types.ts +4 -0
  43. package/src/core/primitives/avatar/avatar.tsx +19 -11
  44. package/src/core/primitives/badge/badge.tsx +20 -12
  45. package/src/core/primitives/box/__workshop__/asComponent.tsx +31 -0
  46. package/src/core/primitives/box/__workshop__/index.ts +5 -0
  47. package/src/core/primitives/box/box.test.tsx +142 -0
  48. package/src/core/primitives/box/box.tsx +41 -18
  49. package/src/core/primitives/button/__workshop__/disabled.tsx +2 -2
  50. package/src/core/primitives/button/__workshop__/sanityUploadButton.tsx +1 -1
  51. package/src/core/primitives/button/__workshop__/uploadButton.tsx +1 -1
  52. package/src/core/primitives/button/button.test.tsx +41 -3
  53. package/src/core/primitives/button/button.tsx +36 -12
  54. package/src/core/primitives/card/__workshop__/asComponent.tsx +1 -1
  55. package/src/core/primitives/card/card.tsx +24 -13
  56. package/src/core/primitives/code/code.tsx +16 -7
  57. package/src/core/primitives/container/container.tsx +23 -10
  58. package/src/core/primitives/flex/flex.tsx +21 -11
  59. package/src/core/primitives/grid/grid.test.tsx +80 -0
  60. package/src/core/primitives/grid/grid.tsx +39 -13
  61. package/src/core/primitives/heading/heading.tsx +19 -11
  62. package/src/core/primitives/inline/inline.test.tsx +51 -0
  63. package/src/core/primitives/inline/inline.tsx +28 -12
  64. package/src/core/primitives/kbd/kbd.tsx +19 -11
  65. package/src/core/primitives/label/label.tsx +19 -11
  66. package/src/core/primitives/popover/__workshop__/SidePanelStory.tsx +1 -1
  67. package/src/core/primitives/select/select.test.tsx +52 -0
  68. package/src/core/primitives/select/select.tsx +8 -2
  69. package/src/core/primitives/stack/stack.test.tsx +57 -0
  70. package/src/core/primitives/stack/stack.tsx +27 -13
  71. package/src/core/primitives/text/text.tsx +19 -11
  72. package/src/core/primitives/textInput/textInput.test.tsx +48 -0
  73. package/src/core/primitives/textInput/textInput.tsx +9 -4
  74. package/src/core/primitives/types.ts +33 -0
  75. package/src/core/types/component.ts +32 -0
  76. package/src/core/types/index.ts +1 -0
  77. package/src/core/utils/virtualList/virtualList.tsx +2 -2
  78. package/src/theme/system/css.ts +10 -4
@@ -0,0 +1,142 @@
1
+ /** @jest-environment jsdom */
2
+
3
+ import {type ComponentProps} from 'react'
4
+
5
+ import {render} from '../../../../test'
6
+ import {responsiveGridItemStyle} from '../../styles/internal'
7
+ import {Box} from './box'
8
+
9
+ jest.mock('../../styles/internal', () => {
10
+ const actual = jest.requireActual('../../styles/internal')
11
+
12
+ return {
13
+ ...actual,
14
+ responsiveGridItemStyle: jest.fn(actual.responsiveGridItemStyle),
15
+ }
16
+ })
17
+
18
+ describe('<Box />', () => {
19
+ const mockedResponsiveGridItemStyle = jest.mocked(responsiveGridItemStyle)
20
+
21
+ beforeEach(() => {
22
+ mockedResponsiveGridItemStyle.mockClear()
23
+ })
24
+
25
+ it('uses column when gridColumn is not provided', () => {
26
+ render(<Box column={3} />)
27
+
28
+ expect(mockedResponsiveGridItemStyle).toHaveBeenCalledWith(
29
+ expect.objectContaining({$column: [3]}),
30
+ )
31
+ })
32
+
33
+ it('uses gridColumn when provided', () => {
34
+ render(<Box gridColumn={4} />)
35
+
36
+ expect(mockedResponsiveGridItemStyle).toHaveBeenCalledWith(
37
+ expect.objectContaining({$column: [4]}),
38
+ )
39
+ })
40
+
41
+ it('prefers gridColumn over column when both are provided', () => {
42
+ render(<Box column={3} gridColumn={5} />)
43
+
44
+ expect(mockedResponsiveGridItemStyle).toHaveBeenCalledWith(
45
+ expect.objectContaining({$column: [5]}),
46
+ )
47
+ expect(mockedResponsiveGridItemStyle).not.toHaveBeenCalledWith(
48
+ expect.objectContaining({$column: [3]}),
49
+ )
50
+ })
51
+
52
+ it('supports responsive arrays with gridColumn', () => {
53
+ const gridColumn: ComponentProps<typeof Box>['gridColumn'] = [2, 'full']
54
+
55
+ render(<Box gridColumn={gridColumn} />)
56
+
57
+ expect(mockedResponsiveGridItemStyle).toHaveBeenCalledWith(
58
+ expect.objectContaining({$column: [2, 'full']}),
59
+ )
60
+ })
61
+
62
+ it('uses columnStart when gridColumnStart is not provided', () => {
63
+ render(<Box columnStart={2} />)
64
+ expect(mockedResponsiveGridItemStyle).toHaveBeenCalledWith(
65
+ expect.objectContaining({$columnStart: [2]}),
66
+ )
67
+ })
68
+
69
+ it('prefers gridColumnStart over columnStart when both are provided', () => {
70
+ render(<Box columnStart={2} gridColumnStart={4} />)
71
+ expect(mockedResponsiveGridItemStyle).toHaveBeenCalledWith(
72
+ expect.objectContaining({$columnStart: [4]}),
73
+ )
74
+ expect(mockedResponsiveGridItemStyle).not.toHaveBeenCalledWith(
75
+ expect.objectContaining({$columnStart: [2]}),
76
+ )
77
+ })
78
+
79
+ it('uses columnEnd when gridColumnEnd is not provided', () => {
80
+ render(<Box columnEnd={3} />)
81
+ expect(mockedResponsiveGridItemStyle).toHaveBeenCalledWith(
82
+ expect.objectContaining({$columnEnd: [3]}),
83
+ )
84
+ })
85
+
86
+ it('prefers gridColumnEnd over columnEnd when both are provided', () => {
87
+ render(<Box columnEnd={3} gridColumnEnd={5} />)
88
+ expect(mockedResponsiveGridItemStyle).toHaveBeenCalledWith(
89
+ expect.objectContaining({$columnEnd: [5]}),
90
+ )
91
+ expect(mockedResponsiveGridItemStyle).not.toHaveBeenCalledWith(
92
+ expect.objectContaining({$columnEnd: [3]}),
93
+ )
94
+ })
95
+
96
+ it('uses row when gridRow is not provided', () => {
97
+ render(<Box row={1} />)
98
+ expect(mockedResponsiveGridItemStyle).toHaveBeenCalledWith(expect.objectContaining({$row: [1]}))
99
+ })
100
+
101
+ it('prefers gridRow over row when both are provided', () => {
102
+ render(<Box row={1} gridRow={2} />)
103
+ expect(mockedResponsiveGridItemStyle).toHaveBeenCalledWith(expect.objectContaining({$row: [2]}))
104
+ expect(mockedResponsiveGridItemStyle).not.toHaveBeenCalledWith(
105
+ expect.objectContaining({$row: [1]}),
106
+ )
107
+ })
108
+
109
+ it('uses rowStart when gridRowStart is not provided', () => {
110
+ render(<Box rowStart={2} />)
111
+ expect(mockedResponsiveGridItemStyle).toHaveBeenCalledWith(
112
+ expect.objectContaining({$rowStart: [2]}),
113
+ )
114
+ })
115
+
116
+ it('prefers gridRowStart over rowStart when both are provided', () => {
117
+ render(<Box rowStart={2} gridRowStart={4} />)
118
+ expect(mockedResponsiveGridItemStyle).toHaveBeenCalledWith(
119
+ expect.objectContaining({$rowStart: [4]}),
120
+ )
121
+ expect(mockedResponsiveGridItemStyle).not.toHaveBeenCalledWith(
122
+ expect.objectContaining({$rowStart: [2]}),
123
+ )
124
+ })
125
+
126
+ it('uses rowEnd when gridRowEnd is not provided', () => {
127
+ render(<Box rowEnd={3} />)
128
+ expect(mockedResponsiveGridItemStyle).toHaveBeenCalledWith(
129
+ expect.objectContaining({$rowEnd: [3]}),
130
+ )
131
+ })
132
+
133
+ it('prefers gridRowEnd over rowEnd when both are provided', () => {
134
+ render(<Box rowEnd={3} gridRowEnd={5} />)
135
+ expect(mockedResponsiveGridItemStyle).toHaveBeenCalledWith(
136
+ expect.objectContaining({$rowEnd: [5]}),
137
+ )
138
+ expect(mockedResponsiveGridItemStyle).not.toHaveBeenCalledWith(
139
+ expect.objectContaining({$rowEnd: [3]}),
140
+ )
141
+ })
142
+ })
@@ -15,6 +15,7 @@ import {
15
15
  responsivePaddingStyle,
16
16
  ResponsivePaddingStyleProps,
17
17
  } from '../../styles/internal'
18
+ import {ElementType, Props} from '../../types'
18
19
  import {
19
20
  ResponsiveBoxProps,
20
21
  ResponsiveFlexItemProps,
@@ -24,18 +25,24 @@ import {
24
25
  } from '../types'
25
26
 
26
27
  /**
28
+ * The props that `Box` adds on top of the element it renders as.
29
+ *
27
30
  * @public
28
31
  */
29
- export interface BoxProps
32
+ export interface BoxOwnProps
30
33
  extends ResponsiveFlexItemProps,
31
34
  ResponsiveBoxProps,
32
35
  ResponsiveGridItemProps,
33
36
  ResponsiveMarginProps,
34
37
  ResponsivePaddingProps {
35
- as?: React.ElementType | keyof React.JSX.IntrinsicElements
36
- forwardedAs?: React.ElementType | keyof React.JSX.IntrinsicElements
38
+ forwardedAs?: ElementType
37
39
  }
38
40
 
41
+ /**
42
+ * @public
43
+ */
44
+ export type BoxProps<E extends ElementType = 'div'> = Props<BoxOwnProps, E>
45
+
39
46
  const StyledBox = styled.div<
40
47
  FlexItemStyleProps &
41
48
  ResponsiveBoxStyleProps &
@@ -51,21 +58,18 @@ const StyledBox = styled.div<
51
58
  responsivePaddingStyle,
52
59
  )
53
60
 
54
- /**
55
- * The `Box` component is a basic layout wrapper component which provides utility properties
56
- * for flex, margins and padding.
57
- *
58
- * @public
59
- */
60
- export const Box = forwardRef(function Box(
61
- props: BoxProps & Omit<React.HTMLProps<HTMLDivElement>, 'as' | 'height'>,
61
+ const BoxComponent = forwardRef(function Box(
62
+ props: BoxOwnProps & {as?: ElementType} & Omit<React.HTMLProps<HTMLDivElement>, 'as' | 'height'>,
62
63
  ref: React.ForwardedRef<HTMLDivElement>,
63
64
  ) {
64
65
  const {
65
66
  as: asProp = 'div',
66
- column,
67
- columnStart,
68
- columnEnd,
67
+ gridColumn,
68
+ column: deprecated_column,
69
+ gridColumnStart,
70
+ columnStart: deprecated_columnStart,
71
+ gridColumnEnd,
72
+ columnEnd: deprecated_columnEnd,
69
73
  display = 'block',
70
74
  flex,
71
75
  height,
@@ -84,12 +88,21 @@ export const Box = forwardRef(function Box(
84
88
  paddingRight,
85
89
  paddingBottom,
86
90
  paddingLeft,
87
- row,
88
- rowStart,
89
- rowEnd,
91
+ gridRow,
92
+ row: deprecated_row,
93
+ gridRowStart,
94
+ rowStart: deprecated_rowStart,
95
+ gridRowEnd,
96
+ rowEnd: deprecated_rowEnd,
90
97
  sizing,
91
98
  ...restProps
92
99
  } = props
100
+ const column = gridColumn === undefined ? deprecated_column : gridColumn
101
+ const columnStart = gridColumnStart === undefined ? deprecated_columnStart : gridColumnStart
102
+ const columnEnd = gridColumnEnd === undefined ? deprecated_columnEnd : gridColumnEnd
103
+ const row = gridRow === undefined ? deprecated_row : gridRow
104
+ const rowStart = gridRowStart === undefined ? deprecated_rowStart : gridRowStart
105
+ const rowEnd = gridRowEnd === undefined ? deprecated_rowEnd : gridRowEnd
93
106
 
94
107
  return (
95
108
  <StyledBox
@@ -128,4 +141,14 @@ export const Box = forwardRef(function Box(
128
141
  </StyledBox>
129
142
  )
130
143
  })
131
- Box.displayName = 'ForwardRef(Box)'
144
+ BoxComponent.displayName = 'ForwardRef(Box)'
145
+
146
+ /**
147
+ * The `Box` component is a basic layout wrapper component which provides utility properties
148
+ * for flex, margins and padding.
149
+ *
150
+ * @public
151
+ */
152
+ export const Box = BoxComponent as unknown as <E extends ElementType = 'div'>(
153
+ props: BoxProps<E>,
154
+ ) => React.JSX.Element
@@ -5,12 +5,12 @@ import {Container} from '../../container/container'
5
5
  import {Grid} from '../../grid/grid'
6
6
  import {Stack} from '../../stack/stack'
7
7
  import {Text} from '../../text/text'
8
- import {Button, ButtonProps} from '../button'
8
+ import {Button, ButtonOwnProps} from '../button'
9
9
 
10
10
  const GAP = 4
11
11
  const COLUMNS = 3
12
12
 
13
- const DEFAULT_PROPS: ButtonProps = {
13
+ const DEFAULT_PROPS: ButtonOwnProps = {
14
14
  icon: SquareIcon,
15
15
  iconRight: SquareIcon,
16
16
  }
@@ -27,7 +27,7 @@ const SanityUploadButton = styled(Button).attrs({forwardedAs: 'label'})`
27
27
 
28
28
  export default function SanityUploadButtonWorkaroundStory() {
29
29
  return (
30
- <Flex align="center" height="fill" htmlFor="file" justify="center">
30
+ <Flex align="center" height="fill" justify="center">
31
31
  <SanityUploadButton icon={UploadIcon} tabIndex={0} text="Upload">
32
32
  <input type="file" />
33
33
  </SanityUploadButton>
@@ -11,7 +11,7 @@ export default function UploadButtonStory() {
11
11
  }, [])
12
12
 
13
13
  return (
14
- <Flex align="center" height="fill" htmlFor="file" justify="center">
14
+ <Flex align="center" height="fill" justify="center">
15
15
  <Button
16
16
  as="label"
17
17
  onKeyDown={handleKeyDown}
@@ -5,9 +5,25 @@ import {screen} from '@testing-library/react'
5
5
  import {axe} from 'jest-axe'
6
6
 
7
7
  import {render} from '../../../../test'
8
- import {Button, ButtonProps} from './button'
8
+ import {Flex} from '../flex'
9
+ import {Button, ButtonOwnProps} from './button'
10
+
11
+ jest.mock('../flex', () => {
12
+ const actual = jest.requireActual('../flex')
13
+
14
+ return {
15
+ ...actual,
16
+ Flex: jest.fn((props: Record<string, unknown>) => (actual.Flex as any).render(props, null)),
17
+ }
18
+ })
9
19
 
10
20
  describe('atoms/button', () => {
21
+ const mockedFlex = jest.mocked(Flex)
22
+
23
+ beforeEach(() => {
24
+ mockedFlex.mockClear()
25
+ })
26
+
11
27
  it('Axe: should have no violations', async () => {
12
28
  const lightResult = render(<Button icon={AddIcon} text="Label" tone="positive" />, {
13
29
  scheme: 'light',
@@ -29,11 +45,11 @@ describe('atoms/button', () => {
29
45
  })
30
46
 
31
47
  it('should wrap button', () => {
32
- function WrappedButton({button: buttonProps}: {button: ButtonProps}) {
48
+ function WrappedButton({button: buttonProps}: {button: ButtonOwnProps}) {
33
49
  return <Button {...buttonProps} />
34
50
  }
35
51
 
36
- const buttonProps: ButtonProps = {
52
+ const buttonProps: ButtonOwnProps = {
37
53
  text: 'Button text',
38
54
  }
39
55
 
@@ -41,4 +57,26 @@ describe('atoms/button', () => {
41
57
 
42
58
  expect(screen.getByText('Button text')).toBeInTheDocument()
43
59
  })
60
+
61
+ it('should support `space`', () => {
62
+ render(<Button icon={AddIcon} space={17} text="Button text" />)
63
+
64
+ const propsList = mockedFlex.mock.calls.map(([props]) => props)
65
+ expect(propsList).toContainEqual(expect.objectContaining({gap: [17]}))
66
+ })
67
+
68
+ it('should support `gap`', () => {
69
+ render(<Button gap={18} icon={AddIcon} text="Button text" />)
70
+
71
+ const propsList = mockedFlex.mock.calls.map(([props]) => props)
72
+ expect(propsList).toContainEqual(expect.objectContaining({gap: [18]}))
73
+ })
74
+
75
+ it('should prefer `gap` over `space` when both are provided', () => {
76
+ render(<Button gap={19} icon={AddIcon} space={20} text="Button text" />)
77
+
78
+ const propsList = mockedFlex.mock.calls.map(([props]) => props)
79
+ expect(propsList).toContainEqual(expect.objectContaining({gap: [19]}))
80
+ expect(propsList).not.toContainEqual(expect.objectContaining({gap: [20]}))
81
+ })
44
82
  })
@@ -6,7 +6,15 @@ import {styled} from 'styled-components'
6
6
  import {_getArrayProp, ThemeProps} from '../../styles'
7
7
  import {responsiveRadiusStyle, ResponsiveRadiusStyleProps} from '../../styles/internal'
8
8
  import {useTheme_v2} from '../../theme'
9
- import {ButtonMode, ButtonTextAlign, ButtonTone, ButtonWidth, FlexJustify} from '../../types'
9
+ import {
10
+ ButtonMode,
11
+ ButtonTextAlign,
12
+ ButtonTone,
13
+ ButtonWidth,
14
+ ElementType,
15
+ FlexJustify,
16
+ Props,
17
+ } from '../../types'
10
18
  import {Box} from '../box'
11
19
  import {Flex} from '../flex'
12
20
  import {Spinner} from '../spinner'
@@ -17,8 +25,7 @@ import {buttonBaseStyles, buttonColorStyles} from './styles'
17
25
  /**
18
26
  * @public
19
27
  */
20
- export interface ButtonProps extends ResponsivePaddingProps, ResponsiveRadiusProps {
21
- as?: React.ElementType | keyof React.JSX.IntrinsicElements
28
+ export interface ButtonOwnProps extends ResponsivePaddingProps, ResponsiveRadiusProps {
22
29
  fontSize?: number | number[]
23
30
  mode?: ButtonMode
24
31
  icon?: React.ElementType | React.ReactNode
@@ -29,7 +36,11 @@ export interface ButtonProps extends ResponsivePaddingProps, ResponsiveRadiusPro
29
36
  */
30
37
  loading?: boolean
31
38
  selected?: boolean
39
+ /**
40
+ * @deprecated Use `gap` instead. `space` will be removed in v4.
41
+ */
32
42
  space?: number | number[]
43
+ gap?: number | number[]
33
44
  muted?: boolean
34
45
  text?: React.ReactNode
35
46
  textAlign?: ButtonTextAlign
@@ -39,6 +50,11 @@ export interface ButtonProps extends ResponsivePaddingProps, ResponsiveRadiusPro
39
50
  width?: ButtonWidth
40
51
  }
41
52
 
53
+ /**
54
+ * @public
55
+ */
56
+ export type ButtonProps<E extends ElementType = 'button'> = Props<ButtonOwnProps, E>
57
+
42
58
  const StyledButton = styled.button<
43
59
  {$mode: ButtonMode; $tone: ButtonTone; $width?: ButtonWidth} & ResponsiveRadiusStyleProps &
44
60
  ThemeProps
@@ -59,11 +75,11 @@ const LoadingBox = styled.div`
59
75
  box-shadow: inherit;
60
76
  `
61
77
 
62
- /**
63
- * @public
64
- */
65
- export const Button = forwardRef(function Button(
66
- props: ButtonProps & Omit<React.HTMLProps<HTMLButtonElement>, 'as' | 'width'>,
78
+ const ButtonComponent = forwardRef(function Button(
79
+ props: ButtonOwnProps & {as?: ElementType} & Omit<
80
+ React.HTMLProps<HTMLButtonElement>,
81
+ 'as' | 'width'
82
+ >,
67
83
  ref: React.ForwardedRef<HTMLButtonElement>,
68
84
  ) {
69
85
  const {
@@ -84,7 +100,8 @@ export const Button = forwardRef(function Button(
84
100
  paddingRight: paddingRightProp,
85
101
  radius: radiusProp = 2,
86
102
  selected,
87
- space: spaceProp = 3,
103
+ gap,
104
+ space: deprecated_space = 3,
88
105
  text,
89
106
  textAlign,
90
107
  textWeight,
@@ -105,7 +122,7 @@ export const Button = forwardRef(function Button(
105
122
  const paddingLeft = _getArrayProp(paddingLeftProp)
106
123
  const paddingRight = _getArrayProp(paddingRightProp)
107
124
  const radius = _getArrayProp(radiusProp)
108
- const space = _getArrayProp(spaceProp)
125
+ const spacing = _getArrayProp(gap === undefined ? deprecated_space : gap)
109
126
 
110
127
  const boxProps = useMemo(
111
128
  () => ({
@@ -143,7 +160,7 @@ export const Button = forwardRef(function Button(
143
160
 
144
161
  {(IconComponent || text || IconRightComponent) && (
145
162
  <Box as="span" {...boxProps}>
146
- <Flex as="span" justify={justify} gap={space}>
163
+ <Flex as="span" justify={justify} gap={spacing}>
147
164
  {IconComponent && (
148
165
  <Text size={fontSize}>
149
166
  {isValidElement(IconComponent) && IconComponent}
@@ -183,4 +200,11 @@ export const Button = forwardRef(function Button(
183
200
  </StyledButton>
184
201
  )
185
202
  })
186
- Button.displayName = 'ForwardRef(Button)'
203
+ ButtonComponent.displayName = 'ForwardRef(Button)'
204
+
205
+ /**
206
+ * @public
207
+ */
208
+ export const Button = ButtonComponent as unknown as <E extends ElementType = 'button'>(
209
+ props: ButtonProps<E>,
210
+ ) => React.JSX.Element
@@ -19,7 +19,7 @@ export default function AsComponentStory() {
19
19
 
20
20
  return (
21
21
  <Flex align="center" height="fill" justify="center">
22
- <Card as={CustomLink} data-as="a" {...props} padding={3}>
22
+ <Card as={CustomLink} data-as="a" {...props} padding={3} req="example">
23
23
  <Text size={1}>As component</Text>
24
24
  </Card>
25
25
  </Flex>
@@ -13,8 +13,8 @@ import {
13
13
  ResponsiveShadowStyleProps,
14
14
  } from '../../styles/internal'
15
15
  import {ThemeColorProvider, useRootTheme} from '../../theme'
16
- import {CardTone} from '../../types'
17
- import {Box, BoxProps} from '../box'
16
+ import {CardTone, ElementType, Props} from '../../types'
17
+ import {Box, BoxOwnProps} from '../box'
18
18
  import {ResponsiveBorderProps, ResponsiveRadiusProps, ResponsiveShadowProps} from '../types'
19
19
  import {cardStyle} from './styles'
20
20
  import {CardStyleProps} from './types'
@@ -22,8 +22,8 @@ import {CardStyleProps} from './types'
22
22
  /**
23
23
  * @public
24
24
  */
25
- export interface CardProps
26
- extends BoxProps,
25
+ export interface CardOwnProps
26
+ extends BoxOwnProps,
27
27
  ResponsiveBorderProps,
28
28
  ResponsiveRadiusProps,
29
29
  ResponsiveShadowProps {
@@ -37,12 +37,19 @@ export interface CardProps
37
37
  * @beta
38
38
  */
39
39
  __unstable_focusRing?: boolean
40
+ disabled?: boolean
40
41
  muted?: boolean
41
42
  pressed?: boolean
42
43
  scheme?: ThemeColorSchemeKey
44
+ selected?: boolean
43
45
  tone?: CardTone
44
46
  }
45
47
 
48
+ /**
49
+ * @public
50
+ */
51
+ export type CardProps<E extends ElementType = 'div'> = Props<CardOwnProps, E>
52
+
46
53
  const StyledCard = styled(Box)<
47
54
  CardStyleProps &
48
55
  ResponsiveRadiusStyleProps &
@@ -50,14 +57,8 @@ const StyledCard = styled(Box)<
50
57
  ResponsiveShadowStyleProps
51
58
  >(responsiveBorderStyle, responsiveRadiusStyle, responsiveShadowStyle, cardStyle)
52
59
 
53
- /**
54
- * The `Card` component acts much like a `Box`, but with a background and foreground color.
55
- * Components within a `Card` inherit its colors.
56
- *
57
- * @public
58
- */
59
- export const Card = forwardRef(function Card(
60
- props: CardProps & Omit<React.HTMLProps<HTMLDivElement>, 'as' | 'height'>,
60
+ const CardComponent = forwardRef(function Card(
61
+ props: CardOwnProps & {as?: ElementType} & Omit<React.HTMLProps<HTMLDivElement>, 'as' | 'height'>,
61
62
  ref: React.ForwardedRef<HTMLDivElement>,
62
63
  ) {
63
64
  const {
@@ -114,4 +115,14 @@ export const Card = forwardRef(function Card(
114
115
  </ThemeColorProvider>
115
116
  )
116
117
  })
117
- Card.displayName = 'ForwardRef(Card)'
118
+ CardComponent.displayName = 'ForwardRef(Card)'
119
+
120
+ /**
121
+ * The `Card` component acts much like a `Box`, but with a background and foreground color.
122
+ * Components within a `Card` inherit its colors.
123
+ *
124
+ * @public
125
+ */
126
+ export const Card = CardComponent as unknown as <E extends ElementType = 'div'>(
127
+ props: CardProps<E>,
128
+ ) => React.JSX.Element
@@ -3,6 +3,7 @@ import {styled} from 'styled-components'
3
3
 
4
4
  import {_getArrayProp} from '../../styles'
5
5
  import {responsiveCodeFontStyle, ResponsiveFontStyleProps} from '../../styles/internal'
6
+ import {ElementType, Props} from '../../types'
6
7
  import {codeBaseStyle} from './styles'
7
8
 
8
9
  const LazyRefractor = lazy(() => import('./refractor'))
@@ -10,21 +11,22 @@ const LazyRefractor = lazy(() => import('./refractor'))
10
11
  /**
11
12
  * @public
12
13
  */
13
- export interface CodeProps {
14
- as?: React.ElementType | keyof React.JSX.IntrinsicElements
14
+ export interface CodeOwnProps {
15
15
  /** Define the language to use for syntax highlighting. */
16
16
  language?: string
17
17
  size?: number | number[]
18
18
  weight?: string
19
19
  }
20
20
 
21
- const StyledCode = styled.pre<ResponsiveFontStyleProps>(codeBaseStyle, responsiveCodeFontStyle)
22
-
23
21
  /**
24
22
  * @public
25
23
  */
26
- export const Code = forwardRef(function Code(
27
- props: CodeProps & Omit<React.HTMLProps<HTMLElement>, 'as' | 'size'>,
24
+ export type CodeProps<E extends ElementType = 'pre'> = Props<CodeOwnProps, E>
25
+
26
+ const StyledCode = styled.pre<ResponsiveFontStyleProps>(codeBaseStyle, responsiveCodeFontStyle)
27
+
28
+ const CodeComponent = forwardRef(function Code(
29
+ props: CodeOwnProps & {as?: ElementType} & Omit<React.HTMLProps<HTMLElement>, 'as' | 'size'>,
28
30
  ref: React.ForwardedRef<HTMLElement>,
29
31
  ) {
30
32
  const {children, language, size = 2, weight, ...restProps} = props
@@ -43,4 +45,11 @@ export const Code = forwardRef(function Code(
43
45
  </StyledCode>
44
46
  )
45
47
  })
46
- Code.displayName = 'ForwardRef(Code)'
48
+ CodeComponent.displayName = 'ForwardRef(Code)'
49
+
50
+ /**
51
+ * @public
52
+ */
53
+ export const Code = CodeComponent as unknown as <E extends ElementType = 'pre'>(
54
+ props: CodeProps<E>,
55
+ ) => React.JSX.Element
@@ -2,7 +2,8 @@ import {forwardRef} from 'react'
2
2
  import {styled} from 'styled-components'
3
3
 
4
4
  import {_getArrayProp} from '../../styles'
5
- import {Box, BoxProps} from '../box'
5
+ import {ElementType, Props} from '../../types'
6
+ import {Box, BoxOwnProps} from '../box'
6
7
  import {ResponsiveWidthProps} from '../types'
7
8
  import {containerBaseStyle, responsiveContainerWidthStyle} from './styles'
8
9
  import {ResponsiveWidthStyleProps} from './types'
@@ -10,20 +11,23 @@ import {ResponsiveWidthStyleProps} from './types'
10
11
  /**
11
12
  * @public
12
13
  */
13
- export interface ContainerProps extends BoxProps, ResponsiveWidthProps {}
14
+ export interface ContainerOwnProps extends BoxOwnProps, ResponsiveWidthProps {}
15
+
16
+ /**
17
+ * @public
18
+ */
19
+ export type ContainerProps<E extends ElementType = 'div'> = Props<ContainerOwnProps, E>
14
20
 
15
21
  const StyledContainer = styled(Box)<ResponsiveWidthStyleProps>(
16
22
  containerBaseStyle,
17
23
  responsiveContainerWidthStyle,
18
24
  )
19
25
 
20
- /**
21
- * The `Container` component wraps content layout in a defined set of widths.
22
- *
23
- * @public
24
- */
25
- export const Container = forwardRef(function Container(
26
- props: ContainerProps & Omit<React.HTMLProps<HTMLDivElement>, 'as' | 'height' | 'width'>,
26
+ const ContainerComponent = forwardRef(function Container(
27
+ props: ContainerOwnProps & {as?: ElementType} & Omit<
28
+ React.HTMLProps<HTMLDivElement>,
29
+ 'as' | 'height' | 'width'
30
+ >,
27
31
  ref: React.ForwardedRef<HTMLDivElement>,
28
32
  ) {
29
33
  const {as, width = 2, ...restProps} = props
@@ -38,4 +42,13 @@ export const Container = forwardRef(function Container(
38
42
  />
39
43
  )
40
44
  })
41
- Container.displayName = 'ForwardRef(Container)'
45
+ ContainerComponent.displayName = 'ForwardRef(Container)'
46
+
47
+ /**
48
+ * The `Container` component wraps content layout in a defined set of widths.
49
+ *
50
+ * @public
51
+ */
52
+ export const Container = ContainerComponent as unknown as <E extends ElementType = 'div'>(
53
+ props: ContainerProps<E>,
54
+ ) => React.JSX.Element