@flamingo-stack/openframe-frontend-core 0.0.458 → 0.0.459-snapshot.20260721100450
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-YV2YA3QH.cjs → chunk-2KRAHL2J.cjs} +31 -31
- package/dist/{chunk-YV2YA3QH.cjs.map → chunk-2KRAHL2J.cjs.map} +1 -1
- package/dist/{chunk-KIIOBK7G.cjs → chunk-32N6U2Z2.cjs} +26 -26
- package/dist/{chunk-KIIOBK7G.cjs.map → chunk-32N6U2Z2.cjs.map} +1 -1
- package/dist/{chunk-R5QYMUKN.js → chunk-3SFYW3J7.js} +2 -2
- package/dist/{chunk-ZHQQRYMB.js → chunk-5AUOHZWP.js} +4 -4
- package/dist/{chunk-HWTUVLYB.js → chunk-5IX4BNIY.js} +2 -2
- package/dist/{chunk-ZDJ4ZUQ4.cjs → chunk-6NACOLUM.cjs} +37 -37
- package/dist/{chunk-ZDJ4ZUQ4.cjs.map → chunk-6NACOLUM.cjs.map} +1 -1
- package/dist/{chunk-WGJPTFRH.js → chunk-6R3NA5WS.js} +2 -2
- package/dist/{chunk-QL7ODLJA.js → chunk-722A62GL.js} +4 -4
- package/dist/{chunk-L676XVP4.cjs → chunk-7VNAK2TM.cjs} +7 -7
- package/dist/{chunk-L676XVP4.cjs.map → chunk-7VNAK2TM.cjs.map} +1 -1
- package/dist/{chunk-IDKDOQZL.js → chunk-AQNZOW6H.js} +2 -2
- package/dist/{chunk-H7ETLG65.js → chunk-BOPT23N4.js} +4 -4
- package/dist/{chunk-FTXDIDNX.cjs → chunk-GTJJ4Y7Z.cjs} +15 -15
- package/dist/{chunk-FTXDIDNX.cjs.map → chunk-GTJJ4Y7Z.cjs.map} +1 -1
- package/dist/{chunk-MKLP2SOZ.cjs → chunk-HFTBMWAO.cjs} +1221 -1380
- package/dist/chunk-HFTBMWAO.cjs.map +1 -0
- package/dist/{chunk-7IRPMNRL.cjs → chunk-IMG46R5G.cjs} +59 -59
- package/dist/{chunk-7IRPMNRL.cjs.map → chunk-IMG46R5G.cjs.map} +1 -1
- package/dist/{chunk-YQBPIUZU.js → chunk-ITCV37Q2.js} +2 -2
- package/dist/{chunk-DQ3EHM6G.cjs → chunk-KG6VKWRF.cjs} +9 -9
- package/dist/{chunk-DQ3EHM6G.cjs.map → chunk-KG6VKWRF.cjs.map} +1 -1
- package/dist/{chunk-XUNJILJT.cjs → chunk-KJOM3JWD.cjs} +62 -62
- package/dist/{chunk-XUNJILJT.cjs.map → chunk-KJOM3JWD.cjs.map} +1 -1
- package/dist/{chunk-5USSSRAL.cjs → chunk-MK5PLTDE.cjs} +26 -26
- package/dist/{chunk-5USSSRAL.cjs.map → chunk-MK5PLTDE.cjs.map} +1 -1
- package/dist/{chunk-U2YDR5DT.js → chunk-NWHCBXRQ.js} +2 -2
- package/dist/{chunk-VTQSB6QB.cjs → chunk-NZNF7RCQ.cjs} +5 -5
- package/dist/{chunk-VTQSB6QB.cjs.map → chunk-NZNF7RCQ.cjs.map} +1 -1
- package/dist/{chunk-KQGFKG6Y.js → chunk-OMY4PRE3.js} +2 -2
- package/dist/{chunk-TNLFAJPA.js → chunk-XFH7PMGS.js} +4746 -4905
- package/dist/chunk-XFH7PMGS.js.map +1 -0
- package/dist/{chunk-6B27O3ZB.js → chunk-YWMHHI3V.js} +4 -4
- package/dist/{chunk-LDAOPWXZ.cjs → chunk-ZODNSYZC.cjs} +11 -11
- package/dist/{chunk-LDAOPWXZ.cjs.map → chunk-ZODNSYZC.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/chart.d.ts +1 -1
- 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 +5 -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 +5 -1
- package/dist/components/chat/mingo-welcome.d.ts.map +1 -1
- package/dist/components/chat/quick-action-wall.d.ts +16 -6
- package/dist/components/chat/quick-action-wall.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 +129 -135
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +9 -15
- 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 +2 -8
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.d.ts +0 -1
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +1 -7
- package/dist/components/ui/modal-v2.d.ts.map +1 -1
- package/dist/components/ui/modal.d.ts.map +1 -1
- package/dist/index.cjs +2 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -7
- package/package.json +1 -3
- package/src/components/chat/chat-message-list.tsx +6 -7
- package/src/components/chat/chat-sidebar.tsx +4 -9
- package/src/components/chat/chat-ticket-list.tsx +2 -8
- package/src/components/chat/embeddable-chat.tsx +6 -0
- package/src/components/chat/guide-welcome.tsx +10 -6
- package/src/components/chat/mingo-chat-history.tsx +4 -6
- package/src/components/chat/mingo-welcome.tsx +10 -6
- package/src/components/chat/quick-action-wall.tsx +53 -8
- package/src/components/features/notifications/notification-drawer.tsx +4 -8
- package/src/components/features/time-tracker/time-tracker-panel.tsx +3 -11
- package/src/components/layout/page-container.tsx +5 -17
- package/src/components/ui/drawer.tsx +3 -8
- package/src/components/ui/index.ts +0 -1
- package/src/components/ui/modal-v2.tsx +2 -12
- package/src/components/ui/modal.tsx +2 -9
- package/src/stories/QuickActionWall.stories.tsx +65 -0
- package/src/styles/index.css +0 -2
- package/dist/chunk-MKLP2SOZ.cjs.map +0 -1
- package/dist/chunk-TNLFAJPA.js.map +0 -1
- package/dist/components/ui/overlay-scroll-area.d.ts +0 -59
- package/dist/components/ui/overlay-scroll-area.d.ts.map +0 -1
- package/src/components/ui/overlay-scroll-area.tsx +0 -219
- package/src/stories/OverlayScrollArea.stories.tsx +0 -52
- package/src/styles/overlay-scrollbars-theme.css +0 -19
- package/src/styles/vendor-overlayscrollbars.css +0 -673
- /package/dist/{chunk-R5QYMUKN.js.map → chunk-3SFYW3J7.js.map} +0 -0
- /package/dist/{chunk-ZHQQRYMB.js.map → chunk-5AUOHZWP.js.map} +0 -0
- /package/dist/{chunk-HWTUVLYB.js.map → chunk-5IX4BNIY.js.map} +0 -0
- /package/dist/{chunk-WGJPTFRH.js.map → chunk-6R3NA5WS.js.map} +0 -0
- /package/dist/{chunk-QL7ODLJA.js.map → chunk-722A62GL.js.map} +0 -0
- /package/dist/{chunk-IDKDOQZL.js.map → chunk-AQNZOW6H.js.map} +0 -0
- /package/dist/{chunk-H7ETLG65.js.map → chunk-BOPT23N4.js.map} +0 -0
- /package/dist/{chunk-YQBPIUZU.js.map → chunk-ITCV37Q2.js.map} +0 -0
- /package/dist/{chunk-U2YDR5DT.js.map → chunk-NWHCBXRQ.js.map} +0 -0
- /package/dist/{chunk-KQGFKG6Y.js.map → chunk-OMY4PRE3.js.map} +0 -0
- /package/dist/{chunk-6B27O3ZB.js.map → chunk-YWMHHI3V.js.map} +0 -0
|
@@ -3,7 +3,6 @@
|
|
|
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'
|
|
7
6
|
import { ChatTicketItem, type ChatTicketItemData } from './entity-cards/chat-ticket-item'
|
|
8
7
|
|
|
9
8
|
export interface ChatTicketListProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
@@ -47,12 +46,7 @@ const ChatTicketList = React.forwardRef<HTMLDivElement, ChatTicketListProps>(
|
|
|
47
46
|
!fadeBottom && "border-b rounded-b-md",
|
|
48
47
|
)}
|
|
49
48
|
>
|
|
50
|
-
<
|
|
51
|
-
viewportRef={scrollRef}
|
|
52
|
-
className="h-full"
|
|
53
|
-
contentClassName="overscroll-contain"
|
|
54
|
-
onScroll={updateFade}
|
|
55
|
-
>
|
|
49
|
+
<div ref={scrollRef} className="overflow-y-auto overscroll-contain h-full" onScroll={updateFade}>
|
|
56
50
|
{tickets.map((ticket) => (
|
|
57
51
|
<ChatTicketItem
|
|
58
52
|
key={ticket.id}
|
|
@@ -60,7 +54,7 @@ const ChatTicketList = React.forwardRef<HTMLDivElement, ChatTicketListProps>(
|
|
|
60
54
|
onClick={onTicketClick}
|
|
61
55
|
/>
|
|
62
56
|
))}
|
|
63
|
-
</
|
|
57
|
+
</div>
|
|
64
58
|
|
|
65
59
|
{/* Scroll-fade overlays — tinted with the page background so edge
|
|
66
60
|
tickets fade into the surface behind the list in BOTH themes
|
|
@@ -2357,6 +2357,9 @@ function EmbeddableChatInner({
|
|
|
2357
2357
|
setQuickActionPreview(action.prompt ?? action.label)
|
|
2358
2358
|
}
|
|
2359
2359
|
onQuickActionHoverEnd={() => setQuickActionPreview(null)}
|
|
2360
|
+
// A built-in agent caps the quick-action wall at 2 rows;
|
|
2361
|
+
// this is the Mingo surface, so fall back to 'mingo'.
|
|
2362
|
+
agentSlug={activeAgentSlug ?? 'mingo'}
|
|
2360
2363
|
/>
|
|
2361
2364
|
) : (
|
|
2362
2365
|
/* Figma node 7532:328214 — Guide-mode empty state: greeting
|
|
@@ -2404,6 +2407,9 @@ function EmbeddableChatInner({
|
|
|
2404
2407
|
setQuickActionPreview(action.prompt ?? action.label)
|
|
2405
2408
|
}
|
|
2406
2409
|
onQuickActionHoverEnd={() => setQuickActionPreview(null)}
|
|
2410
|
+
// In agent mode a built-in agent (fae/mingo) caps the wall at
|
|
2411
|
+
// 2 rows; host/guide mode (no active agent) keeps the default.
|
|
2412
|
+
agentSlug={activeAgentSlug}
|
|
2407
2413
|
>
|
|
2408
2414
|
{/* Figma node 7363:205938 — single-column slash-command
|
|
2409
2415
|
list. No own scroll (GuideWelcome's region scrolls); the
|
|
@@ -4,7 +4,6 @@ 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'
|
|
8
7
|
import { Skeleton } from '../ui/skeleton'
|
|
9
8
|
import { QuickActionWall } from './quick-action-wall'
|
|
10
9
|
import { EntityIcon } from '../icon-display'
|
|
@@ -60,6 +59,10 @@ export interface GuideWelcomeProps {
|
|
|
60
59
|
onQuickActionHover?: (action: GuideQuickAction) => void
|
|
61
60
|
/** Pointer/keyboard focus leaves the chip — e.g. restore the composer. */
|
|
62
61
|
onQuickActionHoverEnd?: () => void
|
|
62
|
+
/** Agent this empty state belongs to — forwarded to the quick-action
|
|
63
|
+
* {@link QuickActionWall} so a built-in agent (`'fae'`/`'mingo'`) caps the
|
|
64
|
+
* brick stack at 2 rows. Unset (host/guide mode) keeps the full `rows` cap. */
|
|
65
|
+
agentSlug?: string
|
|
63
66
|
/** Slash-command onboarding list — rendered inside the shared scroll region
|
|
64
67
|
* below the greeting (so greeting + list scroll together, with edge fades). */
|
|
65
68
|
children?: React.ReactNode
|
|
@@ -96,6 +99,7 @@ export function GuideWelcome({
|
|
|
96
99
|
onQuickAction,
|
|
97
100
|
onQuickActionHover,
|
|
98
101
|
onQuickActionHoverEnd,
|
|
102
|
+
agentSlug,
|
|
99
103
|
children,
|
|
100
104
|
className,
|
|
101
105
|
}: GuideWelcomeProps) {
|
|
@@ -142,11 +146,10 @@ export function GuideWelcome({
|
|
|
142
146
|
{/* Greeting + slash-command list share one scroll region; `relative` so
|
|
143
147
|
the edge fades can overlay it. */}
|
|
144
148
|
<div className="relative flex flex-1 min-h-0 flex-col">
|
|
145
|
-
<
|
|
146
|
-
|
|
149
|
+
<div
|
|
150
|
+
ref={scrollRef}
|
|
147
151
|
onScroll={updateScrollFade}
|
|
148
|
-
className="flex-1 min-h-0"
|
|
149
|
-
contentClassName="flex min-h-full flex-col gap-[var(--spacing-system-m)] overscroll-contain"
|
|
152
|
+
className="flex flex-1 min-h-0 flex-col gap-[var(--spacing-system-m)] overflow-y-auto overscroll-contain"
|
|
150
153
|
>
|
|
151
154
|
{/* Greeting grows to fill (`flex-1`) so the slash-command list stays
|
|
152
155
|
anchored below it — but its content is anchored at the TOP of the
|
|
@@ -189,7 +192,7 @@ export function GuideWelcome({
|
|
|
189
192
|
</div>
|
|
190
193
|
|
|
191
194
|
{children}
|
|
192
|
-
</
|
|
195
|
+
</div>
|
|
193
196
|
|
|
194
197
|
{/* Edge scroll-fades — visible only when content is hidden beyond them. */}
|
|
195
198
|
<ScrollFadeOverlay edge="top" visible={fadeTop} className="h-12" />
|
|
@@ -207,6 +210,7 @@ export function GuideWelcome({
|
|
|
207
210
|
{quickActions.length > 0 && (
|
|
208
211
|
<QuickActionWall
|
|
209
212
|
chips={chipItems}
|
|
213
|
+
agentSlug={agentSlug}
|
|
210
214
|
rows={4}
|
|
211
215
|
pauseOnHover
|
|
212
216
|
dragScroll
|
|
@@ -5,7 +5,6 @@ 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'
|
|
9
8
|
import { Ellipsis01Icon, SearchXmarkIcon } from '../icons-v2-generated'
|
|
10
9
|
import { ChatListEmptyState } from './chat-list-empty-state'
|
|
11
10
|
import type { DialogItem } from './types/component.types'
|
|
@@ -339,11 +338,10 @@ export function MingoChatHistory({
|
|
|
339
338
|
{/* Scroll region — the search INPUT now lives in the panel header
|
|
340
339
|
(Figma 116:51217), so the list is just the grouped rows + fades. */}
|
|
341
340
|
<div className="relative flex flex-1 min-h-0 flex-col">
|
|
342
|
-
<
|
|
343
|
-
|
|
341
|
+
<div
|
|
342
|
+
ref={scrollRef}
|
|
344
343
|
onScroll={updateFade}
|
|
345
|
-
className="flex-1 min-h-0"
|
|
346
|
-
contentClassName="flex flex-col gap-[var(--spacing-system-m)] overscroll-contain"
|
|
344
|
+
className="flex flex-1 min-h-0 flex-col gap-[var(--spacing-system-m)] overflow-y-auto overscroll-contain"
|
|
347
345
|
>
|
|
348
346
|
{noSearchResults ? (
|
|
349
347
|
// No search matches — same centred glyph + title + caption layout as
|
|
@@ -376,7 +374,7 @@ export function MingoChatHistory({
|
|
|
376
374
|
))
|
|
377
375
|
)}
|
|
378
376
|
{hasMore ? <div ref={sentinelRef} className="h-px shrink-0" /> : null}
|
|
379
|
-
</
|
|
377
|
+
</div>
|
|
380
378
|
|
|
381
379
|
{/* Scroll-fade — only while content is hidden in that direction. */}
|
|
382
380
|
<ScrollFadeOverlay edge="top" visible={fadeTop} color="var(--color-bg-card)" className="h-12" />
|
|
@@ -8,7 +8,6 @@ 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'
|
|
12
11
|
import { XmarkIcon } from '../icons-v2-generated/signs-and-symbols/xmark-icon'
|
|
13
12
|
import {
|
|
14
13
|
CompassIcon,
|
|
@@ -88,6 +87,10 @@ export interface MingoWelcomeProps {
|
|
|
88
87
|
* action — switches the host chat to Guide mode) and enables the default
|
|
89
88
|
* promo notification. When omitted, both are suppressed. */
|
|
90
89
|
onStartGuideChat?: () => void
|
|
90
|
+
/** Agent this empty state belongs to — forwarded to the quick-action
|
|
91
|
+
* {@link QuickActionWall} so a built-in agent (`'fae'`/`'mingo'`) caps the
|
|
92
|
+
* brick stack at 2 rows. Defaults to `'mingo'` (this is the Mingo surface). */
|
|
93
|
+
agentSlug?: string
|
|
91
94
|
/** Appended to the root element. */
|
|
92
95
|
className?: string
|
|
93
96
|
}
|
|
@@ -139,6 +142,7 @@ export function MingoWelcome({
|
|
|
139
142
|
loadError = false,
|
|
140
143
|
onRetry,
|
|
141
144
|
onStartGuideChat,
|
|
145
|
+
agentSlug = 'mingo',
|
|
142
146
|
className,
|
|
143
147
|
}: MingoWelcomeProps) {
|
|
144
148
|
// Greeting never weaves the user's name in — always the plain "Hey, I'm
|
|
@@ -240,11 +244,10 @@ export function MingoWelcome({
|
|
|
240
244
|
input. The wrapper is `relative` so the scroll-fade gradients can
|
|
241
245
|
overlay the top/bottom edges. */}
|
|
242
246
|
<div className="relative flex flex-1 min-h-0 flex-col">
|
|
243
|
-
<
|
|
244
|
-
|
|
247
|
+
<div
|
|
248
|
+
ref={scrollRef}
|
|
245
249
|
onScroll={updateScrollFade}
|
|
246
|
-
className="flex-1 min-h-0"
|
|
247
|
-
contentClassName="flex min-h-full flex-col gap-[var(--spacing-system-m)] overscroll-contain"
|
|
250
|
+
className="flex flex-1 min-h-0 flex-col gap-[var(--spacing-system-m)] overflow-y-auto overscroll-contain"
|
|
248
251
|
>
|
|
249
252
|
{/* Greeting — grows to fill (`flex-1`) so it centres vertically,
|
|
250
253
|
keeping the grid anchored at the bottom of the scroll area. Default
|
|
@@ -263,7 +266,7 @@ export function MingoWelcome({
|
|
|
263
266
|
<p className="text-h4 text-ods-text-secondary">{subtitle}</p>
|
|
264
267
|
</div>
|
|
265
268
|
</div>
|
|
266
|
-
</
|
|
269
|
+
</div>
|
|
267
270
|
|
|
268
271
|
{/* Edge scroll-fades — visible only when content is hidden beyond them.
|
|
269
272
|
Fade into the panel's dark `ods-bg` surface (the default color), matching
|
|
@@ -339,6 +342,7 @@ export function MingoWelcome({
|
|
|
339
342
|
onHoverStart: () => onQuickActionHover?.(action),
|
|
340
343
|
onHoverEnd: () => onQuickActionHoverEnd?.(),
|
|
341
344
|
}))}
|
|
345
|
+
agentSlug={agentSlug}
|
|
342
346
|
rows={4}
|
|
343
347
|
pauseOnHover
|
|
344
348
|
dragScroll
|
|
@@ -42,6 +42,11 @@ export function interleave<T>(a: ReadonlyArray<T>, b: ReadonlyArray<T>): T[] {
|
|
|
42
42
|
// row copy overflows any sensible container, so the loop always engages.
|
|
43
43
|
const DEFAULT_MIN_CHIPS_PER_ROW = 14
|
|
44
44
|
|
|
45
|
+
// Chat-agent walls (fae/mingo) cap the brick stack at 2 rows so the quick
|
|
46
|
+
// actions never crowd the composer; every other surface keeps the caller's
|
|
47
|
+
// `rows` as its cap.
|
|
48
|
+
const AGENT_MAX_ROWS = 2
|
|
49
|
+
|
|
45
50
|
// =============================================================================
|
|
46
51
|
// Types
|
|
47
52
|
// =============================================================================
|
|
@@ -92,14 +97,24 @@ export interface QuickActionWallProps {
|
|
|
92
97
|
* walls where repeats would duplicate flip ids, need no padding). */
|
|
93
98
|
minChips?: number
|
|
94
99
|
/**
|
|
95
|
-
* BRICK-WALL mode:
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* of
|
|
99
|
-
*
|
|
100
|
+
* BRICK-WALL mode: the MAXIMUM number of stacked single-row marquees. The
|
|
101
|
+
* actual row count grows with the chip supply — `ceil(chips / 14)` capped at
|
|
102
|
+
* `rows` — so a short action set fills one row (padded with its own repeats)
|
|
103
|
+
* instead of spreading one chip per row. The originals are split evenly
|
|
104
|
+
* ACROSS the active rows first, THEN each row pads to a full course, so no
|
|
105
|
+
* row is ever all-duplicates while another holds the unique chips. Rows pack
|
|
106
|
+
* edge-to-edge like bricks (a grid would column-align mismatched widths and
|
|
107
|
+
* leave holes) and each loops on its own wrap. Horizontal only; the fades
|
|
100
108
|
* draw ONCE over the whole stack.
|
|
101
109
|
*/
|
|
102
110
|
rows?: number
|
|
111
|
+
/**
|
|
112
|
+
* Chat agent this wall belongs to (`'fae'` / `'mingo'`). When set to a
|
|
113
|
+
* built-in agent it caps the brick stack at {@link AGENT_MAX_ROWS} (2) so the
|
|
114
|
+
* actions stay compact above the composer; any other value (or unset) leaves
|
|
115
|
+
* the cap at `rows`. Optional — decorative/marketing walls omit it.
|
|
116
|
+
*/
|
|
117
|
+
agentSlug?: string
|
|
103
118
|
/** Draw skeleton chips instead of `chips` (the shared
|
|
104
119
|
* {@link QuickActionChipSkeleton} — 1:1 geometry with loaded chips).
|
|
105
120
|
* Callers own the policy (`loading` flag vs skeleton-when-empty). */
|
|
@@ -150,6 +165,7 @@ export function QuickActionWall({
|
|
|
150
165
|
copyGap,
|
|
151
166
|
minChips,
|
|
152
167
|
rows,
|
|
168
|
+
agentSlug,
|
|
153
169
|
loading = false,
|
|
154
170
|
skeletonCount = 24,
|
|
155
171
|
className,
|
|
@@ -159,7 +175,9 @@ export function QuickActionWall({
|
|
|
159
175
|
// Repeat-pad the track (stable suffixed keys; repeats keep the full chip —
|
|
160
176
|
// identical selected/interactive state, so every visible instance behaves
|
|
161
177
|
// the same and the clone copy stays geometry-identical by construction).
|
|
162
|
-
|
|
178
|
+
// Brick mode does its own per-row padding below, so this pads only the
|
|
179
|
+
// single-track (wrap / vertical) walls.
|
|
180
|
+
const padTarget = rows ? undefined : minChips
|
|
163
181
|
const track = React.useMemo(() => {
|
|
164
182
|
if (!padTarget || chips.length === 0 || chips.length >= padTarget) return chips
|
|
165
183
|
const repeats = Math.ceil(padTarget / chips.length)
|
|
@@ -198,8 +216,35 @@ export function QuickActionWall({
|
|
|
198
216
|
|
|
199
217
|
// ---- BRICK-WALL mode: stacked independent row marquees ---------------------
|
|
200
218
|
if (rows && rows > 0) {
|
|
201
|
-
|
|
202
|
-
|
|
219
|
+
// Chat-agent walls (fae/mingo) grow the stack with the chip supply and cap
|
|
220
|
+
// it at AGENT_MAX_ROWS (2) so the actions stay compact above the composer.
|
|
221
|
+
// Every other surface keeps exactly `rows` rows (marketing/onboarding walls
|
|
222
|
+
// are sized for their design and carry far fewer than a full course/row).
|
|
223
|
+
const agentCapped = agentSlug === 'fae' || agentSlug === 'mingo'
|
|
224
|
+
const rowCap = agentCapped ? Math.min(rows, AGENT_MAX_ROWS) : rows
|
|
225
|
+
const dataRows = agentCapped
|
|
226
|
+
? Math.min(Math.max(1, Math.ceil(chips.length / DEFAULT_MIN_CHIPS_PER_ROW)), rowCap)
|
|
227
|
+
: rows
|
|
228
|
+
// Skeletons hold the cap so the row count never jumps when real chips land.
|
|
229
|
+
const stackRows = loading ? rowCap : dataRows
|
|
230
|
+
// Per-row overflow target: a custom `minChips` budget split across the
|
|
231
|
+
// stack, else the 14-chip default that guarantees the loop engages.
|
|
232
|
+
const perRowTarget = minChips ? Math.ceil(minChips / stackRows) : DEFAULT_MIN_CHIPS_PER_ROW
|
|
233
|
+
|
|
234
|
+
// Split the ORIGINAL chips evenly across the rows FIRST (each row holds
|
|
235
|
+
// distinct actions), THEN pad each row to a full course with repeats of its
|
|
236
|
+
// OWN chips — so a row is never all-duplicates while another carries the
|
|
237
|
+
// unique ones (the old pad-then-slice split did exactly that when the chip
|
|
238
|
+
// count lined up with the row count).
|
|
239
|
+
const rowLists = Array.from({ length: stackRows }, (_, r) => {
|
|
240
|
+
const base = chips.filter((_, i) => i % stackRows === r)
|
|
241
|
+
if (base.length === 0 || base.length >= perRowTarget) return base
|
|
242
|
+
const repeats = Math.ceil(perRowTarget / base.length)
|
|
243
|
+
return Array.from({ length: repeats }, (_, rep) =>
|
|
244
|
+
rep === 0 ? base : base.map(chip => ({ ...chip, id: `${chip.id}__r${rep}` })),
|
|
245
|
+
).flat()
|
|
246
|
+
})
|
|
247
|
+
const skelPerRow = Math.ceil(skeletonCount / stackRows)
|
|
203
248
|
return (
|
|
204
249
|
<div className={cn('relative flex flex-col overflow-hidden', className)} style={{ gap }}>
|
|
205
250
|
{rowLists.map((list, r) => (
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import { useEffect, useRef } from 'react'
|
|
4
|
-
import { OverlayScrollArea } from '../../ui/overlay-scroll-area'
|
|
5
4
|
import { BellOffIcon } from '../../icons-v2-generated/interface/bell-off-icon'
|
|
6
5
|
import { ClockHistoryIcon, ArrowRightUpIcon } from '../../icons-v2-generated'
|
|
7
6
|
import { useAppLayoutDrawerContainer } from '../../navigation/app-layout-context'
|
|
@@ -190,12 +189,9 @@ function DrawerScrollList({
|
|
|
190
189
|
|
|
191
190
|
const isEmpty = unreadNotifications.length === 0
|
|
192
191
|
return (
|
|
193
|
-
<
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
// padding, so `px-*` on `contentClassName` would be silently dropped.
|
|
197
|
-
className="flex-1 min-h-0 px-[var(--spacing-system-m)]"
|
|
198
|
-
contentClassName="flex flex-col gap-[var(--spacing-system-xs)]"
|
|
192
|
+
<div
|
|
193
|
+
ref={scrollRef}
|
|
194
|
+
className="flex flex-1 flex-col gap-[var(--spacing-system-xs)] overflow-y-auto px-[var(--spacing-system-m)]"
|
|
199
195
|
>
|
|
200
196
|
{isEmpty && !isLoadingMore ? (
|
|
201
197
|
<EmptyState />
|
|
@@ -218,7 +214,7 @@ function DrawerScrollList({
|
|
|
218
214
|
{loadMore && hasMore && <div ref={sentinelRef} className="h-1" aria-hidden="true" />}
|
|
219
215
|
</>
|
|
220
216
|
)}
|
|
221
|
-
</
|
|
217
|
+
</div>
|
|
222
218
|
)
|
|
223
219
|
}
|
|
224
220
|
|
|
@@ -21,7 +21,6 @@ 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'
|
|
25
24
|
import type { TimeTrackerData, TimeTrackerEntry, TimeTrackerStatus } from './types'
|
|
26
25
|
|
|
27
26
|
interface CustomerAutocompleteOption extends AutocompleteOption {
|
|
@@ -150,18 +149,11 @@ export function TimeTrackerPanel({
|
|
|
150
149
|
const visibleEntries = lastEntries.slice(0, 3)
|
|
151
150
|
|
|
152
151
|
return (
|
|
153
|
-
<
|
|
152
|
+
<div
|
|
154
153
|
className={cn(
|
|
155
|
-
|
|
156
|
-
// forces `padding: 0` on the viewport, so padding on the scroller is
|
|
157
|
-
// silently dropped (see OverlayScrollArea docs).
|
|
158
|
-
'max-h-[calc(100vh-6rem)] w-full rounded-md border border-ods-border bg-ods-card p-[var(--spacing-system-m)]',
|
|
154
|
+
'relative flex max-h-[calc(100vh-6rem)] w-full flex-col gap-[var(--spacing-system-l)] overflow-y-auto rounded-md border border-ods-border bg-ods-card p-[var(--spacing-system-m)]',
|
|
159
155
|
className,
|
|
160
156
|
)}
|
|
161
|
-
// No `relative` here so the absolute close button anchors to the padded
|
|
162
|
-
// host (OverlayScrollArea's host is always relative) and keeps its inset
|
|
163
|
-
// from the card edge instead of from the padding box.
|
|
164
|
-
contentClassName="flex flex-col gap-[var(--spacing-system-l)]"
|
|
165
157
|
>
|
|
166
158
|
<Button
|
|
167
159
|
variant="transparent"
|
|
@@ -322,7 +314,7 @@ export function TimeTrackerPanel({
|
|
|
322
314
|
<Button variant="outline" fullWidth onClick={onClose} className="md:hidden">
|
|
323
315
|
Close
|
|
324
316
|
</Button>
|
|
325
|
-
</
|
|
317
|
+
</div>
|
|
326
318
|
)
|
|
327
319
|
}
|
|
328
320
|
|
|
@@ -4,7 +4,6 @@ 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'
|
|
8
7
|
import { BackButton } from './back-button'
|
|
9
8
|
|
|
10
9
|
// Legacy interface for backward compatibility (layout version)
|
|
@@ -394,7 +393,7 @@ function renderAdvancedPageContainer({
|
|
|
394
393
|
|
|
395
394
|
switch (variant) {
|
|
396
395
|
case 'detail':
|
|
397
|
-
return cn('flex-1
|
|
396
|
+
return cn('flex-1 overflow-auto', mobilePadding, contentClassName)
|
|
398
397
|
case 'list':
|
|
399
398
|
return cn('flex flex-col gap-4 md:gap-6', mobilePadding, contentClassName)
|
|
400
399
|
case 'form':
|
|
@@ -408,21 +407,10 @@ function renderAdvancedPageContainer({
|
|
|
408
407
|
return (
|
|
409
408
|
<div className={getContainerClasses()}>
|
|
410
409
|
{renderHeader()}
|
|
411
|
-
|
|
412
|
-
{
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
// on the host, while layout (`flex flex-col gap-*`) reaches the scroller,
|
|
416
|
-
// the direct parent of the children (OverlayScrollbars zeroes viewport
|
|
417
|
-
// padding, so padding on the scroller alone would be dropped).
|
|
418
|
-
<OverlayScrollArea className={getContentClasses()} contentClassName={contentClassName}>
|
|
419
|
-
{children}
|
|
420
|
-
</OverlayScrollArea>
|
|
421
|
-
) : (
|
|
422
|
-
<div className={getContentClasses()}>
|
|
423
|
-
{children}
|
|
424
|
-
</div>
|
|
425
|
-
)}
|
|
410
|
+
|
|
411
|
+
<div className={getContentClasses()}>
|
|
412
|
+
{children}
|
|
413
|
+
</div>
|
|
426
414
|
</div>
|
|
427
415
|
)
|
|
428
416
|
}
|
|
@@ -7,7 +7,6 @@ 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"
|
|
11
10
|
|
|
12
11
|
/** Unified overlay backdrop — dimmed, no blur. Single source of truth for
|
|
13
12
|
* every full-screen backdrop (Drawer, AppLayoutDrawer, MobileBurgerMenu,
|
|
@@ -531,16 +530,12 @@ DrawerDescription.displayName = "DrawerDescription"
|
|
|
531
530
|
|
|
532
531
|
const DrawerBody = ({
|
|
533
532
|
className,
|
|
534
|
-
children,
|
|
535
533
|
...props
|
|
536
534
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
537
|
-
<
|
|
538
|
-
className={cn("flex-1
|
|
539
|
-
contentClassName="flex flex-col gap-4"
|
|
535
|
+
<div
|
|
536
|
+
className={cn("flex flex-1 flex-col gap-4 overflow-y-auto", className)}
|
|
540
537
|
{...props}
|
|
541
|
-
|
|
542
|
-
{children}
|
|
543
|
-
</OverlayScrollArea>
|
|
538
|
+
/>
|
|
544
539
|
)
|
|
545
540
|
DrawerBody.displayName = "DrawerBody"
|
|
546
541
|
|
|
@@ -5,7 +5,6 @@ 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"
|
|
9
8
|
|
|
10
9
|
// Duration of the open/close animation in ms — keep in sync with the
|
|
11
10
|
// `duration-200` utilities applied to the backdrop and panel below.
|
|
@@ -132,18 +131,9 @@ Modal.displayName = "ModalV2"
|
|
|
132
131
|
|
|
133
132
|
const ModalContent = React.forwardRef<HTMLDivElement, ModalContentProps>(
|
|
134
133
|
({ children, className }, ref) => (
|
|
135
|
-
|
|
136
|
-
// single scrolling div that directly parented the children, so it may carry
|
|
137
|
-
// layout (`flex flex-col gap-*` — must reach the scroller/`contentClassName`,
|
|
138
|
-
// the direct parent of the children) OR padding (must stay on the host, since
|
|
139
|
-
// OverlayScrollbars zeroes viewport padding). Each class lands where it works.
|
|
140
|
-
<OverlayScrollArea
|
|
141
|
-
viewportRef={ref}
|
|
142
|
-
className={cn("flex-1 min-h-0", className)}
|
|
143
|
-
contentClassName={className}
|
|
144
|
-
>
|
|
134
|
+
<div ref={ref} className={cn("flex-1 min-h-0 overflow-y-auto", className)}>
|
|
145
135
|
{children}
|
|
146
|
-
</
|
|
136
|
+
</div>
|
|
147
137
|
)
|
|
148
138
|
)
|
|
149
139
|
ModalContent.displayName = "ModalV2Content"
|
|
@@ -4,7 +4,6 @@ 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"
|
|
8
7
|
|
|
9
8
|
interface ModalProps {
|
|
10
9
|
isOpen: boolean
|
|
@@ -83,15 +82,9 @@ Modal.displayName = "Modal"
|
|
|
83
82
|
/** @deprecated Use ModalV2Content from './modal-v2' instead. */
|
|
84
83
|
const ModalContent = React.forwardRef<HTMLDivElement, ModalContentProps>(
|
|
85
84
|
({ children, className }, ref) => (
|
|
86
|
-
|
|
87
|
-
// or padding (must stay on the host), so it goes to both layers.
|
|
88
|
-
<OverlayScrollArea
|
|
89
|
-
viewportRef={ref}
|
|
90
|
-
className={cn("min-h-0 flex-1", className)}
|
|
91
|
-
contentClassName={className}
|
|
92
|
-
>
|
|
85
|
+
<div ref={ref} className={cn("overflow-y-auto min-h-0 flex-1", className)}>
|
|
93
86
|
{children}
|
|
94
|
-
</
|
|
87
|
+
</div>
|
|
95
88
|
)
|
|
96
89
|
)
|
|
97
90
|
ModalContent.displayName = "ModalContent"
|
|
@@ -127,3 +127,68 @@ export const Loading: Story = {
|
|
|
127
127
|
</div>
|
|
128
128
|
),
|
|
129
129
|
}
|
|
130
|
+
|
|
131
|
+
// Brick-mode chip set: enough distinct actions to fill more than two full
|
|
132
|
+
// courses, so the agent cap and the even split are both visible.
|
|
133
|
+
const BRICK_ACTIONS: ReadonlyArray<QuickActionChip> = [
|
|
134
|
+
...IT_ACTIONS,
|
|
135
|
+
...SEC_ACTIONS,
|
|
136
|
+
...FAE_ACTIONS.map((c) => ({ ...c, theme: FAE_THEME })),
|
|
137
|
+
].map((c) => ({ ...c, onSelect: () => console.log(c.id) }))
|
|
138
|
+
|
|
139
|
+
/** Brick, chat agent (`agentSlug="mingo"`): the stack grows with the chip
|
|
140
|
+
* supply but caps at 2 rows. Originals are split evenly across the two rows
|
|
141
|
+
* first, then each row pads to a full course — no row is all-duplicates. */
|
|
142
|
+
export const BrickAgentCapped: Story = {
|
|
143
|
+
render: () => (
|
|
144
|
+
<QuickActionWall
|
|
145
|
+
chips={BRICK_ACTIONS}
|
|
146
|
+
agentSlug="mingo"
|
|
147
|
+
rows={4}
|
|
148
|
+
pauseOnHover
|
|
149
|
+
dragScroll
|
|
150
|
+
fade={['left', 'right']}
|
|
151
|
+
fadeSize={{ left: 32 }}
|
|
152
|
+
fadeColor="var(--color-bg)"
|
|
153
|
+
copyGap="var(--spacing-system-xxs)"
|
|
154
|
+
className="max-h-44"
|
|
155
|
+
/>
|
|
156
|
+
),
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** Brick, few actions (`agentSlug="fae"`, 3 chips): fewer than one course, so
|
|
160
|
+
* the stack collapses to a SINGLE row padded with its own repeats instead of
|
|
161
|
+
* spreading one chip per row. */
|
|
162
|
+
export const BrickFewActions: Story = {
|
|
163
|
+
render: () => (
|
|
164
|
+
<QuickActionWall
|
|
165
|
+
chips={FAE_ACTIONS.slice(0, 3).map((c) => ({ ...c, theme: FAE_THEME, onSelect: () => console.log(c.id) }))}
|
|
166
|
+
agentSlug="fae"
|
|
167
|
+
rows={4}
|
|
168
|
+
pauseOnHover
|
|
169
|
+
dragScroll
|
|
170
|
+
fade={['left', 'right']}
|
|
171
|
+
fadeSize={{ left: 32 }}
|
|
172
|
+
fadeColor="var(--color-bg)"
|
|
173
|
+
copyGap="var(--spacing-system-xxs)"
|
|
174
|
+
className="max-h-44"
|
|
175
|
+
/>
|
|
176
|
+
),
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** Brick, non-agent (no `agentSlug`): keeps exactly `rows` rows (marketing /
|
|
180
|
+
* onboarding walls are sized for their design), still getting the even split
|
|
181
|
+
* so a row is never filled with only one repeated chip. */
|
|
182
|
+
export const BrickNonAgent: Story = {
|
|
183
|
+
render: () => (
|
|
184
|
+
<QuickActionWall
|
|
185
|
+
chips={BRICK_ACTIONS}
|
|
186
|
+
rows={4}
|
|
187
|
+
fade={['left', 'right']}
|
|
188
|
+
fadeSize={{ left: 32 }}
|
|
189
|
+
fadeColor="var(--color-bg)"
|
|
190
|
+
copyGap="var(--spacing-system-xxs)"
|
|
191
|
+
className="max-h-56"
|
|
192
|
+
/>
|
|
193
|
+
),
|
|
194
|
+
}
|
package/src/styles/index.css
CHANGED