@sanity/ui 2.0.2 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,11 +1,25 @@
1
1
  {
2
2
  "name": "@sanity/ui",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
4
+ "keywords": [
5
+ "sanity",
6
+ "ui",
7
+ "primitives",
8
+ "react",
9
+ "components",
10
+ "design-system"
11
+ ],
12
+ "homepage": "https://www.sanity.io/",
13
+ "bugs": {
14
+ "url": "https://github.com/sanity-io/ui/issues"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/sanity-io/ui.git"
19
+ },
20
+ "license": "MIT",
21
+ "author": "Sanity.io <hello@sanity.io>",
4
22
  "sideEffects": false,
5
- "types": "./dist/index.d.ts",
6
- "source": "./exports/index.ts",
7
- "module": "./dist/index.esm.js",
8
- "main": "./dist/index.js",
9
23
  "exports": {
10
24
  ".": {
11
25
  "types": "./dist/index.d.ts",
@@ -31,6 +45,10 @@
31
45
  },
32
46
  "./package.json": "./package.json"
33
47
  },
48
+ "main": "./dist/index.js",
49
+ "module": "./dist/index.esm.js",
50
+ "source": "./exports/index.ts",
51
+ "types": "./dist/index.d.ts",
34
52
  "typesVersions": {
35
53
  "*": {
36
54
  "theme": [
@@ -43,7 +61,6 @@
43
61
  "exports",
44
62
  "src"
45
63
  ],
46
- "license": "MIT",
47
64
  "scripts": {
48
65
  "build": "run-s clean pkg:build pkg:check figma:pkg:build",
49
66
  "clean": "rimraf .workshop dist",
@@ -70,62 +87,88 @@
70
87
  "workshop:dev": "workshop dev",
71
88
  "workshop:start": "http-server -a localhost -c-0 -p 1337 -s -P http://localhost:1337/index.html? dist"
72
89
  },
90
+ "commitlint": {
91
+ "extends": [
92
+ "@commitlint/config-conventional"
93
+ ]
94
+ },
95
+ "lint-staged": {
96
+ "*": [
97
+ "prettier --write --cache --ignore-unknown"
98
+ ]
99
+ },
100
+ "release": {
101
+ "branches": [
102
+ "+([0-9])?(.{+([0-9]),x}).x",
103
+ "main",
104
+ "next",
105
+ {
106
+ "name": "beta",
107
+ "prerelease": true
108
+ },
109
+ {
110
+ "name": "alpha",
111
+ "prerelease": true
112
+ }
113
+ ],
114
+ "extends": "@sanity/semantic-release-preset"
115
+ },
73
116
  "dependencies": {
74
- "@floating-ui/react-dom": "^2.0.4",
117
+ "@floating-ui/react-dom": "^2.0.8",
75
118
  "@sanity/color": "^3.0.0",
76
- "@sanity/icons": "^2.7.0",
77
- "csstype": "^3.1.2",
78
- "framer-motion": "^11.0.3",
119
+ "@sanity/icons": "^2.10.2",
120
+ "csstype": "^3.1.3",
121
+ "framer-motion": "^11.0.5",
79
122
  "react-refractor": "^2.1.7"
80
123
  },
81
124
  "devDependencies": {
82
- "@babel/core": "^7.23.3",
83
- "@babel/preset-env": "^7.23.3",
125
+ "@babel/core": "^7.23.9",
126
+ "@babel/preset-env": "^7.23.9",
84
127
  "@babel/preset-react": "^7.23.3",
85
128
  "@babel/preset-typescript": "^7.23.3",
86
- "@commitlint/cli": "^18.4.3",
87
- "@commitlint/config-conventional": "^18.4.3",
129
+ "@commitlint/cli": "^18.6.1",
130
+ "@commitlint/config-conventional": "^18.6.2",
88
131
  "@juggle/resize-observer": "^3.4.0",
89
- "@sanity/pkg-utils": "^3.2.5",
132
+ "@sanity/pkg-utils": "^4.2.2",
90
133
  "@sanity/semantic-release-preset": "^4.1.6",
91
134
  "@sanity/ui-workshop": "^2.0.3",
92
- "@storybook/addon-a11y": "^7.6.1",
93
- "@storybook/addon-docs": "^7.6.1",
94
- "@storybook/addon-essentials": "^7.6.1",
95
- "@storybook/addon-interactions": "^7.6.1",
96
- "@storybook/addon-links": "^7.6.1",
97
- "@storybook/addon-storysource": "^7.6.1",
98
- "@storybook/addon-themes": "^7.6.1",
99
- "@storybook/blocks": "^7.6.1",
135
+ "@storybook/addon-a11y": "^7.6.16",
136
+ "@storybook/addon-docs": "^7.6.16",
137
+ "@storybook/addon-essentials": "^7.6.16",
138
+ "@storybook/addon-interactions": "^7.6.16",
139
+ "@storybook/addon-links": "^7.6.16",
140
+ "@storybook/addon-storysource": "^7.6.16",
141
+ "@storybook/addon-themes": "^7.6.16",
142
+ "@storybook/blocks": "^7.6.16",
100
143
  "@storybook/jest": "^0.2.3",
101
- "@storybook/manager-api": "^7.6.1",
102
- "@storybook/react": "^7.6.1",
103
- "@storybook/react-vite": "^7.6.1",
144
+ "@storybook/manager-api": "^7.6.16",
145
+ "@storybook/react": "^7.6.16",
146
+ "@storybook/react-vite": "^7.6.16",
104
147
  "@storybook/testing-library": "^0.2.2",
105
- "@storybook/theming": "^7.6.1",
106
- "@testing-library/dom": "^9.3.3",
148
+ "@storybook/theming": "^7.6.16",
149
+ "@testing-library/dom": "^9.3.4",
107
150
  "@testing-library/jest-dom": "^5.17.0",
108
- "@testing-library/react": "^14.1.2",
109
- "@types/jest": "^29.5.10",
151
+ "@testing-library/react": "^14.2.1",
152
+ "@types/jest": "^29.5.12",
110
153
  "@types/jest-axe": "^3.5.9",
111
154
  "@types/node": "^20.5.9",
112
- "@types/react": "^18.2.39",
113
- "@types/react-dom": "^18.2.17",
155
+ "@types/react": "^18.2.55",
156
+ "@types/react-dom": "^18.2.19",
114
157
  "@types/react-is": "^18.2.4",
115
158
  "@types/refractor": "^3.4.0",
116
159
  "@types/testing-library__jest-dom": "^5.14.9",
117
- "@typescript-eslint/eslint-plugin": "^6.13.1",
118
- "@typescript-eslint/parser": "^6.13.1",
160
+ "@typescript-eslint/eslint-plugin": "^6.21.0",
161
+ "@typescript-eslint/parser": "^6.21.0",
119
162
  "commitizen": "^4.3.0",
120
- "cypress": "^13.6.0",
163
+ "cypress": "^13.6.4",
121
164
  "cypress-real-events": "^1.11.0",
122
165
  "cz-conventional-changelog": "^3.3.0",
123
- "eslint": "^8.54.0",
124
- "eslint-config-prettier": "^9.0.0",
166
+ "eslint": "^8.56.0",
167
+ "eslint-config-prettier": "^9.1.0",
125
168
  "eslint-plugin-boundaries": "^3.4.1",
126
- "eslint-plugin-import": "^2.29.0",
169
+ "eslint-plugin-import": "^2.29.1",
127
170
  "eslint-plugin-jsx-a11y": "^6.8.0",
128
- "eslint-plugin-prettier": "^5.0.1",
171
+ "eslint-plugin-prettier": "^5.1.3",
129
172
  "eslint-plugin-react": "^7.33.2",
130
173
  "eslint-plugin-react-hooks": "^4.6.0",
131
174
  "eslint-plugin-storybook": "^0.6.15",
@@ -136,21 +179,22 @@
136
179
  "jest-environment-jsdom": "^29.7.0",
137
180
  "lint-staged": "^14.0.1",
138
181
  "module-alias": "^2.2.3",
139
- "npm-run-all": "^4.1.5",
140
- "prettier": "^3.1.0",
182
+ "npm-run-all2": "^5.0.0",
183
+ "prettier": "^3.2.5",
184
+ "prettier-plugin-packagejson": "^2.4.11",
141
185
  "react": "^18.2.0",
142
186
  "react-dom": "^18.2.0",
143
187
  "react-is": "^18.2.0",
144
188
  "refractor": "^4.8.1",
145
189
  "rimraf": "^5.0.1",
146
- "semantic-release": "^22.0.8",
190
+ "semantic-release": "^22.0.12",
147
191
  "start-server-and-test": "^2.0.3",
148
- "storybook": "^7.6.1",
149
- "styled-components": "^6.1.1",
192
+ "storybook": "^7.6.16",
193
+ "styled-components": "^6.1.8",
150
194
  "tsconfig-paths": "^4.2.0",
151
- "typescript": "^5.3.2",
152
- "vite": "^5.0.2",
153
- "vite-tsconfig-paths": "^4.2.1"
195
+ "typescript": "^5.3.3",
196
+ "vite": "^5.1.3",
197
+ "vite-tsconfig-paths": "^4.3.1"
154
198
  },
155
199
  "peerDependencies": {
156
200
  "react": "^18",
@@ -158,55 +202,12 @@
158
202
  "react-is": "^18",
159
203
  "styled-components": "^5.2 || ^6"
160
204
  },
205
+ "packageManager": "pnpm@8.11.0",
161
206
  "engines": {
162
207
  "node": ">=14.0.0"
163
208
  },
164
- "repository": {
165
- "type": "git",
166
- "url": "git+https://github.com/sanity-io/ui.git"
167
- },
168
- "bugs": {
169
- "url": "https://github.com/sanity-io/ui/issues"
170
- },
171
- "keywords": [
172
- "sanity",
173
- "ui",
174
- "primitives",
175
- "react",
176
- "components",
177
- "design-system"
178
- ],
179
- "author": "Sanity.io <hello@sanity.io>",
180
- "homepage": "https://www.sanity.io/",
181
- "commitlint": {
182
- "extends": [
183
- "@commitlint/config-conventional"
184
- ]
185
- },
186
- "lint-staged": {
187
- "*": [
188
- "prettier --write --cache --ignore-unknown"
189
- ]
190
- },
191
- "packageManager": "pnpm@8.11.0",
192
209
  "publishConfig": {
193
210
  "access": "public",
194
211
  "provenance": true
195
- },
196
- "release": {
197
- "extends": "@sanity/semantic-release-preset",
198
- "branches": [
199
- "+([0-9])?(.{+([0-9]),x}).x",
200
- "main",
201
- "next",
202
- {
203
- "name": "beta",
204
- "prerelease": true
205
- },
206
- {
207
- "name": "alpha",
208
- "prerelease": true
209
- }
210
- ]
211
212
  }
212
213
  }
@@ -8,7 +8,13 @@ import {
8
8
  focusLastDescendant,
9
9
  isHTMLElement,
10
10
  } from '../../helpers'
11
- import {useArrayProp, useClickOutside, useForwardedRef, useGlobalKeyDown} from '../../hooks'
11
+ import {
12
+ useArrayProp,
13
+ useClickOutside,
14
+ useForwardedRef,
15
+ useGlobalKeyDown,
16
+ usePrefersReducedMotion,
17
+ } from '../../hooks'
12
18
  import {Box, Button, Card, Container, Flex, Text} from '../../primitives'
13
19
  import {ResponsivePaddingProps, ResponsiveWidthProps} from '../../primitives/types'
14
20
  import {responsivePaddingStyle, ResponsivePaddingStyleProps} from '../../styles/internal'
@@ -317,9 +323,11 @@ export const Dialog = forwardRef(function Dialog(
317
323
  scheme,
318
324
  width: widthProp = 0,
319
325
  zOffset: zOffsetProp = dialog.zOffset || layer.dialog.zOffset,
320
- animate = false,
326
+ animate: _animate = false,
321
327
  ...restProps
322
328
  } = props
329
+ const prefersReducedMotion = usePrefersReducedMotion()
330
+ const animate = prefersReducedMotion ? false : _animate
323
331
  const portal = usePortal()
324
332
  const portalElement = portalProp ? portal.elements?.[portalProp] || null : portal.element
325
333
  const boundaryElement = useBoundaryElement().element
@@ -1,8 +1,9 @@
1
- import {AnimatePresence, motion} from 'framer-motion'
2
- import {useCallback, useEffect, useMemo, useRef, useState, startTransition} from 'react'
1
+ import {AnimatePresence, motion, type Variants} from 'framer-motion'
2
+ import {useMemo, useRef, useState, startTransition, useEffect} from 'react'
3
3
  import styled from 'styled-components'
4
4
  import {POPOVER_MOTION_CONTENT_OPACITY_PROPERTY} from '../../constants'
5
5
  import {useMounted} from '../../hooks/useMounted'
6
+ import {usePrefersReducedMotion} from '../../hooks/usePrefersReducedMotion'
6
7
  import {Box} from '../../primitives'
7
8
  import {Layer} from '../../utils'
8
9
  import {Toast} from './toast'
@@ -52,59 +53,88 @@ let toastId = 0
52
53
  export function ToastProvider(props: ToastProviderProps): React.ReactElement {
53
54
  const {children, padding = 4, paddingX, paddingY, zOffset} = props
54
55
  const [state, _setState] = useState<ToastState>([])
55
-
56
56
  const toastsRef = useRef<{[key: string]: {timeoutId: NodeJS.Timeout}}>({})
57
+ const mounted = useMounted()
58
+ const prefersReducedMotion = usePrefersReducedMotion()
59
+ const variants = useMemo<Variants>(
60
+ () => ({
61
+ initial: {
62
+ opacity: 0,
63
+ [POPOVER_MOTION_CONTENT_OPACITY_PROPERTY as string]: 0,
64
+ y: 32,
65
+ scale: 0.25,
66
+ willChange: 'transform',
67
+ },
68
+ animate: {
69
+ opacity: [0, 1, 1],
70
+ [POPOVER_MOTION_CONTENT_OPACITY_PROPERTY as string]: [0, 0, 1],
71
+ y: 0,
72
+ scale: 1,
73
+ },
74
+ exit: {
75
+ opacity: [1, 1, 0],
76
+ [POPOVER_MOTION_CONTENT_OPACITY_PROPERTY as string]: [1, 0, 0],
77
+ scale: 0.5,
78
+ transition: prefersReducedMotion ? {duration: 0} : {duration: 0.2},
79
+ },
80
+ }),
81
+ [prefersReducedMotion],
82
+ )
57
83
 
58
- const push = useCallback((params: ToastParams) => {
59
- // Wrap setState in startTransition to allow React to give input state updates higher priority
60
- const setState: typeof _setState = (state) => startTransition(() => _setState(state))
84
+ const value: ToastContextValue = useMemo(() => {
85
+ const push = (params: ToastParams) => {
86
+ // Wrap setState in startTransition to allow React to give input state updates higher priority
87
+ const setState: typeof _setState = (state) => startTransition(() => _setState(state))
61
88
 
62
- const id = params.id || String(toastId++)
63
- const duration = params.duration || 5000
89
+ const id = params.id || String(toastId++)
90
+ const duration = params.duration || 5000
64
91
 
65
- const dismiss = () => {
66
- const timeoutId = toastsRef.current[id]?.timeoutId
92
+ const dismiss = () => {
93
+ const timeoutId = toastsRef.current[id]?.timeoutId
67
94
 
68
- setState((prevState): ToastState => {
69
- const idx = prevState.findIndex((t) => t.id === id)
95
+ setState((prevState): ToastState => {
96
+ const idx = prevState.findIndex((t) => t.id === id)
70
97
 
71
- if (idx > -1) {
72
- const toasts = prevState.slice(0)
98
+ if (idx > -1) {
99
+ const toasts = prevState.slice(0)
73
100
 
74
- toasts.splice(idx, 1)
101
+ toasts.splice(idx, 1)
75
102
 
76
- return toasts
103
+ return toasts
104
+ }
105
+
106
+ return prevState
107
+ })
108
+
109
+ if (timeoutId !== undefined) {
110
+ clearTimeout(timeoutId)
111
+ delete toastsRef.current[id]
77
112
  }
113
+ }
78
114
 
115
+ setState((prevState): ToastState => {
79
116
  return prevState
117
+ .filter((t) => t.id !== id)
118
+ .concat([
119
+ {
120
+ dismiss,
121
+ id,
122
+ params: {...params, duration},
123
+ },
124
+ ])
80
125
  })
81
126
 
82
- if (timeoutId !== undefined) {
83
- clearTimeout(timeoutId)
127
+ if (toastsRef.current[id]) {
128
+ clearTimeout(toastsRef.current[id].timeoutId)
84
129
  delete toastsRef.current[id]
85
130
  }
86
- }
87
131
 
88
- setState((prevState): ToastState => {
89
- return prevState
90
- .filter((t) => t.id !== id)
91
- .concat([
92
- {
93
- dismiss,
94
- id,
95
- params: {...params, duration},
96
- },
97
- ])
98
- })
99
-
100
- if (toastsRef.current[id]) {
101
- clearTimeout(toastsRef.current[id].timeoutId)
102
- delete toastsRef.current[id]
103
- }
132
+ toastsRef.current[id] = {timeoutId: setTimeout(dismiss, duration)}
104
133
 
105
- toastsRef.current[id] = {timeoutId: setTimeout(dismiss, duration)}
134
+ return id
135
+ }
106
136
 
107
- return id
137
+ return {version: 0.0, push}
108
138
  }, [])
109
139
 
110
140
  // clear timeouts on unmount
@@ -119,13 +149,9 @@ export function ToastProvider(props: ToastProviderProps): React.ReactElement {
119
149
  [],
120
150
  )
121
151
 
122
- const value: ToastContextValue = useMemo(() => ({version: 0.0, push}), [push])
123
- const mounted = useMounted()
124
-
125
152
  return (
126
153
  <ToastContext.Provider value={value}>
127
154
  {children}
128
-
129
155
  {mounted && (
130
156
  <Root data-ui="ToastProvider" zOffset={zOffset}>
131
157
  <ToastContainer>
@@ -133,28 +159,17 @@ export function ToastProvider(props: ToastProviderProps): React.ReactElement {
133
159
  <AnimatePresence initial={false}>
134
160
  {state.map(({dismiss, id, params}) => (
135
161
  <motion.div
136
- animate={{
137
- opacity: [0, 1, 1],
138
- [POPOVER_MOTION_CONTENT_OPACITY_PROPERTY as string]: [0, 0, 1],
139
- y: 0,
140
- scale: 1,
141
- }}
142
- exit={{
143
- opacity: [1, 1, 0],
144
- [POPOVER_MOTION_CONTENT_OPACITY_PROPERTY as string]: [1, 0, 0],
145
- scale: 0.5,
146
- transition: {duration: 0.2},
147
- }}
148
- initial={{
149
- opacity: 0,
150
- [POPOVER_MOTION_CONTENT_OPACITY_PROPERTY as string]: 0,
151
- y: 32,
152
- scale: 0.25,
153
- willChange: 'transform',
154
- }}
155
162
  key={id}
156
163
  layout="position"
157
- transition={{type: 'spring', damping: 30, stiffness: 400}}
164
+ initial="initial"
165
+ animate="animate"
166
+ exit="exit"
167
+ variants={variants}
168
+ transition={
169
+ prefersReducedMotion
170
+ ? {duration: 0}
171
+ : {type: 'spring', damping: 30, stiffness: 400}
172
+ }
158
173
  >
159
174
  <Toast
160
175
  closable={params.closable}
@@ -1,14 +1,15 @@
1
- import {useEffect, useReducer} from 'react'
1
+ import {useSyncExternalStore} from 'react'
2
2
 
3
3
  /**
4
4
  * Some components should only render after mounting to the DOM, and not be rendered at all during SSR renderToString or equivalent.
5
5
  * @public
6
6
  */
7
7
  export function useMounted(): boolean {
8
- // Use useReducer instead of useState as it's more low-level and creates the least amount of functions for the garbage collector to clean up
9
- const [mounted, mount] = useReducer(() => true, false)
10
-
11
- useEffect(mount, [mount])
12
-
13
- return mounted
8
+ return useSyncExternalStore(
9
+ subscribe,
10
+ () => true,
11
+ () => false,
12
+ )
14
13
  }
14
+
15
+ const subscribe = () => () => {}
@@ -33,7 +33,6 @@ function avatarArrowStyle(): CSSObject {
33
33
  left: '50%',
34
34
  transform: 'translateX(-6px)',
35
35
 
36
- // @ts-expect-error -- TODO wait for CSSObject types to be fixed in `styled-components` itself
37
36
  '&:not([hidden])': {
38
37
  display: 'block',
39
38
  },
@@ -75,7 +74,6 @@ export function avatarRootStyle(props: AvatarRootStyleProps & ThemeProps): CSSOb
75
74
  },
76
75
 
77
76
  '&>svg': {
78
- // @ts-expect-error -- TODO wait for CSSObject types to be fixed in `styled-components` itself
79
77
  '&:not([hidden])': {
80
78
  display: 'block',
81
79
  },
@@ -92,7 +90,6 @@ export function avatarRootStyle(props: AvatarRootStyleProps & ThemeProps): CSSOb
92
90
  color: 'inherit',
93
91
  outline: 'none',
94
92
 
95
- // @ts-expect-error -- TODO wait for CSSObject types to be fixed in `styled-components` itself
96
93
  '&:focus': {
97
94
  boxShadow: focusRingStyle({focusRing: avatar.focusRing}),
98
95
  },
@@ -22,7 +22,13 @@ import {
22
22
  useMemo,
23
23
  useRef,
24
24
  } from 'react'
25
- import {useForwardedRef, useArrayProp, useElementSize, useMediaIndex} from '../../hooks'
25
+ import {
26
+ useForwardedRef,
27
+ useArrayProp,
28
+ useElementSize,
29
+ useMediaIndex,
30
+ usePrefersReducedMotion,
31
+ } from '../../hooks'
26
32
  import {origin} from '../../middleware/origin'
27
33
  import {useTheme_v2} from '../../theme'
28
34
  import {BoxOverflow, CardTone, Placement, PopoverMargins} from '../../types'
@@ -128,7 +134,7 @@ export const Popover = memo(
128
134
 
129
135
  const {
130
136
  __unstable_margins: margins = DEFAULT_POPOVER_MARGINS,
131
- animate = false,
137
+ animate: _animate = false,
132
138
  arrow: arrowProp = false,
133
139
  boundaryElement = boundaryElementContext.element,
134
140
  children: childProp,
@@ -158,6 +164,8 @@ export const Popover = memo(
158
164
  updateRef,
159
165
  ...restProps
160
166
  } = props
167
+ const prefersReducedMotion = usePrefersReducedMotion()
168
+ const animate = prefersReducedMotion ? false : _animate
161
169
  const boundarySize = useElementSize(boundaryElement)?.border
162
170
  const padding = useArrayProp(paddingProp)
163
171
  const radius = useArrayProp(radiusProp)
@@ -23,7 +23,7 @@ import {
23
23
  useId,
24
24
  } from 'react'
25
25
  import styled from 'styled-components'
26
- import {useArrayProp, useForwardedRef} from '../../hooks'
26
+ import {useArrayProp, useForwardedRef, usePrefersReducedMotion} from '../../hooks'
27
27
  import {useDelayedState} from '../../hooks/useDelayedState'
28
28
  import {origin} from '../../middleware/origin'
29
29
  import {useTheme_v2} from '../../theme'
@@ -101,7 +101,7 @@ export const Tooltip = forwardRef(function Tooltip(
101
101
  const boundaryElementContext = useBoundaryElement()
102
102
  const {layer} = useTheme_v2()
103
103
  const {
104
- animate = false,
104
+ animate: _animate = false,
105
105
  arrow: arrowProp = false,
106
106
  boundaryElement = boundaryElementContext?.element,
107
107
  children: childProp,
@@ -119,6 +119,8 @@ export const Tooltip = forwardRef(function Tooltip(
119
119
  delay,
120
120
  ...restProps
121
121
  } = props
122
+ const prefersReducedMotion = usePrefersReducedMotion()
123
+ const animate = prefersReducedMotion ? false : _animate
122
124
  const fallbackPlacements = useArrayProp(fallbackPlacementsProp)
123
125
  const forwardedRef = useForwardedRef(ref)
124
126
  const [referenceElement, setReferenceElement] = useState<HTMLElement | null>(null)