@flamingo-stack/openframe-frontend-core 0.0.754 → 0.0.756
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/{chunk-AG4HR6Z6.cjs → chunk-2ANICXS7.cjs} +16 -16
- package/dist/{chunk-U4I3QR2A.cjs → chunk-4YL4Y3BV.cjs} +11 -11
- package/dist/{chunk-YSFOYBYC.cjs → chunk-57JA37HP.cjs} +428 -411
- package/dist/{chunk-TPJTFN7O.cjs → chunk-7KPU7RGS.cjs} +73 -73
- package/dist/{chunk-MGF3FUKD.cjs → chunk-AKK3EO37.cjs} +4 -1
- package/dist/{chunk-3GG3QAPT.cjs → chunk-AXBVN5SW.cjs} +63 -57
- package/dist/{chunk-JXACH52M.cjs → chunk-BTIYXBA2.cjs} +4 -4
- package/dist/{chunk-BLZIUELR.cjs → chunk-CYDWQYIQ.cjs} +22 -22
- package/dist/{chunk-P6F6PHVK.cjs → chunk-EFTUFJS2.cjs} +4 -4
- package/dist/{chunk-LVO7FALW.cjs → chunk-F64VMOIB.cjs} +5 -5
- package/dist/{chunk-MOEILCEX.cjs → chunk-KFUC2XF7.cjs} +7 -7
- package/dist/{chunk-GQYCVZJI.cjs → chunk-KNNJ4WLF.cjs} +4 -4
- package/dist/{chunk-BQQ3JGEO.cjs → chunk-KSU3CXKY.cjs} +3 -3
- package/dist/{chunk-YRULLK7N.cjs → chunk-LOFDIDSD.cjs} +8 -2
- package/dist/{chunk-EDSFLB7J.cjs → chunk-MBQTLZAG.cjs} +11 -11
- package/dist/{chunk-TBDVF4SN.cjs → chunk-MDXZMTCK.cjs} +38 -38
- package/dist/{chunk-FAFFWYEH.cjs → chunk-MR5KMPSE.cjs} +6 -6
- package/dist/{chunk-ZNV5FE4T.cjs → chunk-PUK27ZB6.cjs} +22 -22
- package/dist/{chunk-RTQN35EP.cjs → chunk-QKFJ6ORK.cjs} +21 -21
- package/dist/{chunk-SDF5UUTE.cjs → chunk-QTYSYEHK.cjs} +74 -74
- package/dist/{chunk-OGKV5NOP.cjs → chunk-TAEEGNFL.cjs} +42 -42
- package/dist/{chunk-DW5OKTUP.cjs → chunk-VOXDBCBV.cjs} +36 -36
- package/dist/{chunk-UNRNLSG4.cjs → chunk-VUSXDMCE.cjs} +2 -2
- package/dist/{chunk-IVAAQSOU.cjs → chunk-W5MEHJRQ.cjs} +6 -6
- package/dist/{cloud-tenants-5OTPO7FL.cjs → cloud-tenants-NOZGXQZY.cjs} +10 -10
- package/dist/components/case-studies/index.cjs +20 -20
- package/dist/components/chat/embeddable-chat.js +11 -6
- package/dist/components/chat/index.cjs +7 -7
- package/dist/components/contact/index.cjs +11 -11
- package/dist/components/context-menu.d.ts +2 -2
- package/dist/components/context-menu.d.ts.map +1 -1
- package/dist/components/context-menu.js +19 -12
- package/dist/components/docs/index.cjs +14 -14
- package/dist/components/embeds/index.cjs +11 -11
- package/dist/components/faq/index.cjs +12 -12
- package/dist/components/features/index.cjs +10 -10
- package/dist/components/features/time-tracker/time-tracker-header-button.d.ts.map +1 -1
- package/dist/components/features/time-tracker/time-tracker-header-button.js +3 -1
- package/dist/components/help-center-pages/index.cjs +71 -71
- package/dist/components/index.cjs +44 -44
- package/dist/components/meeting-scheduler/index.cjs +35 -35
- package/dist/components/navigation/index.cjs +13 -13
- package/dist/components/onboarding-guides/index.cjs +13 -13
- package/dist/components/popover.d.ts.map +1 -1
- package/dist/components/popover.js +3 -1
- package/dist/components/product-demo/index.cjs +9 -9
- package/dist/components/tickets/index.cjs +15 -15
- package/dist/components/ui/date-picker.d.ts.map +1 -1
- package/dist/components/ui/date-picker.js +9 -4
- package/dist/components/ui/dropdown-menu.d.ts +2 -2
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
- package/dist/components/ui/dropdown-menu.js +4 -1
- package/dist/components/ui/file-manager/index.cjs +6 -6
- package/dist/components/ui/index.cjs +10 -10
- package/dist/components/ui/menubar.d.ts +2 -2
- package/dist/components/ui/menubar.d.ts.map +1 -1
- package/dist/components/ui/menubar.js +22 -15
- package/dist/components/ui/modal-v2.d.ts.map +1 -1
- package/dist/components/ui/modal-v2.js +5 -2
- package/dist/components/ui/searchable-select.d.ts.map +1 -1
- package/dist/components/ui/searchable-select.js +3 -1
- package/dist/components/ui/select.d.ts.map +1 -1
- package/dist/components/ui/select.js +27 -23
- package/dist/components/ui/tag-select-dropdown.d.ts.map +1 -1
- package/dist/components/ui/tag-select-dropdown.js +3 -1
- package/dist/{devices-MBGMD7BO.cjs → devices-M4KBTOTC.cjs} +11 -11
- package/dist/{embeddable-chat-CMEHSDV7.cjs → embeddable-chat-KGJVVG2V.cjs} +88 -83
- package/dist/index.cjs +14 -14
- package/dist/{knowledge-LO5RK6PM.cjs → knowledge-VVF6CJEG.cjs} +11 -11
- package/dist/{logs-QRGJSZ4G.cjs → logs-7E6HBJ55.cjs} +18 -18
- package/dist/{policies-OIQDO6F5.cjs → policies-UMZLJTBD.cjs} +14 -14
- package/dist/{remote-session-57DGC4X3.cjs → remote-session-SKNXYG6K.cjs} +7 -7
- package/dist/{scripts-XULUNPDV.cjs → scripts-XVNAEYCH.cjs} +17 -17
- package/dist/{software-update-SRF55434.cjs → software-update-U43ZFHMC.cjs} +14 -14
- package/dist/{tickets-board-EP6L3BSV.cjs → tickets-board-B2FH7Z4B.cjs} +9 -9
- package/eslint-config/base.js +7 -1
- package/eslint-config/popup-portal.js +68 -0
- package/package.json +1 -1
- package/src/components/chat/embeddable-chat.tsx +13 -6
- package/src/components/context-menu.tsx +20 -13
- package/src/components/features/time-tracker/time-tracker-header-button.tsx +3 -1
- package/src/components/popover.tsx +3 -1
- package/src/components/ui/date-picker.tsx +9 -4
- package/src/components/ui/dropdown-menu.tsx +4 -1
- package/src/components/ui/menubar.tsx +23 -16
- package/src/components/ui/modal-v2.tsx +17 -3
- package/src/components/ui/searchable-select.tsx +3 -1
- package/src/components/ui/select.tsx +28 -24
- package/src/components/ui/tag-select-dropdown.tsx +3 -1
|
@@ -2320,8 +2320,10 @@ function EmbeddableChatInner({
|
|
|
2320
2320
|
// archived one, one still loading or blocked as above) a new chat opens with
|
|
2321
2321
|
// it: adding prompts under a pending approval or a running turn would mix
|
|
2322
2322
|
// two conversations. A new chat with nothing sent yet gets another exchange.
|
|
2323
|
-
|
|
2324
|
-
|
|
2323
|
+
// `newChat`: asked from a screen with no chat open (the archive list), where
|
|
2324
|
+
// the conversation open before it is not the one the user is looking at.
|
|
2325
|
+
const showWhatToAsk = (content: WhatToAskContent, newChat = false) => {
|
|
2326
|
+
if (!newChat && activeDialogId && hasConversation && !isViewingArchived && !isMessagesLoading && !isChatBlocked) {
|
|
2325
2327
|
whatToAsk.ask('current', content);
|
|
2326
2328
|
return;
|
|
2327
2329
|
}
|
|
@@ -2354,16 +2356,16 @@ function EmbeddableChatInner({
|
|
|
2354
2356
|
showWhatToAskRef.current = showWhatToAsk;
|
|
2355
2357
|
});
|
|
2356
2358
|
const whatToAskPendingRef = useRef(false);
|
|
2357
|
-
const requestWhatToAsk = () => {
|
|
2359
|
+
const requestWhatToAsk = (newChat: boolean) => {
|
|
2358
2360
|
if (!whatToAskContent) return;
|
|
2359
2361
|
if (typeof whatToAskContent !== 'function') {
|
|
2360
|
-
showWhatToAsk(whatToAskContent);
|
|
2362
|
+
showWhatToAsk(whatToAskContent, newChat);
|
|
2361
2363
|
return;
|
|
2362
2364
|
}
|
|
2363
2365
|
if (whatToAskPendingRef.current) return;
|
|
2364
2366
|
whatToAskPendingRef.current = true;
|
|
2365
2367
|
whatToAskContent()
|
|
2366
|
-
.then(content => showWhatToAskRef.current(content))
|
|
2368
|
+
.then(content => showWhatToAskRef.current(content, newChat))
|
|
2367
2369
|
.catch((err: unknown) => console.error('[EmbeddableChat] whatToAsk failed:', err))
|
|
2368
2370
|
.finally(() => {
|
|
2369
2371
|
whatToAskPendingRef.current = false;
|
|
@@ -2538,7 +2540,12 @@ function EmbeddableChatInner({
|
|
|
2538
2540
|
onOpenArchive: headerOnOpenArchive && (archiveOpen ? closeArchive : headerOnOpenArchive),
|
|
2539
2541
|
archiveActive: archiveOpen,
|
|
2540
2542
|
// The suggestions a new chat opens on, unless the host has a surface of its own.
|
|
2541
|
-
|
|
2543
|
+
// From the archive list no chat is on screen, even though the one open
|
|
2544
|
+
// before it is still the active dialog: that click opens a new chat.
|
|
2545
|
+
onWhatToAsk: () => {
|
|
2546
|
+
const fromArchive = archiveOpen;
|
|
2547
|
+
leaveArchiveThen(onWhatToAsk ?? (whatToAskContent ? () => requestWhatToAsk(fromArchive) : handleNewChat))();
|
|
2548
|
+
},
|
|
2542
2549
|
statusOf: dialogStatusOf,
|
|
2543
2550
|
onRequestRename: mingoCaps.canRename ? setRenameTarget : undefined,
|
|
2544
2551
|
onRequestArchive: mingoCaps.canArchive ? setArchiveTarget : undefined,
|
|
@@ -5,6 +5,7 @@ import { Check, ChevronRight, Circle } from 'lucide-react';
|
|
|
5
5
|
import { type ComponentPropsWithoutRef, type ElementRef, type HTMLAttributes, forwardRef } from 'react';
|
|
6
6
|
|
|
7
7
|
import { cn } from '../utils/cn';
|
|
8
|
+
import { usePortalContainer } from './ui/portal-container';
|
|
8
9
|
|
|
9
10
|
const ContextMenu = ContextMenuPrimitive.Root;
|
|
10
11
|
|
|
@@ -12,7 +13,10 @@ const ContextMenuTrigger = ContextMenuPrimitive.Trigger;
|
|
|
12
13
|
|
|
13
14
|
const ContextMenuGroup = ContextMenuPrimitive.Group;
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
function ContextMenuPortal({ container, ...props }: ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Portal>) {
|
|
17
|
+
const active = usePortalContainer();
|
|
18
|
+
return <ContextMenuPrimitive.Portal container={container ?? active ?? undefined} {...props} />;
|
|
19
|
+
}
|
|
16
20
|
|
|
17
21
|
const ContextMenuSub = ContextMenuPrimitive.Sub;
|
|
18
22
|
|
|
@@ -57,18 +61,21 @@ ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
|
|
|
57
61
|
const ContextMenuContent = forwardRef<
|
|
58
62
|
ElementRef<typeof ContextMenuPrimitive.Content>,
|
|
59
63
|
ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>
|
|
60
|
-
>(({ className, ...props }, ref) =>
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
className
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
64
|
+
>(({ className, ...props }, ref) => {
|
|
65
|
+
const container = usePortalContainer();
|
|
66
|
+
return (
|
|
67
|
+
<ContextMenuPrimitive.Portal container={container ?? undefined}>
|
|
68
|
+
<ContextMenuPrimitive.Content
|
|
69
|
+
ref={ref}
|
|
70
|
+
className={cn(
|
|
71
|
+
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
|
72
|
+
className,
|
|
73
|
+
)}
|
|
74
|
+
{...props}
|
|
75
|
+
/>
|
|
76
|
+
</ContextMenuPrimitive.Portal>
|
|
77
|
+
);
|
|
78
|
+
});
|
|
72
79
|
ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
|
|
73
80
|
|
|
74
81
|
const ContextMenuItem = forwardRef<
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from '../../navigation/app-layout-context';
|
|
12
12
|
import { HeaderButton } from '../../navigation/header-button';
|
|
13
13
|
import { OVERLAY_BACKDROP_CLASS } from '../../ui/drawer';
|
|
14
|
+
import { usePortalContainer } from '../../ui/portal-container';
|
|
14
15
|
import { useOptionalTimeTracker } from './time-tracker-context';
|
|
15
16
|
import { TimeTrackerPanel } from './time-tracker-panel';
|
|
16
17
|
import { useTrackerClock } from './use-tracker-clock';
|
|
@@ -39,6 +40,7 @@ export function TimeTrackerHeaderButton({ className, disabled }: TimeTrackerHead
|
|
|
39
40
|
accumulatedMs: ctx?.accumulatedMs,
|
|
40
41
|
});
|
|
41
42
|
const layoutContainer = useAppLayoutDrawerContainer();
|
|
43
|
+
const portalContainer = usePortalContainer();
|
|
42
44
|
const coordination = useAppLayoutDrawerCoordination();
|
|
43
45
|
|
|
44
46
|
const isOpen = ctx?.isOpen ?? false;
|
|
@@ -129,7 +131,7 @@ export function TimeTrackerHeaderButton({ className, disabled }: TimeTrackerHead
|
|
|
129
131
|
)}
|
|
130
132
|
/>
|
|
131
133
|
</PopoverPrimitive.Portal>
|
|
132
|
-
<PopoverPrimitive.Portal>
|
|
134
|
+
<PopoverPrimitive.Portal container={portalContainer ?? undefined}>
|
|
133
135
|
<PopoverPrimitive.Content
|
|
134
136
|
align="end"
|
|
135
137
|
sideOffset={8}
|
|
@@ -5,6 +5,7 @@ import { type ComponentPropsWithoutRef, type ElementRef, forwardRef } from 'reac
|
|
|
5
5
|
|
|
6
6
|
import { useKeyboardCollisionPadding } from '../hooks/ui/use-keyboard-collision-padding';
|
|
7
7
|
import { cn } from '../utils/cn';
|
|
8
|
+
import { usePortalContainer } from './ui/portal-container';
|
|
8
9
|
|
|
9
10
|
const Popover = PopoverPrimitive.Root;
|
|
10
11
|
|
|
@@ -18,8 +19,9 @@ const PopoverContent = forwardRef<
|
|
|
18
19
|
// box — is positioned against a collision viewport that does not know the
|
|
19
20
|
// software keyboard exists. See useKeyboardCollisionPadding.
|
|
20
21
|
const keyboardPadding = useKeyboardCollisionPadding();
|
|
22
|
+
const container = usePortalContainer();
|
|
21
23
|
return (
|
|
22
|
-
<PopoverPrimitive.Portal>
|
|
24
|
+
<PopoverPrimitive.Portal container={container ?? undefined}>
|
|
23
25
|
<PopoverPrimitive.Content
|
|
24
26
|
ref={ref}
|
|
25
27
|
align={align}
|
|
@@ -9,6 +9,7 @@ import { cn } from '../../utils/cn';
|
|
|
9
9
|
import { formatDateWithTimezone, VIEWER_TIMEZONE } from '../../utils/format';
|
|
10
10
|
import { Button } from './button';
|
|
11
11
|
import { FieldWrapper } from './field-wrapper';
|
|
12
|
+
import { usePortalContainer } from './portal-container';
|
|
12
13
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './select';
|
|
13
14
|
import type { SortDirection } from './sort-column-item';
|
|
14
15
|
|
|
@@ -677,6 +678,7 @@ export function DatePicker(props: DatePickerProps) {
|
|
|
677
678
|
} = props;
|
|
678
679
|
|
|
679
680
|
const [open, setOpen] = useState(false);
|
|
681
|
+
const portalContainer = usePortalContainer();
|
|
680
682
|
const isInvalid = invalid || !!error;
|
|
681
683
|
|
|
682
684
|
const displayValue = useMemo(() => {
|
|
@@ -730,7 +732,7 @@ export function DatePicker(props: DatePickerProps) {
|
|
|
730
732
|
</button>
|
|
731
733
|
</Popover.Trigger>
|
|
732
734
|
|
|
733
|
-
<Popover.Portal>
|
|
735
|
+
<Popover.Portal container={portalContainer ?? undefined}>
|
|
734
736
|
<Popover.Content
|
|
735
737
|
className={cn(
|
|
736
738
|
'z-[9999]',
|
|
@@ -809,6 +811,7 @@ export function DatePickerInput(props: DatePickerInputProps) {
|
|
|
809
811
|
invalid = false,
|
|
810
812
|
} = props;
|
|
811
813
|
const [open, setOpen] = useState(false);
|
|
814
|
+
const portalContainer = usePortalContainer();
|
|
812
815
|
const isInvalid = invalid || !!error;
|
|
813
816
|
|
|
814
817
|
const displayValue = value ? formatDate(value) : '';
|
|
@@ -913,7 +916,7 @@ export function DatePickerInput(props: DatePickerInputProps) {
|
|
|
913
916
|
</button>
|
|
914
917
|
</Popover.Trigger>
|
|
915
918
|
|
|
916
|
-
<Popover.Portal>
|
|
919
|
+
<Popover.Portal container={portalContainer ?? undefined}>
|
|
917
920
|
<Popover.Content
|
|
918
921
|
className={cn(
|
|
919
922
|
'z-[9999]',
|
|
@@ -1057,6 +1060,7 @@ export function DatePickerInputSimple(props: DatePickerInputSimpleProps) {
|
|
|
1057
1060
|
invalid = false,
|
|
1058
1061
|
} = props;
|
|
1059
1062
|
const [open, setOpen] = useState(false);
|
|
1063
|
+
const portalContainer = usePortalContainer();
|
|
1060
1064
|
const isInvalid = invalid || !!error;
|
|
1061
1065
|
|
|
1062
1066
|
const displayValue = value ? formatDate(value) : '';
|
|
@@ -1139,7 +1143,7 @@ export function DatePickerInputSimple(props: DatePickerInputSimpleProps) {
|
|
|
1139
1143
|
</button>
|
|
1140
1144
|
</Popover.Trigger>
|
|
1141
1145
|
|
|
1142
|
-
<Popover.Portal>
|
|
1146
|
+
<Popover.Portal container={portalContainer ?? undefined}>
|
|
1143
1147
|
<Popover.Content
|
|
1144
1148
|
className={cn(
|
|
1145
1149
|
'z-[9999]',
|
|
@@ -1350,6 +1354,7 @@ export function DateFilterMenu({
|
|
|
1350
1354
|
'aria-label': ariaLabel = 'Open date filter',
|
|
1351
1355
|
}: DateFilterMenuProps) {
|
|
1352
1356
|
const [open, setOpen] = useState(false);
|
|
1357
|
+
const portalContainer = usePortalContainer();
|
|
1353
1358
|
|
|
1354
1359
|
// Drafted selection — initialized from props each time the menu opens.
|
|
1355
1360
|
const [draftSort, setDraftSort] = useState<SortDirection>(sort);
|
|
@@ -1412,7 +1417,7 @@ export function DateFilterMenu({
|
|
|
1412
1417
|
)}
|
|
1413
1418
|
</Popover.Trigger>
|
|
1414
1419
|
|
|
1415
|
-
<Popover.Portal>
|
|
1420
|
+
<Popover.Portal container={portalContainer ?? undefined}>
|
|
1416
1421
|
<Popover.Content
|
|
1417
1422
|
className={cn(
|
|
1418
1423
|
'z-[9999] w-80 max-w-[calc(100vw-2rem)]',
|
|
@@ -13,7 +13,10 @@ const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
|
13
13
|
|
|
14
14
|
const DropdownMenuGroup = DropdownMenuPrimitive.Group;
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
function DropdownMenuPortal({ container, ...props }: ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Portal>) {
|
|
17
|
+
const active = usePortalContainer();
|
|
18
|
+
return <DropdownMenuPrimitive.Portal container={container ?? active ?? undefined} {...props} />;
|
|
19
|
+
}
|
|
17
20
|
|
|
18
21
|
const DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
|
19
22
|
|
|
@@ -5,12 +5,16 @@ import { Check, ChevronRight, Circle } from 'lucide-react';
|
|
|
5
5
|
import { type ComponentPropsWithoutRef, type ElementRef, type HTMLAttributes, forwardRef } from 'react';
|
|
6
6
|
|
|
7
7
|
import { cn } from '../../utils/cn';
|
|
8
|
+
import { usePortalContainer } from './portal-container';
|
|
8
9
|
|
|
9
10
|
const MenubarMenu = MenubarPrimitive.Menu;
|
|
10
11
|
|
|
11
12
|
const MenubarGroup = MenubarPrimitive.Group;
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
function MenubarPortal({ container, ...props }: ComponentPropsWithoutRef<typeof MenubarPrimitive.Portal>) {
|
|
15
|
+
const active = usePortalContainer();
|
|
16
|
+
return <MenubarPrimitive.Portal container={container ?? active ?? undefined} {...props} />;
|
|
17
|
+
}
|
|
14
18
|
|
|
15
19
|
const MenubarSub = MenubarPrimitive.Sub;
|
|
16
20
|
|
|
@@ -82,21 +86,24 @@ MenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName;
|
|
|
82
86
|
const MenubarContent = forwardRef<
|
|
83
87
|
ElementRef<typeof MenubarPrimitive.Content>,
|
|
84
88
|
ComponentPropsWithoutRef<typeof MenubarPrimitive.Content>
|
|
85
|
-
>(({ className, align = 'start', alignOffset = -4, sideOffset = 8, ...props }, ref) =>
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
className
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
89
|
+
>(({ className, align = 'start', alignOffset = -4, sideOffset = 8, ...props }, ref) => {
|
|
90
|
+
const container = usePortalContainer();
|
|
91
|
+
return (
|
|
92
|
+
<MenubarPrimitive.Portal container={container ?? undefined}>
|
|
93
|
+
<MenubarPrimitive.Content
|
|
94
|
+
ref={ref}
|
|
95
|
+
align={align}
|
|
96
|
+
alignOffset={alignOffset}
|
|
97
|
+
sideOffset={sideOffset}
|
|
98
|
+
className={cn(
|
|
99
|
+
'z-50 min-w-[12rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
|
100
|
+
className,
|
|
101
|
+
)}
|
|
102
|
+
{...props}
|
|
103
|
+
/>
|
|
104
|
+
</MenubarPrimitive.Portal>
|
|
105
|
+
);
|
|
106
|
+
});
|
|
100
107
|
MenubarContent.displayName = MenubarPrimitive.Content.displayName;
|
|
101
108
|
|
|
102
109
|
const MenubarItem = forwardRef<
|
|
@@ -5,6 +5,7 @@ import { RemoveScroll } from 'react-remove-scroll';
|
|
|
5
5
|
import { ViewportBreakpoints } from '../../hooks/ui/use-content-breakpoint';
|
|
6
6
|
import { cn } from '../../utils/cn';
|
|
7
7
|
import { XmarkIcon } from '../icons-v2-generated';
|
|
8
|
+
import { CollisionBoundaryContext, PortalContainerContext } from './portal-container';
|
|
8
9
|
|
|
9
10
|
// Duration of the open/close animation in ms — keep in sync with the
|
|
10
11
|
// `duration-200` utilities applied to the backdrop and panel below.
|
|
@@ -66,8 +67,9 @@ interface ModalTwoColumnProps {
|
|
|
66
67
|
// TOP one may contain focus, or they fight each other.
|
|
67
68
|
const modalStack: symbol[] = [];
|
|
68
69
|
|
|
69
|
-
// Radix popups (Select/DropdownMenu/Popover content) PORTAL
|
|
70
|
-
//
|
|
70
|
+
// Radix popups (Select/DropdownMenu/Popover content) PORTAL out of the panel —
|
|
71
|
+
// to <body> or the modal's own portal host — so a dropdown opened from inside
|
|
72
|
+
// the modal focuses nodes OUTSIDE the panel.
|
|
71
73
|
// Focus landing there is NOT an escape — yanking it back (containFocus /
|
|
72
74
|
// reasserts / Tab trap) fights Radix's own item-focus management and strands
|
|
73
75
|
// stale `data-highlighted` on items it never got to blur-clean (observed:
|
|
@@ -82,6 +84,7 @@ const Modal = forwardRef<HTMLDivElement, ModalProps>(
|
|
|
82
84
|
({ isOpen, onClose, children, className, size = 'default' }, ref) => {
|
|
83
85
|
// Keep the modal mounted while the exit animation plays.
|
|
84
86
|
const [isMounted, setIsMounted] = useState(isOpen);
|
|
87
|
+
const [portalHost, setPortalHost] = useState<HTMLDivElement | null>(null);
|
|
85
88
|
const panelRef = useRef<HTMLDivElement | null>(null);
|
|
86
89
|
const restoreFocusRef = useRef<HTMLElement | null>(null);
|
|
87
90
|
const stackIdRef = useRef<symbol>(Symbol('modal'));
|
|
@@ -307,9 +310,20 @@ const Modal = forwardRef<HTMLDivElement, ModalProps>(
|
|
|
307
310
|
aria-modal="true"
|
|
308
311
|
>
|
|
309
312
|
<ModalContext.Provider value={{ onClose }}>
|
|
310
|
-
|
|
313
|
+
{/* Menus and tooltips opened inside portal into this layer, so they
|
|
314
|
+
stack over the panel instead of under the `z-[1300]` overlay. The
|
|
315
|
+
boundary resets too: a modal follows the window, not the surface
|
|
316
|
+
it was opened from. */}
|
|
317
|
+
<PortalContainerContext.Provider value={portalHost}>
|
|
318
|
+
<CollisionBoundaryContext.Provider value={null}>
|
|
319
|
+
<ViewportBreakpoints>{children}</ViewportBreakpoints>
|
|
320
|
+
</CollisionBoundaryContext.Provider>
|
|
321
|
+
</PortalContainerContext.Provider>
|
|
311
322
|
</ModalContext.Provider>
|
|
312
323
|
</div>
|
|
324
|
+
{/* Outside the panel: its open/close zoom is a transform, which would
|
|
325
|
+
anchor the menus' `position: fixed` to the panel. */}
|
|
326
|
+
<div ref={setPortalHost} className="contents" />
|
|
313
327
|
</div>
|
|
314
328
|
</RemoveScroll>
|
|
315
329
|
);
|
|
@@ -8,6 +8,7 @@ import { CheckIcon, SearchIcon } from '../icons-v2-generated';
|
|
|
8
8
|
import { Chevron02DownIcon } from '../icons-v2-generated/arrows/chevron-02-down-icon';
|
|
9
9
|
import { FieldWrapper } from './field-wrapper';
|
|
10
10
|
import { Input } from './input';
|
|
11
|
+
import { usePortalContainer } from './portal-container';
|
|
11
12
|
|
|
12
13
|
export interface SearchableSelectOption {
|
|
13
14
|
value: string;
|
|
@@ -112,6 +113,7 @@ export function SearchableSelect(allProps: SearchableSelectProps) {
|
|
|
112
113
|
const [isOpen, setIsOpen] = useState(false);
|
|
113
114
|
const [search, setSearch] = useState('');
|
|
114
115
|
const keyboardPadding = useKeyboardCollisionPadding();
|
|
116
|
+
const portalContainer = usePortalContainer();
|
|
115
117
|
|
|
116
118
|
// Clear the query on close, while rendering rather than from an effect: the
|
|
117
119
|
// popover closes and reopens without unmounting, so an effect left the
|
|
@@ -189,7 +191,7 @@ export function SearchableSelect(allProps: SearchableSelectProps) {
|
|
|
189
191
|
) : (
|
|
190
192
|
triggerElement
|
|
191
193
|
)}
|
|
192
|
-
<PopoverPrimitive.Portal>
|
|
194
|
+
<PopoverPrimitive.Portal container={portalContainer ?? undefined}>
|
|
193
195
|
<PopoverPrimitive.Content
|
|
194
196
|
align={align}
|
|
195
197
|
sideOffset={6}
|
|
@@ -7,6 +7,7 @@ import { cn } from '../../utils/cn';
|
|
|
7
7
|
import { Chevron02DownIcon } from '../icons-v2-generated/arrows/chevron-02-down-icon';
|
|
8
8
|
import { CheckIcon } from '../icons-v2-generated/signs-and-symbols/check-icon';
|
|
9
9
|
import { FieldWrapper } from './field-wrapper';
|
|
10
|
+
import { usePortalContainer } from './portal-container';
|
|
10
11
|
|
|
11
12
|
const Select = SelectPrimitive.Root;
|
|
12
13
|
|
|
@@ -114,30 +115,33 @@ SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayNam
|
|
|
114
115
|
const SelectContent = forwardRef<
|
|
115
116
|
ComponentRef<typeof SelectPrimitive.Content>,
|
|
116
117
|
ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
|
117
|
-
>(({ className, children, position = 'popper', ...props }, ref) =>
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
'data-[side=bottom]:
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
118
|
+
>(({ className, children, position = 'popper', ...props }, ref) => {
|
|
119
|
+
const container = usePortalContainer();
|
|
120
|
+
return (
|
|
121
|
+
<SelectPrimitive.Portal container={container ?? undefined}>
|
|
122
|
+
<SelectPrimitive.Content
|
|
123
|
+
ref={ref}
|
|
124
|
+
className={cn(
|
|
125
|
+
'relative z-[9999] max-h-96 overflow-hidden rounded-[4px] border border-ods-border bg-ods-card text-ods-text-primary',
|
|
126
|
+
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
|
127
|
+
position === 'popper' &&
|
|
128
|
+
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
|
|
129
|
+
className,
|
|
130
|
+
)}
|
|
131
|
+
position={position}
|
|
132
|
+
style={{
|
|
133
|
+
width: 'var(--radix-select-trigger-width)',
|
|
134
|
+
minWidth: 'var(--radix-select-trigger-width)',
|
|
135
|
+
}}
|
|
136
|
+
{...props}
|
|
137
|
+
>
|
|
138
|
+
<SelectScrollUpButton />
|
|
139
|
+
<SelectPrimitive.Viewport className="w-full">{children}</SelectPrimitive.Viewport>
|
|
140
|
+
<SelectScrollDownButton />
|
|
141
|
+
</SelectPrimitive.Content>
|
|
142
|
+
</SelectPrimitive.Portal>
|
|
143
|
+
);
|
|
144
|
+
});
|
|
141
145
|
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
142
146
|
|
|
143
147
|
const SelectLabel = forwardRef<
|
|
@@ -7,6 +7,7 @@ import { cn } from '../../utils/cn';
|
|
|
7
7
|
import { CheckIcon, PlusIcon, SearchIcon, TrashIcon } from '../icons-v2-generated';
|
|
8
8
|
import { Button } from './button';
|
|
9
9
|
import { Input } from './input';
|
|
10
|
+
import { usePortalContainer } from './portal-container';
|
|
10
11
|
|
|
11
12
|
export interface TagSelectOption {
|
|
12
13
|
id: string;
|
|
@@ -61,6 +62,7 @@ export function TagSelectDropdown({
|
|
|
61
62
|
const [isOpen, setIsOpen] = useState(false);
|
|
62
63
|
const [search, setSearch] = useState('');
|
|
63
64
|
const keyboardPadding = useKeyboardCollisionPadding();
|
|
65
|
+
const portalContainer = usePortalContainer();
|
|
64
66
|
|
|
65
67
|
// Clear the query on close, while rendering rather than from an effect: the
|
|
66
68
|
// popover closes and reopens without unmounting, so an effect left the
|
|
@@ -110,7 +112,7 @@ export function TagSelectDropdown({
|
|
|
110
112
|
{triggerLabel}
|
|
111
113
|
</Button>
|
|
112
114
|
</PopoverPrimitive.Trigger>
|
|
113
|
-
<PopoverPrimitive.Portal>
|
|
115
|
+
<PopoverPrimitive.Portal container={portalContainer ?? undefined}>
|
|
114
116
|
<PopoverPrimitive.Content
|
|
115
117
|
align={align}
|
|
116
118
|
sideOffset={6}
|