@multiplatform.one/forms 7.80.0 → 7.81.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/AdaptivePopup/index.cjs +2 -1
- package/dist/cjs/AdaptivePopup/index.native.js +2 -1
- package/dist/cjs/AdaptivePopup/index.native.js.map +1 -1
- package/dist/cjs/Button/index.cjs +12 -5
- package/dist/cjs/Button/index.native.js +14 -6
- package/dist/cjs/Button/index.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/PanelHeader.cjs +3 -8
- package/dist/cjs/FloatingPanel/PanelHeader.native.js +3 -8
- package/dist/cjs/FloatingPanel/PanelHeader.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/coverRect.cjs +0 -8
- package/dist/cjs/FloatingPanel/coverRect.native.js +0 -8
- package/dist/cjs/FloatingPanel/coverRect.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/echoContext.cjs +5 -27
- package/dist/cjs/FloatingPanel/echoContext.native.js +5 -28
- package/dist/cjs/FloatingPanel/echoContext.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/index.cjs +49 -131
- package/dist/cjs/FloatingPanel/index.native.js +216 -135
- package/dist/cjs/FloatingPanel/index.native.js.map +1 -1
- package/dist/cjs/fields/Combobox/index.cjs +3 -10
- package/dist/cjs/fields/Combobox/index.native.js +3 -10
- package/dist/cjs/fields/Combobox/index.native.js.map +1 -1
- package/dist/cjs/fields/Select/InlineChoices.cjs +4 -8
- package/dist/cjs/fields/Select/InlineChoices.native.js +4 -8
- package/dist/cjs/fields/Select/InlineChoices.native.js.map +1 -1
- package/dist/cjs/fields/Select/index.cjs +65 -201
- package/dist/cjs/fields/Select/index.native.js +74 -209
- package/dist/cjs/fields/Select/index.native.js.map +1 -1
- package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.cjs +2 -2
- package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js +2 -2
- package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
- package/dist/cjs/index.cjs +4 -0
- package/dist/cjs/index.native.js +4 -0
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/shared/CheckGlyph.cjs +40 -0
- package/dist/cjs/shared/CheckGlyph.native.js +44 -0
- package/dist/cjs/shared/CheckGlyph.native.js.map +1 -0
- package/dist/cjs/shared/checkedOnField.cjs +104 -0
- package/dist/cjs/shared/checkedOnField.native.js +117 -0
- package/dist/cjs/shared/checkedOnField.native.js.map +1 -0
- package/dist/cjs/shared/floatingList.cjs +12 -5
- package/dist/cjs/shared/floatingList.native.js +15 -7
- package/dist/cjs/shared/floatingList.native.js.map +1 -1
- package/dist/esm/AdaptivePopup/index.mjs +3 -2
- package/dist/esm/AdaptivePopup/index.mjs.map +1 -1
- package/dist/esm/AdaptivePopup/index.native.js +3 -2
- package/dist/esm/AdaptivePopup/index.native.js.map +1 -1
- package/dist/esm/Button/index.mjs +12 -5
- package/dist/esm/Button/index.mjs.map +1 -1
- package/dist/esm/Button/index.native.js +14 -6
- package/dist/esm/Button/index.native.js.map +1 -1
- package/dist/esm/FloatingPanel/PanelHeader.mjs +3 -8
- package/dist/esm/FloatingPanel/PanelHeader.mjs.map +1 -1
- package/dist/esm/FloatingPanel/PanelHeader.native.js +3 -8
- package/dist/esm/FloatingPanel/PanelHeader.native.js.map +1 -1
- package/dist/esm/FloatingPanel/coverRect.mjs +1 -8
- package/dist/esm/FloatingPanel/coverRect.mjs.map +1 -1
- package/dist/esm/FloatingPanel/coverRect.native.js +1 -8
- package/dist/esm/FloatingPanel/coverRect.native.js.map +1 -1
- package/dist/esm/FloatingPanel/echoContext.mjs +4 -24
- package/dist/esm/FloatingPanel/echoContext.mjs.map +1 -1
- package/dist/esm/FloatingPanel/echoContext.native.js +4 -25
- package/dist/esm/FloatingPanel/echoContext.native.js.map +1 -1
- package/dist/esm/FloatingPanel/index.mjs +53 -135
- package/dist/esm/FloatingPanel/index.mjs.map +1 -1
- package/dist/esm/FloatingPanel/index.native.js +180 -99
- package/dist/esm/FloatingPanel/index.native.js.map +1 -1
- package/dist/esm/fields/Combobox/index.mjs +4 -11
- package/dist/esm/fields/Combobox/index.mjs.map +1 -1
- package/dist/esm/fields/Combobox/index.native.js +4 -11
- package/dist/esm/fields/Combobox/index.native.js.map +1 -1
- package/dist/esm/fields/Select/InlineChoices.mjs +2 -6
- package/dist/esm/fields/Select/InlineChoices.mjs.map +1 -1
- package/dist/esm/fields/Select/InlineChoices.native.js +2 -6
- package/dist/esm/fields/Select/InlineChoices.native.js.map +1 -1
- package/dist/esm/fields/Select/index.mjs +68 -204
- package/dist/esm/fields/Select/index.mjs.map +1 -1
- package/dist/esm/fields/Select/index.native.js +77 -212
- package/dist/esm/fields/Select/index.native.js.map +1 -1
- package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.mjs +3 -3
- package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.mjs.map +1 -1
- package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js +3 -3
- package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
- package/dist/esm/index.mjs +3 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +3 -1
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/shared/CheckGlyph.mjs +15 -0
- package/dist/esm/shared/CheckGlyph.mjs.map +1 -0
- package/dist/esm/shared/CheckGlyph.native.js +16 -0
- package/dist/esm/shared/CheckGlyph.native.js.map +1 -0
- package/dist/esm/shared/checkedOnField.mjs +76 -0
- package/dist/esm/shared/checkedOnField.mjs.map +1 -0
- package/dist/esm/shared/checkedOnField.native.js +86 -0
- package/dist/esm/shared/checkedOnField.native.js.map +1 -0
- package/dist/esm/shared/floatingList.mjs +9 -5
- package/dist/esm/shared/floatingList.mjs.map +1 -1
- package/dist/esm/shared/floatingList.native.js +12 -7
- package/dist/esm/shared/floatingList.native.js.map +1 -1
- package/dist/jsx/AdaptivePopup/index.mjs +3 -2
- package/dist/jsx/AdaptivePopup/index.mjs.map +1 -1
- package/dist/jsx/AdaptivePopup/index.native.js +2 -1
- package/dist/jsx/AdaptivePopup/index.native.js.map +1 -1
- package/dist/jsx/Button/index.mjs +12 -5
- package/dist/jsx/Button/index.mjs.map +1 -1
- package/dist/jsx/Button/index.native.js +14 -6
- package/dist/jsx/Button/index.native.js.map +1 -1
- package/dist/jsx/FloatingPanel/PanelHeader.mjs +3 -8
- package/dist/jsx/FloatingPanel/PanelHeader.mjs.map +1 -1
- package/dist/jsx/FloatingPanel/PanelHeader.native.js +3 -8
- package/dist/jsx/FloatingPanel/PanelHeader.native.js.map +1 -1
- package/dist/jsx/FloatingPanel/coverRect.mjs +1 -8
- package/dist/jsx/FloatingPanel/coverRect.mjs.map +1 -1
- package/dist/jsx/FloatingPanel/coverRect.native.js +0 -8
- package/dist/jsx/FloatingPanel/coverRect.native.js.map +1 -1
- package/dist/jsx/FloatingPanel/echoContext.mjs +4 -24
- package/dist/jsx/FloatingPanel/echoContext.mjs.map +1 -1
- package/dist/jsx/FloatingPanel/echoContext.native.js +5 -28
- package/dist/jsx/FloatingPanel/echoContext.native.js.map +1 -1
- package/dist/jsx/FloatingPanel/index.mjs +53 -135
- package/dist/jsx/FloatingPanel/index.mjs.map +1 -1
- package/dist/jsx/FloatingPanel/index.native.js +216 -135
- package/dist/jsx/FloatingPanel/index.native.js.map +1 -1
- package/dist/jsx/fields/Combobox/index.mjs +4 -11
- package/dist/jsx/fields/Combobox/index.mjs.map +1 -1
- package/dist/jsx/fields/Combobox/index.native.js +3 -10
- package/dist/jsx/fields/Combobox/index.native.js.map +1 -1
- package/dist/jsx/fields/Select/InlineChoices.mjs +2 -6
- package/dist/jsx/fields/Select/InlineChoices.mjs.map +1 -1
- package/dist/jsx/fields/Select/InlineChoices.native.js +4 -8
- package/dist/jsx/fields/Select/InlineChoices.native.js.map +1 -1
- package/dist/jsx/fields/Select/index.mjs +68 -204
- package/dist/jsx/fields/Select/index.mjs.map +1 -1
- package/dist/jsx/fields/Select/index.native.js +74 -209
- package/dist/jsx/fields/Select/index.native.js.map +1 -1
- package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.mjs +3 -3
- package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.mjs.map +1 -1
- package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.native.js +2 -2
- package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
- package/dist/jsx/index.js +3 -1
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs +3 -1
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.js +4 -0
- package/dist/jsx/index.native.js.map +1 -1
- package/dist/jsx/shared/CheckGlyph.mjs +15 -0
- package/dist/jsx/shared/CheckGlyph.mjs.map +1 -0
- package/dist/jsx/shared/CheckGlyph.native.js +44 -0
- package/dist/jsx/shared/CheckGlyph.native.js.map +1 -0
- package/dist/jsx/shared/checkedOnField.mjs +76 -0
- package/dist/jsx/shared/checkedOnField.mjs.map +1 -0
- package/dist/jsx/shared/checkedOnField.native.js +117 -0
- package/dist/jsx/shared/checkedOnField.native.js.map +1 -0
- package/dist/jsx/shared/floatingList.mjs +9 -5
- package/dist/jsx/shared/floatingList.mjs.map +1 -1
- package/dist/jsx/shared/floatingList.native.js +15 -7
- package/dist/jsx/shared/floatingList.native.js.map +1 -1
- package/package.json +8 -8
- package/src/AdaptivePopup/index.tsx +6 -3
- package/src/Button/Button.iconButton.spec.tsx +39 -0
- package/src/Button/index.tsx +20 -8
- package/src/FloatingPanel/FloatingPanel.iconCover.spec.tsx +279 -0
- package/src/FloatingPanel/FloatingPanel.menuFace.native.spec.tsx +78 -69
- package/src/FloatingPanel/FloatingPanel.seamlessCover.spec.tsx +12 -0
- package/src/FloatingPanel/PanelHeader.tsx +4 -12
- package/src/FloatingPanel/coverRect.ts +2 -15
- package/src/FloatingPanel/echoContext.ts +6 -40
- package/src/FloatingPanel/index.native.tsx +209 -144
- package/src/FloatingPanel/index.tsx +71 -187
- package/src/FloatingPanel/pointAnchor.spec.ts +1 -1
- package/src/FloatingPanel/pointAnchor.ts +4 -4
- package/src/FloatingPanel/sheetGrabber.spec.tsx +53 -0
- package/src/fields/Combobox/index.tsx +4 -9
- package/src/fields/Select/InlineChoices.tsx +2 -2
- package/src/fields/Select/Select.containingBlock.spec.tsx +131 -130
- package/src/fields/Select/Select.popUp.native.spec.tsx +276 -0
- package/src/fields/Select/Select.stories.tsx +26 -0
- package/src/fields/Select/index.tsx +84 -255
- package/src/fields/nativeDateTime/OsDateTimeSheet.tsx +3 -3
- package/src/index.ts +2 -1
- package/src/shared/CheckGlyph.tsx +12 -0
- package/src/shared/checkedOnField.ts +116 -0
- package/src/shared/floatingList.spec.tsx +154 -1
- package/src/shared/floatingList.tsx +18 -9
- package/types/AdaptivePopup/index.d.ts.map +1 -1
- package/types/Button/index.d.ts.map +1 -1
- package/types/FloatingPanel/PanelHeader.d.ts +1 -6
- package/types/FloatingPanel/PanelHeader.d.ts.map +1 -1
- package/types/FloatingPanel/coverRect.d.ts +2 -11
- package/types/FloatingPanel/coverRect.d.ts.map +1 -1
- package/types/FloatingPanel/echoContext.d.ts +5 -22
- package/types/FloatingPanel/echoContext.d.ts.map +1 -1
- package/types/FloatingPanel/index.d.ts +22 -9
- package/types/FloatingPanel/index.d.ts.map +1 -1
- package/types/FloatingPanel/index.native.d.ts +8 -1
- package/types/FloatingPanel/index.native.d.ts.map +1 -1
- package/types/FloatingPanel/pointAnchor.d.ts +4 -4
- package/types/fields/Combobox/index.d.ts.map +1 -1
- package/types/fields/Select/index.d.ts.map +1 -1
- package/types/index.d.ts +2 -1
- package/types/index.d.ts.map +1 -1
- package/types/shared/CheckGlyph.d.ts +10 -0
- package/types/shared/CheckGlyph.d.ts.map +1 -0
- package/types/shared/checkedOnField.d.ts +54 -0
- package/types/shared/checkedOnField.d.ts.map +1 -0
- package/types/shared/floatingList.d.ts +5 -2
- package/types/shared/floatingList.d.ts.map +1 -1
- package/dist/cjs/FloatingPanel/iconEcho.cjs +0 -106
- package/dist/cjs/FloatingPanel/iconEcho.native.js +0 -116
- package/dist/cjs/FloatingPanel/iconEcho.native.js.map +0 -1
- package/dist/esm/FloatingPanel/iconEcho.mjs +0 -79
- package/dist/esm/FloatingPanel/iconEcho.mjs.map +0 -1
- package/dist/esm/FloatingPanel/iconEcho.native.js +0 -86
- package/dist/esm/FloatingPanel/iconEcho.native.js.map +0 -1
- package/dist/jsx/FloatingPanel/iconEcho.mjs +0 -79
- package/dist/jsx/FloatingPanel/iconEcho.mjs.map +0 -1
- package/dist/jsx/FloatingPanel/iconEcho.native.js +0 -116
- package/dist/jsx/FloatingPanel/iconEcho.native.js.map +0 -1
- package/src/FloatingPanel/FloatingPanel.iconEcho.spec.tsx +0 -357
- package/src/FloatingPanel/iconEcho.tsx +0 -124
- package/types/FloatingPanel/iconEcho.d.ts +0 -29
- package/types/FloatingPanel/iconEcho.d.ts.map +0 -1
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
transitionProps,
|
|
3
|
+
overlayScrim,
|
|
4
|
+
sheetGrabber,
|
|
5
|
+
sheetGrabberClearance,
|
|
6
|
+
} from "@multiplatform.one/theme";
|
|
2
7
|
import type { ReactNode, RefObject, UIEvent } from "react";
|
|
3
8
|
import {
|
|
4
9
|
cloneElement,
|
|
@@ -15,7 +20,6 @@ import {
|
|
|
15
20
|
OVERLAY_ATTACH_GAP,
|
|
16
21
|
OVERLAY_BREAKPOINT,
|
|
17
22
|
Surface,
|
|
18
|
-
SurfaceContext,
|
|
19
23
|
useResolvedKnobs,
|
|
20
24
|
wasKeyboardFocus,
|
|
21
25
|
ensureKeyboardModalityTracking,
|
|
@@ -41,14 +45,8 @@ import { OverlayStackProvider, useInsideOverlay, useOverlayZIndex } from "../sha
|
|
|
41
45
|
import { resolveCompactFace, type CompactFace } from "./compactFace";
|
|
42
46
|
import { isNestedPanelAction, type PanelActionEvent } from "./nestedAction";
|
|
43
47
|
import { PanelPortal } from "./PanelPortal";
|
|
44
|
-
import {
|
|
45
|
-
|
|
46
|
-
PanelIconEchoBoxContext,
|
|
47
|
-
sameEchoBox,
|
|
48
|
-
type PanelIconEchoBox,
|
|
49
|
-
} from "./echoContext";
|
|
50
|
-
import { iconEchoElement, iconEchoOverlays, type IconEcho } from "./iconEcho";
|
|
51
|
-
import { echoInCover, iconCoverRect } from "./coverRect";
|
|
48
|
+
import { PanelSheetContext } from "./echoContext";
|
|
49
|
+
import { iconCoverRect } from "./coverRect";
|
|
52
50
|
import { groupSurfaceOf, paintedTriggerBox } from "./paintedBox";
|
|
53
51
|
import {
|
|
54
52
|
contextMenuPoint,
|
|
@@ -103,14 +101,23 @@ export interface FloatingPanelProps {
|
|
|
103
101
|
*/
|
|
104
102
|
coverAlign?: "start" | "auto";
|
|
105
103
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
|
|
104
|
+
* The trigger is an icon-only button (LC-112, FZ-8665 Round 45). Its panel
|
|
105
|
+
* covers the surface the button is seen on, a glass capsule or its press
|
|
106
|
+
* target, and repeats nothing: the content starts at the panel's top edge,
|
|
107
|
+
* and a press outside it closes it. The panel never slides off the button:
|
|
108
|
+
* it opens down from the button's top edge, or up from its bottom edge.
|
|
109
|
+
*/
|
|
110
|
+
iconCover?: boolean;
|
|
111
|
+
/**
|
|
112
|
+
* Native only: the panel opens the way a macOS pop-up does (LC-112, FZ-8655).
|
|
113
|
+
* `row` is the row that sits on the trigger, its offset and height in the
|
|
114
|
+
* panel's content, `null` until the caller has measured it. There's no
|
|
115
|
+
* trigger echo, a list that fits the safe edges shows whole, and a taller one
|
|
116
|
+
* scrolls under opaque arrow bands (`placeCheckedOnField`). At regular width
|
|
117
|
+
* this is the panel's face at every list length, so a Select never takes
|
|
118
|
+
* RegularPanel's echo or a sheet there.
|
|
112
119
|
*/
|
|
113
|
-
|
|
120
|
+
popUp?: { row: { top: number; height: number } | null };
|
|
114
121
|
/**
|
|
115
122
|
* Optional control rendered beside the trigger but OUTSIDE the native press
|
|
116
123
|
* capture (e.g. DatePicker/ColorPicker clear). On native the trigger subtree
|
|
@@ -410,7 +417,6 @@ export function TriggerEchoRow({
|
|
|
410
417
|
const stretched = grown > rect.width;
|
|
411
418
|
row.style.width = `${stretched ? grown : rect.width}px`;
|
|
412
419
|
row.style.height = `${rect.height}px`;
|
|
413
|
-
const rtl = isRtl(source);
|
|
414
420
|
row.style.alignSelf = "flex-start";
|
|
415
421
|
const frameStyle = row.parentElement ? getComputedStyle(row.parentElement) : null;
|
|
416
422
|
row.style.position = "sticky";
|
|
@@ -419,12 +425,10 @@ export function TriggerEchoRow({
|
|
|
419
425
|
row.style.zIndex = "1";
|
|
420
426
|
// Sticky over a scrolled body, so it carries the panel's own fill.
|
|
421
427
|
row.style.backgroundColor = frameStyle?.backgroundColor ?? "";
|
|
422
|
-
row
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
row.style.marginRight =
|
|
426
|
-
? `${-(parseFloat(frameStyle?.borderRightWidth || "0") || 0)}px`
|
|
427
|
-
: "";
|
|
428
|
+
// Both sides overlap the frame's border, so a trigger-wide row fits a
|
|
429
|
+
// trigger-wide panel instead of pushing it a border wider (FZ-8557).
|
|
430
|
+
row.style.marginLeft = `${-(parseFloat(frameStyle?.borderLeftWidth || "0") || 0)}px`;
|
|
431
|
+
row.style.marginRight = `${-(parseFloat(frameStyle?.borderRightWidth || "0") || 0)}px`;
|
|
428
432
|
const snapshot =
|
|
429
433
|
children == null ? (source.cloneNode(true) as HTMLElement) : visualRef.current;
|
|
430
434
|
if (!snapshot) return;
|
|
@@ -521,97 +525,6 @@ export function placeEchoOverTrigger(
|
|
|
521
525
|
}
|
|
522
526
|
}
|
|
523
527
|
|
|
524
|
-
/**
|
|
525
|
-
* The band an icon trigger's echo rides (LC-112, FZ-8480): as tall as the
|
|
526
|
-
* trigger, sticky on the panel's top edge (or its bottom edge when the panel
|
|
527
|
-
* opened upward), filled with the panel's surface so scrolled rows pass under
|
|
528
|
-
* it. It comes last in the document, so a keyboard open lands on the panel's
|
|
529
|
-
* content and the echo is the last tab stop; CSS order draws it first.
|
|
530
|
-
*/
|
|
531
|
-
function IconEchoRow({ children }: { children: ReactNode }) {
|
|
532
|
-
return (
|
|
533
|
-
<View
|
|
534
|
-
data-fp-icon-echo=""
|
|
535
|
-
flexShrink={0}
|
|
536
|
-
alignSelf="stretch"
|
|
537
|
-
pointerEvents="box-none"
|
|
538
|
-
style={{ order: -1, position: "sticky", zIndex: 1 }}
|
|
539
|
-
>
|
|
540
|
-
<View data-fp-icon-echo-box="" alignItems="flex-start" justifyContent="flex-start">
|
|
541
|
-
{children}
|
|
542
|
-
</View>
|
|
543
|
-
</View>
|
|
544
|
-
);
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
/**
|
|
548
|
-
* Lay the icon echo on the trigger's measured box: the band is the trigger's
|
|
549
|
-
* height on the edge the panel shares with it, and the box sits `offset` in
|
|
550
|
-
* from the panel's start edge, pulled back over the frame's border so the
|
|
551
|
-
* button lands exactly where the trigger is. An overlaid echo (an X) takes no
|
|
552
|
-
* height of its own and lets the content show beside it.
|
|
553
|
-
*/
|
|
554
|
-
function placeIconEcho(
|
|
555
|
-
panelElement: HTMLElement,
|
|
556
|
-
{
|
|
557
|
-
offset,
|
|
558
|
-
width,
|
|
559
|
-
height,
|
|
560
|
-
up,
|
|
561
|
-
overlay,
|
|
562
|
-
group = null,
|
|
563
|
-
}: {
|
|
564
|
-
offset: number;
|
|
565
|
-
width: number;
|
|
566
|
-
height: number;
|
|
567
|
-
up: boolean;
|
|
568
|
-
overlay: boolean;
|
|
569
|
-
/**
|
|
570
|
-
* The surface the panel covers when it is not the trigger's own box (a
|
|
571
|
-
* grouped capsule, or the 44pt target of a smaller avatar): the band
|
|
572
|
-
* covers all of it, and only the pressed trigger shows, at its own spot.
|
|
573
|
-
*/
|
|
574
|
-
group?: { top: number; height: number } | null;
|
|
575
|
-
},
|
|
576
|
-
) {
|
|
577
|
-
const row = panelElement.querySelector<HTMLElement>("[data-fp-icon-echo]");
|
|
578
|
-
const box = row?.querySelector<HTMLElement>("[data-fp-icon-echo-box]");
|
|
579
|
-
if (!row || !box) return;
|
|
580
|
-
const frame = getComputedStyle(panelElement);
|
|
581
|
-
const border = (side: "Top" | "Bottom" | "Left" | "Right") =>
|
|
582
|
-
parseFloat(frame[`border${side}Width`] || "0") || 0;
|
|
583
|
-
const rtl = panelElement.dir === "rtl";
|
|
584
|
-
row.style.order = up ? "1" : "-1";
|
|
585
|
-
row.style.height = `${height}px`;
|
|
586
|
-
row.style.backgroundColor = overlay ? "transparent" : frame.backgroundColor;
|
|
587
|
-
if (up) {
|
|
588
|
-
row.style.top = "";
|
|
589
|
-
row.style.marginTop = "";
|
|
590
|
-
row.style.marginBottom = `${-border("Bottom")}px`;
|
|
591
|
-
row.style.bottom = row.style.marginBottom;
|
|
592
|
-
} else {
|
|
593
|
-
row.style.bottom = "";
|
|
594
|
-
row.style.marginTop = `${-border("Top")}px`;
|
|
595
|
-
row.style.marginBottom = overlay ? `${-(height - border("Top"))}px` : "";
|
|
596
|
-
row.style.top = row.style.marginTop;
|
|
597
|
-
}
|
|
598
|
-
row.setAttribute("data-fp-icon-echo", overlay ? "overlay" : "band");
|
|
599
|
-
if (group) {
|
|
600
|
-
row.style.height = `${group.height}px`;
|
|
601
|
-
if (!up && overlay) row.style.marginBottom = `${-(group.height - border("Top"))}px`;
|
|
602
|
-
}
|
|
603
|
-
row.style.marginLeft = `${-border("Left")}px`;
|
|
604
|
-
row.style.marginRight = `${-border("Right")}px`;
|
|
605
|
-
box.style.width = `${width}px`;
|
|
606
|
-
box.style.height = `${height}px`;
|
|
607
|
-
box.style.marginLeft = rtl ? "" : `${offset}px`;
|
|
608
|
-
box.style.marginRight = rtl ? `${offset}px` : "";
|
|
609
|
-
box.style.alignSelf = "flex-start";
|
|
610
|
-
box.style.marginTop = group ? `${group.top}px` : "";
|
|
611
|
-
box.style.position = "relative";
|
|
612
|
-
box.style.zIndex = "1";
|
|
613
|
-
}
|
|
614
|
-
|
|
615
528
|
/** The box that lays an element out, past any `display: contents` wrappers. */
|
|
616
529
|
function layoutParentOf(element: HTMLElement | null): HTMLElement | null {
|
|
617
530
|
let parent = element?.parentElement ?? null;
|
|
@@ -815,11 +728,11 @@ function FloatingPanelSheet({
|
|
|
815
728
|
>
|
|
816
729
|
<Sheet.Overlay
|
|
817
730
|
{...transitionProps(scrimMotion)}
|
|
818
|
-
backgroundColor=
|
|
731
|
+
backgroundColor={overlayScrim}
|
|
819
732
|
enterStyle={{ opacity: 0 }}
|
|
820
733
|
exitStyle={{ opacity: 0 }}
|
|
821
734
|
/>
|
|
822
|
-
<Sheet.Handle />
|
|
735
|
+
<Sheet.Handle {...sheetGrabber} aria-label="Resize" />
|
|
823
736
|
<Sheet.Frame
|
|
824
737
|
data-testid="floating-panel-sheet"
|
|
825
738
|
// Sheet.Frame forwards its ref at runtime; the styled prop type
|
|
@@ -829,19 +742,32 @@ function FloatingPanelSheet({
|
|
|
829
742
|
{...knobProps.elevatedSurface}
|
|
830
743
|
borderBottomLeftRadius={0}
|
|
831
744
|
borderBottomRightRadius={0}
|
|
745
|
+
// A sheet spans the screen: only its top edge meets the page, so the
|
|
746
|
+
// sides and bottom draw no border beside a full-width row (FZ-8557).
|
|
747
|
+
borderLeftWidth={0}
|
|
748
|
+
borderRightWidth={0}
|
|
749
|
+
borderBottomWidth={0}
|
|
832
750
|
{...panelChromeFocus}
|
|
833
751
|
padding={framePadding}
|
|
752
|
+
{...(contentPadding === "none" ? { paddingTop: sheetGrabberClearance } : null)}
|
|
834
753
|
gap={frameGap}
|
|
835
754
|
>
|
|
836
755
|
<OverlayStackProvider zIndex={sheetZIndex}>
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
{
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
756
|
+
<PanelSheetContext.Provider value>
|
|
757
|
+
{header}
|
|
758
|
+
{scrollable ? (
|
|
759
|
+
<Sheet.ScrollView flex={header ? 1 : undefined} {...scrollViewProps}>
|
|
760
|
+
{children}
|
|
761
|
+
</Sheet.ScrollView>
|
|
762
|
+
) : (
|
|
763
|
+
children
|
|
764
|
+
)}
|
|
765
|
+
{contentPadding === "none" ? (
|
|
766
|
+
// An edge-to-edge list clears the home indicator (HIG); a padded
|
|
767
|
+
// frame's own padding already does.
|
|
768
|
+
<View style={{ height: "env(safe-area-inset-bottom)" }} flexShrink={0} />
|
|
769
|
+
) : null}
|
|
770
|
+
</PanelSheetContext.Provider>
|
|
845
771
|
</OverlayStackProvider>
|
|
846
772
|
</Sheet.Frame>
|
|
847
773
|
</Sheet>
|
|
@@ -867,7 +793,7 @@ function FloatingPanelWeb({
|
|
|
867
793
|
cover = true,
|
|
868
794
|
triggerEcho = true,
|
|
869
795
|
coverAlign = "start",
|
|
870
|
-
|
|
796
|
+
iconCover,
|
|
871
797
|
triggerRow,
|
|
872
798
|
anchorRect,
|
|
873
799
|
clampCollisions = false,
|
|
@@ -880,10 +806,8 @@ function FloatingPanelWeb({
|
|
|
880
806
|
// A context menu anchored on its trigger (a bar button's long-press menu)
|
|
881
807
|
// covers the trigger like any other menu; only a free one opens at the point.
|
|
882
808
|
const pointMenu = isContextMenu && sheetProps.anchorMode !== "cover-trigger";
|
|
883
|
-
const
|
|
884
|
-
const
|
|
885
|
-
const iconEchoUpRef = useRef(false);
|
|
886
|
-
const [echoBox, setEchoBox] = useState<PanelIconEchoBox | null>(null);
|
|
809
|
+
const coversIcon = cover && !pointMenu && iconCover === true;
|
|
810
|
+
const openedUpRef = useRef(false);
|
|
887
811
|
const overlayStyleRef = useRef<{ top: number; left?: number; maxHeight: number } | null>(null);
|
|
888
812
|
const pinnedTopRef = useRef(0);
|
|
889
813
|
const pinnedHeightRef = useRef(0);
|
|
@@ -996,11 +920,10 @@ function FloatingPanelWeb({
|
|
|
996
920
|
const viewportBottom = viewportTop + (viewport?.height ?? window.innerHeight);
|
|
997
921
|
dropdownElement.style.left = `${viewportLeft - containingBlock.left}px`;
|
|
998
922
|
// LC-112 (FZ-8480 Round 37): a grouped icon trigger's surface is the
|
|
999
|
-
// group's plate, so the panel covers the whole plate
|
|
1000
|
-
|
|
1001
|
-
const groupSurface = showIconEcho ? groupSurfaceOf(trig) : null;
|
|
923
|
+
// group's plate, so the panel covers the whole plate.
|
|
924
|
+
const groupSurface = coversIcon ? groupSurfaceOf(trig) : null;
|
|
1002
925
|
const groupBox = groupSurface?.getBoundingClientRect() ?? null;
|
|
1003
|
-
if (
|
|
926
|
+
if (coversIcon) dropdownElement.style.minWidth = groupBox ? `${groupBox.width}px` : "";
|
|
1004
927
|
const layoutStyle = getComputedStyle(dropdownElement);
|
|
1005
928
|
const scale =
|
|
1006
929
|
layoutStyle.transform &&
|
|
@@ -1069,7 +992,7 @@ function FloatingPanelWeb({
|
|
|
1069
992
|
: totalContentHeight;
|
|
1070
993
|
// LC-112 (FZ-8480): an icon trigger's panel covers the surface the
|
|
1071
994
|
// trigger is seen on: its capsule, else its press target.
|
|
1072
|
-
const painted =
|
|
995
|
+
const painted = coversIcon ? paintedTriggerBox(trig, measured) : null;
|
|
1073
996
|
const coverRect = painted
|
|
1074
997
|
? iconCoverRect(
|
|
1075
998
|
{
|
|
@@ -1088,20 +1011,14 @@ function FloatingPanelWeb({
|
|
|
1088
1011
|
: null,
|
|
1089
1012
|
)
|
|
1090
1013
|
: null;
|
|
1091
|
-
const echoCover = coverRect
|
|
1092
|
-
? echoInCover(
|
|
1093
|
-
{ x: measured.left, y: measured.top, width: measured.width, height: measured.height },
|
|
1094
|
-
coverRect,
|
|
1095
|
-
)
|
|
1096
|
-
: null;
|
|
1097
1014
|
let placedTop = measured.top;
|
|
1098
1015
|
let placedLeft = left;
|
|
1099
1016
|
let placedMaxHeight: number | null = null;
|
|
1100
|
-
|
|
1017
|
+
openedUpRef.current = false;
|
|
1101
1018
|
if (coverRect && measured.width > 0 && measured.height > 0) {
|
|
1102
|
-
// LC-112 (FZ-8480): the
|
|
1103
|
-
//
|
|
1104
|
-
//
|
|
1019
|
+
// LC-112 (FZ-8480): the panel stays on its button: down from its top
|
|
1020
|
+
// edge, or up from its bottom. It covers the button's plate and press
|
|
1021
|
+
// box where they reach past it.
|
|
1105
1022
|
const placed = placeOverTrigger({
|
|
1106
1023
|
trigger: coverRect,
|
|
1107
1024
|
width,
|
|
@@ -1120,7 +1037,7 @@ function FloatingPanelWeb({
|
|
|
1120
1037
|
if (!slides) placedLeft = placed.left;
|
|
1121
1038
|
alignEnd = placed.end;
|
|
1122
1039
|
placedMaxHeight = placed.maxHeight;
|
|
1123
|
-
|
|
1040
|
+
openedUpRef.current = placed.up;
|
|
1124
1041
|
} else if (
|
|
1125
1042
|
measured.width > 0 &&
|
|
1126
1043
|
measured.height > 0 &&
|
|
@@ -1162,33 +1079,9 @@ function FloatingPanelWeb({
|
|
|
1162
1079
|
alignEnd = placed.end;
|
|
1163
1080
|
}
|
|
1164
1081
|
coverAlignEndRef.current = alignEnd;
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
panelLeft: placedLeft,
|
|
1169
|
-
panelWidth: width,
|
|
1170
|
-
rtl,
|
|
1171
|
-
});
|
|
1172
|
-
const echoOverlays = iconEcho != null && iconEchoOverlays(iconEcho, iconEchoUpRef.current);
|
|
1173
|
-
const nextEchoBox =
|
|
1174
|
-
showIconEcho && echoOverlays
|
|
1175
|
-
? echoHeaderBox({
|
|
1176
|
-
offset: echoStart,
|
|
1177
|
-
width: measured.width,
|
|
1178
|
-
height: echoCover?.height ?? measured.height,
|
|
1179
|
-
panelWidth: width,
|
|
1180
|
-
rtl,
|
|
1181
|
-
})
|
|
1182
|
-
: null;
|
|
1183
|
-
setEchoBox((previous) => (sameEchoBox(previous, nextEchoBox) ? previous : nextEchoBox));
|
|
1184
|
-
placeIconEcho(dropdownElement, {
|
|
1185
|
-
offset: echoStart,
|
|
1186
|
-
width: measured.width,
|
|
1187
|
-
height: measured.height,
|
|
1188
|
-
up: iconEchoUpRef.current,
|
|
1189
|
-
overlay: echoOverlays,
|
|
1190
|
-
group: echoCover,
|
|
1191
|
-
});
|
|
1082
|
+
// A whole-pixel start edge: at a half pixel the rows paint a device
|
|
1083
|
+
// pixel short of the panel's far edge, a gutter of panel fill (FZ-8557).
|
|
1084
|
+
placedLeft = Math.round(placedLeft);
|
|
1192
1085
|
placeEchoOverTrigger(
|
|
1193
1086
|
dropdownElement,
|
|
1194
1087
|
{
|
|
@@ -1208,7 +1101,7 @@ function FloatingPanelWeb({
|
|
|
1208
1101
|
dropdownElement.style.left = `${cssLeft}px`;
|
|
1209
1102
|
dropdownElement.style.maxHeight = `${maxHeight}px`;
|
|
1210
1103
|
dropdownElement.dir = rtl ? "rtl" : "ltr";
|
|
1211
|
-
dropdownElement.style.transformOrigin = `${
|
|
1104
|
+
dropdownElement.style.transformOrigin = `${openedUpRef.current ? "bottom" : "top"} ${rtl !== alignEnd ? "right" : "left"}`;
|
|
1212
1105
|
dropdownElement.style.visibility = "visible";
|
|
1213
1106
|
overlayStyleRef.current = { top, left: cssLeft, maxHeight };
|
|
1214
1107
|
panel.initializingRef.current = false;
|
|
@@ -1369,7 +1262,7 @@ function FloatingPanelWeb({
|
|
|
1369
1262
|
isFill,
|
|
1370
1263
|
isContextMenu,
|
|
1371
1264
|
pointMenu,
|
|
1372
|
-
|
|
1265
|
+
coversIcon,
|
|
1373
1266
|
cover,
|
|
1374
1267
|
anchorRect,
|
|
1375
1268
|
clampCollisions,
|
|
@@ -1644,7 +1537,7 @@ function FloatingPanelWeb({
|
|
|
1644
1537
|
transition: webTransition,
|
|
1645
1538
|
transformOrigin:
|
|
1646
1539
|
cover && !pointMenu
|
|
1647
|
-
? `${
|
|
1540
|
+
? `${openedUpRef.current ? "bottom" : "top"} ${
|
|
1648
1541
|
isRtl(panel.triggerRef.current) !== coverAlignEndRef.current
|
|
1649
1542
|
? "right"
|
|
1650
1543
|
: "left"
|
|
@@ -1680,7 +1573,7 @@ function FloatingPanelWeb({
|
|
|
1680
1573
|
paddingVertical={0}
|
|
1681
1574
|
paddingBottom={panel.coverCornerInset || 0}
|
|
1682
1575
|
>
|
|
1683
|
-
{pointMenu || !cover || !triggerEcho ||
|
|
1576
|
+
{pointMenu || !cover || !triggerEcho || coversIcon ? null : (
|
|
1684
1577
|
<TriggerEchoRow
|
|
1685
1578
|
sourceRef={panel.triggerRef}
|
|
1686
1579
|
source={trigger}
|
|
@@ -1701,11 +1594,7 @@ function FloatingPanelWeb({
|
|
|
1701
1594
|
{...(contentPadding !== "none" ? panel.knobProps.panelPadding : undefined)}
|
|
1702
1595
|
{...(contentPadding !== "none" ? panel.knobProps.gapLg : undefined)}
|
|
1703
1596
|
>
|
|
1704
|
-
<OverlayStackProvider zIndex={panelZIndex}>
|
|
1705
|
-
<PanelIconEchoBoxContext.Provider value={echoBox}>
|
|
1706
|
-
{children}
|
|
1707
|
-
</PanelIconEchoBoxContext.Provider>
|
|
1708
|
-
</OverlayStackProvider>
|
|
1597
|
+
<OverlayStackProvider zIndex={panelZIndex}>{children}</OverlayStackProvider>
|
|
1709
1598
|
</View>
|
|
1710
1599
|
<ScrollArrow
|
|
1711
1600
|
direction="down"
|
|
@@ -1713,11 +1602,6 @@ function FloatingPanelWeb({
|
|
|
1713
1602
|
visible={panel.arrowDown}
|
|
1714
1603
|
arrowScrollDirRef={panel.arrowScrollDirRef}
|
|
1715
1604
|
/>
|
|
1716
|
-
{showIconEcho && iconEcho ? (
|
|
1717
|
-
<IconEchoRow>
|
|
1718
|
-
{iconEchoElement(trigger, iconEcho, () => onOpenChange(false), triggerSurface)}
|
|
1719
|
-
</IconEchoRow>
|
|
1720
|
-
) : null}
|
|
1721
1605
|
</YStack>
|
|
1722
1606
|
</Theme>
|
|
1723
1607
|
</PanelPortal>
|
|
@@ -277,7 +277,7 @@ describe("placeOverTrigger (FZ-7830, LC-112 where no sheet may take it)", () =>
|
|
|
277
277
|
});
|
|
278
278
|
});
|
|
279
279
|
|
|
280
|
-
describe("placeOverTrigger pinned:
|
|
280
|
+
describe("placeOverTrigger pinned: a panel stays on its icon trigger (LC-112, FZ-8480)", () => {
|
|
281
281
|
const phone: PanelBounds = { top: 57, left: 10, right: 380, bottom: 800 };
|
|
282
282
|
|
|
283
283
|
it("opens down from the button's top edge where the menu fits", () => {
|
|
@@ -169,10 +169,10 @@ export function placeOverTrigger({
|
|
|
169
169
|
*/
|
|
170
170
|
align?: "start" | "auto";
|
|
171
171
|
/**
|
|
172
|
-
* The menu
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
172
|
+
* The menu covers its icon trigger (LC-112, FZ-8480), so it never slides
|
|
173
|
+
* off the button vertically: it opens down from the button's top edge, or
|
|
174
|
+
* up from its bottom edge where there is more room above, and scrolls what
|
|
175
|
+
* still does not fit.
|
|
176
176
|
*/
|
|
177
177
|
pinned?: boolean;
|
|
178
178
|
}): TriggerPlacement {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FZ-8648: one grabber. A FloatingPanel's phone sheet draws the theme's
|
|
3
|
+
* `sheetGrabber` on the web and on native, with nothing local on top, so it
|
|
4
|
+
* can't drift from SheetModal's (whose spec holds it to the same recipe).
|
|
5
|
+
*/
|
|
6
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
7
|
+
import { sheetGrabber } from "@multiplatform.one/theme";
|
|
8
|
+
import { describe, expect, it, vi } from "vitest";
|
|
9
|
+
import { Text, View } from "tamagui";
|
|
10
|
+
import { FloatingPanel as NativePanel } from "./index.native";
|
|
11
|
+
import { FloatingPanel } from "./index";
|
|
12
|
+
|
|
13
|
+
vi.mock("react-native-web", async (importOriginal) => ({
|
|
14
|
+
...(await importOriginal<typeof import("react-native")>()),
|
|
15
|
+
ActionSheetIOS: undefined,
|
|
16
|
+
Modal: ({ children }: { children: import("react").ReactNode }) => children,
|
|
17
|
+
useWindowDimensions: () => ({ width: 390, height: 844, scale: 3, fontScale: 1 }),
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
const atoms = (node: Element) => String(node.className).split(/\s+/).filter(Boolean);
|
|
21
|
+
|
|
22
|
+
function recipeAtoms() {
|
|
23
|
+
const view = renderWithProviders(<View testID="recipe" {...sheetGrabber} />);
|
|
24
|
+
const list = atoms(view.getByTestId("recipe"));
|
|
25
|
+
view.unmount();
|
|
26
|
+
return list;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe("FloatingPanel sheet grabber (FZ-8648)", () => {
|
|
30
|
+
it("draws the recipe in the native sheet", () => {
|
|
31
|
+
const recipe = recipeAtoms();
|
|
32
|
+
const result = renderWithProviders(
|
|
33
|
+
<NativePanel open onOpenChange={() => {}} trigger={<Text>Open</Text>}>
|
|
34
|
+
<Text>Row</Text>
|
|
35
|
+
</NativePanel>,
|
|
36
|
+
);
|
|
37
|
+
const capsule = result.getByTestId("floating-panel-grabber").firstElementChild as Element;
|
|
38
|
+
expect(atoms(capsule)).toEqual(expect.arrayContaining(recipe));
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("draws the recipe in the web sheet, with no transform", async () => {
|
|
42
|
+
const recipe = recipeAtoms();
|
|
43
|
+
const result = renderWithProviders(
|
|
44
|
+
<FloatingPanel open sheet onOpenChange={() => {}} trigger={<Text>Open</Text>}>
|
|
45
|
+
<Text>Row</Text>
|
|
46
|
+
</FloatingPanel>,
|
|
47
|
+
);
|
|
48
|
+
await result.findByTestId("floating-panel-sheet");
|
|
49
|
+
const handle = result.getByLabelText("Resize");
|
|
50
|
+
expect(atoms(handle)).toEqual(expect.arrayContaining(recipe));
|
|
51
|
+
expect(handle.getAttribute("style") ?? "").not.toMatch(/transform/);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useTouchSurface } from "@multiplatform.one/theme";
|
|
2
|
+
import { CheckGlyph } from "../../shared/CheckGlyph";
|
|
2
3
|
import type { ReactNode } from "react";
|
|
3
4
|
import {
|
|
4
5
|
Fragment,
|
|
@@ -11,13 +12,7 @@ import {
|
|
|
11
12
|
memo,
|
|
12
13
|
} from "react";
|
|
13
14
|
import { useTranslation } from "../../shared/i18n";
|
|
14
|
-
import {
|
|
15
|
-
CaretDownIcon,
|
|
16
|
-
CheckIcon,
|
|
17
|
-
MagnifyingGlassIcon,
|
|
18
|
-
PlusIcon,
|
|
19
|
-
XIcon,
|
|
20
|
-
} from "@phosphor-icons/react";
|
|
15
|
+
import { CaretDownIcon, MagnifyingGlassIcon, PlusIcon, XIcon } from "@phosphor-icons/react";
|
|
21
16
|
import {
|
|
22
17
|
useClick,
|
|
23
18
|
useDismiss,
|
|
@@ -427,7 +422,7 @@ const ComboboxItem = memo(function ComboboxItem({
|
|
|
427
422
|
{option.label}
|
|
428
423
|
</Text>
|
|
429
424
|
)}
|
|
430
|
-
{isSelected && <
|
|
425
|
+
{isSelected && <CheckGlyph />}
|
|
431
426
|
</ComboboxRow>
|
|
432
427
|
);
|
|
433
428
|
});
|
|
@@ -2237,7 +2232,7 @@ function NativeComboboxCore({
|
|
|
2237
2232
|
{option.label}
|
|
2238
2233
|
</Text>
|
|
2239
2234
|
)}
|
|
2240
|
-
{selected && <
|
|
2235
|
+
{selected && <CheckGlyph />}
|
|
2241
2236
|
</View>
|
|
2242
2237
|
);
|
|
2243
2238
|
return (
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { hairline, IconSlot, keyboardFocusRingProps } from "@multiplatform.one/theme";
|
|
2
|
-
import {
|
|
2
|
+
import { CheckGlyph } from "../../shared/CheckGlyph";
|
|
3
3
|
import { useRef, type KeyboardEvent, type ReactNode } from "react";
|
|
4
4
|
import { Pressable } from "react-native";
|
|
5
5
|
import { isWeb, Text, View, XStack, YStack } from "tamagui";
|
|
@@ -100,7 +100,7 @@ export function InlineChoices({
|
|
|
100
100
|
>
|
|
101
101
|
{option.label}
|
|
102
102
|
</Text>
|
|
103
|
-
{selected ? <
|
|
103
|
+
{selected ? <CheckGlyph /> : null}
|
|
104
104
|
</XStack>
|
|
105
105
|
);
|
|
106
106
|
|