@flamingo-stack/openframe-frontend-core 0.0.685-snapshot.20260929164409 → 0.0.685
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-DL67S7H4.cjs → chunk-5LJZPJHX.cjs} +59 -59
- package/dist/{chunk-DL67S7H4.cjs.map → chunk-5LJZPJHX.cjs.map} +1 -1
- package/dist/{chunk-IZ3WKG62.js → chunk-65KTXRBY.js} +6 -6
- package/dist/{chunk-IBKMIJ7Y.js → chunk-7XF63THA.js} +6 -6
- package/dist/{chunk-SI77HF4U.cjs → chunk-A3CSQB4A.cjs} +805 -1247
- package/dist/chunk-A3CSQB4A.cjs.map +1 -0
- package/dist/{chunk-5MUR43QD.cjs → chunk-B25CF3PO.cjs} +30 -30
- package/dist/{chunk-5MUR43QD.cjs.map → chunk-B25CF3PO.cjs.map} +1 -1
- package/dist/{chunk-32KBPEF7.js → chunk-B32YLOYQ.js} +4 -4
- package/dist/{chunk-OBLED7JY.cjs → chunk-B5N3AHPG.cjs} +81 -81
- package/dist/{chunk-OBLED7JY.cjs.map → chunk-B5N3AHPG.cjs.map} +1 -1
- package/dist/{chunk-QSRUYHTW.js → chunk-BZ2XOEHW.js} +3 -3
- package/dist/{chunk-XATA4OVO.cjs → chunk-C3B36OYZ.cjs} +3 -3
- package/dist/{chunk-XATA4OVO.cjs.map → chunk-C3B36OYZ.cjs.map} +1 -1
- package/dist/{chunk-V26TKJ4Z.cjs → chunk-CMQXPD5C.cjs} +28 -28
- package/dist/{chunk-V26TKJ4Z.cjs.map → chunk-CMQXPD5C.cjs.map} +1 -1
- package/dist/{chunk-QNWQQ4RT.cjs → chunk-DQOQ3KTP.cjs} +73 -78
- package/dist/chunk-DQOQ3KTP.cjs.map +1 -0
- package/dist/{chunk-5HVGOIAE.cjs → chunk-DWXWEGGO.cjs} +22 -22
- package/dist/{chunk-5HVGOIAE.cjs.map → chunk-DWXWEGGO.cjs.map} +1 -1
- package/dist/{chunk-6CMH53MP.cjs → chunk-EFBMNVSH.cjs} +15 -15
- package/dist/{chunk-6CMH53MP.cjs.map → chunk-EFBMNVSH.cjs.map} +1 -1
- package/dist/{chunk-DDFYKF3B.js → chunk-GHLGXFNU.js} +3 -3
- package/dist/{chunk-VDV7K5TD.js → chunk-GXV6UEVY.js} +3 -3
- package/dist/{chunk-AEAFQTVR.cjs → chunk-HMXUOLZR.cjs} +20 -20
- package/dist/{chunk-AEAFQTVR.cjs.map → chunk-HMXUOLZR.cjs.map} +1 -1
- package/dist/{chunk-2OD2PPNO.cjs → chunk-K2HZG4RM.cjs} +32 -32
- package/dist/{chunk-2OD2PPNO.cjs.map → chunk-K2HZG4RM.cjs.map} +1 -1
- package/dist/{chunk-JNDHXL2D.cjs → chunk-M4HYIXP6.cjs} +383 -384
- package/dist/chunk-M4HYIXP6.cjs.map +1 -0
- package/dist/{chunk-KTWJKCUB.js → chunk-N4Z6X5BV.js} +5 -5
- package/dist/{chunk-T2RHI676.js → chunk-O7LOZW4R.js} +5 -5
- package/dist/{chunk-ZHYYGIAI.cjs → chunk-P2ASEPA2.cjs} +6 -6
- package/dist/{chunk-ZHYYGIAI.cjs.map → chunk-P2ASEPA2.cjs.map} +1 -1
- package/dist/{chunk-CHRDLXXX.js → chunk-PSQKD6ZN.js} +3 -3
- package/dist/{chunk-GSJR33UP.cjs → chunk-QHLJSB2J.cjs} +12 -12
- package/dist/{chunk-GSJR33UP.cjs.map → chunk-QHLJSB2J.cjs.map} +1 -1
- package/dist/{chunk-CFL3EW4V.cjs → chunk-T4DUTP5C.cjs} +5 -5
- package/dist/{chunk-CFL3EW4V.cjs.map → chunk-T4DUTP5C.cjs.map} +1 -1
- package/dist/{chunk-22RSJ57Z.js → chunk-T6KWNJDW.js} +465 -470
- package/dist/chunk-T6KWNJDW.js.map +1 -0
- package/dist/{chunk-2FGFB2HY.cjs → chunk-TJI5V5BR.cjs} +7 -7
- package/dist/{chunk-2FGFB2HY.cjs.map → chunk-TJI5V5BR.cjs.map} +1 -1
- package/dist/{chunk-HLEXYTOE.js → chunk-TUG7IT6H.js} +2 -2
- package/dist/{chunk-DWCVA6XT.cjs → chunk-U3IXG7TR.cjs} +33 -33
- package/dist/{chunk-DWCVA6XT.cjs.map → chunk-U3IXG7TR.cjs.map} +1 -1
- package/dist/{chunk-WJ5XN4AL.js → chunk-UT333EOT.js} +4 -4
- package/dist/{chunk-OTV4W3YD.js → chunk-VDPCK437.js} +5 -6
- package/dist/{chunk-OTV4W3YD.js.map → chunk-VDPCK437.js.map} +1 -1
- package/dist/{chunk-5GK7TU2Q.js → chunk-WJK2EETW.js} +2 -2
- package/dist/{chunk-YPXXXX6R.js → chunk-XGX6JSEU.js} +1644 -2086
- package/dist/chunk-XGX6JSEU.js.map +1 -0
- package/dist/{chunk-XODE4YTG.js → chunk-XW7MUIW4.js} +3 -3
- package/dist/{chunk-N74MQ4HQ.js → chunk-Y7ZYOQNB.js} +3 -3
- package/dist/{chunk-2NUB5EMG.cjs → chunk-YCTVLN47.cjs} +10 -10
- package/dist/{chunk-2NUB5EMG.cjs.map → chunk-YCTVLN47.cjs.map} +1 -1
- package/dist/{chunk-TILC52ZF.js → chunk-ZF4Z36G4.js} +7 -7
- package/dist/components/case-studies/index.cjs +16 -16
- package/dist/components/case-studies/index.js +4 -4
- package/dist/components/chat/ai-assistant-info.d.ts.map +1 -1
- package/dist/components/chat/approval-request-message.d.ts.map +1 -1
- package/dist/components/chat/chat-input.d.ts.map +1 -1
- package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
- package/dist/components/chat/chat-message-list.d.ts.map +1 -1
- package/dist/components/chat/error-message-display.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +3 -21
- package/dist/components/chat/index.cjs.map +1 -1
- package/dist/components/chat/index.d.ts +0 -6
- package/dist/components/chat/index.d.ts.map +1 -1
- package/dist/components/chat/index.js +2 -20
- package/dist/components/chat/msp-organization-card.d.ts +1 -7
- package/dist/components/chat/msp-organization-card.d.ts.map +1 -1
- package/dist/components/chat/types/chat.types.d.ts +0 -13
- package/dist/components/chat/types/chat.types.d.ts.map +1 -1
- package/dist/components/chat/types/component.types.d.ts +1 -20
- package/dist/components/chat/types/component.types.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +5 -5
- package/dist/components/contact/index.js +4 -4
- package/dist/components/docs/index.cjs +8 -8
- package/dist/components/docs/index.js +7 -7
- package/dist/components/embeds/index.cjs +5 -5
- package/dist/components/embeds/index.js +4 -4
- package/dist/components/faq/index.cjs +5 -5
- package/dist/components/faq/index.js +4 -4
- package/dist/components/features/index.cjs +4 -4
- package/dist/components/features/index.js +3 -3
- package/dist/components/help-center-pages/index.cjs +91 -91
- package/dist/components/help-center-pages/index.js +15 -15
- package/dist/components/index.cjs +55 -73
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +15 -33
- package/dist/components/index.js.map +1 -1
- package/dist/components/meeting-scheduler/index.cjs +41 -41
- package/dist/components/meeting-scheduler/index.js +3 -3
- package/dist/components/navigation/index.cjs +7 -7
- package/dist/components/navigation/index.js +6 -6
- package/dist/components/onboarding-guides/index.cjs +7 -7
- package/dist/components/onboarding-guides/index.js +6 -6
- package/dist/components/related-content/index.cjs +3 -3
- package/dist/components/related-content/index.js +2 -2
- package/dist/components/tickets/index.cjs +8 -8
- package/dist/components/tickets/index.js +7 -7
- package/dist/components/ui/avatar-stack.d.ts +1 -5
- package/dist/components/ui/avatar-stack.d.ts.map +1 -1
- package/dist/components/ui/index.cjs +4 -22
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.js +3 -21
- package/dist/components/ui/reopen-ticket-request-modal.d.ts +1 -4
- package/dist/components/ui/reopen-ticket-request-modal.d.ts.map +1 -1
- package/dist/index.cjs +9 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +7 -25
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/chat/ai-assistant-info.tsx +1 -7
- package/src/components/chat/approval-request-message.tsx +1 -6
- package/src/components/chat/chat-input.tsx +1 -26
- package/src/components/chat/chat-message-enhanced.tsx +142 -180
- package/src/components/chat/chat-message-list.tsx +164 -169
- package/src/components/chat/error-message-display.tsx +3 -21
- package/src/components/chat/index.ts +0 -6
- package/src/components/chat/msp-organization-card.tsx +0 -35
- package/src/components/chat/types/chat.types.ts +0 -15
- package/src/components/chat/types/component.types.ts +0 -20
- package/src/components/ui/avatar-stack.tsx +5 -15
- package/src/components/ui/reopen-ticket-request-modal.tsx +2 -6
- package/src/styles/ods-colors.css +0 -10
- package/src/styles/ods-effects.css +0 -13
- package/dist/chunk-22RSJ57Z.js.map +0 -1
- package/dist/chunk-JNDHXL2D.cjs.map +0 -1
- package/dist/chunk-QNWQQ4RT.cjs.map +0 -1
- package/dist/chunk-SI77HF4U.cjs.map +0 -1
- package/dist/chunk-YPXXXX6R.js.map +0 -1
- package/dist/components/chat/chat-appearance-context.d.ts +0 -9
- package/dist/components/chat/chat-appearance-context.d.ts.map +0 -1
- package/dist/components/chat/chat-nav-sidebar.d.ts +0 -50
- package/dist/components/chat/chat-nav-sidebar.d.ts.map +0 -1
- package/dist/components/chat/chat-top-navigation.d.ts +0 -29
- package/dist/components/chat/chat-top-navigation.d.ts.map +0 -1
- package/dist/components/chat/onboarding-carousel.d.ts +0 -29
- package/dist/components/chat/onboarding-carousel.d.ts.map +0 -1
- package/dist/components/chat/system-event-message.d.ts +0 -14
- package/dist/components/chat/system-event-message.d.ts.map +0 -1
- package/src/components/chat/__tests__/chat-appearance.test.tsx +0 -79
- package/src/components/chat/__tests__/onboarding-carousel.test.tsx +0 -56
- package/src/components/chat/chat-appearance-context.tsx +0 -15
- package/src/components/chat/chat-nav-sidebar.tsx +0 -163
- package/src/components/chat/chat-top-navigation.tsx +0 -109
- package/src/components/chat/onboarding-carousel.tsx +0 -162
- package/src/components/chat/system-event-message.tsx +0 -54
- package/src/components/ui/__tests__/avatar-stack.test.tsx +0 -25
- package/src/stories/FaeLayoutV2.stories.tsx +0 -150
- package/src/stories/FaeOnboardingV2.stories.tsx +0 -68
- package/src/stories/FaeThreadV2.stories.tsx +0 -192
- package/src/stories/fae-brand-decorator.tsx +0 -28
- /package/dist/{chunk-IZ3WKG62.js.map → chunk-65KTXRBY.js.map} +0 -0
- /package/dist/{chunk-IBKMIJ7Y.js.map → chunk-7XF63THA.js.map} +0 -0
- /package/dist/{chunk-32KBPEF7.js.map → chunk-B32YLOYQ.js.map} +0 -0
- /package/dist/{chunk-QSRUYHTW.js.map → chunk-BZ2XOEHW.js.map} +0 -0
- /package/dist/{chunk-DDFYKF3B.js.map → chunk-GHLGXFNU.js.map} +0 -0
- /package/dist/{chunk-VDV7K5TD.js.map → chunk-GXV6UEVY.js.map} +0 -0
- /package/dist/{chunk-KTWJKCUB.js.map → chunk-N4Z6X5BV.js.map} +0 -0
- /package/dist/{chunk-T2RHI676.js.map → chunk-O7LOZW4R.js.map} +0 -0
- /package/dist/{chunk-CHRDLXXX.js.map → chunk-PSQKD6ZN.js.map} +0 -0
- /package/dist/{chunk-HLEXYTOE.js.map → chunk-TUG7IT6H.js.map} +0 -0
- /package/dist/{chunk-WJ5XN4AL.js.map → chunk-UT333EOT.js.map} +0 -0
- /package/dist/{chunk-5GK7TU2Q.js.map → chunk-WJK2EETW.js.map} +0 -0
- /package/dist/{chunk-XODE4YTG.js.map → chunk-XW7MUIW4.js.map} +0 -0
- /package/dist/{chunk-N74MQ4HQ.js.map → chunk-Y7ZYOQNB.js.map} +0 -0
- /package/dist/{chunk-TILC52ZF.js.map → chunk-ZF4Z36G4.js.map} +0 -0
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type ChatAppearance } from './types/chat.types';
|
|
2
|
-
/**
|
|
3
|
-
* Thread-wide `ChatAppearance`. `ChatMessageList` provides it, so the blocks a
|
|
4
|
-
* message renders (error, lifecycle receipts) follow the thread without every
|
|
5
|
-
* segment component growing an `appearance` prop.
|
|
6
|
-
*/
|
|
7
|
-
export declare const ChatAppearanceContext: import("react").Context<ChatAppearance>;
|
|
8
|
-
export declare function useChatAppearance(): ChatAppearance;
|
|
9
|
-
//# sourceMappingURL=chat-appearance-context.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chat-appearance-context.d.ts","sourceRoot":"","sources":["../../../src/components/chat/chat-appearance-context.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAE1E;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,yCAAyD,CAAC;AAE5F,wBAAgB,iBAAiB,IAAI,cAAc,CAElD"}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { type ButtonHTMLAttributes, type HTMLAttributes, type ReactNode } from 'react';
|
|
2
|
-
export interface ChatNavSidebarItem {
|
|
3
|
-
id: string;
|
|
4
|
-
label: string;
|
|
5
|
-
/** 24px glyph before the label. */
|
|
6
|
-
icon: ReactNode;
|
|
7
|
-
/** The view this item opens is the one on screen. */
|
|
8
|
-
active?: boolean;
|
|
9
|
-
onClick?: () => void;
|
|
10
|
-
}
|
|
11
|
-
export interface ChatNavSidebarProps extends HTMLAttributes<HTMLElement> {
|
|
12
|
-
/** Brand row at the top. */
|
|
13
|
-
logo?: ReactNode;
|
|
14
|
-
/** Primary actions under the logo (new chat, archive, help, ...). */
|
|
15
|
-
items: ChatNavSidebarItem[];
|
|
16
|
-
/** Caption over the list (e.g. "Your Current Chats"). */
|
|
17
|
-
sectionLabel?: string;
|
|
18
|
-
/** The list itself, typically `ChatListItem` rows or an empty state. Scrolls
|
|
19
|
-
* on its own; everything above it stays put. */
|
|
20
|
-
children?: ReactNode;
|
|
21
|
-
/** Pinned under the list, full width, above a divider (e.g. the MSP card). */
|
|
22
|
-
footer?: ReactNode;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Left rail of the fae chat v2 layout (Figma `chat-sidebar`): brand, a stack of
|
|
26
|
-
* navigation actions, a captioned scrolling list and a pinned footer. It only
|
|
27
|
-
* lays things out; which rows exist, what they show and what selecting them
|
|
28
|
-
* does belong to the host.
|
|
29
|
-
*/
|
|
30
|
-
declare const ChatNavSidebar: import("react").ForwardRefExoticComponent<ChatNavSidebarProps & import("react").RefAttributes<HTMLElement>>;
|
|
31
|
-
export interface ChatListItemProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'title'> {
|
|
32
|
-
title: ReactNode;
|
|
33
|
-
/** Second line (e.g. the ticket number). */
|
|
34
|
-
subtitle?: ReactNode;
|
|
35
|
-
/** 16px mark before the title (e.g. a resolved check). */
|
|
36
|
-
leading?: ReactNode;
|
|
37
|
-
/** 24px status glyph at the row's end. */
|
|
38
|
-
trailing?: ReactNode;
|
|
39
|
-
/** The chat open on screen. */
|
|
40
|
-
active?: boolean;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* One row of the `ChatNavSidebar` list (Figma `chat-list-item`): a one-line
|
|
44
|
-
* title over a caption, an optional mark before the title and a status glyph
|
|
45
|
-
* at the end. The selected row takes the accent's secondary fill, so a tenant
|
|
46
|
-
* accent recolours it with the rest of the brand.
|
|
47
|
-
*/
|
|
48
|
-
declare const ChatListItem: import("react").ForwardRefExoticComponent<ChatListItemProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
49
|
-
export { ChatNavSidebar, ChatListItem };
|
|
50
|
-
//# sourceMappingURL=chat-nav-sidebar.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chat-nav-sidebar.d.ts","sourceRoot":"","sources":["../../../src/components/chat/chat-nav-sidebar.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,oBAAoB,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAInG,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,IAAI,EAAE,SAAS,CAAC;IAChB,qDAAqD;IACrD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,mBAAoB,SAAQ,cAAc,CAAC,WAAW,CAAC;IACtE,4BAA4B;IAC5B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,qEAAqE;IACrE,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;qDACiD;IACjD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAED;;;;;GAKG;AACH,QAAA,MAAM,cAAc,6GA6CnB,CAAC;AA6BF,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC/F,KAAK,EAAE,SAAS,CAAC;IACjB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,+BAA+B;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;GAKG;AACH,QAAA,MAAM,YAAY,iHA8BjB,CAAC;AAIF,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { type HTMLAttributes, type ReactNode } from 'react';
|
|
2
|
-
export interface ChatTopNavigationProps extends HTMLAttributes<HTMLElement> {
|
|
3
|
-
/** Who the user is talking to. */
|
|
4
|
-
name: string;
|
|
5
|
-
/** Line under the name (e.g. "Your AI Assistant", "IT Technician"). */
|
|
6
|
-
subtitle?: string;
|
|
7
|
-
avatarUrl?: string | null;
|
|
8
|
-
/** Actions after the identity (e.g. "Request a Technician"). */
|
|
9
|
-
actions?: ReactNode;
|
|
10
|
-
/** Shows the sidebar toggle at the start of the bar. */
|
|
11
|
-
onToggleSidebar?: () => void;
|
|
12
|
-
/** Whether the sidebar is currently shown; drives the toggle's state. */
|
|
13
|
-
sidebarOpen?: boolean;
|
|
14
|
-
/** Shows the settings button at the end of the bar. */
|
|
15
|
-
onOpenSettings?: () => void;
|
|
16
|
-
/** Content above the bar, full width (e.g. a "Back to ..." strip). */
|
|
17
|
-
before?: ReactNode;
|
|
18
|
-
/** Identity still resolving: placeholders instead of a default name that
|
|
19
|
-
* would flash before the tenant's branding lands. */
|
|
20
|
-
isLoading?: boolean;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Top bar of the fae chat v2 layout (Figma `chat-top-navigation`): an optional
|
|
24
|
-
* sidebar toggle, the counterpart's avatar, name and role, the host's actions
|
|
25
|
-
* and an optional settings button, split by vertical dividers.
|
|
26
|
-
*/
|
|
27
|
-
declare const ChatTopNavigation: import("react").ForwardRefExoticComponent<ChatTopNavigationProps & import("react").RefAttributes<HTMLElement>>;
|
|
28
|
-
export { ChatTopNavigation };
|
|
29
|
-
//# sourceMappingURL=chat-top-navigation.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chat-top-navigation.d.ts","sourceRoot":"","sources":["../../../src/components/chat/chat-top-navigation.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAMxE,MAAM,WAAW,sBAAuB,SAAQ,cAAc,CAAC,WAAW,CAAC;IACzE,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gEAAgE;IAChE,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,wDAAwD;IACxD,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,yEAAyE;IACzE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,sEAAsE;IACtE,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB;0DACsD;IACtD,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAQD;;;;GAIG;AACH,QAAA,MAAM,iBAAiB,gHAgEtB,CAAC;AAIF,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { type ReactNode } from 'react';
|
|
2
|
-
export interface OnboardingCarouselStep {
|
|
3
|
-
id: string;
|
|
4
|
-
/** Glyph in the 64px tile above the title. Pass it sized to 28px. */
|
|
5
|
-
icon: ReactNode;
|
|
6
|
-
title: ReactNode;
|
|
7
|
-
description?: ReactNode;
|
|
8
|
-
}
|
|
9
|
-
export interface OnboardingCarouselProps {
|
|
10
|
-
steps: OnboardingCarouselStep[];
|
|
11
|
-
/** The last step's primary action. */
|
|
12
|
-
onComplete: () => void;
|
|
13
|
-
/** Label of the last step's primary action. */
|
|
14
|
-
completeLabel?: string;
|
|
15
|
-
previousLabel?: string;
|
|
16
|
-
nextLabel?: string;
|
|
17
|
-
/** Accessible name of the carousel region. */
|
|
18
|
-
label?: string;
|
|
19
|
-
className?: string;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Step-by-step introduction: one card at a time in the middle, its neighbours
|
|
23
|
-
* peeking in from the sides under an edge fade, dots below, Previous / Next
|
|
24
|
-
* underneath. The last step swaps Next for `completeLabel`. There is no skip:
|
|
25
|
-
* the design walks every step. Fills the height its parent gives it: the cards
|
|
26
|
-
* stretch, the dots and buttons keep their size.
|
|
27
|
-
*/
|
|
28
|
-
export declare function OnboardingCarousel({ steps, onComplete, completeLabel, previousLabel, nextLabel, label, className, }: OnboardingCarouselProps): import("react").JSX.Element;
|
|
29
|
-
//# sourceMappingURL=onboarding-carousel.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"onboarding-carousel.d.ts","sourceRoot":"","sources":["../../../src/components/chat/onboarding-carousel.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA0C,KAAK,SAAS,EAAY,MAAM,OAAO,CAAC;AAIzF,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,qEAAqE;IACrE,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;CACzB;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,sBAAsB,EAAE,CAAC;IAChC,sCAAsC;IACtC,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,+CAA+C;IAC/C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,UAAU,EACV,aAA4B,EAC5B,aAA+B,EAC/B,SAAuB,EACvB,KAAsB,EACtB,SAAS,GACV,EAAE,uBAAuB,+BAuHzB"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { type HTMLAttributes } from 'react';
|
|
2
|
-
export interface SystemEventMessageProps extends HTMLAttributes<HTMLDivElement> {
|
|
3
|
-
/** The system line as the backend sent it. */
|
|
4
|
-
text: string;
|
|
5
|
-
timestamp?: Date;
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* A system line in the fae chat v2 thread (`ai-assistant-info`,
|
|
9
|
-
* type=direct-chat): a technician joining becomes "Technician Joined" with
|
|
10
|
-
* their initials; any other line keeps its own wording under an info icon.
|
|
11
|
-
*/
|
|
12
|
-
declare const SystemEventMessage: import("react").ForwardRefExoticComponent<SystemEventMessageProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
13
|
-
export { SystemEventMessage };
|
|
14
|
-
//# sourceMappingURL=system-event-message.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"system-event-message.d.ts","sourceRoot":"","sources":["../../../src/components/chat/system-event-message.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC;AAWxD,MAAM,WAAW,uBAAwB,SAAQ,cAAc,CAAC,cAAc,CAAC;IAC7E,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,IAAI,CAAC;CAClB;AAED;;;;GAIG;AACH,QAAA,MAAM,kBAAkB,oHAyBtB,CAAC;AAIH,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { render, screen } from '@testing-library/react';
|
|
2
|
-
import { describe, expect, it } from 'vitest';
|
|
3
|
-
import { AiAssistantInfo } from '../ai-assistant-info';
|
|
4
|
-
import { ChatAppearanceContext } from '../chat-appearance-context';
|
|
5
|
-
import { ChatInput } from '../chat-input';
|
|
6
|
-
import { ChatMessageEnhanced } from '../chat-message-enhanced';
|
|
7
|
-
import { ErrorMessageDisplay } from '../error-message-display';
|
|
8
|
-
|
|
9
|
-
describe('chat appearance', () => {
|
|
10
|
-
it('classic keeps the colon after the author name', () => {
|
|
11
|
-
render(<ChatMessageEnhanced role="assistant" assistantType="fae" name="Fae" content="Hi" />);
|
|
12
|
-
expect(screen.getByText('Fae:')).toBeTruthy();
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('v2 drops the colon after the author name', () => {
|
|
16
|
-
render(<ChatMessageEnhanced role="assistant" assistantType="fae" name="Fae" content="Hi" appearance="v2" />);
|
|
17
|
-
expect(screen.getByText('Fae')).toBeTruthy();
|
|
18
|
-
expect(screen.queryByText('Fae:')).toBeNull();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('a row inherits v2 from the thread context', () => {
|
|
22
|
-
render(
|
|
23
|
-
<ChatAppearanceContext.Provider value="v2">
|
|
24
|
-
<ChatMessageEnhanced role="user" name="John Smith" content="Hi" />
|
|
25
|
-
</ChatAppearanceContext.Provider>,
|
|
26
|
-
);
|
|
27
|
-
expect(screen.getByText('John Smith')).toBeTruthy();
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('v2 blocks sit on the page surface', () => {
|
|
31
|
-
render(
|
|
32
|
-
<ChatAppearanceContext.Provider value="v2">
|
|
33
|
-
<ErrorMessageDisplay data-testid="error" title="AI response error" details="Something went wrong." />
|
|
34
|
-
<AiAssistantInfo data-testid="info" title="Handed Off to a Technician" />
|
|
35
|
-
</ChatAppearanceContext.Provider>,
|
|
36
|
-
);
|
|
37
|
-
const error = screen.getByTestId('error');
|
|
38
|
-
const info = screen.getByTestId('info');
|
|
39
|
-
expect(error.className).toContain('bg-ods-bg');
|
|
40
|
-
expect(error.className).not.toContain('mb-');
|
|
41
|
-
expect(info.className).toContain('bg-ods-bg');
|
|
42
|
-
expect(info.className).toContain('items-center');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('v2 turns a technician joining into a receipt card', () => {
|
|
46
|
-
render(
|
|
47
|
-
<ChatMessageEnhanced
|
|
48
|
-
role="user"
|
|
49
|
-
authorType="system"
|
|
50
|
-
name="Roman Smith joined the chat"
|
|
51
|
-
content=""
|
|
52
|
-
appearance="v2"
|
|
53
|
-
/>,
|
|
54
|
-
);
|
|
55
|
-
expect(screen.getByText('Technician Joined')).toBeTruthy();
|
|
56
|
-
expect(screen.getByText("You're now chatting with Roman Smith.")).toBeTruthy();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('classic keeps the system line as an author row', () => {
|
|
60
|
-
render(<ChatMessageEnhanced role="user" authorType="system" name="Roman Smith joined the chat" content="" />);
|
|
61
|
-
expect(screen.getByText('Roman Smith joined the chat')).toBeTruthy();
|
|
62
|
-
expect(screen.queryByText('Technician Joined')).toBeNull();
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('hand-off bar names the team and shows their faces', () => {
|
|
66
|
-
render(
|
|
67
|
-
<ChatInput
|
|
68
|
-
awaitingResponse
|
|
69
|
-
appearance="v2"
|
|
70
|
-
awaitingTeam={[
|
|
71
|
-
{ key: '1', name: 'Roman Smith' },
|
|
72
|
-
{ key: '2', name: 'Ada Lin' },
|
|
73
|
-
]}
|
|
74
|
-
/>,
|
|
75
|
-
);
|
|
76
|
-
expect(screen.getByText('Handed off to your technical support team')).toBeTruthy();
|
|
77
|
-
expect(screen.getByRole('group', { name: 'Technicians: Roman Smith, Ada Lin' })).toBeTruthy();
|
|
78
|
-
});
|
|
79
|
-
});
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { fireEvent, render, screen } from '@testing-library/react';
|
|
2
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import { OnboardingCarousel } from '../onboarding-carousel';
|
|
4
|
-
|
|
5
|
-
const STEPS = [
|
|
6
|
-
{ id: 'a', icon: null, title: 'First' },
|
|
7
|
-
{ id: 'b', icon: null, title: 'Second' },
|
|
8
|
-
{ id: 'c', icon: null, title: 'Third' },
|
|
9
|
-
];
|
|
10
|
-
|
|
11
|
-
const currentSlide = () =>
|
|
12
|
-
screen.getAllByRole('group', { hidden: true }).find(el => el.getAttribute('aria-hidden') === 'false');
|
|
13
|
-
|
|
14
|
-
describe('OnboardingCarousel', () => {
|
|
15
|
-
it('starts on the first step with Previous disabled', () => {
|
|
16
|
-
render(<OnboardingCarousel steps={STEPS} onComplete={vi.fn()} />);
|
|
17
|
-
expect(currentSlide()).toHaveTextContent('First');
|
|
18
|
-
expect(screen.getByRole('button', { name: 'Previous Step' })).toHaveAttribute('aria-disabled', 'true');
|
|
19
|
-
expect(screen.getByRole('button', { name: 'Next Step' })).toBeEnabled();
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('walks forward and back', () => {
|
|
23
|
-
render(<OnboardingCarousel steps={STEPS} onComplete={vi.fn()} />);
|
|
24
|
-
fireEvent.click(screen.getByRole('button', { name: 'Next Step' }));
|
|
25
|
-
expect(currentSlide()).toHaveTextContent('Second');
|
|
26
|
-
fireEvent.click(screen.getByRole('button', { name: 'Previous Step' }));
|
|
27
|
-
expect(currentSlide()).toHaveTextContent('First');
|
|
28
|
-
expect(screen.getByText('Step 1 of 3: First')).toHaveAttribute('aria-live', 'polite');
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('swaps Next for the complete action on the last step', () => {
|
|
32
|
-
const onComplete = vi.fn();
|
|
33
|
-
render(<OnboardingCarousel steps={STEPS} onComplete={onComplete} />);
|
|
34
|
-
fireEvent.click(screen.getByRole('button', { name: 'Go to step 3' }));
|
|
35
|
-
expect(screen.queryByRole('button', { name: 'Next Step' })).not.toBeInTheDocument();
|
|
36
|
-
fireEvent.click(screen.getByRole('button', { name: 'Start Chat' }));
|
|
37
|
-
expect(onComplete).toHaveBeenCalledTimes(1);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('follows the arrow keys and stops at the ends', () => {
|
|
41
|
-
render(<OnboardingCarousel steps={STEPS} onComplete={vi.fn()} />);
|
|
42
|
-
const region = screen.getByRole('region', { name: 'Introduction' });
|
|
43
|
-
fireEvent.keyDown(region, { key: 'ArrowLeft' });
|
|
44
|
-
expect(currentSlide()).toHaveTextContent('First');
|
|
45
|
-
fireEvent.keyDown(region, { key: 'ArrowRight' });
|
|
46
|
-
fireEvent.keyDown(region, { key: 'ArrowRight' });
|
|
47
|
-
fireEvent.keyDown(region, { key: 'ArrowRight' });
|
|
48
|
-
expect(currentSlide()).toHaveTextContent('Third');
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('marks the current dot', () => {
|
|
52
|
-
render(<OnboardingCarousel steps={STEPS} onComplete={vi.fn()} />);
|
|
53
|
-
expect(screen.getByRole('button', { name: 'Go to step 1' })).toHaveAttribute('aria-current', 'step');
|
|
54
|
-
expect(screen.getByRole('button', { name: 'Go to step 2' })).not.toHaveAttribute('aria-current');
|
|
55
|
-
});
|
|
56
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { createContext, useContext } from 'react';
|
|
4
|
-
import { CHAT_APPEARANCE, type ChatAppearance } from './types/chat.types';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Thread-wide `ChatAppearance`. `ChatMessageList` provides it, so the blocks a
|
|
8
|
-
* message renders (error, lifecycle receipts) follow the thread without every
|
|
9
|
-
* segment component growing an `appearance` prop.
|
|
10
|
-
*/
|
|
11
|
-
export const ChatAppearanceContext = createContext<ChatAppearance>(CHAT_APPEARANCE.CLASSIC);
|
|
12
|
-
|
|
13
|
-
export function useChatAppearance(): ChatAppearance {
|
|
14
|
-
return useContext(ChatAppearanceContext);
|
|
15
|
-
}
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { forwardRef, type ButtonHTMLAttributes, type HTMLAttributes, type ReactNode } from 'react';
|
|
4
|
-
import { cn } from '../../utils/cn';
|
|
5
|
-
import { ScrollFadeOverlay, useScrollFade } from '../ui/scroll-fade';
|
|
6
|
-
|
|
7
|
-
export interface ChatNavSidebarItem {
|
|
8
|
-
id: string;
|
|
9
|
-
label: string;
|
|
10
|
-
/** 24px glyph before the label. */
|
|
11
|
-
icon: ReactNode;
|
|
12
|
-
/** The view this item opens is the one on screen. */
|
|
13
|
-
active?: boolean;
|
|
14
|
-
onClick?: () => void;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface ChatNavSidebarProps extends HTMLAttributes<HTMLElement> {
|
|
18
|
-
/** Brand row at the top. */
|
|
19
|
-
logo?: ReactNode;
|
|
20
|
-
/** Primary actions under the logo (new chat, archive, help, ...). */
|
|
21
|
-
items: ChatNavSidebarItem[];
|
|
22
|
-
/** Caption over the list (e.g. "Your Current Chats"). */
|
|
23
|
-
sectionLabel?: string;
|
|
24
|
-
/** The list itself, typically `ChatListItem` rows or an empty state. Scrolls
|
|
25
|
-
* on its own; everything above it stays put. */
|
|
26
|
-
children?: ReactNode;
|
|
27
|
-
/** Pinned under the list, full width, above a divider (e.g. the MSP card). */
|
|
28
|
-
footer?: ReactNode;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Left rail of the fae chat v2 layout (Figma `chat-sidebar`): brand, a stack of
|
|
33
|
-
* navigation actions, a captioned scrolling list and a pinned footer. It only
|
|
34
|
-
* lays things out; which rows exist, what they show and what selecting them
|
|
35
|
-
* does belong to the host.
|
|
36
|
-
*/
|
|
37
|
-
const ChatNavSidebar = forwardRef<HTMLElement, ChatNavSidebarProps>(
|
|
38
|
-
({ className, logo, items, sectionLabel, children, footer, ...props }, ref) => {
|
|
39
|
-
const { scrollRef, fadeTop, fadeBottom, update: updateFade } = useScrollFade<HTMLDivElement>();
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<aside
|
|
43
|
-
ref={ref}
|
|
44
|
-
className={cn('flex h-full w-[296px] shrink-0 flex-col border-r border-ods-border bg-ods-bg', className)}
|
|
45
|
-
{...props}
|
|
46
|
-
>
|
|
47
|
-
<div className="flex min-h-0 flex-1 flex-col gap-[var(--spacing-system-m)] px-[var(--spacing-system-xs)] pt-[var(--spacing-system-mf)]">
|
|
48
|
-
{logo && <div className="flex shrink-0 items-center px-[var(--spacing-system-xs)]">{logo}</div>}
|
|
49
|
-
|
|
50
|
-
<nav className="flex shrink-0 flex-col gap-[var(--spacing-system-xxs)]">
|
|
51
|
-
{items.map(item => (
|
|
52
|
-
<ChatNavSidebarButton key={item.id} icon={item.icon} active={item.active} onClick={item.onClick}>
|
|
53
|
-
{item.label}
|
|
54
|
-
</ChatNavSidebarButton>
|
|
55
|
-
))}
|
|
56
|
-
</nav>
|
|
57
|
-
|
|
58
|
-
<div className="flex min-h-0 flex-1 flex-col gap-[var(--spacing-system-xxs)]">
|
|
59
|
-
{sectionLabel && (
|
|
60
|
-
<p className="shrink-0 px-[var(--spacing-system-xs)] pt-[var(--spacing-system-xs)] text-ods-text-secondary text-h5">
|
|
61
|
-
{sectionLabel}
|
|
62
|
-
</p>
|
|
63
|
-
)}
|
|
64
|
-
<div className="relative flex min-h-0 flex-1 flex-col">
|
|
65
|
-
<div
|
|
66
|
-
ref={scrollRef}
|
|
67
|
-
onScroll={updateFade}
|
|
68
|
-
className="flex min-h-0 flex-1 flex-col gap-[var(--spacing-system-xxs)] overflow-y-auto overscroll-contain pb-[var(--spacing-system-mf)]"
|
|
69
|
-
>
|
|
70
|
-
{children}
|
|
71
|
-
</div>
|
|
72
|
-
<ScrollFadeOverlay edge="top" visible={fadeTop} />
|
|
73
|
-
<ScrollFadeOverlay edge="bottom" visible={fadeBottom} />
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
76
|
-
</div>
|
|
77
|
-
|
|
78
|
-
{footer && <div className="shrink-0 border-t border-ods-border">{footer}</div>}
|
|
79
|
-
</aside>
|
|
80
|
-
);
|
|
81
|
-
},
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
ChatNavSidebar.displayName = 'ChatNavSidebar';
|
|
85
|
-
|
|
86
|
-
interface ChatNavSidebarButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
87
|
-
icon: ReactNode;
|
|
88
|
-
active?: boolean;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function ChatNavSidebarButton({ icon, active, className, children, ...props }: ChatNavSidebarButtonProps) {
|
|
92
|
-
return (
|
|
93
|
-
<button
|
|
94
|
-
type="button"
|
|
95
|
-
aria-current={active ? 'page' : undefined}
|
|
96
|
-
className={cn(
|
|
97
|
-
'flex w-full items-center gap-[var(--spacing-system-xs)] rounded-md p-[var(--spacing-system-xs)] text-left text-h4',
|
|
98
|
-
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ods-focus',
|
|
99
|
-
'[&_svg]:size-6 [&_svg]:shrink-0',
|
|
100
|
-
active ? 'text-ods-accent' : 'text-ods-text-primary [&_svg]:text-ods-text-secondary',
|
|
101
|
-
className,
|
|
102
|
-
)}
|
|
103
|
-
{...props}
|
|
104
|
-
>
|
|
105
|
-
{icon}
|
|
106
|
-
<span className="min-w-0 flex-1 truncate">{children}</span>
|
|
107
|
-
</button>
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export interface ChatListItemProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'title'> {
|
|
112
|
-
title: ReactNode;
|
|
113
|
-
/** Second line (e.g. the ticket number). */
|
|
114
|
-
subtitle?: ReactNode;
|
|
115
|
-
/** 16px mark before the title (e.g. a resolved check). */
|
|
116
|
-
leading?: ReactNode;
|
|
117
|
-
/** 24px status glyph at the row's end. */
|
|
118
|
-
trailing?: ReactNode;
|
|
119
|
-
/** The chat open on screen. */
|
|
120
|
-
active?: boolean;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* One row of the `ChatNavSidebar` list (Figma `chat-list-item`): a one-line
|
|
125
|
-
* title over a caption, an optional mark before the title and a status glyph
|
|
126
|
-
* at the end. The selected row takes the accent's secondary fill, so a tenant
|
|
127
|
-
* accent recolours it with the rest of the brand.
|
|
128
|
-
*/
|
|
129
|
-
const ChatListItem = forwardRef<HTMLButtonElement, ChatListItemProps>(
|
|
130
|
-
({ className, title, subtitle, leading, trailing, active, ...props }, ref) => (
|
|
131
|
-
<button
|
|
132
|
-
ref={ref}
|
|
133
|
-
type="button"
|
|
134
|
-
aria-current={active ? 'true' : undefined}
|
|
135
|
-
className={cn(
|
|
136
|
-
'flex w-full shrink-0 items-center gap-[var(--spacing-system-xs)] rounded-md p-[var(--spacing-system-xs)] text-left',
|
|
137
|
-
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ods-focus',
|
|
138
|
-
active && 'bg-ods-accent-secondary',
|
|
139
|
-
className,
|
|
140
|
-
)}
|
|
141
|
-
{...props}
|
|
142
|
-
>
|
|
143
|
-
<span className="flex min-w-0 flex-1 flex-col">
|
|
144
|
-
<span className="flex min-w-0 items-center gap-[var(--spacing-system-xxs)]">
|
|
145
|
-
{leading && <span className="flex shrink-0 items-center [&_svg]:size-4">{leading}</span>}
|
|
146
|
-
<span className={cn('min-w-0 flex-1 truncate text-h4', active ? 'text-ods-accent' : 'text-ods-text-primary')}>
|
|
147
|
-
{title}
|
|
148
|
-
</span>
|
|
149
|
-
</span>
|
|
150
|
-
{subtitle != null && (
|
|
151
|
-
<span className={cn('truncate text-h6', active ? 'text-ods-text-primary' : 'text-ods-text-secondary')}>
|
|
152
|
-
{subtitle}
|
|
153
|
-
</span>
|
|
154
|
-
)}
|
|
155
|
-
</span>
|
|
156
|
-
{trailing && <span className="flex shrink-0 items-center [&_svg]:size-6">{trailing}</span>}
|
|
157
|
-
</button>
|
|
158
|
-
),
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
ChatListItem.displayName = 'ChatListItem';
|
|
162
|
-
|
|
163
|
-
export { ChatNavSidebar, ChatListItem };
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { forwardRef, type HTMLAttributes, type ReactNode } from 'react';
|
|
4
|
-
import { cn } from '../../utils/cn';
|
|
5
|
-
import { Settings01Icon, SidebarIcon } from '../icons-v2-generated';
|
|
6
|
-
import { Skeleton } from '../ui/skeleton';
|
|
7
|
-
import { SquareAvatar } from '../ui/square-avatar';
|
|
8
|
-
|
|
9
|
-
export interface ChatTopNavigationProps extends HTMLAttributes<HTMLElement> {
|
|
10
|
-
/** Who the user is talking to. */
|
|
11
|
-
name: string;
|
|
12
|
-
/** Line under the name (e.g. "Your AI Assistant", "IT Technician"). */
|
|
13
|
-
subtitle?: string;
|
|
14
|
-
avatarUrl?: string | null;
|
|
15
|
-
/** Actions after the identity (e.g. "Request a Technician"). */
|
|
16
|
-
actions?: ReactNode;
|
|
17
|
-
/** Shows the sidebar toggle at the start of the bar. */
|
|
18
|
-
onToggleSidebar?: () => void;
|
|
19
|
-
/** Whether the sidebar is currently shown; drives the toggle's state. */
|
|
20
|
-
sidebarOpen?: boolean;
|
|
21
|
-
/** Shows the settings button at the end of the bar. */
|
|
22
|
-
onOpenSettings?: () => void;
|
|
23
|
-
/** Content above the bar, full width (e.g. a "Back to ..." strip). */
|
|
24
|
-
before?: ReactNode;
|
|
25
|
-
/** Identity still resolving: placeholders instead of a default name that
|
|
26
|
-
* would flash before the tenant's branding lands. */
|
|
27
|
-
isLoading?: boolean;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const edgeButtonClass = cn(
|
|
31
|
-
'flex size-14 shrink-0 items-center justify-center border-ods-border text-ods-text-secondary',
|
|
32
|
-
'hover:text-ods-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ods-focus',
|
|
33
|
-
'[&_svg]:size-6',
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Top bar of the fae chat v2 layout (Figma `chat-top-navigation`): an optional
|
|
38
|
-
* sidebar toggle, the counterpart's avatar, name and role, the host's actions
|
|
39
|
-
* and an optional settings button, split by vertical dividers.
|
|
40
|
-
*/
|
|
41
|
-
const ChatTopNavigation = forwardRef<HTMLElement, ChatTopNavigationProps>(
|
|
42
|
-
(
|
|
43
|
-
{
|
|
44
|
-
className,
|
|
45
|
-
name,
|
|
46
|
-
subtitle,
|
|
47
|
-
avatarUrl,
|
|
48
|
-
actions,
|
|
49
|
-
onToggleSidebar,
|
|
50
|
-
sidebarOpen,
|
|
51
|
-
onOpenSettings,
|
|
52
|
-
before,
|
|
53
|
-
isLoading,
|
|
54
|
-
...props
|
|
55
|
-
},
|
|
56
|
-
ref,
|
|
57
|
-
) => (
|
|
58
|
-
<header ref={ref} className={cn('flex shrink-0 flex-col bg-ods-bg', className)} {...props}>
|
|
59
|
-
{before}
|
|
60
|
-
<div className="flex h-14 items-stretch border-b border-ods-border">
|
|
61
|
-
{onToggleSidebar && (
|
|
62
|
-
<button
|
|
63
|
-
type="button"
|
|
64
|
-
onClick={onToggleSidebar}
|
|
65
|
-
aria-label={sidebarOpen ? 'Hide sidebar' : 'Show sidebar'}
|
|
66
|
-
aria-expanded={sidebarOpen}
|
|
67
|
-
className={cn(edgeButtonClass, 'border-r')}
|
|
68
|
-
>
|
|
69
|
-
<SidebarIcon />
|
|
70
|
-
</button>
|
|
71
|
-
)}
|
|
72
|
-
<div className="flex min-w-0 flex-1 items-center gap-[var(--spacing-system-m)] px-[var(--spacing-system-m)]">
|
|
73
|
-
{isLoading ? (
|
|
74
|
-
<>
|
|
75
|
-
<Skeleton className="size-10 shrink-0 rounded-full" />
|
|
76
|
-
<div className="flex min-w-0 flex-1 flex-col gap-[var(--spacing-system-xxs)]">
|
|
77
|
-
<Skeleton className="h-5 w-24" />
|
|
78
|
-
<Skeleton className="h-4 w-32" />
|
|
79
|
-
</div>
|
|
80
|
-
</>
|
|
81
|
-
) : (
|
|
82
|
-
<>
|
|
83
|
-
<SquareAvatar src={avatarUrl ?? undefined} alt={name} fallback={name} size="md" variant="round" />
|
|
84
|
-
<div className="flex min-w-0 flex-1 flex-col">
|
|
85
|
-
<p className="truncate text-ods-text-primary text-h3">{name}</p>
|
|
86
|
-
{subtitle && <p className="truncate text-ods-text-secondary text-h6">{subtitle}</p>}
|
|
87
|
-
</div>
|
|
88
|
-
</>
|
|
89
|
-
)}
|
|
90
|
-
{actions && <div className="flex shrink-0 items-center gap-[var(--spacing-system-xs)]">{actions}</div>}
|
|
91
|
-
</div>
|
|
92
|
-
{onOpenSettings && (
|
|
93
|
-
<button
|
|
94
|
-
type="button"
|
|
95
|
-
onClick={onOpenSettings}
|
|
96
|
-
aria-label="Settings"
|
|
97
|
-
className={cn(edgeButtonClass, 'border-l')}
|
|
98
|
-
>
|
|
99
|
-
<Settings01Icon />
|
|
100
|
-
</button>
|
|
101
|
-
)}
|
|
102
|
-
</div>
|
|
103
|
-
</header>
|
|
104
|
-
),
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
ChatTopNavigation.displayName = 'ChatTopNavigation';
|
|
108
|
-
|
|
109
|
-
export { ChatTopNavigation };
|