@primer/react 38.6.0-rc.7ef904ff4 → 38.6.0-rc.83fd63ead

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.

Potentially problematic release.


This version of @primer/react might be problematic. Click here for more details.

package/CHANGELOG.md CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  ### Minor Changes
6
6
 
7
+ - [#7157](https://github.com/primer/react/pull/7157) [`eddd934`](https://github.com/primer/react/commit/eddd9340cab24ebf8054c79ca855028ed511c495) Thanks [@joshblack](https://github.com/joshblack)! - Add feature flag to control whether Spinner animations are synchronized
8
+
7
9
  - [#7277](https://github.com/primer/react/pull/7277) [`4a1c9a5`](https://github.com/primer/react/commit/4a1c9a5e48cdce7059358cd37a6d7f3f23e20c43) Thanks [@kendallgassner](https://github.com/kendallgassner)! - Added callback prop onActiveDescendantChanged to FilteredActionList
8
10
 
9
11
  ## 38.5.0
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultFeatureFlags.d.ts","sourceRoot":"","sources":["../../src/FeatureFlags/DefaultFeatureFlags.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAA;AAEnD,eAAO,MAAM,mBAAmB,kBAO9B,CAAA"}
1
+ {"version":3,"file":"DefaultFeatureFlags.d.ts","sourceRoot":"","sources":["../../src/FeatureFlags/DefaultFeatureFlags.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAA;AAEnD,eAAO,MAAM,mBAAmB,kBAQ9B,CAAA"}
@@ -6,7 +6,8 @@ const DefaultFeatureFlags = FeatureFlagScope.create({
6
6
  primer_react_overlay_overflow: false,
7
7
  primer_react_select_panel_fullscreen_on_narrow: false,
8
8
  primer_react_select_panel_order_selected_at_top: false,
9
- primer_react_select_panel_remove_active_descendant: false
9
+ primer_react_select_panel_remove_active_descendant: false,
10
+ primer_react_spinner_synchronize_animations: false
10
11
  });
11
12
 
12
13
  export { DefaultFeatureFlags };
@@ -1 +1 @@
1
- {"version":3,"file":"Spinner.d.ts","sourceRoot":"","sources":["../../src/Spinner/Spinner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,4BAA4B,CAAA;AAKlE,QAAA,MAAM,OAAO;;;;CAIZ,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,OAAO,OAAO,CAAA;IAC3B,0KAA0K;IAC1K,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IAC3B,2EAA2E;IAC3E,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,GAAG,kBAAkB,CAAA;AAEtB,iBAAS,OAAO,CAAC,EACf,IAAI,EAAE,OAAkB,EACxB,MAAkB,EAClB,YAAY,EAAE,SAAS,EACvB,SAAS,EACT,KAAK,EACL,KAAa,EACb,GAAG,KAAK,EACT,EAAE,YAAY,4BAwDd;kBAhEQ,OAAO;;;AAoEhB,eAAe,OAAO,CAAA"}
1
+ {"version":3,"file":"Spinner.d.ts","sourceRoot":"","sources":["../../src/Spinner/Spinner.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,4BAA4B,CAAA;AAMlE,QAAA,MAAM,OAAO;;;;CAIZ,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,OAAO,OAAO,CAAA;IAC3B,0KAA0K;IAC1K,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IAC3B,2EAA2E;IAC3E,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,GAAG,kBAAkB,CAAA;AAEtB,iBAAS,OAAO,CAAC,EACf,IAAI,EAAE,OAAkB,EACxB,MAAkB,EAClB,YAAY,EAAE,SAAS,EACvB,SAAS,EACT,KAAK,EACL,KAAa,EACb,GAAG,KAAK,EACT,EAAE,YAAY,4BA2Dd;kBAnEQ,OAAO;;;AAkMhB,eAAe,OAAO,CAAA"}
@@ -1,8 +1,10 @@
1
1
  import { c } from 'react-compiler-runtime';
2
- import { useState, useEffect } from 'react';
3
- import classes from './Spinner.module.css.js';
4
2
  import { clsx } from 'clsx';
3
+ import { useState, useEffect, useRef, useSyncExternalStore } from 'react';
4
+ import classes from './Spinner.module.css.js';
5
+ import { useMedia } from '../hooks/useMedia.js';
5
6
  import { jsxs, jsx } from 'react/jsx-runtime';
7
+ import { useFeatureFlag } from '../FeatureFlags/useFeatureFlag.js';
6
8
  import { useId } from '../hooks/useId.js';
7
9
  import { VisuallyHidden } from '../VisuallyHidden/VisuallyHidden.js';
8
10
 
@@ -13,7 +15,7 @@ const sizeMap = {
13
15
  };
14
16
  function Spinner(t0) {
15
17
  var _ariaLabel;
16
- const $ = c(29);
18
+ const $ = c(30);
17
19
  let ariaLabel;
18
20
  let className;
19
21
  let props;
@@ -51,6 +53,8 @@ function Spinner(t0) {
51
53
  const sizeKey = t1 === undefined ? "medium" : t1;
52
54
  const srText = t2 === undefined ? "Loading" : t2;
53
55
  const delay = t3 === undefined ? false : t3;
56
+ const syncAnimationsEnabled = useFeatureFlag("primer_react_spinner_synchronize_animations");
57
+ const animationRef = useSpinnerAnimation();
54
58
  const size = sizeMap[sizeKey];
55
59
  const hasHiddenLabel = srText !== null && ariaLabel === undefined;
56
60
  const labelId = useId();
@@ -78,20 +82,21 @@ function Spinner(t0) {
78
82
  if (!isVisible) {
79
83
  return null;
80
84
  }
81
- const t6 = (_ariaLabel = ariaLabel) !== null && _ariaLabel !== void 0 ? _ariaLabel : undefined;
82
- const t7 = hasHiddenLabel ? labelId : undefined;
83
- let t8;
85
+ const t6 = syncAnimationsEnabled ? animationRef : undefined;
86
+ const t7 = (_ariaLabel = ariaLabel) !== null && _ariaLabel !== void 0 ? _ariaLabel : undefined;
87
+ const t8 = hasHiddenLabel ? labelId : undefined;
88
+ let t9;
84
89
  if ($[11] !== className) {
85
- t8 = clsx(className, classes.SpinnerAnimation);
90
+ t9 = clsx(className, classes.SpinnerAnimation);
86
91
  $[11] = className;
87
- $[12] = t8;
92
+ $[12] = t9;
88
93
  } else {
89
- t8 = $[12];
94
+ t9 = $[12];
90
95
  }
91
96
  let t10;
92
- let t9;
97
+ let t11;
93
98
  if ($[13] === Symbol.for("react.memo_cache_sentinel")) {
94
- t9 = /*#__PURE__*/jsx("circle", {
99
+ t10 = /*#__PURE__*/jsx("circle", {
95
100
  cx: "8",
96
101
  cy: "8",
97
102
  r: "7",
@@ -100,7 +105,7 @@ function Spinner(t0) {
100
105
  strokeWidth: "2",
101
106
  vectorEffect: "non-scaling-stroke"
102
107
  });
103
- t10 = /*#__PURE__*/jsx("path", {
108
+ t11 = /*#__PURE__*/jsx("path", {
104
109
  d: "M15 8a7.002 7.002 0 00-7-7",
105
110
  stroke: "currentColor",
106
111
  strokeWidth: "2",
@@ -108,25 +113,26 @@ function Spinner(t0) {
108
113
  vectorEffect: "non-scaling-stroke"
109
114
  });
110
115
  $[13] = t10;
111
- $[14] = t9;
116
+ $[14] = t11;
112
117
  } else {
113
118
  t10 = $[13];
114
- t9 = $[14];
119
+ t11 = $[14];
115
120
  }
116
- let t11;
117
- if ($[15] !== props || $[16] !== size || $[17] !== style || $[18] !== t6 || $[19] !== t7 || $[20] !== t8) {
118
- t11 = /*#__PURE__*/jsxs("svg", {
121
+ let t12;
122
+ if ($[15] !== props || $[16] !== size || $[17] !== style || $[18] !== t6 || $[19] !== t7 || $[20] !== t8 || $[21] !== t9) {
123
+ t12 = /*#__PURE__*/jsxs("svg", {
124
+ ref: t6,
119
125
  height: size,
120
126
  width: size,
121
127
  viewBox: "0 0 16 16",
122
128
  fill: "none",
123
129
  "aria-hidden": true,
124
- "aria-label": t6,
125
- "aria-labelledby": t7,
126
- className: t8,
130
+ "aria-label": t7,
131
+ "aria-labelledby": t8,
132
+ className: t9,
127
133
  style: style,
128
134
  ...props,
129
- children: [t9, t10]
135
+ children: [t10, t11]
130
136
  });
131
137
  $[15] = props;
132
138
  $[16] = size;
@@ -134,37 +140,128 @@ function Spinner(t0) {
134
140
  $[18] = t6;
135
141
  $[19] = t7;
136
142
  $[20] = t8;
137
- $[21] = t11;
143
+ $[21] = t9;
144
+ $[22] = t12;
138
145
  } else {
139
- t11 = $[21];
146
+ t12 = $[22];
140
147
  }
141
- let t12;
142
- if ($[22] !== hasHiddenLabel || $[23] !== labelId || $[24] !== srText) {
143
- t12 = hasHiddenLabel ? /*#__PURE__*/jsx(VisuallyHidden, {
148
+ let t13;
149
+ if ($[23] !== hasHiddenLabel || $[24] !== labelId || $[25] !== srText) {
150
+ t13 = hasHiddenLabel ? /*#__PURE__*/jsx(VisuallyHidden, {
144
151
  id: labelId,
145
152
  children: srText
146
153
  }) : null;
147
- $[22] = hasHiddenLabel;
148
- $[23] = labelId;
149
- $[24] = srText;
150
- $[25] = t12;
154
+ $[23] = hasHiddenLabel;
155
+ $[24] = labelId;
156
+ $[25] = srText;
157
+ $[26] = t13;
151
158
  } else {
152
- t12 = $[25];
159
+ t13 = $[26];
153
160
  }
154
- let t13;
155
- if ($[26] !== t11 || $[27] !== t12) {
156
- t13 = /*#__PURE__*/jsxs("span", {
161
+ let t14;
162
+ if ($[27] !== t12 || $[28] !== t13) {
163
+ t14 = /*#__PURE__*/jsxs("span", {
157
164
  className: classes.Box,
158
- children: [t11, t12]
165
+ children: [t12, t13]
159
166
  });
160
- $[26] = t11;
161
167
  $[27] = t12;
162
168
  $[28] = t13;
169
+ $[29] = t14;
163
170
  } else {
164
- t13 = $[28];
171
+ t14 = $[29];
165
172
  }
166
- return t13;
173
+ return t14;
167
174
  }
168
175
  Spinner.displayName = 'Spinner';
176
+ const animationTimingStore = {
177
+ subscribers: new Set(),
178
+ value: {
179
+ startTime: null
180
+ },
181
+ update(startTime) {
182
+ const value = {
183
+ startTime
184
+ };
185
+ animationTimingStore.value = value;
186
+ for (const subscriber of animationTimingStore.subscribers) {
187
+ subscriber();
188
+ }
189
+ },
190
+ subscribe(subscriber) {
191
+ animationTimingStore.subscribers.add(subscriber);
192
+ return () => {
193
+ animationTimingStore.subscribers.delete(subscriber);
194
+ };
195
+ },
196
+ getSnapshot() {
197
+ return animationTimingStore.value;
198
+ },
199
+ getServerSnapshot() {
200
+ return animationTimingStore.value;
201
+ }
202
+ };
203
+
204
+ /**
205
+ * A utility hook for reading a common `startTime` value so that all animations
206
+ * are in sync. This is a global value and is coordinated through `useSyncExternalStore`.
207
+ */
208
+ function useAnimationTiming() {
209
+ return useSyncExternalStore(animationTimingStore.subscribe, animationTimingStore.getSnapshot, animationTimingStore.getServerSnapshot);
210
+ }
211
+
212
+ /**
213
+ * Uses a technique from Spectrum to coordinate animations:
214
+ * @see https://github.com/adobe/react-spectrum/blob/ab5e6f3dba4235dafab9f81f8b5c506ce5f11230/packages/%40react-spectrum/s2/src/Skeleton.tsx#L21
215
+ */
216
+ function useSpinnerAnimation() {
217
+ const $ = c(3);
218
+ const ref = useRef(null);
219
+ const noMotionPreference = useMedia("(prefers-reduced-motion: no-preference)", false);
220
+ const animationTiming = useAnimationTiming();
221
+ let t0;
222
+ if ($[0] !== animationTiming || $[1] !== noMotionPreference) {
223
+ t0 = element => {
224
+ if (!element) {
225
+ return;
226
+ }
227
+ if (ref.current !== null) {
228
+ return;
229
+ }
230
+ if (noMotionPreference) {
231
+ const cssAnimation = element.getAnimations().find(_temp);
232
+ cssAnimation === null || cssAnimation === void 0 ? void 0 : cssAnimation.pause();
233
+ ref.current = element.animate([{
234
+ transform: "rotate(0deg)"
235
+ }, {
236
+ transform: "rotate(360deg)"
237
+ }], {
238
+ duration: 1000,
239
+ easing: "cubic-bezier(0,0,1,1)",
240
+ iterations: Infinity
241
+ });
242
+ if (animationTiming.startTime === null) {
243
+ var _cssAnimation$startTi;
244
+ const startTime = (_cssAnimation$startTi = cssAnimation === null || cssAnimation === void 0 ? void 0 : cssAnimation.startTime) !== null && _cssAnimation$startTi !== void 0 ? _cssAnimation$startTi : 0;
245
+ animationTimingStore.update(startTime);
246
+ ref.current.startTime = startTime;
247
+ } else {
248
+ ref.current.startTime = animationTiming.startTime;
249
+ }
250
+ }
251
+ };
252
+ $[0] = animationTiming;
253
+ $[1] = noMotionPreference;
254
+ $[2] = t0;
255
+ } else {
256
+ t0 = $[2];
257
+ }
258
+ return t0;
259
+ }
260
+ function _temp(animation) {
261
+ if (animation instanceof CSSAnimation) {
262
+ return animation.animationName.startsWith("Spinner") && animation.animationName.endsWith("rotate-keyframes");
263
+ }
264
+ return false;
265
+ }
169
266
 
170
267
  export { Spinner as default };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@primer/react",
3
3
  "type": "module",
4
- "version": "38.6.0-rc.7ef904ff4",
4
+ "version": "38.6.0-rc.83fd63ead",
5
5
  "description": "An implementation of GitHub's Primer Design System using React",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",