@tamagui/popper 2.0.0-rc.8 → 2.0.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.
@@ -1,61 +1,65 @@
1
+ import { flushSync } from "react-dom";
1
2
  import { useComposedRefs } from "@tamagui/compose-refs";
2
3
  import { isWeb, useIsomorphicLayoutEffect } from "@tamagui/constants";
3
- import { LayoutMeasurementController, View as TamaguiView, createStyledContext, getVariableValue, styled, useProps } from "@tamagui/core";
4
- import { arrow, autoUpdate, flip, offset as offsetFn, platform, shift, size as sizeMiddleware, useFloating } from "@tamagui/floating";
4
+ import { LayoutMeasurementController, View as TamaguiView, createStyledContext, getVariableValue, registerLayoutNode, styled } from "@tamagui/core";
5
+ import { FloatingOverrideContext } from "@tamagui/floating";
6
+ import { arrow, flip, getOverflowAncestors, offset as offsetFn, platform, shift, size as sizeMiddleware, useFloating } from "@tamagui/floating";
5
7
  import { getSpace } from "@tamagui/get-token";
6
8
  import { YStack } from "@tamagui/stacks";
7
9
  import { startTransition } from "@tamagui/start-transition";
8
10
  import * as React from "react";
11
+ import { Keyboard, useWindowDimensions } from "react-native-web";
9
12
  import { jsx } from "react/jsx-runtime";
10
13
  const PopperContextFast = createStyledContext(
11
- // since we always provide this we can avoid setting here
12
- {}, "Popper__"),
13
- PopperPositionContext = createStyledContext,
14
- {
15
- useStyledContext: usePopperContext,
16
- Provider: PopperProviderFast
17
- } = PopperContextFast,
18
- PopperContextSlow = createStyledContext(
19
- // since we always provide this we can avoid setting here
20
- {}, "PopperSlow__"),
21
- {
22
- useStyledContext: usePopperContextSlow,
23
- Provider: PopperProviderSlow
24
- } = PopperContextSlow,
25
- PopperProvider = ({
14
+ // since we always provide this we can avoid setting here
15
+ {}, "Popper__");
16
+ const PopperPositionContext = createStyledContext;
17
+ const {
18
+ useStyledContext: usePopperContext,
19
+ Provider: PopperProviderFast
20
+ } = PopperContextFast;
21
+ const PopperContextSlow = createStyledContext(
22
+ // since we always provide this we can avoid setting here
23
+ {}, "PopperSlow__");
24
+ const {
25
+ useStyledContext: usePopperContextSlow,
26
+ Provider: PopperProviderSlow
27
+ } = PopperContextSlow;
28
+ const PopperProvider = ({
29
+ scope,
30
+ children,
31
+ ...context
32
+ }) => {
33
+ const fns = React.useRef(context);
34
+ fns.current = context;
35
+ const [slowContext] = React.useState(() => ({
36
+ refs: context.refs,
37
+ triggerElements: context.triggerElements,
38
+ update(...a) {
39
+ fns.current.update(...a);
40
+ },
41
+ getReferenceProps(p) {
42
+ return fns.current.getReferenceProps?.(p);
43
+ },
44
+ onHoverReference(e) {
45
+ fns.current.onHoverReference?.(e);
46
+ },
47
+ onLeaveReference() {
48
+ fns.current.onLeaveReference?.();
49
+ }
50
+ }));
51
+ return /* @__PURE__ */jsx(PopperProviderFast, {
26
52
  scope,
27
- children,
28
- ...context
29
- }) => {
30
- const slowContext = getContextSlow(context);
31
- return /* @__PURE__ */jsx(PopperProviderFast, {
53
+ ...context,
54
+ children: /* @__PURE__ */jsx(PopperProviderSlow, {
32
55
  scope,
33
- ...context,
34
- children: /* @__PURE__ */jsx(PopperProviderSlow, {
35
- scope,
36
- ...slowContext,
37
- children
38
- })
39
- });
40
- };
41
- function getContextSlow(context) {
42
- return {
43
- refs: context.refs,
44
- size: context.size,
45
- arrowRef: context.arrowRef,
46
- arrowStyle: context.arrowStyle,
47
- onArrowSize: context.onArrowSize,
48
- hasFloating: context.hasFloating,
49
- strategy: context.strategy,
50
- update: context.update,
51
- context: context.context,
52
- getFloatingProps: context.getFloatingProps,
53
- getReferenceProps: context.getReferenceProps,
54
- open: context.open
55
- };
56
- }
57
- const checkFloating = void 0,
58
- setupOptions = {};
56
+ ...slowContext,
57
+ children
58
+ })
59
+ });
60
+ };
61
+ const checkFloating = void 0;
62
+ const setupOptions = {};
59
63
  function setupPopper(options) {
60
64
  Object.assign(setupOptions, options);
61
65
  }
@@ -68,24 +72,37 @@ const transformOriginMiddleware = options => ({
68
72
  options,
69
73
  fn(data) {
70
74
  const {
71
- placement,
72
- rects,
73
- middlewareData
74
- } = data,
75
- isArrowHidden = middlewareData.arrow?.centerOffset !== 0,
76
- arrowWidth = isArrowHidden ? 0 : options.arrowWidth,
77
- arrowHeight = isArrowHidden ? 0 : options.arrowHeight,
78
- [placedSide, placedAlign] = getSideAndAlignFromPlacement(placement),
79
- noArrowAlign = {
80
- start: "0%",
81
- center: "50%",
82
- end: "100%"
83
- }[placedAlign],
84
- arrowXCenter = (middlewareData.arrow?.x ?? 0) + arrowWidth / 2,
85
- arrowYCenter = (middlewareData.arrow?.y ?? 0) + arrowHeight / 2;
86
- let x = "",
87
- y = "";
88
- return placedSide === "bottom" ? (x = isArrowHidden ? noArrowAlign : `${arrowXCenter}px`, y = `${-arrowHeight}px`) : placedSide === "top" ? (x = isArrowHidden ? noArrowAlign : `${arrowXCenter}px`, y = `${rects.floating.height + arrowHeight}px`) : placedSide === "right" ? (x = `${-arrowHeight}px`, y = isArrowHidden ? noArrowAlign : `${arrowYCenter}px`) : placedSide === "left" && (x = `${rects.floating.width + arrowHeight}px`, y = isArrowHidden ? noArrowAlign : `${arrowYCenter}px`), {
75
+ placement,
76
+ rects,
77
+ middlewareData
78
+ } = data;
79
+ const isArrowHidden = middlewareData.arrow?.centerOffset !== 0;
80
+ const arrowWidth = isArrowHidden ? 0 : options.arrowWidth;
81
+ const arrowHeight = isArrowHidden ? 0 : options.arrowHeight;
82
+ const [placedSide, placedAlign] = getSideAndAlignFromPlacement(placement);
83
+ const noArrowAlign = {
84
+ start: "0%",
85
+ center: "50%",
86
+ end: "100%"
87
+ }[placedAlign];
88
+ const arrowXCenter = (middlewareData.arrow?.x ?? 0) + arrowWidth / 2;
89
+ const arrowYCenter = (middlewareData.arrow?.y ?? 0) + arrowHeight / 2;
90
+ let x = "";
91
+ let y = "";
92
+ if (placedSide === "bottom") {
93
+ x = isArrowHidden ? noArrowAlign : `${arrowXCenter}px`;
94
+ y = `${-arrowHeight}px`;
95
+ } else if (placedSide === "top") {
96
+ x = isArrowHidden ? noArrowAlign : `${arrowXCenter}px`;
97
+ y = `${rects.floating.height + arrowHeight}px`;
98
+ } else if (placedSide === "right") {
99
+ x = `${-arrowHeight}px`;
100
+ y = isArrowHidden ? noArrowAlign : `${arrowYCenter}px`;
101
+ } else if (placedSide === "left") {
102
+ x = `${rects.floating.width + arrowHeight}px`;
103
+ y = isArrowHidden ? noArrowAlign : `${arrowYCenter}px`;
104
+ }
105
+ return {
89
106
  data: {
90
107
  x,
91
108
  y
@@ -93,258 +110,331 @@ const transformOriginMiddleware = options => ({
93
110
  };
94
111
  }
95
112
  });
113
+ function tamaguiAutoUpdate(reference, floating, update) {
114
+ update();
115
+ let rafId = requestAnimationFrame(() => {
116
+ update();
117
+ rafId = 0;
118
+ });
119
+ const cleanups = [() => {
120
+ if (rafId) cancelAnimationFrame(rafId);
121
+ }];
122
+ if (reference instanceof HTMLElement) cleanups.push(registerLayoutNode(reference, update));
123
+ const ancestors = [...(reference instanceof Element ? getOverflowAncestors(reference) : []), ...getOverflowAncestors(floating)];
124
+ const uniqueAncestors = [...new Set(ancestors)];
125
+ for (const ancestor of uniqueAncestors) ancestor.addEventListener("scroll", update, {
126
+ passive: true
127
+ });
128
+ window.addEventListener("resize", update);
129
+ cleanups.push(() => {
130
+ for (const ancestor of uniqueAncestors) ancestor.removeEventListener("scroll", update);
131
+ window.removeEventListener("resize", update);
132
+ });
133
+ return () => cleanups.forEach(fn => fn());
134
+ }
96
135
  function Popper(props) {
97
136
  const {
98
- children,
99
- size,
100
- strategy = "absolute",
101
- placement = "bottom",
102
- stayInFrame,
103
- allowFlip,
104
- offset,
105
- disableRTL,
106
- resize,
107
- passThrough,
108
- open,
109
- scope
110
- } = props,
111
- [arrowEl, setArrow] = React.useState(null),
112
- [arrowSize, setArrowSize] = React.useState(0),
113
- offsetOptions = offset ?? arrowSize,
114
- floatingStyle = React.useRef({}),
115
- isOpen = passThrough ? !1 : open || !0;
137
+ children,
138
+ size,
139
+ strategy = "absolute",
140
+ placement = "bottom",
141
+ stayInFrame,
142
+ allowFlip,
143
+ offset,
144
+ disableRTL,
145
+ resize,
146
+ passThrough,
147
+ open,
148
+ scope
149
+ } = props;
150
+ const [arrowEl, setArrow] = React.useState(null);
151
+ const [arrowSize, setArrowSize] = React.useState(0);
152
+ const offsetOptions = offset ?? arrowSize;
153
+ const floatingStyle = React.useRef({});
154
+ const isOpen = passThrough ? false : open ?? true;
155
+ const middlewareRef = React.useRef([]);
156
+ if (isOpen) middlewareRef.current = [typeof offsetOptions !== "undefined" ? offsetFn(offsetOptions) : null, allowFlip ? flip(typeof allowFlip === "boolean" ? {} : allowFlip) : null, stayInFrame ? shift({
157
+ padding: 10,
158
+ mainAxis: true,
159
+ crossAxis: false,
160
+ ...(typeof stayInFrame === "object" ? stayInFrame : null)
161
+ }) : null, arrowEl ? arrow({
162
+ element: arrowEl
163
+ }) : null, checkFloating, resize ? sizeMiddleware({
164
+ padding: typeof stayInFrame === "object" ? stayInFrame.padding : 10,
165
+ apply({
166
+ availableHeight,
167
+ availableWidth
168
+ }) {
169
+ if (passThrough) return;
170
+ Object.assign(floatingStyle.current, {
171
+ maxHeight: `${availableHeight}px`,
172
+ maxWidth: `${availableWidth}px`
173
+ });
174
+ const floatingChild = floating.refs.floating.current?.firstChild;
175
+ if (floatingChild && floatingChild instanceof HTMLElement) Object.assign(floatingChild.style, floatingStyle.current);
176
+ },
177
+ ...(typeof resize === "object" && resize)
178
+ }) : null, sizeMiddleware({
179
+ apply({
180
+ elements,
181
+ rects,
182
+ availableWidth,
183
+ availableHeight
184
+ }) {
185
+ const {
186
+ width: anchorWidth,
187
+ height: anchorHeight
188
+ } = rects.reference;
189
+ const contentStyle = elements.floating.style;
190
+ contentStyle.setProperty("--tamagui-popper-available-width", `${availableWidth}px`);
191
+ contentStyle.setProperty("--tamagui-popper-available-height", `${availableHeight}px`);
192
+ contentStyle.setProperty("--tamagui-popper-anchor-width", `${anchorWidth}px`);
193
+ contentStyle.setProperty("--tamagui-popper-anchor-height", `${anchorHeight}px`);
194
+ }
195
+ }), transformOriginMiddleware({
196
+ arrowHeight: arrowSize,
197
+ arrowWidth: arrowSize
198
+ })].filter(Boolean);
116
199
  let floating = useFloating({
117
200
  open: isOpen,
118
201
  strategy,
119
202
  placement,
120
- sameScrollView: !1,
121
- // this only takes effect on native
122
- whileElementsMounted: isOpen ? autoUpdate : void 0,
203
+ sameScrollView: false,
204
+ whileElementsMounted: !isOpen ? void 0 : tamaguiAutoUpdate,
123
205
  platform: disableRTL ?? setupOptions.disableRTL ? {
124
206
  ...platform,
125
207
  isRTL(element) {
126
- return !1;
208
+ return false;
127
209
  }
128
210
  } : platform,
129
- middleware: [stayInFrame ? shift(typeof stayInFrame == "boolean" ? {} : stayInFrame) : null, allowFlip ? flip(typeof allowFlip == "boolean" ? {} : allowFlip) : null, arrowEl ? arrow({
130
- element: arrowEl
131
- }) : null, typeof offsetOptions < "u" ? offsetFn(offsetOptions) : null, checkFloating, resize ? sizeMiddleware({
132
- apply({
133
- availableHeight,
134
- availableWidth
135
- }) {
136
- if (passThrough) return;
137
- Object.assign(floatingStyle.current, {
138
- maxHeight: `${availableHeight}px`,
139
- maxWidth: `${availableWidth}px`
140
- });
141
- const floatingChild = floating.refs.floating.current?.firstChild;
142
- floatingChild && floatingChild instanceof HTMLElement && Object.assign(floatingChild.style, floatingStyle.current);
143
- },
144
- ...(typeof resize == "object" && resize)
145
- }) : null, sizeMiddleware({
146
- apply({
147
- elements,
148
- rects,
149
- availableWidth,
150
- availableHeight
151
- }) {
152
- const {
153
- width: anchorWidth,
154
- height: anchorHeight
155
- } = rects.reference,
156
- contentStyle = elements.floating.style;
157
- contentStyle.setProperty("--tamagui-popper-available-width", `${availableWidth}px`), contentStyle.setProperty("--tamagui-popper-available-height", `${availableHeight}px`), contentStyle.setProperty("--tamagui-popper-anchor-width", `${anchorWidth}px`), contentStyle.setProperty("--tamagui-popper-anchor-height", `${anchorHeight}px`);
158
- }
159
- }), transformOriginMiddleware({
160
- arrowHeight: arrowSize,
161
- arrowWidth: arrowSize
162
- })].filter(Boolean)
211
+ middleware: middlewareRef.current
163
212
  });
164
213
  floating = React.useMemo(() => {
165
214
  const og = floating.getFloatingProps;
166
- return resize && og && (floating.getFloatingProps = props2 => og({
167
- ...props2,
168
- style: {
169
- ...props2.style,
170
- ...floatingStyle.current
171
- }
172
- })), floating;
215
+ if (resize && og) floating.getFloatingProps = props2 => {
216
+ return og({
217
+ ...props2,
218
+ style: {
219
+ ...props2.style,
220
+ ...floatingStyle.current
221
+ }
222
+ });
223
+ };
224
+ return floating;
173
225
  }, [floating, resize ? JSON.stringify(resize) : null]);
174
226
  const {
175
- middlewareData
176
- } = floating,
177
- popperContext = React.useMemo(() => ({
178
- size,
179
- arrowRef: setArrow,
180
- arrowStyle: middlewareData.arrow,
181
- onArrowSize: setArrowSize,
182
- hasFloating: middlewareData.checkFloating?.hasFloating,
183
- transformOrigin: middlewareData.transformOrigin,
184
- open: !!open,
185
- ...floating
186
- }), [open, size, floating.x, floating.y, floating.placement, JSON.stringify(middlewareData.arrow || null), JSON.stringify(middlewareData.transformOrigin || null), floating.isPositioned]);
187
- return /* @__PURE__ */jsx(LayoutMeasurementController, {
188
- disable: !isOpen,
189
- children: /* @__PURE__ */jsx(PopperProvider, {
190
- scope,
191
- ...popperContext,
227
+ middlewareData
228
+ } = floating;
229
+ return /* @__PURE__ */jsx(PopperProvider, {
230
+ scope,
231
+ ...React.useMemo(() => {
232
+ return {
233
+ size,
234
+ arrowRef: setArrow,
235
+ arrowStyle: middlewareData.arrow,
236
+ onArrowSize: setArrowSize,
237
+ hasFloating: middlewareData.checkFloating?.hasFloating,
238
+ transformOrigin: middlewareData.transformOrigin,
239
+ open: !!open,
240
+ ...floating
241
+ };
242
+ }, [open, size, floating, JSON.stringify(middlewareData.arrow || null), JSON.stringify(middlewareData.transformOrigin || null)]),
243
+ children: /* @__PURE__ */jsx(FloatingOverrideContext.Provider, {
244
+ value: null,
192
245
  children
193
246
  })
194
247
  });
195
248
  }
196
- const PopperAnchor = YStack.styleable(function (props, forwardedRef) {
197
- const {
198
- virtualRef,
199
- scope,
200
- ...rest
201
- } = props,
202
- context = usePopperContextSlow(scope),
203
- {
204
- getReferenceProps,
205
- refs,
206
- update
207
- } = context,
208
- ref = React.useRef(null);
209
- React.useEffect(() => {
210
- virtualRef && refs.setReference(virtualRef.current);
211
- }, [virtualRef]);
212
- const refProps = getReferenceProps?.({
213
- ...rest,
214
- ref
215
- }) || null,
216
- safeSetReference = React.useCallback(node => {
217
- startTransition(() => {
218
- refs.setReference(node);
219
- });
220
- }, [refs.setReference]),
221
- shouldHandleInHover = isWeb && scope,
222
- composedRefs = useComposedRefs(forwardedRef, ref,
223
- // web handles this onMouseEnter below so it can support multiple targets + hovering
224
- shouldHandleInHover ? void 0 : safeSetReference);
225
- return /* @__PURE__ */jsx(TamaguiView, {
226
- ...rest,
227
- ...refProps,
228
- ref: composedRefs,
229
- ...(shouldHandleInHover && {
230
- // this helps us with handling scoped poppers with many different targets
231
- // basically we wait for mouseEnter to ever set a reference and remove it on leave
232
- // otherwise floating ui gets confused by having >1 reference
233
- onMouseEnter: e => {
234
- if (ref.current instanceof HTMLElement) {
235
- if (refs.setReference(ref.current), !refProps) return;
236
- refProps.onPointerEnter?.(e), update();
237
- }
238
- },
239
- onMouseLeave: e => {
240
- refProps?.onMouseLeave?.(e);
241
- }
242
- })
249
+ const PopperAnchor = YStack.styleable(function PopperAnchor2(props, forwardedRef) {
250
+ const {
251
+ virtualRef,
252
+ scope,
253
+ ...rest
254
+ } = props;
255
+ const context = usePopperContextSlow(scope);
256
+ const {
257
+ getReferenceProps,
258
+ refs,
259
+ update
260
+ } = context;
261
+ const ref = React.useRef(null);
262
+ const triggerId = React.useId();
263
+ React.useEffect(() => {
264
+ if (!scope || !context.triggerElements || !ref.current) return;
265
+ if (!(ref.current instanceof Element)) return;
266
+ const el = ref.current;
267
+ context.triggerElements.add(triggerId, el);
268
+ return () => {
269
+ context.triggerElements?.delete(triggerId);
270
+ };
271
+ }, [scope, triggerId, context.triggerElements]);
272
+ React.useEffect(() => {
273
+ if (virtualRef) {
274
+ refs.setReference(virtualRef.current);
275
+ update();
276
+ }
277
+ }, [virtualRef]);
278
+ const refProps = getReferenceProps?.({
279
+ ...rest,
280
+ ref
281
+ }) || null;
282
+ const safeSetReference = React.useCallback(node => {
283
+ startTransition(() => {
284
+ refs.setReference(node);
243
285
  });
244
- }),
245
- PopperContentFrame = styled(YStack, {
246
- name: "PopperContent",
247
- variants: {
248
- unstyled: {
249
- false: {
250
- size: "$true",
251
- backgroundColor: "$background",
252
- alignItems: "center"
286
+ },
287
+ // it was refs.setRefernce but its stable and refs is undefined on server
288
+ [refs]);
289
+ const shouldHandleInHover = isWeb && scope;
290
+ const composedRefs = useComposedRefs(forwardedRef, ref,
291
+ // web handles this onMouseEnter below so it can support multiple targets + hovering
292
+ shouldHandleInHover ? void 0 : safeSetReference);
293
+ return /* @__PURE__ */jsx(TamaguiView, {
294
+ ...rest,
295
+ ...refProps,
296
+ ref: composedRefs,
297
+ ...(shouldHandleInHover && {
298
+ onMouseEnter: e => {
299
+ const el = e.currentTarget ?? ref.current;
300
+ if (el instanceof HTMLElement) {
301
+ flushSync(() => refs.setReference(el));
302
+ update();
303
+ if (!refProps) return;
304
+ refProps.onPointerEnter?.(e);
305
+ context.onHoverReference?.(e.nativeEvent);
253
306
  }
254
307
  },
255
- size: {
256
- "...size": (val, {
257
- tokens
258
- }) => ({
308
+ onMouseLeave: e => {
309
+ context.onLeaveReference?.();
310
+ refProps?.onMouseLeave?.(e);
311
+ }
312
+ })
313
+ });
314
+ });
315
+ const PopperContentFrame = styled(YStack, {
316
+ name: "PopperContent",
317
+ variants: {
318
+ unstyled: {
319
+ true: {}
320
+ },
321
+ size: {
322
+ "...size": (val, {
323
+ tokens
324
+ }) => {
325
+ return {
259
326
  padding: tokens.space[val],
260
327
  borderRadius: tokens.radius[val]
261
- })
328
+ };
262
329
  }
263
- },
264
- defaultVariants: {
265
- unstyled: process.env.TAMAGUI_HEADLESS === "1"
266
330
  }
267
- }),
268
- PopperContent = React.forwardRef(function (props, forwardedRef) {
269
- const {
270
- scope,
271
- animatePosition,
272
- enableAnimationForPositionChange,
273
- children,
274
- passThrough,
275
- ...rest
276
- } = props,
277
- animatePos = animatePosition ?? enableAnimationForPositionChange,
278
- context = usePopperContext(scope),
279
- {
280
- strategy,
281
- placement,
282
- refs,
283
- x,
284
- y,
285
- getFloatingProps,
286
- size,
287
- isPositioned,
288
- transformOrigin
289
- } = context,
290
- safeSetFloating = React.useCallback(node => {
291
- startTransition(() => {
292
- refs.setFloating(node);
293
- });
294
- }, [refs.setFloating]),
295
- contentRefs = useComposedRefs(safeSetFloating, forwardedRef),
296
- [needsMeasure, setNeedsMeasure] = React.useState(animatePos);
297
- useIsomorphicLayoutEffect(() => {
298
- needsMeasure && x && y && setNeedsMeasure(!1);
299
- }, [needsMeasure, animatePos, x, y]);
300
- const hide = x === 0 && y === 0,
301
- disableAnimationProp =
302
- // if they want to animate also when re-positioning allow it
303
- animatePos === "even-when-repositioning" ? needsMeasure : !isPositioned || needsMeasure,
304
- [disableAnimation, setDisableAnimation] = React.useState(disableAnimationProp);
305
- React.useEffect(() => {
306
- setDisableAnimation(disableAnimationProp);
307
- }, [disableAnimationProp]);
308
- const frameProps = {
309
- ref: contentRefs,
310
- ...(hide ? {} : {
311
- x: x || 0,
312
- y: y || 0
313
- }),
314
- top: 0,
315
- left: 0,
316
- position: strategy,
317
- opacity: 1,
318
- ...(animatePos && {
319
- transition: rest.transition,
320
- animateOnly: disableAnimation ? [] : rest.animateOnly,
321
- // apply animation but disable it on initial render to avoid animating from 0 to the first position
322
- animatePresence: !1
323
- }),
324
- ...(hide && {
325
- opacity: 0,
326
- animateOnly: []
327
- })
328
- },
329
- {
330
- style,
331
- ...floatingProps
332
- } = getFloatingProps ? getFloatingProps(frameProps) : frameProps,
333
- transformOriginStyle = isWeb && transformOrigin ? {
334
- transformOrigin: `${transformOrigin.x} ${transformOrigin.y}`
335
- } : void 0;
336
- return /* @__PURE__ */jsx(TamaguiView, {
331
+ }
332
+ });
333
+ const PopperContent = React.forwardRef(function PopperContent2(props, forwardedRef) {
334
+ const isAnimatePosControlled = "animatePosition" in props || "enableAnimationForPositionChange" in props;
335
+ const {
336
+ scope,
337
+ animatePosition,
338
+ enableAnimationForPositionChange,
339
+ children,
340
+ passThrough,
341
+ unstyled,
342
+ ...rest
343
+ } = props;
344
+ const animatePos = animatePosition ?? enableAnimationForPositionChange;
345
+ const context = usePopperContext(scope);
346
+ const {
347
+ strategy,
348
+ placement,
349
+ refs,
350
+ x,
351
+ y,
352
+ getFloatingProps,
353
+ size,
354
+ isPositioned,
355
+ transformOrigin,
356
+ update
357
+ } = context;
358
+ const updateRef = React.useRef(update);
359
+ updateRef.current = update;
360
+ const lastNodeRef = React.useRef(null);
361
+ const safeSetFloating = React.useCallback(node => {
362
+ const isNewNode = node !== lastNodeRef.current;
363
+ if (node) {
364
+ lastNodeRef.current = node;
365
+ refs.setFloating(node);
366
+ if (!isNewNode) updateRef.current?.();
367
+ }
368
+ }, [refs.setFloating]);
369
+ React.useEffect(() => {
370
+ return () => {
371
+ const ourNode = lastNodeRef.current;
372
+ if (ourNode && refs.floating.current === ourNode) refs.setFloating(null);
373
+ lastNodeRef.current = null;
374
+ };
375
+ }, []);
376
+ const contentRefs = useComposedRefs(safeSetFloating, forwardedRef);
377
+ const [needsMeasure, setNeedsMeasure] = React.useState(animatePos);
378
+ useIsomorphicLayoutEffect(() => {
379
+ if (needsMeasure && x && y) setNeedsMeasure(false);
380
+ }, [needsMeasure, animatePos, x, y]);
381
+ const hasBeenPositioned = React.useRef(false);
382
+ const lastGoodPosition = React.useRef({
383
+ x: 0,
384
+ y: 0
385
+ });
386
+ if (x !== 0 || y !== 0) {
387
+ lastGoodPosition.current = {
388
+ x,
389
+ y
390
+ };
391
+ if (isPositioned) hasBeenPositioned.current = true;
392
+ }
393
+ const brieflyZero = hasBeenPositioned.current && x === 0 && y === 0;
394
+ const effectiveX = brieflyZero ? lastGoodPosition.current.x : x;
395
+ const effectiveY = brieflyZero ? lastGoodPosition.current.y : y;
396
+ const hide = !hasBeenPositioned.current && effectiveX === 0 && effectiveY === 0;
397
+ const disableAnimationProp = animatePos === "even-when-repositioning" ? needsMeasure : !hasBeenPositioned.current && !isPositioned || needsMeasure;
398
+ const [disableAnimation, setDisableAnimation] = React.useState(disableAnimationProp);
399
+ React.useEffect(() => {
400
+ setDisableAnimation(disableAnimationProp);
401
+ }, [disableAnimationProp]);
402
+ const frameProps = {
403
+ ref: contentRefs,
404
+ ...(hide ? {} : {
405
+ x: effectiveX || 0,
406
+ y: effectiveY || 0
407
+ }),
408
+ top: 0,
409
+ left: 0,
410
+ position: strategy,
411
+ opacity: hide ? 0 : 1,
412
+ ...(isAnimatePosControlled && {
413
+ transition: animatePos ? rest.transition : void 0,
414
+ animateOnly: animatePos && !disableAnimation ? rest.animateOnly : [],
415
+ animatePresence: false
416
+ })
417
+ };
418
+ const {
419
+ style,
420
+ ...floatingProps
421
+ } = getFloatingProps ? getFloatingProps(frameProps) : frameProps;
422
+ const transformOriginStyle = isWeb && transformOrigin ? {
423
+ transformOrigin: `${transformOrigin.x} ${transformOrigin.y}`
424
+ } : void 0;
425
+ return /* @__PURE__ */jsx(LayoutMeasurementController, {
426
+ disable: !context.open,
427
+ children: /* @__PURE__ */jsx(TamaguiView, {
337
428
  passThrough,
338
429
  ref: contentRefs,
339
- contain: "layout style",
430
+ direction: rest.direction,
340
431
  ...(passThrough ? null : floatingProps),
341
432
  ...(!passThrough && animatePos && {
342
- // marker for animation driver to know this is a popper element
343
- // that needs special handling for position animation interruption
344
433
  "data-popper-animate-position": "true"
345
434
  }),
346
435
  children: /* @__PURE__ */jsx(PopperContentFrame, {
347
436
  passThrough,
437
+ unstyled,
348
438
  ...(!passThrough && {
349
439
  "data-placement": placement,
350
440
  "data-strategy": strategy,
@@ -355,121 +445,132 @@ const PopperAnchor = YStack.styleable(function (props, forwardedRef) {
355
445
  }),
356
446
  children
357
447
  }, "popper-content-frame")
358
- });
359
- }),
360
- PopperArrowFrame = styled(YStack, {
361
- name: "PopperArrow",
362
- variants: {
363
- unstyled: {
364
- false: {
365
- borderColor: "$borderColor",
366
- backgroundColor: "$background",
367
- position: "relative"
368
- }
448
+ })
449
+ });
450
+ });
451
+ const PopperArrowFrame = styled(YStack, {
452
+ name: "PopperArrow",
453
+ variants: {
454
+ unstyled: {
455
+ false: {
456
+ borderColor: "$borderColor",
457
+ backgroundColor: "$background",
458
+ position: "relative"
369
459
  }
370
- },
371
- defaultVariants: {
372
- unstyled: process.env.TAMAGUI_HEADLESS === "1"
373
460
  }
374
- }),
375
- PopperArrowOuterFrame = styled(YStack, {
376
- name: "PopperArrowOuter",
377
- variants: {
378
- unstyled: {
379
- false: {
380
- position: "absolute",
381
- zIndex: 1e6,
382
- pointerEvents: "none",
383
- overflow: "hidden",
384
- alignItems: "center",
385
- justifyContent: "center"
386
- }
461
+ },
462
+ defaultVariants: {
463
+ unstyled: process.env.TAMAGUI_HEADLESS === "1"
464
+ }
465
+ });
466
+ const PopperArrowOuterFrame = styled(YStack, {
467
+ name: "PopperArrowOuter",
468
+ variants: {
469
+ unstyled: {
470
+ false: {
471
+ position: "absolute",
472
+ zIndex: 1e6,
473
+ pointerEvents: "none",
474
+ overflow: "hidden",
475
+ alignItems: "center",
476
+ justifyContent: "center"
387
477
  }
388
- },
389
- defaultVariants: {
390
- unstyled: process.env.TAMAGUI_HEADLESS === "1"
391
478
  }
392
- }),
393
- opposites = {
394
- top: "bottom",
395
- right: "left",
396
- bottom: "top",
397
- left: "right"
398
479
  },
399
- PopperArrow = React.forwardRef(function (propsIn, forwardedRef) {
400
- const {
401
- scope,
402
- animatePosition,
403
- transition,
404
- ...rest
405
- } = propsIn,
406
- props = useProps(rest),
407
- {
408
- offset,
409
- size: sizeProp,
410
- borderWidth = 0,
411
- ...arrowProps
412
- } = props,
413
- context = usePopperContext(scope),
414
- sizeVal = typeof sizeProp == "number" ? sizeProp : getVariableValue(getSpace(sizeProp ?? context.size, {
415
- shift: -2,
416
- bounds: [2]
417
- })),
418
- size = Math.max(0, +sizeVal),
419
- {
420
- placement
421
- } = context,
422
- refs = useComposedRefs(context.arrowRef, forwardedRef),
423
- x = context.arrowStyle?.x || 0,
424
- y = context.arrowStyle?.y || 0,
425
- primaryPlacement = placement ? placement.split("-")[0] : "top",
426
- arrowStyle = {
427
- x,
428
- y,
429
- width: size,
430
- height: size
431
- },
432
- innerArrowStyle = {},
433
- isVertical = primaryPlacement === "bottom" || primaryPlacement === "top";
434
- if (primaryPlacement) {
435
- arrowStyle[isVertical ? "width" : "height"] = size * 2;
436
- const oppSide = opposites[primaryPlacement];
437
- oppSide && (arrowStyle[oppSide] = -size, innerArrowStyle[oppSide] = size / 2), (oppSide === "top" || oppSide === "bottom") && (arrowStyle.left = 0), (oppSide === "left" || oppSide === "right") && (arrowStyle.top = 0), useIsomorphicLayoutEffect(() => {
438
- context.onArrowSize?.(size);
439
- }, [size, context.onArrowSize]);
480
+ defaultVariants: {
481
+ unstyled: process.env.TAMAGUI_HEADLESS === "1"
482
+ }
483
+ });
484
+ const opposites = {
485
+ top: "bottom",
486
+ right: "left",
487
+ bottom: "top",
488
+ left: "right"
489
+ };
490
+ const PopperArrow = React.forwardRef(function PopperArrow2(propsIn, forwardedRef) {
491
+ const isAnimatePosControlled = "animatePosition" in propsIn;
492
+ const {
493
+ scope,
494
+ animatePosition,
495
+ transition,
496
+ ...rest
497
+ } = propsIn;
498
+ const {
499
+ offset,
500
+ size: sizeProp,
501
+ borderWidth = 0,
502
+ ...arrowProps
503
+ } = rest;
504
+ const context = usePopperContext(scope);
505
+ const sizeVal = typeof sizeProp === "number" ? sizeProp : getVariableValue(getSpace(sizeProp ?? context.size, {
506
+ shift: -2,
507
+ bounds: [2]
508
+ }));
509
+ const size = Math.max(0, +sizeVal);
510
+ const {
511
+ placement
512
+ } = context;
513
+ const refs = useComposedRefs(context.arrowRef, forwardedRef);
514
+ const x = context.arrowStyle?.x || 0;
515
+ const y = context.arrowStyle?.y || 0;
516
+ const arrowPositioned = context.arrowStyle != null;
517
+ const primaryPlacement = placement ? placement.split("-")[0] : "top";
518
+ const arrowStyle = {
519
+ x,
520
+ y,
521
+ width: size,
522
+ height: size
523
+ };
524
+ const innerArrowStyle = {};
525
+ const isVertical = primaryPlacement === "bottom" || primaryPlacement === "top";
526
+ if (primaryPlacement) {
527
+ arrowStyle[isVertical ? "width" : "height"] = size * 2;
528
+ const oppSide = opposites[primaryPlacement];
529
+ if (oppSide) {
530
+ arrowStyle[oppSide] = -size;
531
+ innerArrowStyle[oppSide] = size / 2;
440
532
  }
441
- return /* @__PURE__ */jsx(PopperArrowOuterFrame, {
442
- ref: refs,
443
- ...arrowStyle,
444
- ...(animatePosition && {
445
- transition,
446
- animateOnly: ["transform"],
447
- animatePresence: !1
533
+ if (oppSide === "top" || oppSide === "bottom") arrowStyle.left = 0;
534
+ if (oppSide === "left" || oppSide === "right") arrowStyle.top = 0;
535
+ useIsomorphicLayoutEffect(() => {
536
+ context.onArrowSize?.(size);
537
+ }, [size, context.onArrowSize]);
538
+ }
539
+ return /* @__PURE__ */jsx(PopperArrowOuterFrame, {
540
+ ref: refs,
541
+ ...arrowStyle,
542
+ ...(!arrowPositioned && {
543
+ opacity: 0
544
+ }),
545
+ ...(isAnimatePosControlled && {
546
+ transition: animatePosition ? transition : void 0,
547
+ animateOnly: animatePosition ? ["transform"] : [],
548
+ animatePresence: false
549
+ }),
550
+ children: /* @__PURE__ */jsx(PopperArrowFrame, {
551
+ width: size,
552
+ height: size,
553
+ ...arrowProps,
554
+ ...innerArrowStyle,
555
+ rotate: "45deg",
556
+ ...(primaryPlacement === "bottom" && {
557
+ borderLeftWidth: borderWidth,
558
+ borderTopWidth: borderWidth
448
559
  }),
449
- children: /* @__PURE__ */jsx(PopperArrowFrame, {
450
- width: size,
451
- height: size,
452
- ...arrowProps,
453
- ...innerArrowStyle,
454
- rotate: "45deg",
455
- ...(primaryPlacement === "bottom" && {
456
- borderLeftWidth: borderWidth,
457
- borderTopWidth: borderWidth
458
- }),
459
- ...(primaryPlacement === "top" && {
460
- borderBottomWidth: borderWidth,
461
- borderRightWidth: borderWidth
462
- }),
463
- ...(primaryPlacement === "right" && {
464
- borderLeftWidth: borderWidth,
465
- borderBottomWidth: borderWidth
466
- }),
467
- ...(primaryPlacement === "left" && {
468
- borderTopWidth: borderWidth,
469
- borderRightWidth: borderWidth
470
- })
560
+ ...(primaryPlacement === "top" && {
561
+ borderBottomWidth: borderWidth,
562
+ borderRightWidth: borderWidth
563
+ }),
564
+ ...(primaryPlacement === "right" && {
565
+ borderLeftWidth: borderWidth,
566
+ borderBottomWidth: borderWidth
567
+ }),
568
+ ...(primaryPlacement === "left" && {
569
+ borderTopWidth: borderWidth,
570
+ borderRightWidth: borderWidth
471
571
  })
472
- });
572
+ })
473
573
  });
574
+ });
474
575
  export { Popper, PopperAnchor, PopperArrow, PopperArrowFrame, PopperContent, PopperContentFrame, PopperContextFast, PopperContextSlow, PopperPositionContext, PopperProvider, PopperProviderFast, PopperProviderSlow, setupPopper, usePopperContext, usePopperContextSlow };
475
576
  //# sourceMappingURL=Popper.mjs.map