@flamingo-stack/openframe-frontend-core 0.0.462 → 0.0.463
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-WSPRJARS.js → chunk-2ZDVWIAX.js} +3715 -3593
- package/dist/chunk-2ZDVWIAX.js.map +1 -0
- package/dist/{chunk-4KKY7ZUY.js → chunk-4RQZ5X6Y.js} +4 -4
- package/dist/{chunk-RMYT3QCX.cjs → chunk-52NND23E.cjs} +62 -62
- package/dist/{chunk-RMYT3QCX.cjs.map → chunk-52NND23E.cjs.map} +1 -1
- package/dist/{chunk-XM3WRNYR.cjs → chunk-5ME74JNR.cjs} +59 -59
- package/dist/{chunk-XM3WRNYR.cjs.map → chunk-5ME74JNR.cjs.map} +1 -1
- package/dist/{chunk-FRXDTBA2.js → chunk-CIWVOQKW.js} +2 -2
- package/dist/{chunk-JOW3AEZZ.cjs → chunk-E6OKPI77.cjs} +15 -15
- package/dist/{chunk-JOW3AEZZ.cjs.map → chunk-E6OKPI77.cjs.map} +1 -1
- package/dist/{chunk-RQJGUEQF.cjs → chunk-G2GSHNSJ.cjs} +5 -5
- package/dist/{chunk-RQJGUEQF.cjs.map → chunk-G2GSHNSJ.cjs.map} +1 -1
- package/dist/{chunk-66XFCYRE.js → chunk-GHSSMGZL.js} +2 -2
- package/dist/{chunk-WUPS5YYG.js → chunk-IDMH7CZO.js} +2 -2
- package/dist/{chunk-JCCVQ3PN.cjs → chunk-IRVMOG4M.cjs} +935 -813
- package/dist/chunk-IRVMOG4M.cjs.map +1 -0
- package/dist/{chunk-HJWJLRSU.cjs → chunk-KFND7IRU.cjs} +26 -26
- package/dist/{chunk-HJWJLRSU.cjs.map → chunk-KFND7IRU.cjs.map} +1 -1
- package/dist/{chunk-DNUF7SJD.cjs → chunk-ME6PX3N3.cjs} +31 -31
- package/dist/{chunk-DNUF7SJD.cjs.map → chunk-ME6PX3N3.cjs.map} +1 -1
- package/dist/{chunk-ZV3T47FO.js → chunk-NXCDJV2N.js} +2 -2
- package/dist/{chunk-GGPVPGIB.js → chunk-OURYLIMA.js} +4 -4
- package/dist/{chunk-BN5T3OP6.cjs → chunk-Q5QILCAZ.cjs} +9 -9
- package/dist/{chunk-BN5T3OP6.cjs.map → chunk-Q5QILCAZ.cjs.map} +1 -1
- package/dist/{chunk-N27ZOEDU.js → chunk-QMJALAKE.js} +2 -2
- package/dist/{chunk-OYYGSA3W.js → chunk-RQG32QZS.js} +2 -2
- package/dist/{chunk-WL4QJ7BD.cjs → chunk-VHR5BOCQ.cjs} +26 -26
- package/dist/{chunk-WL4QJ7BD.cjs.map → chunk-VHR5BOCQ.cjs.map} +1 -1
- package/dist/{chunk-4KD6NQDK.cjs → chunk-VUDXSYY7.cjs} +37 -37
- package/dist/{chunk-4KD6NQDK.cjs.map → chunk-VUDXSYY7.cjs.map} +1 -1
- package/dist/{chunk-LE7N2KEE.cjs → chunk-WDN6RDXY.cjs} +7 -7
- package/dist/{chunk-LE7N2KEE.cjs.map → chunk-WDN6RDXY.cjs.map} +1 -1
- package/dist/{chunk-MBHZJTZC.js → chunk-XEQCEYTI.js} +4 -4
- package/dist/{chunk-CARCB5BE.cjs → chunk-YMRAEKRR.cjs} +11 -11
- package/dist/{chunk-CARCB5BE.cjs.map → chunk-YMRAEKRR.cjs.map} +1 -1
- package/dist/{chunk-QO2YQ7V4.js → chunk-YQI5NNA2.js} +4 -4
- package/dist/{chunk-ZST5WNYI.js → chunk-YROSJGPY.js} +2 -2
- package/dist/components/case-studies/index.cjs +8 -8
- package/dist/components/case-studies/index.js +2 -2
- package/dist/components/chat/chat-panel-header.d.ts +9 -1
- package/dist/components/chat/chat-panel-header.d.ts.map +1 -1
- package/dist/components/chat/embeddable-chat.d.ts +8 -0
- package/dist/components/chat/embeddable-chat.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-unified-chat.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-history-rail.d.ts +11 -1
- package/dist/components/chat/mingo-history-rail.d.ts.map +1 -1
- package/dist/components/chat/types/component.types.d.ts +8 -0
- package/dist/components/chat/types/component.types.d.ts.map +1 -1
- package/dist/components/chat/types/unified-chat-state.types.d.ts +7 -0
- package/dist/components/chat/types/unified-chat-state.types.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/help-center-pages/index.cjs +20 -20
- package/dist/components/help-center-pages/index.js +11 -11
- package/dist/components/index.cjs +129 -129
- package/dist/components/index.js +9 -9
- 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/index.cjs +2 -2
- package/dist/components/ui/index.js +1 -1
- package/dist/components/ui/tab-selector.d.ts.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/components/chat/chat-panel-header.tsx +21 -1
- package/src/components/chat/embeddable-chat.tsx +51 -4
- package/src/components/chat/hooks/use-unified-chat.ts +9 -0
- package/src/components/chat/mingo-chat-history.tsx +85 -37
- package/src/components/chat/mingo-history-rail.tsx +31 -0
- package/src/components/chat/types/component.types.ts +8 -0
- package/src/components/chat/types/unified-chat-state.types.ts +9 -0
- package/src/components/ui/tab-selector.tsx +7 -4
- package/dist/chunk-JCCVQ3PN.cjs.map +0 -1
- package/dist/chunk-WSPRJARS.js.map +0 -1
- /package/dist/{chunk-4KKY7ZUY.js.map → chunk-4RQZ5X6Y.js.map} +0 -0
- /package/dist/{chunk-FRXDTBA2.js.map → chunk-CIWVOQKW.js.map} +0 -0
- /package/dist/{chunk-66XFCYRE.js.map → chunk-GHSSMGZL.js.map} +0 -0
- /package/dist/{chunk-WUPS5YYG.js.map → chunk-IDMH7CZO.js.map} +0 -0
- /package/dist/{chunk-ZV3T47FO.js.map → chunk-NXCDJV2N.js.map} +0 -0
- /package/dist/{chunk-GGPVPGIB.js.map → chunk-OURYLIMA.js.map} +0 -0
- /package/dist/{chunk-N27ZOEDU.js.map → chunk-QMJALAKE.js.map} +0 -0
- /package/dist/{chunk-OYYGSA3W.js.map → chunk-RQG32QZS.js.map} +0 -0
- /package/dist/{chunk-MBHZJTZC.js.map → chunk-XEQCEYTI.js.map} +0 -0
- /package/dist/{chunk-QO2YQ7V4.js.map → chunk-YQI5NNA2.js.map} +0 -0
- /package/dist/{chunk-ZST5WNYI.js.map → chunk-YROSJGPY.js.map} +0 -0
|
@@ -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 { SquareAvatar } from '../ui/square-avatar'
|
|
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'
|
|
@@ -107,6 +108,8 @@ function MingoChatHistoryRow({
|
|
|
107
108
|
const title = dialog.title || 'Untitled Chat'
|
|
108
109
|
const unread = dialog.unreadMessagesCount ?? 0
|
|
109
110
|
const hasMenu = !!onRequestRename || !!onRequestArchive
|
|
111
|
+
const owner = dialog.owner
|
|
112
|
+
const hasAvatar = !!(owner?.name || owner?.avatarUrl)
|
|
110
113
|
// Keep the `⋯` visible while its menu is open — once Radix moves focus into
|
|
111
114
|
// the portalled content the row loses hover/focus-within.
|
|
112
115
|
const [menuOpen, setMenuOpen] = React.useState(false)
|
|
@@ -173,46 +176,82 @@ function MingoChatHistoryRow({
|
|
|
173
176
|
{title}
|
|
174
177
|
</span>
|
|
175
178
|
</div>
|
|
176
|
-
{hasMenu ? (
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
//
|
|
179
|
+
{hasMenu || hasAvatar ? (
|
|
180
|
+
// Trailing 48px cell (Figma 113:63224): the owner avatar sits centred
|
|
181
|
+
// by default; hovering the row (or opening the menu) swaps it for the
|
|
182
|
+
// `⋯` actions button IN PLACE, so the title never reflows. Without an
|
|
183
|
+
// avatar the cell exists only for the hover menu, so it collapses on
|
|
184
|
+
// mobile exactly like the old hover-only gutter (no hover on touch).
|
|
181
185
|
<span
|
|
182
|
-
onClick={(e) => e.stopPropagation()}
|
|
183
186
|
className={cn(
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
// row's `items-center` the wrapper would otherwise collapse to its
|
|
187
|
-
// content and `h-full` on the button would no-op).
|
|
188
|
-
'self-stretch shrink-0 transition-opacity max-md:hidden',
|
|
189
|
-
menuOpen
|
|
190
|
-
? 'opacity-100'
|
|
191
|
-
: 'opacity-0 group-hover/row:opacity-100 focus-within:opacity-100',
|
|
187
|
+
'relative w-12 self-stretch shrink-0',
|
|
188
|
+
!hasAvatar && 'max-md:hidden',
|
|
192
189
|
)}
|
|
193
190
|
>
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
191
|
+
{hasMenu ? (
|
|
192
|
+
// Revealed on row hover/its own focus; kept visible while the menu
|
|
193
|
+
// is open. Hidden on mobile — it's a hover affordance. `peer/menu`
|
|
194
|
+
// so the avatar layer (a later sibling) can fade when the trigger
|
|
195
|
+
// holds keyboard focus.
|
|
196
|
+
<span
|
|
197
|
+
onClick={(e) => e.stopPropagation()}
|
|
198
|
+
className={cn(
|
|
199
|
+
'peer/menu absolute inset-0 transition-opacity max-md:hidden',
|
|
200
|
+
menuOpen
|
|
201
|
+
? 'opacity-100'
|
|
202
|
+
: 'opacity-0 group-hover/row:opacity-100 focus-within:opacity-100',
|
|
203
|
+
)}
|
|
204
|
+
>
|
|
205
|
+
<ActionsMenuDropdown
|
|
206
|
+
triggerAriaLabel="Chat actions"
|
|
207
|
+
groups={[{ items: menuItems }]}
|
|
208
|
+
open={menuOpen}
|
|
209
|
+
onOpenChange={setMenuOpen}
|
|
210
|
+
// Don't return focus (and its ring) to the `⋯` trigger on close.
|
|
211
|
+
onCloseAutoFocus={(e) => e.preventDefault()}
|
|
212
|
+
customTrigger={
|
|
213
|
+
<Button
|
|
214
|
+
variant="transparent"
|
|
215
|
+
size="icon"
|
|
216
|
+
aria-label="Chat actions"
|
|
217
|
+
// Square, grey icon → white on hover. `h-full`/`w-full` fill
|
|
218
|
+
// the 48px cell exactly (no breakpoint poke from
|
|
219
|
+
// `size="icon"`'s responsive `md:h-12`); `p-0` drops the
|
|
220
|
+
// icon-size padding. tailwind-merge so these win over
|
|
221
|
+
// defaults.
|
|
222
|
+
className="h-full md:h-full w-full rounded-none p-0 text-ods-text-secondary hover:text-ods-text-primary"
|
|
223
|
+
>
|
|
224
|
+
<Ellipsis01Icon />
|
|
225
|
+
</Button>
|
|
226
|
+
}
|
|
227
|
+
/>
|
|
228
|
+
</span>
|
|
229
|
+
) : null}
|
|
230
|
+
{hasAvatar ? (
|
|
231
|
+
// Avatar layer — clicks fall through to row selection (it covers
|
|
232
|
+
// the cell whenever the menu trigger is faded out). On desktop it
|
|
233
|
+
// fades for the menu swap; on mobile it's always shown.
|
|
234
|
+
<span
|
|
235
|
+
onClick={() => onSelect?.(dialog.id)}
|
|
236
|
+
title={owner?.name || undefined}
|
|
237
|
+
className={cn(
|
|
238
|
+
'absolute inset-0 flex cursor-pointer items-center justify-center transition-opacity',
|
|
239
|
+
hasMenu &&
|
|
240
|
+
(menuOpen
|
|
241
|
+
? 'opacity-0 pointer-events-none'
|
|
242
|
+
: 'md:group-hover/row:opacity-0 md:group-hover/row:pointer-events-none md:peer-[:focus-within]/menu:opacity-0 md:peer-[:focus-within]/menu:pointer-events-none'),
|
|
243
|
+
)}
|
|
244
|
+
>
|
|
245
|
+
<SquareAvatar
|
|
246
|
+
variant="round"
|
|
247
|
+
sizePx={24}
|
|
248
|
+
src={owner?.avatarUrl || undefined}
|
|
249
|
+
alt={owner?.name || undefined}
|
|
250
|
+
fallback={owner?.name || undefined}
|
|
251
|
+
initialsClassName="text-[10px] text-ods-text-secondary"
|
|
252
|
+
/>
|
|
253
|
+
</span>
|
|
254
|
+
) : null}
|
|
216
255
|
</span>
|
|
217
256
|
) : null}
|
|
218
257
|
</div>
|
|
@@ -316,6 +355,7 @@ export function MingoChatHistory({
|
|
|
316
355
|
onLoadMoreRef.current = onLoadMore
|
|
317
356
|
const isLoadingMoreRef = React.useRef(isLoadingMore)
|
|
318
357
|
isLoadingMoreRef.current = isLoadingMore
|
|
358
|
+
const dialogCount = dialogs.length
|
|
319
359
|
React.useEffect(() => {
|
|
320
360
|
const root = scrollRef.current
|
|
321
361
|
const sentinel = sentinelRef.current
|
|
@@ -331,7 +371,15 @@ export function MingoChatHistory({
|
|
|
331
371
|
)
|
|
332
372
|
io.observe(sentinel)
|
|
333
373
|
return () => io.disconnect()
|
|
334
|
-
|
|
374
|
+
// `dialogCount`/`isLoadingMore` deps re-arm the observer after every page
|
|
375
|
+
// lands: `observe()` re-reports the CURRENT intersection, so a sentinel
|
|
376
|
+
// that stays in view (short host-filtered list — e.g. the "My Chats"
|
|
377
|
+
// scope keeps a handful of rows out of a 20-row page) keeps chaining
|
|
378
|
+
// loads until the viewport fills or `hasMore` flips. A continuously
|
|
379
|
+
// visible sentinel never re-crosses the threshold, so the previous
|
|
380
|
+
// [hasMore]-only observer fired exactly once per mount and the list
|
|
381
|
+
// grew by a single page per drawer open.
|
|
382
|
+
}, [hasMore, isLoadingMore, dialogCount])
|
|
335
383
|
|
|
336
384
|
return (
|
|
337
385
|
<div className={cn('relative flex flex-1 min-h-0 flex-col gap-[var(--spacing-system-m)]', className)}>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import * as React from 'react'
|
|
4
4
|
import { cn } from '../../utils/cn'
|
|
5
5
|
import { Button } from '../ui/button'
|
|
6
|
+
import { TabSelector } from '../ui/tab-selector'
|
|
6
7
|
import { ChatsIcon } from '../icons-v2-generated/communication/chats-icon'
|
|
7
8
|
import { PlusCircleIcon } from '../icons-v2-generated/signs-and-symbols/plus-circle-icon'
|
|
8
9
|
import { AlertCircleIcon, Refresh01RightIcon } from '../icons-v2-generated'
|
|
@@ -14,6 +15,10 @@ import type { DialogItem } from './types/component.types'
|
|
|
14
15
|
// Types
|
|
15
16
|
// =============================================================================
|
|
16
17
|
|
|
18
|
+
/** Ownership scope of the rail's dialog list — the current user's chats only,
|
|
19
|
+
* or every admin's chats in the tenant. */
|
|
20
|
+
export type MingoHistoryScope = 'my' | 'all'
|
|
21
|
+
|
|
17
22
|
export interface MingoHistoryRailProps {
|
|
18
23
|
/** Dialogs to list, assumed already sorted newest-first by the host. */
|
|
19
24
|
dialogs: ReadonlyArray<DialogItem>
|
|
@@ -32,6 +37,13 @@ export interface MingoHistoryRailProps {
|
|
|
32
37
|
onRequestRename?: (dialog: DialogItem) => void
|
|
33
38
|
/** Request archive — enables the row "Archive chat" action. */
|
|
34
39
|
onRequestArchive?: (dialog: DialogItem) => void
|
|
40
|
+
/** Ownership scope shown as a two-state "My Chats / All Chats" selector
|
|
41
|
+
* between "Start New Chat" and the list. Rendered only when BOTH `scope`
|
|
42
|
+
* and `onScopeChange` are provided; the host owns the state and refilters
|
|
43
|
+
* the `dialogs` it passes in. */
|
|
44
|
+
scope?: MingoHistoryScope
|
|
45
|
+
/** Scope selector change handler — see `scope`. */
|
|
46
|
+
onScopeChange?: (scope: MingoHistoryScope) => void
|
|
35
47
|
/** Current server-side search term. Drives the list's "No chats found"
|
|
36
48
|
* empty state; the search INPUT itself lives in the panel header now, not
|
|
37
49
|
* in the rail body. */
|
|
@@ -77,6 +89,8 @@ export function MingoHistoryRail({
|
|
|
77
89
|
newChatAlways = false,
|
|
78
90
|
onRequestRename,
|
|
79
91
|
onRequestArchive,
|
|
92
|
+
scope,
|
|
93
|
+
onScopeChange,
|
|
80
94
|
searchQuery,
|
|
81
95
|
hasMore = false,
|
|
82
96
|
isLoadingMore = false,
|
|
@@ -114,6 +128,23 @@ export function MingoHistoryRail({
|
|
|
114
128
|
</Button>
|
|
115
129
|
)}
|
|
116
130
|
|
|
131
|
+
{/* Two-state ownership scope — "My Chats" / "All Chats". Stays visible in
|
|
132
|
+
the empty state too: an empty "My Chats" list must still offer the
|
|
133
|
+
switch to "All Chats" (host filters, so the empty state can be
|
|
134
|
+
scope-induced). Hidden while the load failed — retry is the only
|
|
135
|
+
useful action there. */}
|
|
136
|
+
{scope && onScopeChange && !loadError ? (
|
|
137
|
+
<TabSelector
|
|
138
|
+
className="shrink-0"
|
|
139
|
+
value={scope}
|
|
140
|
+
onValueChange={(value) => onScopeChange(value as MingoHistoryScope)}
|
|
141
|
+
items={[
|
|
142
|
+
{ id: 'my', label: 'My Chats' },
|
|
143
|
+
{ id: 'all', label: 'All Chats' },
|
|
144
|
+
]}
|
|
145
|
+
/>
|
|
146
|
+
) : null}
|
|
147
|
+
|
|
117
148
|
{loadError ? (
|
|
118
149
|
<div className="flex flex-1 min-h-0 flex-col items-center justify-center gap-[var(--spacing-system-m)] text-center">
|
|
119
150
|
<AlertCircleIcon className="h-8 w-8 text-ods-text-secondary shrink-0" />
|
|
@@ -608,6 +608,14 @@ export interface DialogItem {
|
|
|
608
608
|
timestamp?: Date | string
|
|
609
609
|
isActive?: boolean
|
|
610
610
|
unreadMessagesCount?: number
|
|
611
|
+
/** Dialog owner (creator) — drives the trailing avatar in the chat-history
|
|
612
|
+
* rows (Figma 113:63224). Omit to render the row without an avatar. */
|
|
613
|
+
owner?: {
|
|
614
|
+
/** Full display name — initials fallback + `title` tooltip. */
|
|
615
|
+
name?: string | null
|
|
616
|
+
/** Absolute avatar URL; falls back to initials when absent or failing. */
|
|
617
|
+
avatarUrl?: string | null
|
|
618
|
+
}
|
|
611
619
|
}
|
|
612
620
|
|
|
613
621
|
// ========== Chat Sidebar Props ==========
|
|
@@ -369,6 +369,15 @@ export interface UnifiedChatState {
|
|
|
369
369
|
/** Fetch the next page of dialogs. No-op when `hasMoreDialogs` is false. */
|
|
370
370
|
loadMoreDialogs: () => Promise<void>
|
|
371
371
|
|
|
372
|
+
/** Ownership scope of `dialogs` — `'my'` (current user's chats) or `'all'`
|
|
373
|
+
* (every admin's). Optional: adapters without ownership data omit it and
|
|
374
|
+
* the "My Chats / All Chats" selector stays hidden. The HOST owns the
|
|
375
|
+
* filtering — `dialogs` must already reflect this scope. */
|
|
376
|
+
dialogScope?: 'my' | 'all'
|
|
377
|
+
|
|
378
|
+
/** Switch the ownership scope — see `dialogScope`. */
|
|
379
|
+
setDialogScope?: (scope: 'my' | 'all') => void
|
|
380
|
+
|
|
372
381
|
/** Whether more historical messages remain in the active dialog. */
|
|
373
382
|
hasMoreMessages: boolean
|
|
374
383
|
|
|
@@ -67,15 +67,18 @@ export function TabSelector({
|
|
|
67
67
|
onClick={() => onValueChange(item.id)}
|
|
68
68
|
aria-label={!item.label ? item.ariaLabel : undefined}
|
|
69
69
|
className={cn(
|
|
70
|
-
|
|
70
|
+
// Bold on BOTH states — a medium↔bold flip between the active
|
|
71
|
+
// and inactive tabs read as inconsistent weight (and nudged
|
|
72
|
+
// label widths on every switch).
|
|
73
|
+
'flex flex-1 items-center justify-center gap-2 rounded-xs p-2 text-h4 font-bold transition-colors duration-200 whitespace-nowrap',
|
|
71
74
|
isDisabled
|
|
72
75
|
? isActive
|
|
73
|
-
? 'cursor-not-allowed bg-ods-bg-surface text-ods-text-secondary
|
|
76
|
+
? 'cursor-not-allowed bg-ods-bg-surface text-ods-text-secondary'
|
|
74
77
|
: 'cursor-not-allowed bg-transparent text-ods-text-secondary'
|
|
75
78
|
: isActive
|
|
76
79
|
? variant === 'primary'
|
|
77
|
-
? 'bg-ods-accent text-ods-text-on-accent cursor-default
|
|
78
|
-
: 'bg-ods-bg-surface text-ods-text-primary cursor-default
|
|
80
|
+
? 'bg-ods-accent text-ods-text-on-accent cursor-default'
|
|
81
|
+
: 'bg-ods-bg-surface text-ods-text-primary cursor-default'
|
|
79
82
|
: 'bg-transparent text-ods-text-primary hover:bg-ods-bg-hover cursor-pointer',
|
|
80
83
|
)}
|
|
81
84
|
>
|