@tamagui/select 1.0.1-beta.113 → 1.0.1-beta.114

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 (109) hide show
  1. package/dist/cjs/Select.js +50 -558
  2. package/dist/cjs/Select.js.map +2 -2
  3. package/dist/cjs/SelectContent.js +53 -0
  4. package/dist/cjs/SelectContent.js.map +7 -0
  5. package/dist/cjs/SelectContent.native.js +31 -0
  6. package/dist/cjs/SelectContent.native.js.map +7 -0
  7. package/dist/cjs/SelectImpl.js +393 -0
  8. package/dist/cjs/SelectImpl.js.map +7 -0
  9. package/dist/cjs/SelectScrollButton.js +128 -0
  10. package/dist/cjs/SelectScrollButton.js.map +7 -0
  11. package/dist/cjs/SelectScrollButton.native.js +32 -0
  12. package/dist/cjs/SelectScrollButton.native.js.map +7 -0
  13. package/dist/cjs/SelectViewport.js +96 -0
  14. package/dist/cjs/SelectViewport.js.map +7 -0
  15. package/dist/cjs/SelectViewport.native.js +43 -0
  16. package/dist/cjs/SelectViewport.native.js.map +7 -0
  17. package/dist/cjs/constants.js +47 -0
  18. package/dist/cjs/constants.js.map +7 -0
  19. package/dist/cjs/context.js +38 -0
  20. package/dist/cjs/context.js.map +7 -0
  21. package/dist/cjs/index.js +19 -0
  22. package/dist/cjs/index.js.map +2 -2
  23. package/dist/cjs/types.js +17 -0
  24. package/dist/cjs/types.js.map +7 -0
  25. package/dist/esm/Select.js +33 -565
  26. package/dist/esm/Select.js.map +2 -2
  27. package/dist/esm/SelectContent.js +26 -0
  28. package/dist/esm/SelectContent.js.map +7 -0
  29. package/dist/esm/SelectContent.native.js +7 -0
  30. package/dist/esm/SelectContent.native.js.map +7 -0
  31. package/dist/esm/SelectImpl.js +378 -0
  32. package/dist/esm/SelectImpl.js.map +7 -0
  33. package/dist/esm/SelectScrollButton.js +100 -0
  34. package/dist/esm/SelectScrollButton.js.map +7 -0
  35. package/dist/esm/SelectScrollButton.native.js +7 -0
  36. package/dist/esm/SelectScrollButton.native.js.map +7 -0
  37. package/dist/esm/SelectViewport.js +68 -0
  38. package/dist/esm/SelectViewport.js.map +7 -0
  39. package/dist/esm/SelectViewport.native.js +16 -0
  40. package/dist/esm/SelectViewport.native.js.map +7 -0
  41. package/dist/esm/constants.js +17 -0
  42. package/dist/esm/constants.js.map +7 -0
  43. package/dist/esm/context.js +11 -0
  44. package/dist/esm/context.js.map +7 -0
  45. package/dist/esm/index.js +13 -0
  46. package/dist/esm/index.js.map +2 -2
  47. package/dist/esm/types.js +1 -0
  48. package/dist/esm/types.js.map +7 -0
  49. package/dist/jsx/Select.js +32 -515
  50. package/dist/jsx/Select.js.map +2 -2
  51. package/dist/jsx/SelectContent.js +19 -0
  52. package/dist/jsx/SelectContent.js.map +7 -0
  53. package/dist/jsx/SelectContent.native.js +7 -0
  54. package/dist/jsx/SelectContent.native.js.map +7 -0
  55. package/dist/jsx/SelectImpl.js +366 -0
  56. package/dist/jsx/SelectImpl.js.map +7 -0
  57. package/dist/jsx/SelectScrollButton.js +78 -0
  58. package/dist/jsx/SelectScrollButton.js.map +7 -0
  59. package/dist/jsx/SelectScrollButton.native.js +7 -0
  60. package/dist/jsx/SelectScrollButton.native.js.map +7 -0
  61. package/dist/jsx/SelectViewport.js +57 -0
  62. package/dist/jsx/SelectViewport.js.map +7 -0
  63. package/dist/jsx/SelectViewport.native.js +14 -0
  64. package/dist/jsx/SelectViewport.native.js.map +7 -0
  65. package/dist/jsx/constants.js +17 -0
  66. package/dist/jsx/constants.js.map +7 -0
  67. package/dist/jsx/context.js +11 -0
  68. package/dist/jsx/context.js.map +7 -0
  69. package/dist/jsx/index.js +13 -0
  70. package/dist/jsx/index.js.map +2 -2
  71. package/dist/jsx/types.js +1 -0
  72. package/dist/jsx/types.js.map +7 -0
  73. package/package.json +12 -12
  74. package/src/Select.tsx +57 -881
  75. package/src/SelectContent.native.tsx +5 -0
  76. package/src/SelectContent.tsx +34 -0
  77. package/src/SelectImpl.tsx +511 -0
  78. package/src/SelectScrollButton.native.tsx +7 -0
  79. package/src/SelectScrollButton.tsx +150 -0
  80. package/src/SelectViewport.native.tsx +17 -0
  81. package/src/SelectViewport.tsx +86 -0
  82. package/src/constants.tsx +7 -0
  83. package/src/context.tsx +9 -0
  84. package/src/index.tsx +7 -0
  85. package/src/types.tsx +83 -0
  86. package/types/Select.d.ts +140 -298
  87. package/types/Select.d.ts.map +1 -1
  88. package/types/SelectContent.d.ts +4 -0
  89. package/types/SelectContent.d.ts.map +1 -0
  90. package/types/SelectContent.native.d.ts +4 -0
  91. package/types/SelectContent.native.d.ts.map +1 -0
  92. package/types/SelectImpl.d.ts +9 -0
  93. package/types/SelectImpl.d.ts.map +1 -0
  94. package/types/SelectScrollButton.d.ts +6 -0
  95. package/types/SelectScrollButton.d.ts.map +1 -0
  96. package/types/SelectScrollButton.native.d.ts +4 -0
  97. package/types/SelectScrollButton.native.d.ts.map +1 -0
  98. package/types/SelectViewport.d.ts +127 -0
  99. package/types/SelectViewport.d.ts.map +1 -0
  100. package/types/SelectViewport.native.d.ts +54 -0
  101. package/types/SelectViewport.native.d.ts.map +1 -0
  102. package/types/constants.d.ts +8 -0
  103. package/types/constants.d.ts.map +1 -0
  104. package/types/context.d.ts +17 -0
  105. package/types/context.d.ts.map +1 -0
  106. package/types/index.d.ts +2 -0
  107. package/types/index.d.ts.map +1 -1
  108. package/types/types.d.ts +74 -0
  109. package/types/types.d.ts.map +1 -0
@@ -1,58 +1,27 @@
1
- import {
2
- FloatingFocusManager,
3
- FloatingOverlay,
4
- FloatingPortal,
5
- autoUpdate,
6
- detectOverflow,
7
- flip,
8
- offset,
9
- size,
10
- useClick,
11
- useDismiss,
12
- useFloating,
13
- useInteractions,
14
- useListNavigation,
15
- useRole,
16
- useTypeahead
17
- } from "@floating-ui/react-dom-interactions";
18
- import { usePrevious } from "@radix-ui/react-use-previous";
19
1
  import { useComposedRefs } from "@tamagui/compose-refs";
20
2
  import { isWeb, useMedia } from "@tamagui/core";
21
- import {
22
- Theme,
23
- styled,
24
- useGet,
25
- useIsomorphicLayoutEffect,
26
- useThemeName,
27
- withStaticProperties
28
- } from "@tamagui/core";
3
+ import { styled, useGet, useIsomorphicLayoutEffect, withStaticProperties } from "@tamagui/core";
29
4
  import { useId } from "@tamagui/core";
30
- import { createContextScope } from "@tamagui/create-context";
31
5
  import { ListItem } from "@tamagui/list-item";
32
- import { PortalHost, PortalItem } from "@tamagui/portal";
6
+ import { PortalHost } from "@tamagui/portal";
33
7
  import { Separator } from "@tamagui/separator";
34
8
  import { Sheet, SheetController } from "@tamagui/sheet";
35
- import { ThemeableStack, XStack, YStack } from "@tamagui/stacks";
9
+ import { XStack, YStack } from "@tamagui/stacks";
36
10
  import { Paragraph } from "@tamagui/text";
37
11
  import { useControllableState } from "@tamagui/use-controllable-state";
38
12
  import * as React from "react";
39
13
  import * as ReactDOM from "react-dom";
40
- const SELECT_NAME = "Select";
41
- const WINDOW_PADDING = 8;
42
- const SCROLL_ARROW_VELOCITY = 8;
43
- const SCROLL_ARROW_THRESHOLD = 8;
44
- const MIN_HEIGHT = 80;
45
- const FALLBACK_THRESHOLD = 16;
14
+ import { SELECT_NAME } from "./constants";
15
+ import { SelectProvider, createSelectContext, useSelectContext } from "./context";
16
+ import { SelectContent } from "./SelectContent";
17
+ import { SelectInlineImpl } from "./SelectImpl";
18
+ import { SelectScrollDownButton, SelectScrollUpButton } from "./SelectScrollButton";
19
+ import { SelectViewport } from "./SelectViewport";
46
20
  const userAgent = typeof navigator !== "undefined" && navigator.userAgent || "";
47
21
  const isFirefox = userAgent.toLowerCase().includes("firefox");
48
- if (isFirefox) {
49
- document.body.classList.add("firefox");
50
- }
51
22
  function getVisualOffsetTop() {
52
23
  return !/^((?!chrome|android).)*safari/i.test(userAgent) ? (visualViewport == null ? void 0 : visualViewport.offsetTop) ?? 0 : 0;
53
24
  }
54
- const [createSelectContext, createSelectScope] = createContextScope(SELECT_NAME);
55
- const [SelectProvider, useSelectContext] = createSelectContext(SELECT_NAME);
56
25
  const TRIGGER_NAME = "SelectTrigger";
57
26
  const SelectTrigger = React.forwardRef((props, forwardedRef) => {
58
27
  const {
@@ -94,14 +63,15 @@ const SelectValueFrame = styled(Paragraph, {
94
63
  name: VALUE_NAME,
95
64
  selectable: false
96
65
  });
97
- const SelectValue = SelectValueFrame.extractable(React.forwardRef(({ __scopeSelect, children, placeholder }, forwardedRef) => {
66
+ const SelectValue = SelectValueFrame.extractable(React.forwardRef(({ __scopeSelect, children: childrenProp, placeholder }, forwardedRef) => {
98
67
  const context = useSelectContext(VALUE_NAME, __scopeSelect);
99
68
  const { onValueNodeHasChildrenChange } = context;
100
- const hasChildren = children !== void 0;
69
+ const hasChildren = childrenProp !== void 0;
101
70
  const composedRefs = useComposedRefs(forwardedRef, context.onValueNodeChange);
102
71
  React.useLayoutEffect(() => {
103
72
  onValueNodeHasChildrenChange(hasChildren);
104
73
  }, [onValueNodeHasChildrenChange, hasChildren]);
74
+ const children = childrenProp ?? context.selectedItem;
105
75
  return /* @__PURE__ */ React.createElement(SelectValueFrame, {
106
76
  size: context.size,
107
77
  ref: composedRefs,
@@ -114,78 +84,6 @@ const SelectIcon = styled(XStack, {
114
84
  "aria-hidden": true,
115
85
  children: /* @__PURE__ */ React.createElement(Paragraph, null, "\u25BC")
116
86
  });
117
- const CONTENT_NAME = "SelectContent";
118
- const SelectContent = ({ children, __scopeSelect }) => {
119
- const context = useSelectContext(CONTENT_NAME, __scopeSelect);
120
- const themeName = useThemeName();
121
- const showSheet = useShowSelectSheet(context);
122
- const contents = /* @__PURE__ */ React.createElement(Theme, {
123
- name: themeName
124
- }, children);
125
- if (showSheet && context.open) {
126
- return contents;
127
- }
128
- return /* @__PURE__ */ React.createElement(FloatingPortal, null, context.open ? /* @__PURE__ */ React.createElement(FloatingOverlay, {
129
- lockScroll: true
130
- }, contents) : /* @__PURE__ */ React.createElement("div", {
131
- style: { display: "none" }
132
- }, contents));
133
- };
134
- const VIEWPORT_NAME = "SelectViewport";
135
- const SelectViewportFrame = styled(ThemeableStack, {
136
- name: VIEWPORT_NAME,
137
- backgroundColor: "$background",
138
- elevate: true,
139
- bordered: true,
140
- overflow: "scroll",
141
- userSelect: "none",
142
- variants: {
143
- size: {
144
- "...size": (val, { tokens }) => {
145
- return {
146
- borderRadius: tokens.radius[val] ?? val
147
- };
148
- }
149
- }
150
- },
151
- defaultVariants: {
152
- size: "$2"
153
- }
154
- });
155
- const SelectViewport = React.forwardRef((props, forwardedRef) => {
156
- var _a;
157
- const { __scopeSelect, children, ...viewportProps } = props;
158
- const context = useSelectContext(VIEWPORT_NAME, __scopeSelect);
159
- const { style, ...floatingProps } = ((_a = context.interactions) == null ? void 0 : _a.getFloatingProps()) ?? {};
160
- const breakpointActive = useSelectBreakpointActive(context.sheetBreakpoint);
161
- if (breakpointActive || !isWeb) {
162
- return /* @__PURE__ */ React.createElement(PortalItem, {
163
- hostName: `${context.scopeKey}SheetContents`
164
- }, children);
165
- }
166
- if (!context.floatingContext) {
167
- return null;
168
- }
169
- delete style["scrollbarWidth"];
170
- delete style["listStyleType"];
171
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("style", {
172
- dangerouslySetInnerHTML: {
173
- __html: `[data-tamagui-select-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-tamagui-select-viewport]::-webkit-scrollbar{display:none}`
174
- }
175
- }), /* @__PURE__ */ React.createElement(FloatingFocusManager, {
176
- context: context.floatingContext,
177
- preventTabbing: true
178
- }, /* @__PURE__ */ React.createElement(SelectViewportFrame, {
179
- size: context.size,
180
- "data-tamagui-select-viewport": "",
181
- role: "presentation",
182
- ...viewportProps,
183
- ref: forwardedRef,
184
- ...floatingProps,
185
- ...style
186
- }, children)));
187
- });
188
- SelectViewport.displayName = VIEWPORT_NAME;
189
87
  const ITEM_NAME = "SelectItem";
190
88
  const [SelectItemContextProvider, useSelectItemContext] = createSelectContext(ITEM_NAME);
191
89
  const SelectItem = React.forwardRef((props, forwardedRef) => {
@@ -215,6 +113,8 @@ const SelectItem = React.forwardRef((props, forwardedRef) => {
215
113
  dataRef
216
114
  } = context;
217
115
  const composedRefs = useComposedRefs(forwardedRef, (node) => {
116
+ if (!isWeb)
117
+ return;
218
118
  if (node instanceof HTMLElement) {
219
119
  if (listRef) {
220
120
  listRef.current[index] = node;
@@ -295,13 +195,22 @@ const SelectItemText = React.forwardRef((props, forwardedRef) => {
295
195
  const itemContext = useSelectItemContext(ITEM_TEXT_NAME, __scopeSelect);
296
196
  const ref = React.useRef(null);
297
197
  const composedRefs = useComposedRefs(forwardedRef, ref, itemContext.onItemTextChange);
298
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(SelectItemTextFrame, {
198
+ const isSelected = itemContext.isSelected && context.valueNode && !context.valueNodeHasChildren;
199
+ const contents = /* @__PURE__ */ React.createElement(SelectItemTextFrame, {
299
200
  className,
300
201
  size: context.size,
301
202
  id: itemContext.textId,
302
203
  ...itemTextProps,
303
204
  ref: composedRefs
304
- }), itemContext.isSelected && context.valueNode && !context.valueNodeHasChildren ? ReactDOM.createPortal(itemTextProps.children, context.valueNode) : null);
205
+ });
206
+ if (!isWeb) {
207
+ React.useEffect(() => {
208
+ if (isSelected) {
209
+ context.setSelectedItem(contents);
210
+ }
211
+ }, [isSelected]);
212
+ }
213
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, contents, isWeb && isSelected ? ReactDOM.createPortal(itemTextProps.children, context.valueNode) : null);
305
214
  });
306
215
  SelectItemText.displayName = ITEM_TEXT_NAME;
307
216
  const ITEM_INDICATOR_NAME = "SelectItemIndicator";
@@ -353,95 +262,6 @@ const SelectLabel = React.forwardRef((props, forwardedRef) => {
353
262
  });
354
263
  });
355
264
  SelectLabel.displayName = LABEL_NAME;
356
- const SCROLL_UP_BUTTON_NAME = "SelectScrollUpButton";
357
- const SelectScrollUpButton = React.forwardRef((props, forwardedRef) => {
358
- return /* @__PURE__ */ React.createElement(SelectScrollButtonImpl, {
359
- componentName: SCROLL_UP_BUTTON_NAME,
360
- ...props,
361
- dir: "up",
362
- ref: forwardedRef
363
- });
364
- });
365
- SelectScrollUpButton.displayName = SCROLL_UP_BUTTON_NAME;
366
- const SCROLL_DOWN_BUTTON_NAME = "SelectScrollDownButton";
367
- const SelectScrollDownButton = React.forwardRef((props, forwardedRef) => {
368
- return /* @__PURE__ */ React.createElement(SelectScrollButtonImpl, {
369
- componentName: SCROLL_DOWN_BUTTON_NAME,
370
- ...props,
371
- dir: "down",
372
- ref: forwardedRef
373
- });
374
- });
375
- SelectScrollDownButton.displayName = SCROLL_DOWN_BUTTON_NAME;
376
- const SelectScrollButtonImpl = React.memo(React.forwardRef((props, forwardedRef) => {
377
- var _a;
378
- const { __scopeSelect, dir, componentName, ...scrollIndicatorProps } = props;
379
- const { floatingRef, increaseHeight, forceUpdate, ...context } = useSelectContext(componentName, __scopeSelect);
380
- const intervalRef = React.useRef();
381
- const loopingRef = React.useRef(false);
382
- const isVisible = context[dir === "down" ? "canScrollDown" : "canScrollUp"];
383
- const { x, y, reference, floating, strategy, update, refs } = useFloating({
384
- strategy: "fixed",
385
- placement: dir === "up" ? "top" : "bottom",
386
- middleware: [offset(({ rects }) => -rects.floating.height)]
387
- });
388
- const composedRefs = useComposedRefs(forwardedRef, floating);
389
- React.useLayoutEffect(() => {
390
- if (!floatingRef)
391
- return;
392
- reference(floatingRef.current);
393
- }, [reference, floatingRef == null ? void 0 : floatingRef.current]);
394
- React.useEffect(() => {
395
- if (!refs.reference.current || !refs.floating.current || !isVisible) {
396
- return;
397
- }
398
- const cleanup = autoUpdate(refs.reference.current, refs.floating.current, update, {
399
- animationFrame: true
400
- });
401
- return () => {
402
- clearInterval(intervalRef.current);
403
- loopingRef.current = false;
404
- cleanup();
405
- };
406
- }, [isVisible, update, refs.floating, refs.reference]);
407
- if (!isVisible) {
408
- return null;
409
- }
410
- const handleScrollArrowChange = () => {
411
- if (!floatingRef)
412
- return;
413
- const floating2 = floatingRef.current;
414
- const isUp = dir === "up";
415
- if (floating2) {
416
- const value = isUp ? -SCROLL_ARROW_VELOCITY : SCROLL_ARROW_VELOCITY;
417
- const multi = isUp && floating2.scrollTop <= SCROLL_ARROW_THRESHOLD * 2 || !isUp && floating2.scrollTop >= floating2.scrollHeight - floating2.clientHeight - SCROLL_ARROW_THRESHOLD * 2 ? 2 : 1;
418
- floating2.scrollTop += multi * (isUp ? -SCROLL_ARROW_VELOCITY : SCROLL_ARROW_VELOCITY);
419
- increaseHeight == null ? void 0 : increaseHeight(floating2, multi === 2 ? value * 2 : value);
420
- forceUpdate();
421
- }
422
- };
423
- return /* @__PURE__ */ React.createElement(YStack, {
424
- ref: composedRefs,
425
- componentName,
426
- "aria-hidden": true,
427
- ...scrollIndicatorProps,
428
- zIndex: 1e3,
429
- position: strategy,
430
- left: x || 0,
431
- top: y || 0,
432
- width: `calc(${(((_a = floatingRef == null ? void 0 : floatingRef.current) == null ? void 0 : _a.offsetWidth) ?? 0) - 2}px)`,
433
- onPointerMove: () => {
434
- if (!loopingRef.current) {
435
- intervalRef.current = setInterval(handleScrollArrowChange, 1e3 / 60);
436
- loopingRef.current = true;
437
- }
438
- },
439
- onPointerLeave: () => {
440
- loopingRef.current = false;
441
- clearInterval(intervalRef.current);
442
- }
443
- });
444
- }));
445
265
  const SelectSeparator = styled(Separator, {
446
266
  name: "SelectSeparator"
447
267
  });
@@ -476,362 +296,6 @@ const SelectSheetContents = ({ __scopeSelect }) => {
476
296
  });
477
297
  };
478
298
  SelectSheetContents.displayName = SHEET_CONTENTS_NAME;
479
- const SelectInlineImpl = (props) => {
480
- const {
481
- __scopeSelect,
482
- children,
483
- open = false,
484
- activeIndexRef,
485
- selectedIndexRef,
486
- listContentRef
487
- } = props;
488
- const selectContext = useSelectContext("SelectSheetImpl", __scopeSelect);
489
- const { setActiveIndex, setOpen, setSelectedIndex, selectedIndex, activeIndex, forceUpdate } = selectContext;
490
- const [showArrows, setShowArrows] = React.useState(false);
491
- const [scrollTop, setScrollTop] = React.useState(0);
492
- const prevActiveIndex = usePrevious(activeIndex);
493
- const listItemsRef = React.useRef([]);
494
- const [controlledScrolling, setControlledScrolling] = React.useState(false);
495
- const [middlewareType, setMiddlewareType] = React.useState("align");
496
- React.useEffect(() => {
497
- const frame = requestAnimationFrame(() => {
498
- setShowArrows(open);
499
- if (!open) {
500
- setScrollTop(0);
501
- setMiddlewareType("align");
502
- setActiveIndex(null);
503
- setControlledScrolling(false);
504
- }
505
- });
506
- return () => {
507
- cancelAnimationFrame(frame);
508
- };
509
- }, [open, setActiveIndex]);
510
- function getFloatingPadding(floating2) {
511
- var _a;
512
- if (!floating2) {
513
- return 0;
514
- }
515
- return Number((_a = getComputedStyle(floating2).paddingLeft) == null ? void 0 : _a.replace("px", ""));
516
- }
517
- const { x, y, reference, floating, strategy, context, refs, middlewareData, update } = useFloating({
518
- open,
519
- onOpenChange: setOpen,
520
- placement: "bottom",
521
- middleware: middlewareType === "align" ? [
522
- offset(({ rects }) => {
523
- const index = activeIndexRef.current ?? selectedIndexRef.current;
524
- if (index == null) {
525
- return 0;
526
- }
527
- const item = listItemsRef.current[index];
528
- if (item == null) {
529
- return 0;
530
- }
531
- const offsetTop = item.offsetTop;
532
- const itemHeight = item.offsetHeight;
533
- const height = rects.reference.height;
534
- return -offsetTop - height - (itemHeight - height) / 2;
535
- }),
536
- {
537
- name: "size",
538
- async fn(args) {
539
- var _a;
540
- const {
541
- elements: { floating: floating2 },
542
- rects: { reference: reference2 },
543
- middlewareData: middlewareData2
544
- } = args;
545
- const overflow = await detectOverflow(args, {
546
- padding: WINDOW_PADDING
547
- });
548
- const top = Math.max(0, overflow.top);
549
- const bottom = Math.max(0, overflow.bottom);
550
- const nextY = args.y + top;
551
- if ((_a = middlewareData2.size) == null ? void 0 : _a.skip) {
552
- return {
553
- y: nextY,
554
- data: {
555
- y: middlewareData2.size.y
556
- }
557
- };
558
- }
559
- Object.assign(floating2.style, {
560
- maxHeight: `${floating2.scrollHeight - Math.abs(top + bottom)}px`,
561
- minWidth: `${reference2.width + getFloatingPadding(floating2) * 2}px`
562
- });
563
- return {
564
- y: nextY,
565
- data: {
566
- y: top,
567
- skip: true
568
- },
569
- reset: {
570
- rects: true
571
- }
572
- };
573
- }
574
- }
575
- ] : [
576
- offset(5),
577
- flip(),
578
- size({
579
- apply({ rects, availableHeight, elements }) {
580
- Object.assign(elements.floating.style, {
581
- width: `${rects.reference.width}px`,
582
- maxHeight: `${availableHeight}px`
583
- });
584
- },
585
- padding: WINDOW_PADDING
586
- })
587
- ]
588
- });
589
- const floatingRef = refs.floating;
590
- const showUpArrow = showArrows && scrollTop > SCROLL_ARROW_THRESHOLD;
591
- const showDownArrow = showArrows && floatingRef.current && scrollTop < floatingRef.current.scrollHeight - floatingRef.current.clientHeight - SCROLL_ARROW_THRESHOLD;
592
- const interactions = useInteractions([
593
- useClick(context, { pointerDown: true }),
594
- useRole(context, { role: "listbox" }),
595
- useDismiss(context),
596
- useListNavigation(context, {
597
- listRef: listItemsRef,
598
- activeIndex,
599
- selectedIndex,
600
- onNavigate: setActiveIndex
601
- }),
602
- useTypeahead(context, {
603
- listRef: listContentRef,
604
- onMatch: open ? setActiveIndex : setSelectedIndex,
605
- selectedIndex,
606
- activeIndex
607
- })
608
- ]);
609
- const increaseHeight = React.useCallback((floating2, amount = 0) => {
610
- if (middlewareType === "fallback") {
611
- return;
612
- }
613
- const currentMaxHeight = Number(floating2.style.maxHeight.replace("px", ""));
614
- const currentTop = Number(floating2.style.top.replace("px", ""));
615
- const rect = floating2.getBoundingClientRect();
616
- const rectTop = rect.top;
617
- const rectBottom = rect.bottom;
618
- const viewportHeight = (visualViewport == null ? void 0 : visualViewport.height) ?? 0;
619
- const visualMaxHeight = viewportHeight - WINDOW_PADDING * 2;
620
- if (amount < 0 && selectedIndexRef.current != null && Math.round(rectBottom) < Math.round(viewportHeight + getVisualOffsetTop() - WINDOW_PADDING)) {
621
- floating2.style.maxHeight = `${Math.min(visualMaxHeight, currentMaxHeight - amount)}px`;
622
- }
623
- if (amount > 0 && Math.round(rectTop) > Math.round(WINDOW_PADDING - getVisualOffsetTop()) && floating2.scrollHeight > floating2.offsetHeight) {
624
- const nextTop = Math.max(WINDOW_PADDING + getVisualOffsetTop(), currentTop - amount);
625
- const nextMaxHeight = Math.min(visualMaxHeight, currentMaxHeight + amount);
626
- Object.assign(floating2.style, {
627
- maxHeight: `${nextMaxHeight}px`,
628
- top: `${nextTop}px`
629
- });
630
- if (nextTop - WINDOW_PADDING > getVisualOffsetTop()) {
631
- floating2.scrollTop -= nextMaxHeight - currentMaxHeight + getFloatingPadding(floating2);
632
- }
633
- return currentTop - nextTop;
634
- }
635
- }, [middlewareType, selectedIndexRef]);
636
- const touchPageYRef = React.useRef(null);
637
- const handleWheel = React.useCallback((event) => {
638
- var _a;
639
- const pinching = event.ctrlKey;
640
- const currentTarget = event.currentTarget;
641
- function isWheelEvent(event2) {
642
- return typeof event2.deltaY === "number";
643
- }
644
- function isTouchEvent(event2) {
645
- return event2.touches != null;
646
- }
647
- if (Math.abs(((currentTarget == null ? void 0 : currentTarget.offsetHeight) ?? 0) - (((visualViewport == null ? void 0 : visualViewport.height) ?? 0) - WINDOW_PADDING * 2)) > 1 && !pinching) {
648
- event.preventDefault();
649
- } else if (isWheelEvent(event) && isFirefox) {
650
- currentTarget.scrollTop += event.deltaY;
651
- }
652
- if (!pinching) {
653
- let delta = 5;
654
- if (isTouchEvent(event)) {
655
- const currentPageY = touchPageYRef.current;
656
- const pageY = (_a = event.touches[0]) == null ? void 0 : _a.pageY;
657
- if (pageY != null) {
658
- touchPageYRef.current = pageY;
659
- if (currentPageY != null) {
660
- delta = currentPageY - pageY;
661
- }
662
- }
663
- }
664
- increaseHeight(currentTarget, isWheelEvent(event) ? event.deltaY : delta);
665
- setScrollTop(currentTarget.scrollTop);
666
- forceUpdate();
667
- }
668
- }, [forceUpdate, increaseHeight]);
669
- React.useEffect(() => {
670
- function onTouchEnd() {
671
- touchPageYRef.current = null;
672
- }
673
- const floating2 = floatingRef.current;
674
- if (open && floating2 && middlewareType === "align") {
675
- floating2.addEventListener("wheel", handleWheel);
676
- floating2.addEventListener("touchmove", handleWheel);
677
- floating2.addEventListener("touchend", onTouchEnd, { passive: true });
678
- return () => {
679
- floating2.removeEventListener("wheel", handleWheel);
680
- floating2.removeEventListener("touchmove", handleWheel);
681
- floating2.removeEventListener("touchend", onTouchEnd);
682
- };
683
- }
684
- }, [open, floatingRef, handleWheel, middlewareType]);
685
- React.useEffect(() => {
686
- window.addEventListener("resize", update);
687
- return () => {
688
- window.removeEventListener("resize", update);
689
- };
690
- }, [update]);
691
- React.useLayoutEffect(() => {
692
- var _a;
693
- const floating2 = floatingRef.current;
694
- if (open && controlledScrolling && floating2) {
695
- const item = activeIndex != null ? listItemsRef.current[activeIndex] : selectedIndex != null ? listItemsRef.current[selectedIndex] : null;
696
- if (item && prevActiveIndex != null) {
697
- const itemHeight = ((_a = listItemsRef.current[prevActiveIndex]) == null ? void 0 : _a.offsetHeight) ?? 0;
698
- const floatingHeight = floating2.offsetHeight;
699
- const top = item.offsetTop;
700
- const bottom = top + itemHeight;
701
- if (top < floating2.scrollTop + 20) {
702
- const diff = floating2.scrollTop - top + 20;
703
- floating2.scrollTop -= diff;
704
- if (activeIndex != selectedIndex && activeIndex != null) {
705
- increaseHeight(floating2, -diff);
706
- }
707
- } else if (bottom > floatingHeight + floating2.scrollTop - 20) {
708
- const diff = bottom - floatingHeight - floating2.scrollTop + 20;
709
- floating2.scrollTop += diff;
710
- if (activeIndex != selectedIndex && activeIndex != null) {
711
- floating2.scrollTop -= increaseHeight(floating2, diff) ?? 0;
712
- }
713
- }
714
- }
715
- }
716
- }, [
717
- open,
718
- controlledScrolling,
719
- prevActiveIndex,
720
- activeIndex,
721
- selectedIndex,
722
- floatingRef,
723
- increaseHeight
724
- ]);
725
- React.useLayoutEffect(() => {
726
- var _a;
727
- const floating2 = refs.floating.current;
728
- const reference2 = refs.reference.current;
729
- if (open && floating2 && reference2 && floating2.offsetHeight < floating2.scrollHeight) {
730
- const referenceRect = reference2.getBoundingClientRect();
731
- if (middlewareType === "fallback") {
732
- const item = listItemsRef.current[selectedIndex];
733
- if (item) {
734
- floating2.scrollTop = item.offsetTop - floating2.clientHeight + referenceRect.height;
735
- }
736
- return;
737
- }
738
- floating2.scrollTop = (_a = middlewareData.size) == null ? void 0 : _a.y;
739
- const closeToBottom = ((visualViewport == null ? void 0 : visualViewport.height) ?? 0) + getVisualOffsetTop() - referenceRect.bottom < FALLBACK_THRESHOLD;
740
- const closeToTop = referenceRect.top < FALLBACK_THRESHOLD;
741
- if (floating2.offsetHeight < MIN_HEIGHT || closeToTop || closeToBottom) {
742
- setMiddlewareType("fallback");
743
- }
744
- }
745
- }, [
746
- open,
747
- increaseHeight,
748
- selectedIndex,
749
- middlewareType,
750
- refs.floating,
751
- refs.reference,
752
- middlewareData
753
- ]);
754
- React.useLayoutEffect(() => {
755
- if (open && selectedIndex != null) {
756
- requestAnimationFrame(() => {
757
- var _a;
758
- (_a = listItemsRef.current[selectedIndex]) == null ? void 0 : _a.focus({ preventScroll: true });
759
- });
760
- }
761
- }, [listItemsRef, selectedIndex, open]);
762
- React.useEffect(() => {
763
- const frame = requestAnimationFrame(() => {
764
- setShowArrows(open);
765
- if (!open) {
766
- setScrollTop(0);
767
- setMiddlewareType("align");
768
- setActiveIndex(null);
769
- setControlledScrolling(false);
770
- }
771
- });
772
- return () => cancelAnimationFrame(frame);
773
- }, [open]);
774
- return /* @__PURE__ */ React.createElement(SelectProvider, {
775
- scope: __scopeSelect,
776
- ...selectContext,
777
- increaseHeight,
778
- floatingRef,
779
- setValueAtIndex: (index, value) => {
780
- listContentRef.current[index] = value;
781
- },
782
- interactions: {
783
- ...interactions,
784
- getReferenceProps() {
785
- return interactions.getReferenceProps({
786
- ref: reference,
787
- className: "SelectTrigger",
788
- onKeyDown(event) {
789
- if (event.key === "Enter" || event.key === " " && !context.dataRef.current.typing) {
790
- event.preventDefault();
791
- setOpen(true);
792
- }
793
- }
794
- });
795
- },
796
- getFloatingProps(props2) {
797
- return interactions.getFloatingProps({
798
- ref: floating,
799
- className: "Select",
800
- ...props2,
801
- style: {
802
- position: strategy,
803
- top: y ?? "",
804
- left: x ?? "",
805
- outline: 0,
806
- listStyleType: "none",
807
- scrollbarWidth: "none",
808
- userSelect: "none",
809
- ...props2 == null ? void 0 : props2.style
810
- },
811
- onPointerEnter() {
812
- setControlledScrolling(false);
813
- },
814
- onPointerMove() {
815
- setControlledScrolling(false);
816
- },
817
- onKeyDown() {
818
- setControlledScrolling(true);
819
- },
820
- onScroll(event) {
821
- setScrollTop(event.currentTarget.scrollTop);
822
- }
823
- });
824
- }
825
- },
826
- floatingContext: context,
827
- activeIndex,
828
- canScrollDown: !!showDownArrow,
829
- canScrollUp: !!showUpArrow,
830
- controlledScrolling: true,
831
- dataRef: context.dataRef,
832
- listRef: listItemsRef
833
- }, children);
834
- };
835
299
  const SelectSheetImpl = (props) => {
836
300
  return /* @__PURE__ */ React.createElement(React.Fragment, null, props.children);
837
301
  };
@@ -845,13 +309,14 @@ const Select = withStaticProperties((props) => {
845
309
  value: valueProp,
846
310
  defaultValue,
847
311
  onValueChange,
848
- size: sizeProp,
312
+ size: sizeProp = "$4",
849
313
  sheetBreakpoint = false,
850
314
  dir
851
315
  } = props;
852
316
  const isSheet = useSelectBreakpointActive(sheetBreakpoint);
853
317
  const SelectImpl = isSheet ? SelectSheetImpl : SelectInlineImpl;
854
318
  const forceUpdate = React.useReducer(() => ({}), {})[1];
319
+ const [selectedItem, setSelectedItem] = React.useState(null);
855
320
  const [open, setOpen] = useControllableState({
856
321
  prop: openProp,
857
322
  defaultProp: defaultOpen || false,
@@ -876,6 +341,8 @@ const Select = withStaticProperties((props) => {
876
341
  return /* @__PURE__ */ React.createElement(SelectProvider, {
877
342
  dir,
878
343
  size: sizeProp,
344
+ selectedItem,
345
+ setSelectedItem,
879
346
  forceUpdate,
880
347
  valueNode,
881
348
  onValueNodeChange: setValueNode,
@@ -932,8 +399,9 @@ export {
932
399
  SelectSeparator,
933
400
  SelectSheetContents,
934
401
  SelectTrigger,
935
- SelectViewport,
936
- SelectViewportFrame,
937
- createSelectScope
402
+ getVisualOffsetTop,
403
+ isFirefox,
404
+ useSelectBreakpointActive,
405
+ useShowSelectSheet
938
406
  };
939
407
  //# sourceMappingURL=Select.js.map