@expofp/ui 3.34.2 → 3.35.1

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.
@@ -52,6 +52,15 @@ const Overlay = ({ children, open, size = 'medium', particles, className, onChan
52
52
  const overlayPanelRef = useRef(null);
53
53
  const scrollRef = useRef(null);
54
54
  const openedAtRef = useRef(undefined);
55
+ // The scroll container is published to descendants through context, and context is read during
56
+ // render — where a ref is still null on the render that mounts the element. Held as state as
57
+ // well, written from the ref callback: that write lands in the mount commit, so consumers see the
58
+ // element as soon as it exists rather than on whichever later render happens to come by.
59
+ const [scrollElement, setScrollElement] = useState(null);
60
+ const attachScroll = useCallback((node) => {
61
+ scrollRef.current = node;
62
+ setScrollElement(node);
63
+ }, []);
55
64
  // The snap point the sheet actually sits on. The prop may be undefined
56
65
  // before the host has chosen one, and a drag needs a value to start from.
57
66
  const [currentSnap, setCurrentSnap] = useState(size);
@@ -164,26 +173,35 @@ const Overlay = ({ children, open, size = 'medium', particles, className, onChan
164
173
  setShouldRender(true);
165
174
  setIsAnimating(true);
166
175
  openedAtRef.current = performance.now();
167
- const timer = setTimeout(() => {
168
- setSize(sizeRef.current);
169
- setIsAnimating(false);
170
- }, 10);
171
- return () => clearTimeout(timer);
176
+ return;
172
177
  }
173
- else {
174
- setIsAnimating(true);
175
- openedAtRef.current = undefined;
176
- if (mobile) {
177
- setCollapsed(true);
178
- }
179
- const timer = setTimeout(() => {
180
- setShouldRender(false);
181
- setIsAnimating(false);
182
- setIsScrolled(false);
183
- }, parseFloat(TRANSITION_DURATION) * 1000);
184
- return () => clearTimeout(timer);
178
+ setIsAnimating(true);
179
+ openedAtRef.current = undefined;
180
+ if (mobile) {
181
+ setCollapsed(true);
185
182
  }
186
- }, [open, setSize, mobile]);
183
+ const timer = setTimeout(() => {
184
+ setShouldRender(false);
185
+ setIsAnimating(false);
186
+ setIsScrolled(false);
187
+ }, parseFloat(TRANSITION_DURATION) * 1000);
188
+ return () => clearTimeout(timer);
189
+ }, [open, mobile]);
190
+ // The step after the mount: the sheet mounts at zero height and takes its size a tick later, so
191
+ // the height transition has a frame to start from. Keyed on `shouldRender` rather than run from
192
+ // the effect above, which fires on the render that only *asked* for the mount and returned null:
193
+ // a timer started there raced the mount render, and when it won, React batched the size flip
194
+ // into the mount itself — no transition, and no second render for anything the mount render
195
+ // could not yet know.
196
+ useEffect(() => {
197
+ if (!open || !shouldRender)
198
+ return;
199
+ const timer = setTimeout(() => {
200
+ setSize(sizeRef.current);
201
+ setIsAnimating(false);
202
+ }, 10);
203
+ return () => clearTimeout(timer);
204
+ }, [open, shouldRender, setSize]);
187
205
  // Host-driven size changes (details open at full, the planner at medium).
188
206
  // The sheet's own reports come back through here too, already applied.
189
207
  useEffect(() => {
@@ -198,7 +216,7 @@ const Overlay = ({ children, open, size = 'medium', particles, className, onChan
198
216
  }, [open, isAnimating, onScrollStateChange, scrollResetKey]);
199
217
  if (!shouldRender)
200
218
  return null;
201
- return (_jsx(OverlayScrollContext, { value: scrollRef.current, children: _jsxs("div", { className: cn('efp-overlay', {
219
+ return (_jsx(OverlayScrollContext, { value: scrollElement, children: _jsxs("div", { className: cn('efp-overlay', {
202
220
  'efp-overlay--draggable': dragging,
203
221
  'efp-overlay--keyboard': mobile && keyboardInset > 0,
204
222
  'efp-overlay--full': currentSnap === 'full',
@@ -207,7 +225,7 @@ const Overlay = ({ children, open, size = 'medium', particles, className, onChan
207
225
  'efp-overlay--hidden': !mobile && !open,
208
226
  'efp-overlay--scrolled': isScrolled,
209
227
  'efp-overlay--forced-full': forceFull && mobile,
210
- }, className), style: positioningStyles, ref: overlayPanelRef, onPointerDown: onPointerDown, children: [!disableDrag && _jsx("div", { className: "efp-overlay__draghandle", "data-sheet-handle": true }), _jsxs("div", { className: "efp-overlay__scroll", ref: scrollRef, onScroll: () => {
228
+ }, className), style: positioningStyles, ref: overlayPanelRef, onPointerDown: onPointerDown, children: [!disableDrag && _jsx("div", { className: "efp-overlay__draghandle", "data-sheet-handle": true }), _jsxs("div", { className: "efp-overlay__scroll", ref: attachScroll, onScroll: () => {
211
229
  handleScroll();
212
230
  debouncedScrollActivity();
213
231
  }, children: [particles, _jsx("div", { className: "efp-overlay__content", children: children ? children : noContentLabel })] })] }) }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expofp/ui",
3
- "version": "3.34.2",
3
+ "version": "3.35.1",
4
4
  "type": "module",
5
5
  "description": "ExpoFP SDK internal: shared pure React UI components",
6
6
  "homepage": "https://developer.expofp.com/",