@flamingo-stack/openframe-frontend-core 0.0.456 → 0.0.457
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-JHIT44TA.js → chunk-2ZW2ZPDW.js} +2 -2
- package/dist/{chunk-DAEKUR3J.js → chunk-4423DHRX.js} +2 -2
- package/dist/{chunk-LMBPJAQ2.js → chunk-5BKBG653.js} +4 -4
- package/dist/{chunk-A7FTNFBX.cjs → chunk-5XFJG3TC.cjs} +59 -59
- package/dist/{chunk-A7FTNFBX.cjs.map → chunk-5XFJG3TC.cjs.map} +1 -1
- package/dist/{chunk-GC63K4VD.cjs → chunk-AB65PWU2.cjs} +62 -62
- package/dist/{chunk-GC63K4VD.cjs.map → chunk-AB65PWU2.cjs.map} +1 -1
- package/dist/{chunk-2I3GN7WW.js → chunk-AJGZ3YSR.js} +2 -2
- package/dist/{chunk-UHVVNVUE.cjs → chunk-BDTQIIJR.cjs} +31 -31
- package/dist/{chunk-UHVVNVUE.cjs.map → chunk-BDTQIIJR.cjs.map} +1 -1
- package/dist/{chunk-KH5VTGCS.cjs → chunk-C2TDHJBO.cjs} +37 -37
- package/dist/{chunk-KH5VTGCS.cjs.map → chunk-C2TDHJBO.cjs.map} +1 -1
- package/dist/{chunk-INH6SIP5.cjs → chunk-CCT5VCRP.cjs} +9 -9
- package/dist/{chunk-INH6SIP5.cjs.map → chunk-CCT5VCRP.cjs.map} +1 -1
- package/dist/{chunk-6K6LAD6H.cjs → chunk-EOVQVVDJ.cjs} +11 -11
- package/dist/{chunk-6K6LAD6H.cjs.map → chunk-EOVQVVDJ.cjs.map} +1 -1
- package/dist/{chunk-YMGOTPY7.cjs → chunk-FM5DTJPA.cjs} +1519 -1257
- package/dist/chunk-FM5DTJPA.cjs.map +1 -0
- package/dist/{chunk-LAFCXJVT.js → chunk-GJ7BN4MI.js} +4 -4
- package/dist/{chunk-ZQHGSR3H.js → chunk-I7M6KCCS.js} +4 -4
- package/dist/{chunk-VZNJ3RYI.cjs → chunk-KQ36EHE4.cjs} +15 -15
- package/dist/{chunk-VZNJ3RYI.cjs.map → chunk-KQ36EHE4.cjs.map} +1 -1
- package/dist/{chunk-DU6R7XNU.js → chunk-KXIIUE75.js} +2 -2
- package/dist/{chunk-UEKCD6WV.js → chunk-NSL5MNS4.js} +5103 -4841
- package/dist/chunk-NSL5MNS4.js.map +1 -0
- package/dist/{chunk-U27TXTAK.js → chunk-O7F7RZFN.js} +4 -4
- package/dist/{chunk-YLTY4Z4B.js → chunk-R5IQJXA3.js} +2 -2
- package/dist/{chunk-F3IBBAKV.js → chunk-RSW42GTZ.js} +2 -2
- package/dist/{chunk-GQZGCMRF.cjs → chunk-SQ3CP2IV.cjs} +7 -7
- package/dist/{chunk-GQZGCMRF.cjs.map → chunk-SQ3CP2IV.cjs.map} +1 -1
- package/dist/{chunk-DYBATZJP.cjs → chunk-U4APSAAR.cjs} +5 -5
- package/dist/{chunk-DYBATZJP.cjs.map → chunk-U4APSAAR.cjs.map} +1 -1
- package/dist/{chunk-UXKSOJR7.js → chunk-WXDEMTLD.js} +2 -2
- package/dist/{chunk-F2CCUPKC.cjs → chunk-YCIVMKRS.cjs} +26 -26
- package/dist/{chunk-F2CCUPKC.cjs.map → chunk-YCIVMKRS.cjs.map} +1 -1
- package/dist/{chunk-TXS2AMFV.cjs → chunk-YHB4MNUX.cjs} +26 -26
- package/dist/{chunk-TXS2AMFV.cjs.map → chunk-YHB4MNUX.cjs.map} +1 -1
- package/dist/components/case-studies/index.cjs +8 -8
- package/dist/components/case-studies/index.js +2 -2
- package/dist/components/chat/chat-message-list.d.ts.map +1 -1
- package/dist/components/chat/chat-sidebar.d.ts.map +1 -1
- package/dist/components/chat/chat-ticket-list.d.ts.map +1 -1
- package/dist/components/chat/guide-welcome.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +2 -2
- package/dist/components/chat/index.js +1 -1
- package/dist/components/chat/mingo-chat-history.d.ts.map +1 -1
- package/dist/components/chat/mingo-welcome.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +3 -3
- package/dist/components/contact/index.js +2 -2
- package/dist/components/docs/index.cjs +5 -5
- package/dist/components/docs/index.js +4 -4
- package/dist/components/embeds/index.cjs +3 -3
- package/dist/components/embeds/index.js +2 -2
- package/dist/components/faq/index.cjs +3 -3
- package/dist/components/faq/index.js +2 -2
- package/dist/components/features/index.cjs +2 -2
- package/dist/components/features/index.js +1 -1
- package/dist/components/features/notifications/notification-drawer.d.ts.map +1 -1
- package/dist/components/features/time-tracker/time-tracker-panel.d.ts.map +1 -1
- package/dist/components/help-center-pages/index.cjs +20 -20
- package/dist/components/help-center-pages/index.js +11 -11
- package/dist/components/index.cjs +135 -129
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +15 -9
- package/dist/components/index.js.map +1 -1
- package/dist/components/layout/page-container.d.ts.map +1 -1
- package/dist/components/navigation/app-layout-drawer.d.ts +1 -1
- package/dist/components/navigation/index.cjs +2 -2
- package/dist/components/navigation/index.js +1 -1
- package/dist/components/onboarding-guides/index.cjs +5 -5
- package/dist/components/onboarding-guides/index.js +4 -4
- package/dist/components/related-content/index.cjs +3 -3
- package/dist/components/related-content/index.js +2 -2
- package/dist/components/tickets/index.cjs +5 -5
- package/dist/components/tickets/index.js +4 -4
- package/dist/components/ui/drawer.d.ts +1 -1
- package/dist/components/ui/drawer.d.ts.map +1 -1
- package/dist/components/ui/index.cjs +8 -2
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.d.ts +1 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +7 -1
- package/dist/components/ui/marquee-wall.d.ts.map +1 -1
- package/dist/components/ui/menubar.d.ts +3 -6
- package/dist/components/ui/menubar.d.ts.map +1 -1
- package/dist/components/ui/modal-v2.d.ts.map +1 -1
- package/dist/components/ui/modal.d.ts.map +1 -1
- package/dist/components/ui/overlay-scroll-area.d.ts +59 -0
- package/dist/components/ui/overlay-scroll-area.d.ts.map +1 -0
- package/dist/index.cjs +8 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +7 -1
- package/package.json +3 -1
- package/src/components/chat/chat-message-list.tsx +7 -6
- package/src/components/chat/chat-sidebar.tsx +9 -4
- package/src/components/chat/chat-ticket-list.tsx +8 -2
- package/src/components/chat/guide-welcome.tsx +6 -4
- package/src/components/chat/mingo-chat-history.tsx +6 -4
- package/src/components/chat/mingo-welcome.tsx +6 -4
- package/src/components/features/notifications/notification-drawer.tsx +6 -4
- package/src/components/features/time-tracker/time-tracker-panel.tsx +5 -3
- package/src/components/layout/page-container.tsx +13 -5
- package/src/components/ui/drawer.tsx +8 -3
- package/src/components/ui/index.ts +1 -0
- package/src/components/ui/marquee-wall.tsx +28 -4
- package/src/components/ui/modal-v2.tsx +6 -2
- package/src/components/ui/modal.tsx +6 -2
- package/src/components/ui/overlay-scroll-area.tsx +219 -0
- package/src/stories/OverlayScrollArea.stories.tsx +52 -0
- package/src/styles/index.css +2 -0
- package/src/styles/overlay-scrollbars-theme.css +19 -0
- package/src/styles/vendor-overlayscrollbars.css +673 -0
- package/dist/chunk-UEKCD6WV.js.map +0 -1
- package/dist/chunk-YMGOTPY7.cjs.map +0 -1
- /package/dist/{chunk-JHIT44TA.js.map → chunk-2ZW2ZPDW.js.map} +0 -0
- /package/dist/{chunk-DAEKUR3J.js.map → chunk-4423DHRX.js.map} +0 -0
- /package/dist/{chunk-LMBPJAQ2.js.map → chunk-5BKBG653.js.map} +0 -0
- /package/dist/{chunk-2I3GN7WW.js.map → chunk-AJGZ3YSR.js.map} +0 -0
- /package/dist/{chunk-LAFCXJVT.js.map → chunk-GJ7BN4MI.js.map} +0 -0
- /package/dist/{chunk-ZQHGSR3H.js.map → chunk-I7M6KCCS.js.map} +0 -0
- /package/dist/{chunk-DU6R7XNU.js.map → chunk-KXIIUE75.js.map} +0 -0
- /package/dist/{chunk-U27TXTAK.js.map → chunk-O7F7RZFN.js.map} +0 -0
- /package/dist/{chunk-YLTY4Z4B.js.map → chunk-R5IQJXA3.js.map} +0 -0
- /package/dist/{chunk-F3IBBAKV.js.map → chunk-RSW42GTZ.js.map} +0 -0
- /package/dist/{chunk-UXKSOJR7.js.map → chunk-WXDEMTLD.js.map} +0 -0
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { useRef, useEffect, useLayoutEffect, useImperativeHandle, forwardRef } from "react"
|
|
4
4
|
import { useStickToBottom } from "use-stick-to-bottom"
|
|
5
5
|
import { cn } from "../../utils/cn"
|
|
6
|
+
import { OverlayScrollArea } from '../ui/overlay-scroll-area'
|
|
6
7
|
import { ChatMessageEnhanced } from "./chat-message-enhanced"
|
|
7
8
|
import { ChatMessageListSkeleton } from "./chat-message-skeleton"
|
|
8
9
|
import { DotsLoaderIcon } from "../icons-v2-generated"
|
|
@@ -529,10 +530,11 @@ const ChatMessageList = forwardRef<HTMLDivElement, ChatMessageListProps>(
|
|
|
529
530
|
|
|
530
531
|
return (
|
|
531
532
|
<div className="relative flex-1 min-h-0 flex flex-col">
|
|
532
|
-
<
|
|
533
|
-
|
|
534
|
-
className=
|
|
535
|
-
|
|
533
|
+
<OverlayScrollArea
|
|
534
|
+
viewportRef={setScrollRef}
|
|
535
|
+
className="flex-1 min-h-0"
|
|
536
|
+
contentClassName={cn(
|
|
537
|
+
"flex flex-col overflow-x-hidden",
|
|
536
538
|
// `overscroll-contain` (default ON, opt-out via `overscrollContain={false}`):
|
|
537
539
|
// reaching the top/bottom of the thread must NOT chain the wheel/
|
|
538
540
|
// touch scroll to the page behind the chat — e.g. the company-hub
|
|
@@ -542,7 +544,6 @@ const ChatMessageList = forwardRef<HTMLDivElement, ChatMessageListProps>(
|
|
|
542
544
|
// the surrounding page keeps scrolling normally when the pointer is
|
|
543
545
|
// over the (non-interactive) thread.
|
|
544
546
|
overscrollContain && "overscroll-contain",
|
|
545
|
-
"scrollbar-thin scrollbar-track-transparent scrollbar-thumb-ods-border/30 hover:scrollbar-thumb-ods-text-secondary/30",
|
|
546
547
|
className,
|
|
547
548
|
)}
|
|
548
549
|
{...props}
|
|
@@ -597,7 +598,7 @@ const ChatMessageList = forwardRef<HTMLDivElement, ChatMessageListProps>(
|
|
|
597
598
|
)
|
|
598
599
|
})}
|
|
599
600
|
</div>
|
|
600
|
-
</
|
|
601
|
+
</OverlayScrollArea>
|
|
601
602
|
|
|
602
603
|
{/* Footer-pinned streaming loader — outside the scroller so it
|
|
603
604
|
doesn't jitter as the streaming message grows. Color is set
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { forwardRef, useRef, useEffect } from "react"
|
|
2
2
|
import { cn } from "../../utils/cn"
|
|
3
3
|
import { Button } from "../ui/button"
|
|
4
|
+
import { OverlayScrollArea } from '../ui/overlay-scroll-area'
|
|
4
5
|
import { ChatPlusIcon, ChatsIcon } from "../icons-v2-generated"
|
|
5
6
|
import { Chevron02RightIcon } from "../icons-v2-generated"
|
|
6
7
|
import { ChatSidebarSkeleton, DialogListItemSkeleton } from "./chat-sidebar-skeleton"
|
|
@@ -154,12 +155,16 @@ const ChatSidebar = forwardRef<HTMLDivElement, ChatSidebarProps>(
|
|
|
154
155
|
</div>
|
|
155
156
|
) : children ? (
|
|
156
157
|
/* Custom children content */
|
|
157
|
-
<
|
|
158
|
+
<OverlayScrollArea className="flex-1 min-h-0" contentClassName="overscroll-contain">
|
|
158
159
|
{children}
|
|
159
|
-
</
|
|
160
|
+
</OverlayScrollArea>
|
|
160
161
|
) : (
|
|
161
162
|
/* Dialogs List */
|
|
162
|
-
<
|
|
163
|
+
<OverlayScrollArea
|
|
164
|
+
viewportRef={scrollContainerRef}
|
|
165
|
+
className="flex-1 min-h-0"
|
|
166
|
+
contentClassName="overscroll-contain"
|
|
167
|
+
>
|
|
163
168
|
<div className="flex flex-col">
|
|
164
169
|
{dialogs.map((dialog) => (
|
|
165
170
|
<DialogListItem
|
|
@@ -183,7 +188,7 @@ const ChatSidebar = forwardRef<HTMLDivElement, ChatSidebarProps>(
|
|
|
183
188
|
</div>
|
|
184
189
|
)}
|
|
185
190
|
</div>
|
|
186
|
-
</
|
|
191
|
+
</OverlayScrollArea>
|
|
187
192
|
)}
|
|
188
193
|
</div>
|
|
189
194
|
</div>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import * as React from 'react'
|
|
4
4
|
import { cn } from '../../utils/cn'
|
|
5
5
|
import { ScrollFadeOverlay, useScrollFade } from '../ui/scroll-fade'
|
|
6
|
+
import { OverlayScrollArea } from '../ui/overlay-scroll-area'
|
|
6
7
|
import { ChatTicketItem, type ChatTicketItemData } from './entity-cards/chat-ticket-item'
|
|
7
8
|
|
|
8
9
|
export interface ChatTicketListProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
@@ -46,7 +47,12 @@ const ChatTicketList = React.forwardRef<HTMLDivElement, ChatTicketListProps>(
|
|
|
46
47
|
!fadeBottom && "border-b rounded-b-md",
|
|
47
48
|
)}
|
|
48
49
|
>
|
|
49
|
-
<
|
|
50
|
+
<OverlayScrollArea
|
|
51
|
+
viewportRef={scrollRef}
|
|
52
|
+
className="h-full"
|
|
53
|
+
contentClassName="overscroll-contain"
|
|
54
|
+
onScroll={updateFade}
|
|
55
|
+
>
|
|
50
56
|
{tickets.map((ticket) => (
|
|
51
57
|
<ChatTicketItem
|
|
52
58
|
key={ticket.id}
|
|
@@ -54,7 +60,7 @@ const ChatTicketList = React.forwardRef<HTMLDivElement, ChatTicketListProps>(
|
|
|
54
60
|
onClick={onTicketClick}
|
|
55
61
|
/>
|
|
56
62
|
))}
|
|
57
|
-
</
|
|
63
|
+
</OverlayScrollArea>
|
|
58
64
|
|
|
59
65
|
{/* Scroll-fade overlays — tinted with the page background so edge
|
|
60
66
|
tickets fade into the surface behind the list in BOTH themes
|
|
@@ -4,6 +4,7 @@ import * as React from 'react'
|
|
|
4
4
|
import { cn } from '../../utils/cn'
|
|
5
5
|
import { MingoIcon } from '../icons'
|
|
6
6
|
import { ScrollFadeOverlay, useScrollFade } from '../ui/scroll-fade'
|
|
7
|
+
import { OverlayScrollArea } from '../ui/overlay-scroll-area'
|
|
7
8
|
import { Skeleton } from '../ui/skeleton'
|
|
8
9
|
import { QuickActionWall } from './quick-action-wall'
|
|
9
10
|
import { EntityIcon } from '../icon-display'
|
|
@@ -141,10 +142,11 @@ export function GuideWelcome({
|
|
|
141
142
|
{/* Greeting + slash-command list share one scroll region; `relative` so
|
|
142
143
|
the edge fades can overlay it. */}
|
|
143
144
|
<div className="relative flex flex-1 min-h-0 flex-col">
|
|
144
|
-
<
|
|
145
|
-
|
|
145
|
+
<OverlayScrollArea
|
|
146
|
+
viewportRef={scrollRef}
|
|
146
147
|
onScroll={updateScrollFade}
|
|
147
|
-
className="flex
|
|
148
|
+
className="flex-1 min-h-0"
|
|
149
|
+
contentClassName="flex min-h-full flex-col gap-[var(--spacing-system-m)] overscroll-contain"
|
|
148
150
|
>
|
|
149
151
|
{/* Greeting grows to fill (`flex-1`) so the slash-command list stays
|
|
150
152
|
anchored below it — but its content is anchored at the TOP of the
|
|
@@ -187,7 +189,7 @@ export function GuideWelcome({
|
|
|
187
189
|
</div>
|
|
188
190
|
|
|
189
191
|
{children}
|
|
190
|
-
</
|
|
192
|
+
</OverlayScrollArea>
|
|
191
193
|
|
|
192
194
|
{/* Edge scroll-fades — visible only when content is hidden beyond them. */}
|
|
193
195
|
<ScrollFadeOverlay edge="top" visible={fadeTop} className="h-12" />
|
|
@@ -5,6 +5,7 @@ import { cn } from '../../utils/cn'
|
|
|
5
5
|
import { ActionsMenuDropdown, type ActionsMenuItem } from '../ui/actions-menu'
|
|
6
6
|
import { Button } from '../ui/button'
|
|
7
7
|
import { ScrollFadeOverlay, useScrollFade } from '../ui/scroll-fade'
|
|
8
|
+
import { OverlayScrollArea } from '../ui/overlay-scroll-area'
|
|
8
9
|
import { Ellipsis01Icon, SearchXmarkIcon } from '../icons-v2-generated'
|
|
9
10
|
import { ChatListEmptyState } from './chat-list-empty-state'
|
|
10
11
|
import type { DialogItem } from './types/component.types'
|
|
@@ -338,10 +339,11 @@ export function MingoChatHistory({
|
|
|
338
339
|
{/* Scroll region — the search INPUT now lives in the panel header
|
|
339
340
|
(Figma 116:51217), so the list is just the grouped rows + fades. */}
|
|
340
341
|
<div className="relative flex flex-1 min-h-0 flex-col">
|
|
341
|
-
<
|
|
342
|
-
|
|
342
|
+
<OverlayScrollArea
|
|
343
|
+
viewportRef={scrollRef}
|
|
343
344
|
onScroll={updateFade}
|
|
344
|
-
className="flex
|
|
345
|
+
className="flex-1 min-h-0"
|
|
346
|
+
contentClassName="flex flex-col gap-[var(--spacing-system-m)] overscroll-contain"
|
|
345
347
|
>
|
|
346
348
|
{noSearchResults ? (
|
|
347
349
|
// No search matches — same centred glyph + title + caption layout as
|
|
@@ -374,7 +376,7 @@ export function MingoChatHistory({
|
|
|
374
376
|
))
|
|
375
377
|
)}
|
|
376
378
|
{hasMore ? <div ref={sentinelRef} className="h-px shrink-0" /> : null}
|
|
377
|
-
</
|
|
379
|
+
</OverlayScrollArea>
|
|
378
380
|
|
|
379
381
|
{/* Scroll-fade — only while content is hidden in that direction. */}
|
|
380
382
|
<ScrollFadeOverlay edge="top" visible={fadeTop} color="var(--color-bg-card)" className="h-12" />
|
|
@@ -8,6 +8,7 @@ import { QuickActionChipButton } from './quick-action-chip'
|
|
|
8
8
|
import { QuickActionWall } from './quick-action-wall'
|
|
9
9
|
import { Button } from '../ui/button'
|
|
10
10
|
import { ScrollFadeOverlay, useScrollFade } from '../ui/scroll-fade'
|
|
11
|
+
import { OverlayScrollArea } from '../ui/overlay-scroll-area'
|
|
11
12
|
import { XmarkIcon } from '../icons-v2-generated/signs-and-symbols/xmark-icon'
|
|
12
13
|
import {
|
|
13
14
|
CompassIcon,
|
|
@@ -239,10 +240,11 @@ export function MingoWelcome({
|
|
|
239
240
|
input. The wrapper is `relative` so the scroll-fade gradients can
|
|
240
241
|
overlay the top/bottom edges. */}
|
|
241
242
|
<div className="relative flex flex-1 min-h-0 flex-col">
|
|
242
|
-
<
|
|
243
|
-
|
|
243
|
+
<OverlayScrollArea
|
|
244
|
+
viewportRef={scrollRef}
|
|
244
245
|
onScroll={updateScrollFade}
|
|
245
|
-
className="flex
|
|
246
|
+
className="flex-1 min-h-0"
|
|
247
|
+
contentClassName="flex min-h-full flex-col gap-[var(--spacing-system-m)] overscroll-contain"
|
|
246
248
|
>
|
|
247
249
|
{/* Greeting — grows to fill (`flex-1`) so it centres vertically,
|
|
248
250
|
keeping the grid anchored at the bottom of the scroll area. Default
|
|
@@ -261,7 +263,7 @@ export function MingoWelcome({
|
|
|
261
263
|
<p className="text-h4 text-ods-text-secondary">{subtitle}</p>
|
|
262
264
|
</div>
|
|
263
265
|
</div>
|
|
264
|
-
</
|
|
266
|
+
</OverlayScrollArea>
|
|
265
267
|
|
|
266
268
|
{/* Edge scroll-fades — visible only when content is hidden beyond them.
|
|
267
269
|
Fade into the panel's dark `ods-bg` surface (the default color), matching
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import { useEffect, useRef } from 'react'
|
|
4
|
+
import { OverlayScrollArea } from '../../ui/overlay-scroll-area'
|
|
4
5
|
import { BellOffIcon } from '../../icons-v2-generated/interface/bell-off-icon'
|
|
5
6
|
import { ClockHistoryIcon, ArrowRightUpIcon } from '../../icons-v2-generated'
|
|
6
7
|
import { useAppLayoutDrawerContainer } from '../../navigation/app-layout-context'
|
|
@@ -189,9 +190,10 @@ function DrawerScrollList({
|
|
|
189
190
|
|
|
190
191
|
const isEmpty = unreadNotifications.length === 0
|
|
191
192
|
return (
|
|
192
|
-
<
|
|
193
|
-
|
|
194
|
-
className="flex
|
|
193
|
+
<OverlayScrollArea
|
|
194
|
+
viewportRef={scrollRef}
|
|
195
|
+
className="flex-1 min-h-0"
|
|
196
|
+
contentClassName="flex flex-col gap-[var(--spacing-system-xs)] px-[var(--spacing-system-m)]"
|
|
195
197
|
>
|
|
196
198
|
{isEmpty && !isLoadingMore ? (
|
|
197
199
|
<EmptyState />
|
|
@@ -214,7 +216,7 @@ function DrawerScrollList({
|
|
|
214
216
|
{loadMore && hasMore && <div ref={sentinelRef} className="h-1" aria-hidden="true" />}
|
|
215
217
|
</>
|
|
216
218
|
)}
|
|
217
|
-
</
|
|
219
|
+
</OverlayScrollArea>
|
|
218
220
|
)
|
|
219
221
|
}
|
|
220
222
|
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
XmarkIcon,
|
|
22
22
|
} from '../../icons-v2-generated'
|
|
23
23
|
import { useTrackerClock } from './use-tracker-clock'
|
|
24
|
+
import { OverlayScrollArea } from '../../ui/overlay-scroll-area'
|
|
24
25
|
import type { TimeTrackerData, TimeTrackerEntry, TimeTrackerStatus } from './types'
|
|
25
26
|
|
|
26
27
|
interface CustomerAutocompleteOption extends AutocompleteOption {
|
|
@@ -149,11 +150,12 @@ export function TimeTrackerPanel({
|
|
|
149
150
|
const visibleEntries = lastEntries.slice(0, 3)
|
|
150
151
|
|
|
151
152
|
return (
|
|
152
|
-
<
|
|
153
|
+
<OverlayScrollArea
|
|
153
154
|
className={cn(
|
|
154
|
-
'
|
|
155
|
+
'max-h-[calc(100vh-6rem)] w-full rounded-md border border-ods-border bg-ods-card',
|
|
155
156
|
className,
|
|
156
157
|
)}
|
|
158
|
+
contentClassName="relative flex flex-col gap-[var(--spacing-system-l)] p-[var(--spacing-system-m)]"
|
|
157
159
|
>
|
|
158
160
|
<Button
|
|
159
161
|
variant="transparent"
|
|
@@ -314,7 +316,7 @@ export function TimeTrackerPanel({
|
|
|
314
316
|
<Button variant="outline" fullWidth onClick={onClose} className="md:hidden">
|
|
315
317
|
Close
|
|
316
318
|
</Button>
|
|
317
|
-
</
|
|
319
|
+
</OverlayScrollArea>
|
|
318
320
|
)
|
|
319
321
|
}
|
|
320
322
|
|
|
@@ -4,6 +4,7 @@ import React from 'react'
|
|
|
4
4
|
import { cn } from '../../utils/cn'
|
|
5
5
|
import type { ActionsMenuGroup } from '../ui/actions-menu'
|
|
6
6
|
import { PageActions, type PageActionButton } from '../ui/page-actions'
|
|
7
|
+
import { OverlayScrollArea } from '../ui/overlay-scroll-area'
|
|
7
8
|
import { BackButton } from './back-button'
|
|
8
9
|
|
|
9
10
|
// Legacy interface for backward compatibility (layout version)
|
|
@@ -393,7 +394,7 @@ function renderAdvancedPageContainer({
|
|
|
393
394
|
|
|
394
395
|
switch (variant) {
|
|
395
396
|
case 'detail':
|
|
396
|
-
return cn('flex-1
|
|
397
|
+
return cn('flex-1 min-h-0', mobilePadding, contentClassName)
|
|
397
398
|
case 'list':
|
|
398
399
|
return cn('flex flex-col gap-4 md:gap-6', mobilePadding, contentClassName)
|
|
399
400
|
case 'form':
|
|
@@ -407,10 +408,17 @@ function renderAdvancedPageContainer({
|
|
|
407
408
|
return (
|
|
408
409
|
<div className={getContainerClasses()}>
|
|
409
410
|
{renderHeader()}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
411
|
+
|
|
412
|
+
{variant === 'detail' ? (
|
|
413
|
+
// The only scrolling variant — standardized overlay scrollbar.
|
|
414
|
+
<OverlayScrollArea className={getContentClasses()}>
|
|
415
|
+
{children}
|
|
416
|
+
</OverlayScrollArea>
|
|
417
|
+
) : (
|
|
418
|
+
<div className={getContentClasses()}>
|
|
419
|
+
{children}
|
|
420
|
+
</div>
|
|
421
|
+
)}
|
|
414
422
|
</div>
|
|
415
423
|
)
|
|
416
424
|
}
|
|
@@ -7,6 +7,7 @@ import { X } from "lucide-react"
|
|
|
7
7
|
|
|
8
8
|
import { cn } from "../../utils/cn"
|
|
9
9
|
import { useHeaderHeight } from "../../hooks/ui/use-header-height"
|
|
10
|
+
import { OverlayScrollArea } from "./overlay-scroll-area"
|
|
10
11
|
|
|
11
12
|
/** Unified overlay backdrop — dimmed, no blur. Single source of truth for
|
|
12
13
|
* every full-screen backdrop (Drawer, AppLayoutDrawer, MobileBurgerMenu,
|
|
@@ -530,12 +531,16 @@ DrawerDescription.displayName = "DrawerDescription"
|
|
|
530
531
|
|
|
531
532
|
const DrawerBody = ({
|
|
532
533
|
className,
|
|
534
|
+
children,
|
|
533
535
|
...props
|
|
534
536
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
535
|
-
<
|
|
536
|
-
className={cn("flex
|
|
537
|
+
<OverlayScrollArea
|
|
538
|
+
className={cn("flex-1 min-h-0", className)}
|
|
539
|
+
contentClassName="flex flex-col gap-4"
|
|
537
540
|
{...props}
|
|
538
|
-
|
|
541
|
+
>
|
|
542
|
+
{children}
|
|
543
|
+
</OverlayScrollArea>
|
|
539
544
|
)
|
|
540
545
|
DrawerBody.displayName = "DrawerBody"
|
|
541
546
|
|
|
@@ -551,13 +551,24 @@ export function MarqueeWall({
|
|
|
551
551
|
// tap's action. A new press is unambiguously a new intent.
|
|
552
552
|
suppressClickRef.current = false
|
|
553
553
|
dragStartRef.current = { coord: axis === 'y' ? e.clientY : e.clientX, pos: posRef.current }
|
|
554
|
-
|
|
554
|
+
// NOTE deliberately NO setPointerCapture here — capture is taken LAZILY in
|
|
555
|
+
// `onDragPointerMove`, once the press is proven to be a drag. Capturing on
|
|
556
|
+
// pointerdown retargets the compatibility mouse events (mouseup, and hence
|
|
557
|
+
// `click`, which fires at the nearest common ancestor of down/up) from the
|
|
558
|
+
// pressed element to this container — so a plain tap on a quick-action chip
|
|
559
|
+
// never reaches the chip's own onClick and the whole wall reads as dead.
|
|
555
560
|
}, [marqueeMounted, axis, posRef])
|
|
556
561
|
|
|
557
562
|
const onDragPointerMove = React.useCallback((e: React.PointerEvent) => {
|
|
558
563
|
if (!draggingRef.current) return
|
|
559
564
|
const delta = (axis === 'y' ? e.clientY : e.clientX) - dragStartRef.current.coord
|
|
560
|
-
if (Math.abs(delta) > 3
|
|
565
|
+
if (Math.abs(delta) > 3 && !dragMovedRef.current) {
|
|
566
|
+
dragMovedRef.current = true
|
|
567
|
+
// Past the threshold this IS a drag: capture so the gesture keeps
|
|
568
|
+
// tracking once the pointer leaves the wall. Retargeting click is now
|
|
569
|
+
// WANTED — the trailing synthetic click is suppressed below anyway.
|
|
570
|
+
try { containerRef.current?.setPointerCapture(e.pointerId) } catch { /* best-effort */ }
|
|
571
|
+
}
|
|
561
572
|
// Track follows the pointer. `applyPos` maps pos→translate as `-pos`
|
|
562
573
|
// (forward) / `pos-wrap` (reverse), so a rightward/downward drag (delta > 0)
|
|
563
574
|
// must DECREASE pos on a forward wall and INCREASE it on a reverse one.
|
|
@@ -574,9 +585,22 @@ export function MarqueeWall({
|
|
|
574
585
|
// doesn't fire the chip's action.
|
|
575
586
|
if (dragMovedRef.current) suppressClickRef.current = true
|
|
576
587
|
dragSuppressUntilRef.current = performance.now() + DRAG_RESUME_MS
|
|
577
|
-
|
|
588
|
+
// Only ever captured past the drag threshold (see `onDragPointerMove`).
|
|
589
|
+
if (dragMovedRef.current) {
|
|
590
|
+
try { containerRef.current?.releasePointerCapture(e.pointerId) } catch { /* best-effort */ }
|
|
591
|
+
}
|
|
578
592
|
}, [])
|
|
579
593
|
|
|
594
|
+
// Pre-threshold presses hold NO pointer capture, so a pointer that leaves the
|
|
595
|
+
// wall before becoming a drag would never deliver its `pointerup` here and
|
|
596
|
+
// `draggingRef` would stay stuck true — freezing the marquee forever. End the
|
|
597
|
+
// gesture on leave; a captured (real) drag keeps running, capture guarantees
|
|
598
|
+
// its own pointerup.
|
|
599
|
+
const onDragPointerLeave = React.useCallback((e: React.PointerEvent) => {
|
|
600
|
+
onPointerLeave(e)
|
|
601
|
+
if (draggingRef.current && !dragMovedRef.current) draggingRef.current = false
|
|
602
|
+
}, [onPointerLeave])
|
|
603
|
+
|
|
580
604
|
const onDragClickCapture = React.useCallback((e: React.MouseEvent) => {
|
|
581
605
|
if (suppressClickRef.current) {
|
|
582
606
|
suppressClickRef.current = false
|
|
@@ -645,7 +669,7 @@ export function MarqueeWall({
|
|
|
645
669
|
style={dragScroll && marqueeMounted ? { touchAction: axis === 'y' ? 'pan-x' : 'pan-y' } : undefined}
|
|
646
670
|
data-marquee-track={trackId}
|
|
647
671
|
onPointerEnter={onPointerEnter}
|
|
648
|
-
onPointerLeave={onPointerLeave}
|
|
672
|
+
onPointerLeave={dragScroll ? onDragPointerLeave : onPointerLeave}
|
|
649
673
|
onPointerDown={dragScroll ? onDragPointerDown : undefined}
|
|
650
674
|
onPointerMove={dragScroll ? onDragPointerMove : undefined}
|
|
651
675
|
onPointerUp={dragScroll ? onDragPointerUp : undefined}
|
|
@@ -5,6 +5,7 @@ import { useEffect, useState } from "react"
|
|
|
5
5
|
import { usePreventScroll } from "@react-aria/overlays"
|
|
6
6
|
import { XmarkIcon } from "../icons-v2-generated"
|
|
7
7
|
import { cn } from "../../utils/cn"
|
|
8
|
+
import { OverlayScrollArea } from "./overlay-scroll-area"
|
|
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.
|
|
@@ -131,9 +132,12 @@ Modal.displayName = "ModalV2"
|
|
|
131
132
|
|
|
132
133
|
const ModalContent = React.forwardRef<HTMLDivElement, ModalContentProps>(
|
|
133
134
|
({ children, className }, ref) => (
|
|
134
|
-
<
|
|
135
|
+
<OverlayScrollArea
|
|
136
|
+
viewportRef={ref}
|
|
137
|
+
className={cn("flex-1 min-h-0", className)}
|
|
138
|
+
>
|
|
135
139
|
{children}
|
|
136
|
-
</
|
|
140
|
+
</OverlayScrollArea>
|
|
137
141
|
)
|
|
138
142
|
)
|
|
139
143
|
ModalContent.displayName = "ModalV2Content"
|
|
@@ -4,6 +4,7 @@ import * as React from "react"
|
|
|
4
4
|
import { useEffect } from "react"
|
|
5
5
|
import { usePreventScroll } from "@react-aria/overlays"
|
|
6
6
|
import { cn } from "../../utils/cn"
|
|
7
|
+
import { OverlayScrollArea } from "./overlay-scroll-area"
|
|
7
8
|
|
|
8
9
|
interface ModalProps {
|
|
9
10
|
isOpen: boolean
|
|
@@ -82,9 +83,12 @@ Modal.displayName = "Modal"
|
|
|
82
83
|
/** @deprecated Use ModalV2Content from './modal-v2' instead. */
|
|
83
84
|
const ModalContent = React.forwardRef<HTMLDivElement, ModalContentProps>(
|
|
84
85
|
({ children, className }, ref) => (
|
|
85
|
-
<
|
|
86
|
+
<OverlayScrollArea
|
|
87
|
+
viewportRef={ref}
|
|
88
|
+
className={cn("min-h-0 flex-1", className)}
|
|
89
|
+
>
|
|
86
90
|
{children}
|
|
87
|
-
</
|
|
91
|
+
</OverlayScrollArea>
|
|
88
92
|
)
|
|
89
93
|
)
|
|
90
94
|
ModalContent.displayName = "ModalContent"
|