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

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 +61 -567
  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 +1 -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 +44 -574
  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 +1 -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 +43 -516
  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 +1 -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 +69 -890
  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 +83 -241
  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,59 +1,38 @@
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";
26
+ const SelectTriggerFrame = styled(ListItem, {
27
+ componentName: TRIGGER_NAME,
28
+ backgrounded: true,
29
+ radiused: true,
30
+ hoverTheme: true,
31
+ pressTheme: true,
32
+ focusTheme: true,
33
+ focusable: false,
34
+ borderWidth: 1
35
+ });
57
36
  const SelectTrigger = React.forwardRef((props, forwardedRef) => {
58
37
  const {
59
38
  __scopeSelect,
@@ -63,15 +42,7 @@ const SelectTrigger = React.forwardRef((props, forwardedRef) => {
63
42
  } = props;
64
43
  const context = useSelectContext(TRIGGER_NAME, __scopeSelect);
65
44
  const labelledBy = ariaLabelledby;
66
- return /* @__PURE__ */ React.createElement(ListItem, {
67
- backgrounded: true,
68
- radiused: true,
69
- hoverTheme: true,
70
- pressTheme: true,
71
- focusTheme: true,
72
- focusable: false,
73
- borderWidth: 1,
74
- componentName: TRIGGER_NAME,
45
+ return /* @__PURE__ */ React.createElement(SelectTriggerFrame, {
75
46
  size: context.size,
76
47
  "aria-expanded": context.open,
77
48
  "aria-autocomplete": "none",
@@ -94,14 +65,15 @@ const SelectValueFrame = styled(Paragraph, {
94
65
  name: VALUE_NAME,
95
66
  selectable: false
96
67
  });
97
- const SelectValue = SelectValueFrame.extractable(React.forwardRef(({ __scopeSelect, children, placeholder }, forwardedRef) => {
68
+ const SelectValue = SelectValueFrame.extractable(React.forwardRef(({ __scopeSelect, children: childrenProp, placeholder }, forwardedRef) => {
98
69
  const context = useSelectContext(VALUE_NAME, __scopeSelect);
99
70
  const { onValueNodeHasChildrenChange } = context;
100
- const hasChildren = children !== void 0;
71
+ const hasChildren = childrenProp !== void 0;
101
72
  const composedRefs = useComposedRefs(forwardedRef, context.onValueNodeChange);
102
73
  React.useLayoutEffect(() => {
103
74
  onValueNodeHasChildrenChange(hasChildren);
104
75
  }, [onValueNodeHasChildrenChange, hasChildren]);
76
+ const children = childrenProp ?? context.selectedItem;
105
77
  return /* @__PURE__ */ React.createElement(SelectValueFrame, {
106
78
  size: context.size,
107
79
  ref: composedRefs,
@@ -114,78 +86,6 @@ const SelectIcon = styled(XStack, {
114
86
  "aria-hidden": true,
115
87
  children: /* @__PURE__ */ React.createElement(Paragraph, null, "\u25BC")
116
88
  });
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
89
  const ITEM_NAME = "SelectItem";
190
90
  const [SelectItemContextProvider, useSelectItemContext] = createSelectContext(ITEM_NAME);
191
91
  const SelectItem = React.forwardRef((props, forwardedRef) => {
@@ -215,6 +115,8 @@ const SelectItem = React.forwardRef((props, forwardedRef) => {
215
115
  dataRef
216
116
  } = context;
217
117
  const composedRefs = useComposedRefs(forwardedRef, (node) => {
118
+ if (!isWeb)
119
+ return;
218
120
  if (node instanceof HTMLElement) {
219
121
  if (listRef) {
220
122
  listRef.current[index] = node;
@@ -295,13 +197,22 @@ const SelectItemText = React.forwardRef((props, forwardedRef) => {
295
197
  const itemContext = useSelectItemContext(ITEM_TEXT_NAME, __scopeSelect);
296
198
  const ref = React.useRef(null);
297
199
  const composedRefs = useComposedRefs(forwardedRef, ref, itemContext.onItemTextChange);
298
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(SelectItemTextFrame, {
200
+ const isSelected = itemContext.isSelected && context.valueNode && !context.valueNodeHasChildren;
201
+ const contents = /* @__PURE__ */ React.createElement(SelectItemTextFrame, {
299
202
  className,
300
203
  size: context.size,
301
204
  id: itemContext.textId,
302
205
  ...itemTextProps,
303
206
  ref: composedRefs
304
- }), itemContext.isSelected && context.valueNode && !context.valueNodeHasChildren ? ReactDOM.createPortal(itemTextProps.children, context.valueNode) : null);
207
+ });
208
+ if (!isWeb) {
209
+ React.useEffect(() => {
210
+ if (isSelected) {
211
+ context.setSelectedItem(contents);
212
+ }
213
+ }, [isSelected]);
214
+ }
215
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, contents, isWeb && isSelected ? ReactDOM.createPortal(itemTextProps.children, context.valueNode) : null);
305
216
  });
306
217
  SelectItemText.displayName = ITEM_TEXT_NAME;
307
218
  const ITEM_INDICATOR_NAME = "SelectItemIndicator";
@@ -353,95 +264,6 @@ const SelectLabel = React.forwardRef((props, forwardedRef) => {
353
264
  });
354
265
  });
355
266
  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
267
  const SelectSeparator = styled(Separator, {
446
268
  name: "SelectSeparator"
447
269
  });
@@ -476,362 +298,6 @@ const SelectSheetContents = ({ __scopeSelect }) => {
476
298
  });
477
299
  };
478
300
  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
301
  const SelectSheetImpl = (props) => {
836
302
  return /* @__PURE__ */ React.createElement(React.Fragment, null, props.children);
837
303
  };
@@ -845,13 +311,14 @@ const Select = withStaticProperties((props) => {
845
311
  value: valueProp,
846
312
  defaultValue,
847
313
  onValueChange,
848
- size: sizeProp,
314
+ size: sizeProp = "$4",
849
315
  sheetBreakpoint = false,
850
316
  dir
851
317
  } = props;
852
318
  const isSheet = useSelectBreakpointActive(sheetBreakpoint);
853
319
  const SelectImpl = isSheet ? SelectSheetImpl : SelectInlineImpl;
854
320
  const forceUpdate = React.useReducer(() => ({}), {})[1];
321
+ const [selectedItem, setSelectedItem] = React.useState(null);
855
322
  const [open, setOpen] = useControllableState({
856
323
  prop: openProp,
857
324
  defaultProp: defaultOpen || false,
@@ -876,6 +343,8 @@ const Select = withStaticProperties((props) => {
876
343
  return /* @__PURE__ */ React.createElement(SelectProvider, {
877
344
  dir,
878
345
  size: sizeProp,
346
+ selectedItem,
347
+ setSelectedItem,
879
348
  forceUpdate,
880
349
  valueNode,
881
350
  onValueNodeChange: setValueNode,
@@ -932,8 +401,9 @@ export {
932
401
  SelectSeparator,
933
402
  SelectSheetContents,
934
403
  SelectTrigger,
935
- SelectViewport,
936
- SelectViewportFrame,
937
- createSelectScope
404
+ getVisualOffsetTop,
405
+ isFirefox,
406
+ useSelectBreakpointActive,
407
+ useShowSelectSheet
938
408
  };
939
409
  //# sourceMappingURL=Select.js.map