@sanity/ui 0.37.12 → 0.37.13

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 (242) hide show
  1. package/lib/dts/src/components/autocomplete/autocomplete.d.ts +2 -2
  2. package/lib/dts/src/components/autocomplete/autocomplete.d.ts.map +1 -1
  3. package/lib/dts/src/components/autocomplete/autocomplete.styles.d.ts.map +1 -1
  4. package/lib/dts/src/components/autocomplete/constants.d.ts +0 -4
  5. package/lib/dts/src/components/autocomplete/constants.d.ts.map +1 -1
  6. package/lib/dts/src/components/breadcrumbs/breadcrumbs.d.ts.map +1 -1
  7. package/lib/dts/src/components/dialog/dialog.d.ts.map +1 -1
  8. package/lib/dts/src/components/dialog/styles.d.ts +1 -1
  9. package/lib/dts/src/components/dialog/styles.d.ts.map +1 -1
  10. package/lib/dts/src/components/hotkeys/hotkeys.d.ts.map +1 -1
  11. package/lib/dts/src/components/menu/menuButton.d.ts.map +1 -1
  12. package/lib/dts/src/components/menu/menuGroup.d.ts.map +1 -1
  13. package/lib/dts/src/components/menu/menuItem.d.ts.map +1 -1
  14. package/lib/dts/src/components/skeleton/skeleton.d.ts.map +1 -1
  15. package/lib/dts/src/hooks/_internal/useUnique.d.ts +2 -3
  16. package/lib/dts/src/hooks/_internal/useUnique.d.ts.map +1 -1
  17. package/lib/dts/src/hooks/index.d.ts +2 -1
  18. package/lib/dts/src/hooks/index.d.ts.map +1 -1
  19. package/lib/dts/src/hooks/useArrayProp.d.ts +7 -0
  20. package/lib/dts/src/hooks/useArrayProp.d.ts.map +1 -0
  21. package/lib/dts/src/hooks/useElementRect/useElementRect.d.ts +1 -1
  22. package/lib/dts/src/hooks/useElementRect/useElementRect.d.ts.map +1 -1
  23. package/lib/dts/src/hooks/useElementSize.d.ts +7 -0
  24. package/lib/dts/src/hooks/useElementSize.d.ts.map +1 -0
  25. package/lib/dts/src/index.d.ts +1 -0
  26. package/lib/dts/src/index.d.ts.map +1 -1
  27. package/lib/dts/src/observers/elementSizeObserver.d.ts +37 -0
  28. package/lib/dts/src/observers/elementSizeObserver.d.ts.map +1 -0
  29. package/lib/dts/src/observers/index.d.ts +3 -0
  30. package/lib/dts/src/observers/index.d.ts.map +1 -0
  31. package/lib/dts/src/observers/resizeObserver.d.ts +5 -0
  32. package/lib/dts/src/observers/resizeObserver.d.ts.map +1 -0
  33. package/lib/dts/src/primitives/_selectable/selectable.d.ts +1 -2
  34. package/lib/dts/src/primitives/_selectable/selectable.d.ts.map +1 -1
  35. package/lib/dts/src/primitives/avatar/avatar.d.ts.map +1 -1
  36. package/lib/dts/src/primitives/avatar/avatarCounter.d.ts +1 -0
  37. package/lib/dts/src/primitives/avatar/avatarCounter.d.ts.map +1 -1
  38. package/lib/dts/src/primitives/avatar/avatarStack.d.ts +1 -0
  39. package/lib/dts/src/primitives/avatar/avatarStack.d.ts.map +1 -1
  40. package/lib/dts/src/primitives/avatar/styles.d.ts.map +1 -1
  41. package/lib/dts/src/primitives/badge/badge.d.ts.map +1 -1
  42. package/lib/dts/src/primitives/box/box.d.ts.map +1 -1
  43. package/lib/dts/src/primitives/button/button.d.ts.map +1 -1
  44. package/lib/dts/src/primitives/card/card.d.ts.map +1 -1
  45. package/lib/dts/src/primitives/code/code.d.ts.map +1 -1
  46. package/lib/dts/src/primitives/container/container.d.ts.map +1 -1
  47. package/lib/dts/src/primitives/container/styles.d.ts.map +1 -1
  48. package/lib/dts/src/primitives/container/types.d.ts +1 -1
  49. package/lib/dts/src/primitives/container/types.d.ts.map +1 -1
  50. package/lib/dts/src/primitives/flex/flex.d.ts.map +1 -1
  51. package/lib/dts/src/primitives/grid/grid.d.ts.map +1 -1
  52. package/lib/dts/src/primitives/heading/heading.d.ts.map +1 -1
  53. package/lib/dts/src/primitives/inline/inline.d.ts.map +1 -1
  54. package/lib/dts/src/primitives/inline/styles.d.ts.map +1 -1
  55. package/lib/dts/src/primitives/inline/types.d.ts +1 -1
  56. package/lib/dts/src/primitives/inline/types.d.ts.map +1 -1
  57. package/lib/dts/src/primitives/kbd/kbd.d.ts.map +1 -1
  58. package/lib/dts/src/primitives/label/label.d.ts.map +1 -1
  59. package/lib/dts/src/primitives/popover/popover.d.ts.map +1 -1
  60. package/lib/dts/src/primitives/select/styles.d.ts +5 -1
  61. package/lib/dts/src/primitives/select/styles.d.ts.map +1 -1
  62. package/lib/dts/src/primitives/stack/stack.d.ts.map +1 -1
  63. package/lib/dts/src/primitives/stack/styles.d.ts +1 -1
  64. package/lib/dts/src/primitives/stack/styles.d.ts.map +1 -1
  65. package/lib/dts/src/primitives/text/text.d.ts.map +1 -1
  66. package/lib/dts/src/primitives/textArea/textArea.d.ts.map +1 -1
  67. package/lib/dts/src/primitives/textInput/textInput.d.ts.map +1 -1
  68. package/lib/dts/src/primitives/tooltip/tooltip.d.ts.map +1 -1
  69. package/lib/dts/src/primitives/types.d.ts +1 -1
  70. package/lib/dts/src/primitives/types.d.ts.map +1 -1
  71. package/lib/dts/src/styles/border/types.d.ts +5 -5
  72. package/lib/dts/src/styles/border/types.d.ts.map +1 -1
  73. package/lib/dts/src/styles/box/types.d.ts +4 -4
  74. package/lib/dts/src/styles/box/types.d.ts.map +1 -1
  75. package/lib/dts/src/styles/flex/flexItemStyle.d.ts.map +1 -1
  76. package/lib/dts/src/styles/flex/types.d.ts +6 -6
  77. package/lib/dts/src/styles/flex/types.d.ts.map +1 -1
  78. package/lib/dts/src/styles/font/responsiveFont.d.ts +1 -1
  79. package/lib/dts/src/styles/font/responsiveFont.d.ts.map +1 -1
  80. package/lib/dts/src/styles/font/types.d.ts +3 -3
  81. package/lib/dts/src/styles/font/types.d.ts.map +1 -1
  82. package/lib/dts/src/styles/grid/types.d.ts +14 -14
  83. package/lib/dts/src/styles/grid/types.d.ts.map +1 -1
  84. package/lib/dts/src/styles/helpers.d.ts +4 -4
  85. package/lib/dts/src/styles/helpers.d.ts.map +1 -1
  86. package/lib/dts/src/styles/input/responsiveInputPaddingStyle.d.ts +12 -12
  87. package/lib/dts/src/styles/input/responsiveInputPaddingStyle.d.ts.map +1 -1
  88. package/lib/dts/src/styles/input/textInputStyle.d.ts +4 -1
  89. package/lib/dts/src/styles/input/textInputStyle.d.ts.map +1 -1
  90. package/lib/dts/src/styles/margin/types.d.ts +7 -7
  91. package/lib/dts/src/styles/margin/types.d.ts.map +1 -1
  92. package/lib/dts/src/styles/padding/types.d.ts +7 -7
  93. package/lib/dts/src/styles/padding/types.d.ts.map +1 -1
  94. package/lib/dts/src/styles/radius/types.d.ts +1 -1
  95. package/lib/dts/src/styles/radius/types.d.ts.map +1 -1
  96. package/lib/dts/src/styles/shadow/shadowStyle.d.ts.map +1 -1
  97. package/lib/dts/src/styles/shadow/types.d.ts +1 -1
  98. package/lib/dts/src/styles/shadow/types.d.ts.map +1 -1
  99. package/lib/dts/src/theme/lib/theme/fonts.d.ts +1 -3
  100. package/lib/dts/src/theme/lib/theme/fonts.d.ts.map +1 -1
  101. package/lib/dts/src/theme/studioTheme/fonts.d.ts.map +1 -1
  102. package/lib/dts/src/types/index.d.ts +2 -1
  103. package/lib/dts/src/types/index.d.ts.map +1 -1
  104. package/lib/dts/src/types/placement.d.ts +7 -0
  105. package/lib/dts/src/types/placement.d.ts.map +1 -0
  106. package/lib/dts/src/types/text.d.ts +5 -0
  107. package/lib/dts/src/types/text.d.ts.map +1 -0
  108. package/lib/dts/src/utils/elementQuery/elementQuery.d.ts.map +1 -1
  109. package/lib/dts/src/utils/index.d.ts +0 -1
  110. package/lib/dts/src/utils/index.d.ts.map +1 -1
  111. package/lib/dts/src/utils/virtualList/virtualList.d.ts.map +1 -1
  112. package/lib/sanity-ui.js +738 -627
  113. package/lib/sanity-ui.js.map +1 -1
  114. package/lib/{sanity-ui.modern.js → sanity-ui.modern.mjs} +736 -616
  115. package/lib/sanity-ui.modern.mjs.map +1 -0
  116. package/lib/sanity-ui.module.js +732 -623
  117. package/lib/sanity-ui.module.js.map +1 -1
  118. package/package.json +11 -11
  119. package/src/__workshop__/color/overview.tsx +9 -11
  120. package/src/components/autocomplete/__workshop__/async.tsx +14 -12
  121. package/src/components/autocomplete/__workshop__/constrainedHeight.tsx +36 -0
  122. package/src/components/autocomplete/autocomplete.styles.tsx +0 -1
  123. package/src/components/autocomplete/autocomplete.tsx +14 -7
  124. package/src/components/autocomplete/constants.ts +0 -5
  125. package/src/components/breadcrumbs/breadcrumbs.tsx +3 -2
  126. package/src/components/dialog/dialog.tsx +17 -9
  127. package/src/components/dialog/styles.ts +3 -3
  128. package/src/components/hotkeys/hotkeys.tsx +3 -1
  129. package/src/components/menu/__workshop__/constrainedInBoundary.tsx +11 -14
  130. package/src/components/menu/__workshop__/groups.tsx +1 -1
  131. package/src/components/menu/menuButton.tsx +21 -13
  132. package/src/components/menu/menuGroup.tsx +3 -2
  133. package/src/components/menu/menuItem.tsx +4 -5
  134. package/src/components/skeleton/skeleton.tsx +10 -1
  135. package/src/components/skeleton/textSkeleton.tsx +7 -7
  136. package/src/hooks/_internal/useUnique.ts +4 -5
  137. package/src/hooks/index.ts +2 -1
  138. package/src/hooks/useArrayProp.ts +23 -0
  139. package/src/hooks/useElementRect/useElementRect.ts +4 -16
  140. package/src/hooks/useElementSize.ts +18 -0
  141. package/src/index.ts +1 -0
  142. package/src/observers/elementSizeObserver.ts +116 -0
  143. package/src/observers/index.ts +2 -0
  144. package/src/{utils → observers}/resizeObserver.ts +1 -4
  145. package/src/primitives/_selectable/selectable.tsx +5 -4
  146. package/src/primitives/avatar/avatar.tsx +7 -5
  147. package/src/primitives/avatar/avatarCounter.tsx +14 -12
  148. package/src/primitives/avatar/avatarStack.tsx +19 -13
  149. package/src/primitives/avatar/styles.ts +2 -2
  150. package/src/primitives/badge/badge.tsx +3 -2
  151. package/src/primitives/box/box.tsx +27 -26
  152. package/src/primitives/button/button.tsx +22 -10
  153. package/src/primitives/card/card.tsx +13 -11
  154. package/src/primitives/checkbox/__workshop__/example.tsx +4 -2
  155. package/src/primitives/checkbox/__workshop__/props.tsx +4 -2
  156. package/src/primitives/checkbox/__workshop__/readOnly.tsx +4 -2
  157. package/src/primitives/code/__workshop__/props.tsx +1 -1
  158. package/src/primitives/code/code.tsx +2 -1
  159. package/src/primitives/container/container.tsx +10 -1
  160. package/src/primitives/container/styles.ts +2 -2
  161. package/src/primitives/container/types.ts +1 -1
  162. package/src/primitives/flex/flex.tsx +6 -5
  163. package/src/primitives/grid/__workshop__/responsive.tsx +13 -12
  164. package/src/primitives/grid/grid.tsx +9 -8
  165. package/src/primitives/heading/__workshop__/opticalAlignment.tsx +19 -7
  166. package/src/primitives/heading/heading.tsx +3 -2
  167. package/src/primitives/inline/inline.tsx +12 -6
  168. package/src/primitives/inline/styles.ts +2 -2
  169. package/src/primitives/inline/types.ts +1 -1
  170. package/src/primitives/kbd/kbd.tsx +2 -1
  171. package/src/primitives/label/label.tsx +4 -3
  172. package/src/primitives/popover/__workshop__/{margins.tsx → MarginsStory.tsx} +1 -1
  173. package/src/primitives/popover/__workshop__/{matchReferenceWidth.tsx → MatchReferenceWidthStory.tsx} +0 -0
  174. package/src/primitives/popover/__workshop__/{plain.tsx → PlainStory.tsx} +12 -14
  175. package/src/primitives/popover/__workshop__/{recursive.tsx → RecursiveStory.tsx} +4 -1
  176. package/src/primitives/popover/__workshop__/RightAlignedStory.tsx +60 -0
  177. package/src/primitives/popover/__workshop__/TestStory.tsx +79 -0
  178. package/src/primitives/popover/__workshop__/index.ts +10 -5
  179. package/src/primitives/popover/popover.tsx +5 -3
  180. package/src/primitives/select/select.tsx +9 -9
  181. package/src/primitives/select/styles.ts +10 -4
  182. package/src/primitives/stack/stack.tsx +2 -1
  183. package/src/primitives/stack/styles.ts +3 -3
  184. package/src/primitives/text/__workshop__/opticalAlignment.tsx +15 -5
  185. package/src/primitives/text/text.tsx +3 -2
  186. package/src/primitives/textArea/__workshop__/plain.tsx +23 -18
  187. package/src/primitives/textArea/textArea.tsx +17 -5
  188. package/src/primitives/textInput/__workshop__/clearButton.tsx +14 -8
  189. package/src/primitives/textInput/__workshop__/index.ts +2 -2
  190. package/src/primitives/textInput/__workshop__/plain.tsx +39 -32
  191. package/src/primitives/textInput/__workshop__/tones.tsx +97 -75
  192. package/src/primitives/textInput/__workshop__/typed.tsx +8 -2
  193. package/src/primitives/textInput/textInput.tsx +43 -12
  194. package/src/primitives/tooltip/__workshop__/props.tsx +5 -1
  195. package/src/primitives/tooltip/tooltip.tsx +3 -2
  196. package/src/primitives/types.ts +1 -1
  197. package/src/styles/border/borderStyle.ts +6 -6
  198. package/src/styles/border/types.ts +5 -5
  199. package/src/styles/box/boxStyle.ts +5 -5
  200. package/src/styles/box/types.ts +4 -4
  201. package/src/styles/flex/flexItemStyle.ts +5 -4
  202. package/src/styles/flex/flexStyle.ts +6 -6
  203. package/src/styles/flex/types.ts +6 -6
  204. package/src/styles/font/responsiveFont.ts +7 -27
  205. package/src/styles/font/textAlignStyle.ts +2 -2
  206. package/src/styles/font/types.ts +4 -3
  207. package/src/styles/grid/gridItemStyle.ts +7 -7
  208. package/src/styles/grid/gridStyle.ts +9 -9
  209. package/src/styles/grid/types.ts +14 -14
  210. package/src/styles/helpers.ts +9 -9
  211. package/src/styles/input/responsiveInputPaddingStyle.ts +24 -27
  212. package/src/styles/input/textInputStyle.ts +89 -79
  213. package/src/styles/margin/marginStyle.ts +8 -8
  214. package/src/styles/margin/marginsStyle.test.ts +1 -1
  215. package/src/styles/margin/types.ts +7 -7
  216. package/src/styles/padding/paddingStyle.test.ts +1 -1
  217. package/src/styles/padding/paddingStyle.ts +8 -8
  218. package/src/styles/padding/types.ts +7 -7
  219. package/src/styles/radius/radiusStyle.ts +2 -2
  220. package/src/styles/radius/types.ts +1 -1
  221. package/src/styles/shadow/shadowStyle.ts +2 -5
  222. package/src/styles/shadow/types.ts +1 -1
  223. package/src/theme/lib/theme/fonts.ts +1 -3
  224. package/src/theme/studioTheme/fonts.ts +5 -9
  225. package/src/types/index.ts +2 -2
  226. package/src/types/placement.ts +18 -0
  227. package/src/types/text.ts +4 -0
  228. package/src/utils/elementQuery/elementQuery.tsx +5 -18
  229. package/src/utils/index.ts +0 -1
  230. package/src/utils/layer/layer.tsx +1 -1
  231. package/src/utils/layer/layerProvider.tsx +2 -2
  232. package/src/utils/virtualList/virtualList.tsx +8 -7
  233. package/lib/dts/src/hooks/useResponsiveProp.d.ts +0 -6
  234. package/lib/dts/src/hooks/useResponsiveProp.d.ts.map +0 -1
  235. package/lib/dts/src/types/common.d.ts +0 -11
  236. package/lib/dts/src/types/common.d.ts.map +0 -1
  237. package/lib/dts/src/utils/resizeObserver.d.ts +0 -6
  238. package/lib/dts/src/utils/resizeObserver.d.ts.map +0 -1
  239. package/lib/sanity-ui.modern.js.map +0 -1
  240. package/src/hooks/useResponsiveProp.ts +0 -10
  241. package/src/primitives/popover/__workshop__/rightAligned.tsx +0 -57
  242. package/src/types/common.ts +0 -12
@@ -1,7 +1,7 @@
1
1
  import React, {forwardRef} from 'react'
2
2
  import styled from 'styled-components'
3
- import {useResponsiveProp} from '../../hooks'
4
- import {responsive} from '../../styles'
3
+ import {useArrayProp} from '../../hooks'
4
+ import {_responsive} from '../../styles'
5
5
  import {Theme, ThemeFontKey} from '../../theme'
6
6
  import {Skeleton, SkeletonProps} from './skeleton'
7
7
 
@@ -10,7 +10,7 @@ const Root = styled(Skeleton)<{$size: number[]; $style: ThemeFontKey}>(
10
10
  const {media} = theme.sanity
11
11
  const font = theme.sanity.fonts[$style]
12
12
 
13
- const styles = responsive(media, $size, (sizeIndex) => {
13
+ const styles = _responsive(media, $size, (sizeIndex) => {
14
14
  const fontSize = font.sizes[sizeIndex]
15
15
  const capHeight = fontSize.lineHeight - fontSize.ascenderHeight - fontSize.descenderHeight
16
16
 
@@ -63,7 +63,7 @@ export const TextSkeleton = forwardRef(function TextSkeleton(
63
63
  ref: React.Ref<HTMLDivElement>
64
64
  ) {
65
65
  const {size = 2, ...restProps} = props
66
- const $size = useResponsiveProp(size)
66
+ const $size = useArrayProp(size)
67
67
 
68
68
  return <Root {...restProps} $size={$size} ref={ref} $style="text" />
69
69
  })
@@ -78,7 +78,7 @@ export const LabelSkeleton = forwardRef(function TextSkeleton(
78
78
  ref: React.Ref<HTMLDivElement>
79
79
  ) {
80
80
  const {size = 2, ...restProps} = props
81
- const $size = useResponsiveProp(size)
81
+ const $size = useArrayProp(size)
82
82
 
83
83
  return <Root {...restProps} $size={$size} ref={ref} $style="label" />
84
84
  })
@@ -93,7 +93,7 @@ export const HeadingSkeleton = forwardRef(function TextSkeleton(
93
93
  ref: React.Ref<HTMLDivElement>
94
94
  ) {
95
95
  const {size = 2, ...restProps} = props
96
- const $size = useResponsiveProp(size)
96
+ const $size = useArrayProp(size)
97
97
 
98
98
  return <Root {...restProps} $size={$size} ref={ref} $style="heading" />
99
99
  })
@@ -108,7 +108,7 @@ export const CodeSkeleton = forwardRef(function TextSkeleton(
108
108
  ref: React.Ref<HTMLDivElement>
109
109
  ) {
110
110
  const {size = 2, ...restProps} = props
111
- const $size = useResponsiveProp(size)
111
+ const $size = useArrayProp(size)
112
112
 
113
113
  return <Root {...restProps} $size={$size} ref={ref} $style="code" />
114
114
  })
@@ -1,9 +1,8 @@
1
1
  import {useRef} from 'react'
2
2
 
3
3
  /**
4
- * This is a React hook – and an escape hatch – to make sure that a record is
5
- * the same on every render. Uses strict equality comparison (eg by identity),
6
- * and only goes one level deep. SHOULD NOT BE USED IN MOST CASES.
4
+ * This is a React hook to make sure that a record identity is the same on every render. Uses strict
5
+ * equality comparison (eg by identity), and only goes one level deep.
7
6
  *
8
7
  * @internal
9
8
  */
@@ -12,14 +11,14 @@ type Comparable = Record<string | number | symbol, unknown> | undefined | null
12
11
  export function useUnique<ValueType extends Comparable = Comparable>(value: ValueType): ValueType {
13
12
  const valueRef = useRef<ValueType>(value)
14
13
 
15
- if (!isEqual(valueRef.current, value)) {
14
+ if (!_isEqual(valueRef.current, value)) {
16
15
  valueRef.current = value
17
16
  }
18
17
 
19
18
  return valueRef.current
20
19
  }
21
20
 
22
- function isEqual(objA: Comparable, objB: Comparable): boolean {
21
+ function _isEqual(objA: Comparable, objB: Comparable): boolean {
23
22
  if (!objA || !objB) {
24
23
  return objA === objB
25
24
  }
@@ -1,8 +1,9 @@
1
+ export * from './useArrayProp'
1
2
  export * from './useClickOutside'
2
3
  export * from './useElementRect'
4
+ export * from './useElementSize'
3
5
  export * from './useGlobalKeyDown'
4
6
  export * from './useMediaIndex'
5
7
  export * from './usePrefersDark'
6
8
  export * from './useForwardedRef'
7
9
  export * from './useCustomValidity'
8
- export * from './useResponsiveProp'
@@ -0,0 +1,23 @@
1
+ import {useMemo} from 'react'
2
+ import {_getArrayProp} from '../styles'
3
+
4
+ export type Primitive = string | number | boolean | undefined | null
5
+
6
+ /**
7
+ * This API might change. DO NOT USE IN PRODUCTION.
8
+ * @beta
9
+ */
10
+ export function useArrayProp<T extends Primitive = Primitive>(
11
+ val: T | T[] | undefined,
12
+ defaultVal?: T[]
13
+ ): T[] {
14
+ const __perf_hash__ = JSON.stringify(val ?? defaultVal)
15
+
16
+ return useMemo(
17
+ () => _getArrayProp(val, defaultVal),
18
+
19
+ // Improve performance: Keep object identify for a given hash of the value
20
+ // eslint-disable-next-line react-hooks/exhaustive-deps
21
+ [__perf_hash__]
22
+ )
23
+ }
@@ -1,23 +1,11 @@
1
- import {useEffect, useState} from 'react'
1
+ import {useElementSize} from '../useElementSize'
2
2
 
3
3
  /**
4
4
  * Subscribe to the rect of a DOM element.
5
- * @beta
5
+ * @deprecated Use `useElementSize` instead
6
6
  */
7
7
  export function useElementRect(element: HTMLElement | null): DOMRectReadOnly | null {
8
- const [rect, setRect] = useState<DOMRectReadOnly | null>(null)
8
+ const elementSize = useElementSize(element)
9
9
 
10
- useEffect(() => {
11
- if (!element) return undefined
12
-
13
- const ro = new ResizeObserver((entries) => {
14
- setRect(entries[0].contentRect)
15
- })
16
-
17
- ro.observe(element)
18
-
19
- return () => ro.disconnect()
20
- }, [element])
21
-
22
- return rect
10
+ return elementSize?._contentRect || null
23
11
  }
@@ -0,0 +1,18 @@
1
+ import {useEffect, useState} from 'react'
2
+ import {ElementSize, _elementSizeObserver} from '../observers/elementSizeObserver'
3
+
4
+ /**
5
+ * Subscribe to the size of a DOM element.
6
+ * @beta
7
+ */
8
+ export function useElementSize(element: HTMLElement | null): ElementSize | null {
9
+ const [size, setSize] = useState<ElementSize | null>(null)
10
+
11
+ useEffect(() => {
12
+ if (!element) return undefined
13
+
14
+ return _elementSizeObserver.subscribe(element, setSize)
15
+ }, [element])
16
+
17
+ return size
18
+ }
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ export * from './primitives'
2
2
  export * from './components'
3
3
  export * from './helpers'
4
4
  export * from './hooks'
5
+ export * from './observers'
5
6
  export * from './styles'
6
7
  export * from './theme'
7
8
  export * from './types'
@@ -0,0 +1,116 @@
1
+ import {_ResizeObserver} from './resizeObserver'
2
+
3
+ /**
4
+ * @beta
5
+ */
6
+ export interface ElementRectValue {
7
+ width: number
8
+ height: number
9
+ }
10
+
11
+ /**
12
+ * @beta
13
+ */
14
+ export interface ElementSize {
15
+ content: ElementRectValue
16
+ border: ElementRectValue
17
+
18
+ /** @deprecated INTERNAL ONLY */
19
+ _contentRect: DOMRectReadOnly
20
+ }
21
+
22
+ /**
23
+ * @internal
24
+ */
25
+ export type _ElementSizeSubscriber = (elementRect: ElementSize) => void
26
+
27
+ /**
28
+ * @internal
29
+ */
30
+ export interface _ElementSizeObserver {
31
+ subscribe: (element: HTMLElement, subscriber: _ElementSizeSubscriber) => () => void
32
+ }
33
+
34
+ /**
35
+ * @internal
36
+ */
37
+ export interface _ElementSizeListener {
38
+ subscribe: (element: HTMLElement, subscriber: _ElementSizeSubscriber) => () => void
39
+ }
40
+
41
+ // Initialize element size observer
42
+ // NOTE: this should NOT have size effects
43
+ /**
44
+ * @internal
45
+ */
46
+ export const _elementSizeObserver = _createElementSizeObserver()
47
+
48
+ function _createElementRectValueListener(): _ElementSizeListener {
49
+ return {
50
+ subscribe(element, subscriber) {
51
+ const resizeObserver = new _ResizeObserver(([entry]) => {
52
+ subscriber({
53
+ _contentRect: entry.contentRect,
54
+ border: {
55
+ width: entry.borderBoxSize[0].inlineSize,
56
+ height: entry.borderBoxSize[0].blockSize,
57
+ },
58
+ content: {
59
+ width: entry.contentRect.width,
60
+ height: entry.contentRect.height,
61
+ },
62
+ })
63
+ })
64
+
65
+ resizeObserver.observe(element)
66
+
67
+ return () => {
68
+ resizeObserver.unobserve(element)
69
+ resizeObserver.disconnect()
70
+ }
71
+ },
72
+ }
73
+ }
74
+
75
+ function _createElementSizeObserver(): _ElementSizeObserver {
76
+ const disposeCache = new WeakMap<HTMLElement, () => void>()
77
+ const subscribersCache = new WeakMap<HTMLElement, _ElementSizeSubscriber[]>()
78
+
79
+ return {
80
+ subscribe(element, subscriber) {
81
+ const subscribers = subscribersCache.get(element) || []
82
+
83
+ let dispose = disposeCache.get(element)
84
+
85
+ if (!subscribersCache.has(element)) {
86
+ subscribersCache.set(element, subscribers)
87
+
88
+ const listener = _createElementRectValueListener()
89
+
90
+ // listen
91
+ dispose = listener.subscribe(element, (elementRect) => {
92
+ for (const sub of subscribers) {
93
+ sub(elementRect)
94
+ }
95
+ })
96
+ }
97
+
98
+ subscribers.push(subscriber)
99
+
100
+ return () => {
101
+ // dispose
102
+
103
+ const idx = subscribers.indexOf(subscriber)
104
+
105
+ if (idx > -1) {
106
+ subscribers.splice(idx, 1)
107
+ }
108
+
109
+ if (subscribers.length === 0) {
110
+ // unlisten
111
+ if (dispose) dispose()
112
+ }
113
+ }
114
+ },
115
+ }
116
+ }
@@ -0,0 +1,2 @@
1
+ export * from './elementSizeObserver'
2
+ export * from './resizeObserver'
@@ -3,10 +3,7 @@ import {ResizeObserver as ResizeObserverPolyfill} from '@juggle/resize-observer'
3
3
  /**
4
4
  * @internal
5
5
  */
6
- const RO: typeof ResizeObserver = (
6
+ export const _ResizeObserver: typeof ResizeObserver =
7
7
  typeof window !== 'undefined' && window.ResizeObserver
8
8
  ? window.ResizeObserver
9
9
  : ResizeObserverPolyfill
10
- ) as any
11
-
12
- export {RO as ResizeObserver}
@@ -1,5 +1,4 @@
1
1
  import styled from 'styled-components'
2
- import {responsiveBorderStyle, ResponsiveBorderStyleProps} from '../../styles/border'
3
2
  import {responsiveRadiusStyle, ResponsiveRadiusStyleProps} from '../../styles/radius'
4
3
  import {Box} from '../box'
5
4
  import {selectableBaseStyle, selectableColorStyle, SelectableStyleProps} from './style'
@@ -7,6 +6,8 @@ import {selectableBaseStyle, selectableColorStyle, SelectableStyleProps} from '.
7
6
  /**
8
7
  * @internal
9
8
  */
10
- export const Selectable = styled(Box)<
11
- SelectableStyleProps & ResponsiveRadiusStyleProps & ResponsiveBorderStyleProps
12
- >(responsiveBorderStyle, responsiveRadiusStyle, selectableBaseStyle, selectableColorStyle)
9
+ export const Selectable = styled(Box)<SelectableStyleProps & ResponsiveRadiusStyleProps>(
10
+ responsiveRadiusStyle,
11
+ selectableBaseStyle,
12
+ selectableColorStyle
13
+ )
@@ -1,8 +1,8 @@
1
1
  import {useId} from '@reach/auto-id'
2
- import React, {forwardRef, useCallback, useEffect, useState} from 'react'
2
+ import React, {forwardRef, useCallback, useEffect, useMemo, useState} from 'react'
3
3
  import ReactIs from 'react-is'
4
4
  import styled from 'styled-components'
5
- import {useResponsiveProp} from '../../hooks'
5
+ import {useArrayProp} from '../../hooks'
6
6
  import {ThemeColorSpotKey, useTheme} from '../../theme'
7
7
  import {AvatarPosition, AvatarSize, AvatarStatus} from '../../types'
8
8
  import {Text} from '../text'
@@ -58,11 +58,11 @@ export const Avatar = forwardRef(function Avatar(
58
58
  arrowPosition: arrowPositionProp,
59
59
  animateArrowFrom,
60
60
  status = 'online',
61
- size: sizeProp,
61
+ size: sizeProp = 0,
62
62
  ...restProps
63
63
  } = props
64
64
  const as = ReactIs.isValidElementType(asProp) ? asProp : 'div'
65
- const size: AvatarSize[] = useResponsiveProp(sizeProp, [0])
65
+ const size = useArrayProp(sizeProp)
66
66
  const theme = useTheme()
67
67
  const color = theme.sanity.color.spot[colorKey] || theme.sanity.color.spot.gray
68
68
 
@@ -101,6 +101,8 @@ export const Avatar = forwardRef(function Avatar(
101
101
  }
102
102
  }, [onImageLoadError])
103
103
 
104
+ const initialsSize = useMemo(() => size.map((s) => (s === 0 ? 0 : s + 1)), [size])
105
+
104
106
  return (
105
107
  <Root
106
108
  as={as}
@@ -154,7 +156,7 @@ export const Avatar = forwardRef(function Avatar(
154
156
  {(imageFailed || !src) && initials && (
155
157
  <>
156
158
  <Initials>
157
- <Text as="span" size={size.map((s) => (s === 0 ? 0 : s + 1))}>
159
+ <Text as="span" size={initialsSize}>
158
160
  <strong>{initials}</strong>
159
161
  </Text>
160
162
  </Initials>
@@ -1,16 +1,16 @@
1
- import React, {forwardRef} from 'react'
1
+ import React, {forwardRef, useMemo} from 'react'
2
2
  import styled, {css} from 'styled-components'
3
3
  import {EMPTY_RECORD} from '../../constants'
4
- import {useResponsiveProp} from '../../hooks'
5
- import {rem, responsive, ThemeProps} from '../../styles'
4
+ import {useArrayProp} from '../../hooks'
5
+ import {rem, _responsive, ThemeProps} from '../../styles'
6
6
  import {AvatarSize} from '../../types'
7
7
  import {Text} from '../text'
8
8
 
9
- function responsiveAvatarCounterSizeStyle(props: {$size: AvatarSize[]} & ThemeProps) {
9
+ function _responsiveAvatarCounterSizeStyle(props: {$size: AvatarSize[]} & ThemeProps) {
10
10
  const {theme} = props
11
11
  const {avatar, media} = theme.sanity
12
12
 
13
- return responsive(media, props.$size, (size) => {
13
+ return _responsive(media, props.$size, (size) => {
14
14
  const avatarSize = avatar.sizes[size]
15
15
 
16
16
  if (!avatarSize) return EMPTY_RECORD
@@ -23,7 +23,7 @@ function responsiveAvatarCounterSizeStyle(props: {$size: AvatarSize[]} & ThemePr
23
23
  })
24
24
  }
25
25
 
26
- function avatarCounterBaseStyle(props: ThemeProps) {
26
+ function _avatarCounterBaseStyle(props: ThemeProps) {
27
27
  const {theme} = props
28
28
 
29
29
  return css`
@@ -44,8 +44,8 @@ function avatarCounterBaseStyle(props: ThemeProps) {
44
44
  }
45
45
 
46
46
  const Root = styled.div<{$size: AvatarSize[]}>(
47
- responsiveAvatarCounterSizeStyle,
48
- avatarCounterBaseStyle
47
+ _responsiveAvatarCounterSizeStyle,
48
+ _avatarCounterBaseStyle
49
49
  )
50
50
 
51
51
  /**
@@ -54,6 +54,7 @@ const Root = styled.div<{$size: AvatarSize[]}>(
54
54
  export interface AvatarCounterProps {
55
55
  count: number
56
56
  size?: AvatarSize | AvatarSize[]
57
+ /** @deprecated No longer supported. */
57
58
  tone?: 'navbar'
58
59
  }
59
60
 
@@ -64,12 +65,13 @@ export const AvatarCounter = forwardRef(function AvatarCounter(
64
65
  props: AvatarCounterProps,
65
66
  ref: React.Ref<HTMLDivElement>
66
67
  ) {
67
- const {count, size: sizeProp = 0, tone} = props
68
- const size: AvatarSize[] = useResponsiveProp(sizeProp, [0])
68
+ const {count, size: sizeProp = 0} = props
69
+ const size = useArrayProp(sizeProp)
70
+ const counterSize = useMemo(() => size.map((s) => (s === 0 ? 0 : s + 1)), [size])
69
71
 
70
72
  return (
71
- <Root $size={size} data-tone={tone} ref={ref}>
72
- <Text as="span" size={size.map((s) => (s === 0 ? 0 : s + 1))}>
73
+ <Root $size={size} data-ui="AvatarCounter" ref={ref}>
74
+ <Text as="span" size={counterSize}>
73
75
  <strong>{count}</strong>
74
76
  </Text>
75
77
  </Root>
@@ -1,7 +1,8 @@
1
1
  import React, {cloneElement, forwardRef} from 'react'
2
2
  import styled, {css} from 'styled-components'
3
3
  import {EMPTY_RECORD} from '../../constants'
4
- import {getResponsiveProp, rem, responsive, ThemeProps} from '../../styles'
4
+ import {useArrayProp} from '../../hooks'
5
+ import {rem, _responsive, ThemeProps} from '../../styles'
5
6
  import {AvatarSize} from '../../types'
6
7
  import {childrenToElementArray} from '../helpers'
7
8
  import {AvatarCounter} from './avatarCounter'
@@ -22,11 +23,11 @@ function avatarStackStyle() {
22
23
  return BASE_STYLES
23
24
  }
24
25
 
25
- function responsiveAvatarStackSizeStyle(props: {size: AvatarSize | AvatarSize[]} & ThemeProps) {
26
+ function responsiveAvatarStackSizeStyle(props: {$size: AvatarSize[]} & ThemeProps) {
26
27
  const {theme} = props
27
28
  const {avatar, media} = theme.sanity
28
29
 
29
- return responsive(media, getResponsiveProp(props.size), (size) => {
30
+ return _responsive(media, props.$size, (size) => {
30
31
  const avatarSize = avatar.sizes[size]
31
32
 
32
33
  if (!avatarSize) return EMPTY_RECORD
@@ -39,10 +40,7 @@ function responsiveAvatarStackSizeStyle(props: {size: AvatarSize | AvatarSize[]}
39
40
  })
40
41
  }
41
42
 
42
- const Root = styled.div<{size: AvatarSize | AvatarSize[]}>(
43
- responsiveAvatarStackSizeStyle,
44
- avatarStackStyle
45
- )
43
+ const Root = styled.div<{$size: AvatarSize[]}>(responsiveAvatarStackSizeStyle, avatarStackStyle)
46
44
 
47
45
  /**
48
46
  * @public
@@ -51,6 +49,7 @@ export interface AvatarStackProps {
51
49
  children: React.ReactNode
52
50
  maxLength?: number
53
51
  size?: AvatarSize | AvatarSize[]
52
+ /** @deprecated No longer supported. */
54
53
  tone?: 'navbar'
55
54
  }
56
55
 
@@ -61,32 +60,39 @@ export const AvatarStack = forwardRef(function AvatarStack(
61
60
  props: AvatarStackProps & Omit<React.HTMLProps<HTMLDivElement>, 'as' | 'ref'>,
62
61
  ref: React.ForwardedRef<HTMLDivElement>
63
62
  ) {
64
- const {children: childrenProp, maxLength: maxLengthProp = 4, size = 0, tone, ...restProps} = props
65
- const maxLength = Math.max(maxLengthProp, 0)
63
+ const {
64
+ children: childrenProp,
65
+ maxLength: maxLengthProp = 4,
66
+ size: sizeProp = 0,
67
+ ...restProps
68
+ } = props
66
69
  const children = childrenToElementArray(childrenProp).filter(
67
70
  (child) => typeof child !== 'string'
68
71
  ) as React.ReactElement[]
72
+ const maxLength = Math.max(maxLengthProp, 0)
73
+ const size = useArrayProp(sizeProp)
74
+
69
75
  const len = children.length
70
76
  const visibleCount = maxLength - 1
71
77
  const extraCount = len - visibleCount
72
78
  const visibleChildren = extraCount > 1 ? children.slice(extraCount, len) : children
73
79
 
74
80
  return (
75
- <Root data-ui="AvatarStack" {...restProps} ref={ref} size={size}>
81
+ <Root data-ui="AvatarStack" {...restProps} ref={ref} $size={size}>
76
82
  {len === 0 && (
77
83
  <div>
78
- <AvatarCounter count={len} tone={tone} />
84
+ <AvatarCounter count={len} />
79
85
  </div>
80
86
  )}
81
87
 
82
88
  {len !== 0 && extraCount > 1 && (
83
89
  <div>
84
- <AvatarCounter count={extraCount} size={size} tone={tone} />
90
+ <AvatarCounter count={extraCount} size={size} />
85
91
  </div>
86
92
  )}
87
93
 
88
94
  {visibleChildren.map((child, childIndex) => (
89
- <div key={String(childIndex)}>{cloneElement(child, {size, tone})}</div>
95
+ <div key={String(childIndex)}>{cloneElement(child, {size})}</div>
90
96
  ))}
91
97
  </Root>
92
98
  )
@@ -1,5 +1,5 @@
1
1
  import {CSSObject} from 'styled-components'
2
- import {rem, responsive, ThemeProps} from '../../styles'
2
+ import {rem, _responsive, ThemeProps} from '../../styles'
3
3
  import {focusRingStyle} from '../../styles/internal'
4
4
  import {AvatarRootStyleProps, ResponsiveAvatarSizeStyleProps} from './types'
5
5
 
@@ -103,7 +103,7 @@ export function responsiveAvatarSizeStyle(
103
103
  const {theme} = props
104
104
  const {avatar, media} = theme.sanity
105
105
 
106
- return responsive(media, props.$size, (size) => {
106
+ return _responsive(media, props.$size, (size) => {
107
107
  const avatarSize = avatar.sizes[size] || avatar.sizes[0]
108
108
 
109
109
  return {
@@ -1,5 +1,6 @@
1
1
  import React, {forwardRef} from 'react'
2
2
  import styled from 'styled-components'
3
+ import {useArrayProp} from '../../hooks'
3
4
  import {responsiveRadiusStyle, ResponsiveRadiusStyleProps} from '../../styles/internal'
4
5
  import {BadgeMode, BadgeTone} from '../../types'
5
6
  import {Box, BoxProps} from '../box'
@@ -46,8 +47,8 @@ export const Badge = forwardRef(function Badge(
46
47
  {...restProps}
47
48
  $mode={mode}
48
49
  $tone={tone}
49
- $radius={radius}
50
- padding={padding}
50
+ $radius={useArrayProp(radius)}
51
+ padding={useArrayProp(padding)}
51
52
  ref={ref}
52
53
  >
53
54
  <Label size={fontSize}>{children}</Label>
@@ -1,5 +1,6 @@
1
1
  import React, {forwardRef} from 'react'
2
2
  import styled from 'styled-components'
3
+ import {useArrayProp} from '../../hooks'
3
4
  import {
4
5
  boxStyle,
5
6
  flexItemStyle,
@@ -87,34 +88,34 @@ export const Box = forwardRef(function Box(
87
88
 
88
89
  return (
89
90
  <Root
90
- data-as={asProp}
91
+ data-as={typeof asProp === 'string' ? asProp : undefined}
91
92
  data-ui="Box"
92
93
  {...restProps}
93
- $column={column}
94
- $columnStart={columnStart}
95
- $columnEnd={columnEnd}
96
- $display={display}
97
- $flex={flex}
98
- $height={height}
99
- $margin={margin}
100
- $marginX={marginX}
101
- $marginY={marginY}
102
- $marginTop={marginTop}
103
- $marginRight={marginRight}
104
- $marginBottom={marginBottom}
105
- $marginLeft={marginLeft}
106
- $overflow={overflow}
107
- $padding={padding}
108
- $paddingX={paddingX}
109
- $paddingY={paddingY}
110
- $paddingTop={paddingTop}
111
- $paddingRight={paddingRight}
112
- $paddingBottom={paddingBottom}
113
- $paddingLeft={paddingLeft}
114
- $row={row}
115
- $rowStart={rowStart}
116
- $rowEnd={rowEnd}
117
- $sizing={sizing}
94
+ $column={useArrayProp(column)}
95
+ $columnStart={useArrayProp(columnStart)}
96
+ $columnEnd={useArrayProp(columnEnd)}
97
+ $display={useArrayProp(display)}
98
+ $flex={useArrayProp(flex)}
99
+ $height={useArrayProp(height)}
100
+ $margin={useArrayProp(margin)}
101
+ $marginX={useArrayProp(marginX)}
102
+ $marginY={useArrayProp(marginY)}
103
+ $marginTop={useArrayProp(marginTop)}
104
+ $marginRight={useArrayProp(marginRight)}
105
+ $marginBottom={useArrayProp(marginBottom)}
106
+ $marginLeft={useArrayProp(marginLeft)}
107
+ $overflow={useArrayProp(overflow)}
108
+ $padding={useArrayProp(padding)}
109
+ $paddingX={useArrayProp(paddingX)}
110
+ $paddingY={useArrayProp(paddingY)}
111
+ $paddingTop={useArrayProp(paddingTop)}
112
+ $paddingRight={useArrayProp(paddingRight)}
113
+ $paddingBottom={useArrayProp(paddingBottom)}
114
+ $paddingLeft={useArrayProp(paddingLeft)}
115
+ $row={useArrayProp(row)}
116
+ $rowStart={useArrayProp(rowStart)}
117
+ $rowEnd={useArrayProp(rowEnd)}
118
+ $sizing={useArrayProp(sizing)}
118
119
  as={asProp}
119
120
  ref={ref}
120
121
  >