@brandsync/wc 0.0.8 → 0.0.9
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/custom-elements.json +1808 -353
- package/dist/brandsync-wc/brandsync-wc.esm.js +1 -1
- package/dist/brandsync-wc/p-0d64ea40.entry.js +1 -0
- package/dist/brandsync-wc/{p-c63d16e1.entry.js → p-1515498e.entry.js} +1 -1
- package/dist/brandsync-wc/p-16a54578.entry.js +1 -0
- package/dist/brandsync-wc/p-18af02df.entry.js +1 -0
- package/dist/brandsync-wc/p-30a0e168.entry.js +1 -0
- package/dist/brandsync-wc/p-3dacae70.entry.js +1 -0
- package/dist/brandsync-wc/p-5333bb5a.entry.js +1 -0
- package/dist/brandsync-wc/p-575ce905.entry.js +1 -0
- package/dist/brandsync-wc/{p-dd0fea0e.entry.js → p-7776b57b.entry.js} +1 -1
- package/dist/brandsync-wc/{p-260bd201.entry.js → p-805644e4.entry.js} +1 -1
- package/dist/brandsync-wc/{p-f88d9a6e.entry.js → p-8a78d6ea.entry.js} +1 -1
- package/dist/brandsync-wc/p-8d12ed96.entry.js +1 -0
- package/dist/brandsync-wc/p-94ed898a.entry.js +1 -0
- package/dist/brandsync-wc/{p-9e5d2211.entry.js → p-96f374be.entry.js} +1 -1
- package/dist/brandsync-wc/{p-ab5cc7af.entry.js → p-a34f460d.entry.js} +1 -1
- package/dist/brandsync-wc/p-bc72439a.entry.js +1 -0
- package/dist/brandsync-wc/{p-76eca100.entry.js → p-ce0914a7.entry.js} +1 -1
- package/dist/brandsync-wc/{p-5a0fe72e.entry.js → p-d682675e.entry.js} +1 -1
- package/dist/brandsync-wc/p-dad4a92c.entry.js +1 -0
- package/dist/brandsync-wc/{p-cfc3421b.entry.js → p-dd747a12.entry.js} +1 -1
- package/dist/brandsync-wc/{p-2742ecef.entry.js → p-eb4d87f0.entry.js} +1 -1
- package/dist/cjs/brandsync-wc.cjs.js +1 -1
- package/dist/cjs/bs-ai-disclaimer.cjs.entry.js +17 -0
- package/dist/cjs/bs-ai-greeting.cjs.entry.js +24 -0
- package/dist/cjs/bs-ai-thinking.cjs.entry.js +1 -1
- package/dist/cjs/bs-attachment-list.cjs.entry.js +47 -0
- package/dist/cjs/bs-attachment.cjs.entry.js +46 -0
- package/dist/cjs/bs-badge.cjs.entry.js +1 -1
- package/dist/cjs/bs-button-skeleton.cjs.entry.js +1 -1
- package/dist/cjs/bs-button.cjs.entry.js +1 -1
- package/dist/cjs/bs-card.cjs.entry.js +1 -1
- package/dist/cjs/bs-chatbot-feedback.cjs.entry.js +94 -0
- package/dist/cjs/bs-chatbot-header.cjs.entry.js +1 -1
- package/dist/cjs/bs-chatbot-response-action.cjs.entry.js +1 -1
- package/dist/cjs/bs-chatbot-sources-drawer.cjs.entry.js +38 -0
- package/dist/cjs/bs-chatbot-suggestion-button.cjs.entry.js +1 -1
- package/dist/cjs/bs-composer-status-banner.cjs.entry.js +43 -0
- package/dist/cjs/bs-composer.cjs.entry.js +16 -2
- package/dist/cjs/bs-data-table.cjs.entry.js +2 -2
- package/dist/cjs/bs-input.cjs.entry.js +270 -4
- package/dist/cjs/{bs-menu-item.cjs.entry.js → bs-menu_2.cjs.entry.js} +14 -1
- package/dist/cjs/bs-source-link.cjs.entry.js +39 -0
- package/dist/cjs/bs-tooltip.cjs.entry.js +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/collection/collection-manifest.json +8 -0
- package/dist/collection/components/bs-ai-chatbot/bs-ai-chatbot.stories.js +180 -0
- package/dist/collection/components/bs-ai-disclaimer/bs-ai-disclaimer.cmp.test.js +14 -0
- package/dist/collection/components/bs-ai-disclaimer/bs-ai-disclaimer.css +27 -0
- package/dist/collection/components/bs-ai-disclaimer/bs-ai-disclaimer.js +41 -0
- package/dist/collection/components/bs-ai-disclaimer/bs-ai-disclaimer.stories.js +15 -0
- package/dist/collection/components/bs-ai-greeting/bs-ai-greeting.cmp.test.js +22 -0
- package/dist/collection/components/bs-ai-greeting/bs-ai-greeting.css +53 -0
- package/dist/collection/components/bs-ai-greeting/bs-ai-greeting.js +103 -0
- package/dist/collection/components/bs-ai-greeting/bs-ai-greeting.stories.js +23 -0
- package/dist/collection/components/bs-ai-thinking/bs-ai-thinking.js +1 -1
- package/dist/collection/components/bs-attachment/bs-attachment.cmp.test.js +41 -0
- package/dist/collection/components/bs-attachment/bs-attachment.css +184 -0
- package/dist/collection/components/bs-attachment/bs-attachment.js +230 -0
- package/dist/collection/components/bs-attachment/bs-attachment.stories.js +58 -0
- package/dist/collection/components/bs-attachment-list/bs-attachment-list.cmp.test.js +28 -0
- package/dist/collection/components/bs-attachment-list/bs-attachment-list.css +56 -0
- package/dist/collection/components/bs-attachment-list/bs-attachment-list.js +105 -0
- package/dist/collection/components/bs-attachment-list/bs-attachment-list.stories.js +47 -0
- package/dist/collection/components/bs-badge/bs-badge.js +1 -1
- package/dist/collection/components/bs-button/bs-button.js +1 -1
- package/dist/collection/components/bs-button-skeleton/bs-button-skeleton.js +1 -1
- package/dist/collection/components/bs-card/bs-card.js +1 -1
- package/dist/collection/components/bs-chatbot-feedback/bs-chatbot-feedback.cmp.test.js +73 -0
- package/dist/collection/components/bs-chatbot-feedback/bs-chatbot-feedback.css +253 -0
- package/dist/collection/components/bs-chatbot-feedback/bs-chatbot-feedback.js +324 -0
- package/dist/collection/components/bs-chatbot-feedback/bs-chatbot-feedback.stories.js +54 -0
- package/dist/collection/components/bs-chatbot-header/bs-chatbot-header.js +1 -1
- package/dist/collection/components/bs-chatbot-response-action/bs-chatbot-response-action.js +1 -1
- package/dist/collection/components/bs-chatbot-sources-drawer/bs-chatbot-sources-drawer.cmp.test.js +34 -0
- package/dist/collection/components/bs-chatbot-sources-drawer/bs-chatbot-sources-drawer.css +106 -0
- package/dist/collection/components/bs-chatbot-sources-drawer/bs-chatbot-sources-drawer.js +142 -0
- package/dist/collection/components/bs-chatbot-sources-drawer/bs-chatbot-sources-drawer.stories.js +44 -0
- package/dist/collection/components/bs-chatbot-suggestion-button/bs-chatbot-suggestion-button.js +1 -1
- package/dist/collection/components/bs-composer/bs-composer.cmp.test.js +12 -0
- package/dist/collection/components/bs-composer/bs-composer.css +10 -0
- package/dist/collection/components/bs-composer/bs-composer.js +25 -1
- package/dist/collection/components/bs-composer/bs-composer.stories.js +13 -0
- package/dist/collection/components/bs-composer-status-banner/bs-composer-status-banner.cmp.test.js +42 -0
- package/dist/collection/components/bs-composer-status-banner/bs-composer-status-banner.css +173 -0
- package/dist/collection/components/bs-composer-status-banner/bs-composer-status-banner.js +270 -0
- package/dist/collection/components/bs-composer-status-banner/bs-composer-status-banner.stories.js +75 -0
- package/dist/collection/components/bs-data-table/bs-data-table.js +2 -2
- package/dist/collection/components/bs-input/bs-input.cmp.test.js +296 -0
- package/dist/collection/components/bs-input/bs-input.css +333 -23
- package/dist/collection/components/bs-input/bs-input.js +647 -11
- package/dist/collection/components/bs-input/bs-input.stories.js +128 -1
- package/dist/collection/components/bs-menu/bs-menu.js +1 -1
- package/dist/collection/components/bs-menu-item/bs-menu-item.js +1 -1
- package/dist/collection/components/bs-source-link/bs-source-link.cmp.test.js +42 -0
- package/dist/collection/components/bs-source-link/bs-source-link.css +114 -0
- package/dist/collection/components/bs-source-link/bs-source-link.js +192 -0
- package/dist/collection/components/bs-source-link/bs-source-link.stories.js +33 -0
- package/dist/collection/components/bs-tooltip/bs-tooltip.js +1 -1
- package/dist/components/bs-ai-disclaimer.d.ts +11 -0
- package/dist/components/bs-ai-disclaimer.js +1 -0
- package/dist/components/bs-ai-greeting.d.ts +11 -0
- package/dist/components/bs-ai-greeting.js +1 -0
- package/dist/components/bs-ai-thinking.js +1 -1
- package/dist/components/bs-attachment-list.d.ts +11 -0
- package/dist/components/bs-attachment-list.js +1 -0
- package/dist/components/bs-attachment.d.ts +11 -0
- package/dist/components/bs-attachment.js +1 -0
- package/dist/components/bs-badge.js +1 -1
- package/dist/components/bs-button-skeleton.js +1 -1
- package/dist/components/bs-button.js +1 -1
- package/dist/components/bs-card.js +1 -1
- package/dist/components/bs-chatbot-feedback.d.ts +11 -0
- package/dist/components/bs-chatbot-feedback.js +1 -0
- package/dist/components/bs-chatbot-header.js +1 -1
- package/dist/components/bs-chatbot-response-action.js +1 -1
- package/dist/components/bs-chatbot-sources-drawer.d.ts +11 -0
- package/dist/components/bs-chatbot-sources-drawer.js +1 -0
- package/dist/components/bs-chatbot-suggestion-button.js +1 -1
- package/dist/components/bs-composer-status-banner.d.ts +11 -0
- package/dist/components/bs-composer-status-banner.js +1 -0
- package/dist/components/bs-composer.js +1 -1
- package/dist/components/bs-data-table.js +1 -1
- package/dist/components/bs-input.js +1 -1
- package/dist/components/bs-menu-item.js +1 -1
- package/dist/components/bs-menu.js +1 -1
- package/dist/components/bs-source-link.d.ts +11 -0
- package/dist/components/bs-source-link.js +1 -0
- package/dist/components/bs-tooltip.js +1 -1
- package/dist/components/{p-CoC4LQCI.js → p-Cz2nfz2j.js} +1 -1
- package/dist/components/p-DndQiCMP.js +1 -0
- package/dist/components/p-_vXDfB3V.js +1 -0
- package/dist/esm/brandsync-wc.js +1 -1
- package/dist/esm/bs-ai-disclaimer.entry.js +15 -0
- package/dist/esm/bs-ai-greeting.entry.js +22 -0
- package/dist/esm/bs-ai-thinking.entry.js +1 -1
- package/dist/esm/bs-attachment-list.entry.js +45 -0
- package/dist/esm/bs-attachment.entry.js +44 -0
- package/dist/esm/bs-badge.entry.js +1 -1
- package/dist/esm/bs-button-skeleton.entry.js +1 -1
- package/dist/esm/bs-button.entry.js +1 -1
- package/dist/esm/bs-card.entry.js +1 -1
- package/dist/esm/bs-chatbot-feedback.entry.js +92 -0
- package/dist/esm/bs-chatbot-header.entry.js +1 -1
- package/dist/esm/bs-chatbot-response-action.entry.js +1 -1
- package/dist/esm/bs-chatbot-sources-drawer.entry.js +36 -0
- package/dist/esm/bs-chatbot-suggestion-button.entry.js +1 -1
- package/dist/esm/bs-composer-status-banner.entry.js +41 -0
- package/dist/esm/bs-composer.entry.js +17 -3
- package/dist/esm/bs-data-table.entry.js +2 -2
- package/dist/esm/bs-input.entry.js +271 -5
- package/dist/esm/{bs-menu-item.entry.js → bs-menu_2.entry.js} +15 -3
- package/dist/esm/bs-source-link.entry.js +37 -0
- package/dist/esm/bs-tooltip.entry.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/types/components/bs-ai-chatbot/bs-ai-chatbot.stories.d.ts +18 -0
- package/dist/types/components/bs-ai-disclaimer/bs-ai-disclaimer.cmp.test.d.ts +1 -0
- package/dist/types/components/bs-ai-disclaimer/bs-ai-disclaimer.d.ts +26 -0
- package/dist/types/components/bs-ai-disclaimer/bs-ai-disclaimer.stories.d.ts +8 -0
- package/dist/types/components/bs-ai-greeting/bs-ai-greeting.cmp.test.d.ts +1 -0
- package/dist/types/components/bs-ai-greeting/bs-ai-greeting.d.ts +42 -0
- package/dist/types/components/bs-ai-greeting/bs-ai-greeting.stories.d.ts +10 -0
- package/dist/types/components/bs-attachment/bs-attachment.cmp.test.d.ts +1 -0
- package/dist/types/components/bs-attachment/bs-attachment.d.ts +59 -0
- package/dist/types/components/bs-attachment/bs-attachment.stories.d.ts +17 -0
- package/dist/types/components/bs-attachment-list/bs-attachment-list.cmp.test.d.ts +1 -0
- package/dist/types/components/bs-attachment-list/bs-attachment-list.d.ts +42 -0
- package/dist/types/components/bs-attachment-list/bs-attachment-list.stories.d.ts +10 -0
- package/dist/types/components/bs-chatbot-feedback/bs-chatbot-feedback.cmp.test.d.ts +1 -0
- package/dist/types/components/bs-chatbot-feedback/bs-chatbot-feedback.d.ts +90 -0
- package/dist/types/components/bs-chatbot-feedback/bs-chatbot-feedback.stories.d.ts +16 -0
- package/dist/types/components/bs-chatbot-sources-drawer/bs-chatbot-sources-drawer.cmp.test.d.ts +1 -0
- package/dist/types/components/bs-chatbot-sources-drawer/bs-chatbot-sources-drawer.d.ts +54 -0
- package/dist/types/components/bs-chatbot-sources-drawer/bs-chatbot-sources-drawer.stories.d.ts +10 -0
- package/dist/types/components/bs-composer/bs-composer.d.ts +14 -0
- package/dist/types/components/bs-composer/bs-composer.stories.d.ts +1 -0
- package/dist/types/components/bs-composer-status-banner/bs-composer-status-banner.cmp.test.d.ts +1 -0
- package/dist/types/components/bs-composer-status-banner/bs-composer-status-banner.d.ts +88 -0
- package/dist/types/components/bs-composer-status-banner/bs-composer-status-banner.stories.d.ts +20 -0
- package/dist/types/components/bs-input/bs-input.d.ts +139 -6
- package/dist/types/components/bs-input/bs-input.stories.d.ts +19 -0
- package/dist/types/components/bs-source-link/bs-source-link.cmp.test.d.ts +1 -0
- package/dist/types/components/bs-source-link/bs-source-link.d.ts +51 -0
- package/dist/types/components/bs-source-link/bs-source-link.stories.d.ts +13 -0
- package/dist/types/components.d.ts +1746 -19
- package/package.json +1 -1
- package/dist/brandsync-wc/p-6abdfaf0.entry.js +0 -1
- package/dist/brandsync-wc/p-6c1fa4da.entry.js +0 -1
- package/dist/brandsync-wc/p-a12d0a60.entry.js +0 -1
- package/dist/brandsync-wc/p-f5f443e2.entry.js +0 -1
- package/dist/cjs/bs-menu.cjs.entry.js +0 -17
- package/dist/esm/bs-menu.entry.js +0 -15
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { html } from "lit";
|
|
2
|
+
/**
|
|
3
|
+
* This is not a real component -- `bs-ai-chatbot` isn't a registered custom element. It's a
|
|
4
|
+
* showcase composing the existing Genie AI components (bs-chatbot-header, bs-ai-greeting,
|
|
5
|
+
* bs-chatbot-suggestion-button, bs-composer, bs-composer-status-banner, bs-attachment-list,
|
|
6
|
+
* bs-ai-thinking, bs-chatbot-response-action, bs-chatbot-sources-drawer, bs-ai-disclaimer) into
|
|
7
|
+
* realistic full-panel use cases, since no single component's own story shows how they fit
|
|
8
|
+
* together end to end.
|
|
9
|
+
*/
|
|
10
|
+
const meta = {
|
|
11
|
+
title: 'Genie AI Components/bs-ai-chatbot',
|
|
12
|
+
parameters: { docs: { description: { component: 'A composed showcase of Genie AI components in realistic full-chat-panel use cases. Not a real custom element.' } } },
|
|
13
|
+
};
|
|
14
|
+
export default meta;
|
|
15
|
+
const PANEL_STYLE = `
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
width: 420px;
|
|
19
|
+
height: 640px;
|
|
20
|
+
border: 1px solid var(--bs-border-default);
|
|
21
|
+
border-radius: var(--bs-border-radius-200);
|
|
22
|
+
overflow: hidden;
|
|
23
|
+
background: var(--bs-surface-base);
|
|
24
|
+
font-family: var(--bs-typography-font-family-body), sans-serif;
|
|
25
|
+
`;
|
|
26
|
+
const TRANSCRIPT_STYLE = `
|
|
27
|
+
flex: 1;
|
|
28
|
+
min-height: 0;
|
|
29
|
+
overflow-y: auto;
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-direction: column;
|
|
32
|
+
gap: var(--bs-spacing-200);
|
|
33
|
+
padding: var(--bs-spacing-200);
|
|
34
|
+
`;
|
|
35
|
+
const USER_BUBBLE_STYLE = `
|
|
36
|
+
align-self: flex-end;
|
|
37
|
+
max-width: 80%;
|
|
38
|
+
padding: var(--bs-spacing-100) var(--bs-spacing-150);
|
|
39
|
+
border-radius: var(--bs-border-radius-150);
|
|
40
|
+
background: var(--bs-color-primary-container);
|
|
41
|
+
color: var(--bs-text-default);
|
|
42
|
+
font-size: var(--bs-font-size-md);
|
|
43
|
+
line-height: 1.5;
|
|
44
|
+
`;
|
|
45
|
+
const AI_RESPONSE_STYLE = `
|
|
46
|
+
max-width: 100%;
|
|
47
|
+
color: var(--bs-text-default);
|
|
48
|
+
font-size: var(--bs-font-size-md);
|
|
49
|
+
line-height: 1.5;
|
|
50
|
+
`;
|
|
51
|
+
export const EmptyState = {
|
|
52
|
+
name: 'Empty state',
|
|
53
|
+
render: () => html `
|
|
54
|
+
<div style=${PANEL_STYLE}>
|
|
55
|
+
<bs-chatbot-header heading="Genie"></bs-chatbot-header>
|
|
56
|
+
<div style="${TRANSCRIPT_STYLE} align-items: center; justify-content: center; gap: var(--bs-spacing-400);">
|
|
57
|
+
<bs-ai-greeting product-name="BrandSync"></bs-ai-greeting>
|
|
58
|
+
<div style="display: flex; flex-wrap: wrap; gap: var(--bs-spacing-100); justify-content: center;">
|
|
59
|
+
<bs-chatbot-suggestion-button>How do I reset my password?</bs-chatbot-suggestion-button>
|
|
60
|
+
<bs-chatbot-suggestion-button>Summarize this document</bs-chatbot-suggestion-button>
|
|
61
|
+
<bs-chatbot-suggestion-button>What's my leave balance?</bs-chatbot-suggestion-button>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
<bs-composer aria-label="Message" style="margin: var(--bs-spacing-100) var(--bs-spacing-200) 0;"></bs-composer>
|
|
65
|
+
<bs-ai-disclaimer style="padding: var(--bs-spacing-100) 0;">AI can make mistakes. Please verify important information.</bs-ai-disclaimer>
|
|
66
|
+
</div>
|
|
67
|
+
`,
|
|
68
|
+
};
|
|
69
|
+
export const ActiveConversation = {
|
|
70
|
+
name: 'Active conversation',
|
|
71
|
+
render: () => html `
|
|
72
|
+
<div style=${PANEL_STYLE}>
|
|
73
|
+
<bs-chatbot-header heading="Genie"></bs-chatbot-header>
|
|
74
|
+
<div style=${TRANSCRIPT_STYLE}>
|
|
75
|
+
<p style=${USER_BUBBLE_STYLE}>How do I submit a ByggSøk application?</p>
|
|
76
|
+
<div style="display: flex; flex-direction: column; gap: var(--bs-spacing-50);">
|
|
77
|
+
<p style=${AI_RESPONSE_STYLE}>
|
|
78
|
+
You can submit a ByggSøk application through the municipal portal. Log in with your ID, select "New
|
|
79
|
+
application", and attach your building plans before submitting for review.
|
|
80
|
+
</p>
|
|
81
|
+
<bs-chatbot-response-action sources-count="3"></bs-chatbot-response-action>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
<bs-composer aria-label="Message" style="margin: var(--bs-spacing-100) var(--bs-spacing-200) 0;"></bs-composer>
|
|
85
|
+
<bs-ai-disclaimer style="padding: var(--bs-spacing-100) 0;">AI can make mistakes. Please verify important information.</bs-ai-disclaimer>
|
|
86
|
+
</div>
|
|
87
|
+
`,
|
|
88
|
+
};
|
|
89
|
+
export const Thinking = {
|
|
90
|
+
name: 'AI is thinking',
|
|
91
|
+
render: () => html `
|
|
92
|
+
<div style=${PANEL_STYLE}>
|
|
93
|
+
<bs-chatbot-header heading="Genie"></bs-chatbot-header>
|
|
94
|
+
<div style=${TRANSCRIPT_STYLE}>
|
|
95
|
+
<p style=${USER_BUBBLE_STYLE}>How do I submit a ByggSøk application?</p>
|
|
96
|
+
<bs-ai-thinking label="Retrieving sources"></bs-ai-thinking>
|
|
97
|
+
</div>
|
|
98
|
+
<bs-composer aria-label="Message" state="generating" style="margin: var(--bs-spacing-100) var(--bs-spacing-200) 0;"></bs-composer>
|
|
99
|
+
<bs-ai-disclaimer style="padding: var(--bs-spacing-100) 0;">AI can make mistakes. Please verify important information.</bs-ai-disclaimer>
|
|
100
|
+
</div>
|
|
101
|
+
`,
|
|
102
|
+
};
|
|
103
|
+
export const WithSourcesDrawerOpen = {
|
|
104
|
+
name: 'Sources drawer open',
|
|
105
|
+
render: () => html `
|
|
106
|
+
<div style="${PANEL_STYLE} position: relative;">
|
|
107
|
+
<bs-chatbot-header heading="Genie"></bs-chatbot-header>
|
|
108
|
+
<div style=${TRANSCRIPT_STYLE}>
|
|
109
|
+
<p style=${USER_BUBBLE_STYLE}>How do I submit a ByggSøk application?</p>
|
|
110
|
+
<div style="display: flex; flex-direction: column; gap: var(--bs-spacing-50);">
|
|
111
|
+
<p style=${AI_RESPONSE_STYLE}>
|
|
112
|
+
You can submit a ByggSøk application through the municipal portal. Log in with your ID, select "New
|
|
113
|
+
application", and attach your building plans before submitting for review.
|
|
114
|
+
</p>
|
|
115
|
+
<bs-chatbot-response-action sources-count="3"></bs-chatbot-response-action>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
<bs-composer aria-label="Message" style="margin: var(--bs-spacing-100) var(--bs-spacing-200) 0;"></bs-composer>
|
|
119
|
+
<bs-ai-disclaimer style="padding: var(--bs-spacing-100) 0;">AI can make mistakes. Please verify important information.</bs-ai-disclaimer>
|
|
120
|
+
|
|
121
|
+
<!-- Backdrop -->
|
|
122
|
+
<div style="position: absolute; inset: 0; background: rgba(33, 38, 46, 0.32);"></div>
|
|
123
|
+
|
|
124
|
+
<!-- Slide-in drawer, docked to the panel's own right edge -- not a separate side-by-side
|
|
125
|
+
column, so it stays within the chat panel's own bounds like a real in-app drawer. -->
|
|
126
|
+
<div style="position: absolute; top: 0; right: 0; bottom: 0; width: 85%; box-shadow: var(--bs-shadow-lg); background: var(--bs-surface-raised);">
|
|
127
|
+
<bs-chatbot-sources-drawer heading="Sources">
|
|
128
|
+
<bs-source-link file-name="Employee Handbook 2026" source-name="HoltePortalen" version="v3.2"></bs-source-link>
|
|
129
|
+
<bs-source-link file-name="Payroll Processing Guide" source-name="WorkdayHQ" version="v2.4"></bs-source-link>
|
|
130
|
+
<bs-source-link file-name="Benefits & Leave Policy" source-name="PeopleOps Wiki" version="v1.8"></bs-source-link>
|
|
131
|
+
</bs-chatbot-sources-drawer>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
`,
|
|
135
|
+
};
|
|
136
|
+
export const UploadingAttachments = {
|
|
137
|
+
name: 'Uploading attachments',
|
|
138
|
+
render: () => html `
|
|
139
|
+
<div style=${PANEL_STYLE}>
|
|
140
|
+
<bs-chatbot-header heading="Genie"></bs-chatbot-header>
|
|
141
|
+
<div style=${TRANSCRIPT_STYLE}></div>
|
|
142
|
+
<div style="margin: 0 var(--bs-spacing-200);">
|
|
143
|
+
<bs-composer-status-banner
|
|
144
|
+
type="info"
|
|
145
|
+
message="Uploading files, please wait."
|
|
146
|
+
style="margin-bottom: calc(-1 * var(--bs-spacing-150));"
|
|
147
|
+
></bs-composer-status-banner>
|
|
148
|
+
<bs-composer aria-label="Message">
|
|
149
|
+
<bs-attachment-list slot="attachments">
|
|
150
|
+
<bs-attachment type="image" image-src="https://images.unsplash.com/photo-1512917774080-9991f1c4c750?w=200&h=200&fit=crop" loading></bs-attachment>
|
|
151
|
+
<bs-attachment type="pdf" file-name="Dummy-pdf-in-here" loading></bs-attachment>
|
|
152
|
+
</bs-attachment-list>
|
|
153
|
+
</bs-composer>
|
|
154
|
+
</div>
|
|
155
|
+
<bs-ai-disclaimer style="padding: var(--bs-spacing-100) 0;">AI can make mistakes. Please verify important information.</bs-ai-disclaimer>
|
|
156
|
+
</div>
|
|
157
|
+
`,
|
|
158
|
+
};
|
|
159
|
+
export const SendFailed = {
|
|
160
|
+
name: 'Send failed',
|
|
161
|
+
render: () => html `
|
|
162
|
+
<div style=${PANEL_STYLE}>
|
|
163
|
+
<bs-chatbot-header heading="Genie"></bs-chatbot-header>
|
|
164
|
+
<div style=${TRANSCRIPT_STYLE}>
|
|
165
|
+
<p style=${USER_BUBBLE_STYLE}>How do I submit a ByggSøk application?</p>
|
|
166
|
+
</div>
|
|
167
|
+
<div style="margin: 0 var(--bs-spacing-200);">
|
|
168
|
+
<bs-composer-status-banner
|
|
169
|
+
type="error"
|
|
170
|
+
message="Message failed to send"
|
|
171
|
+
show-button
|
|
172
|
+
action-label="Retry"
|
|
173
|
+
style="margin-bottom: calc(-1 * var(--bs-spacing-150));"
|
|
174
|
+
></bs-composer-status-banner>
|
|
175
|
+
<bs-composer aria-label="Message"></bs-composer>
|
|
176
|
+
</div>
|
|
177
|
+
<bs-ai-disclaimer style="padding: var(--bs-spacing-100) 0;">AI can make mistakes. Please verify important information.</bs-ai-disclaimer>
|
|
178
|
+
</div>
|
|
179
|
+
`,
|
|
180
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { render, h, describe, it, expect } from "@stencil/vitest";
|
|
2
|
+
describe('bs-ai-disclaimer', () => {
|
|
3
|
+
it('renders the default slot content inside the text part', async () => {
|
|
4
|
+
const { root } = await render(h("bs-ai-disclaimer", null, "AI can make mistakes. Please verify important information."));
|
|
5
|
+
expect(root).toHaveTextContent('AI can make mistakes. Please verify important information.');
|
|
6
|
+
const text = root.shadowRoot.querySelector('[part="text"]');
|
|
7
|
+
expect(text).not.toBeNull();
|
|
8
|
+
expect(text.tagName).toBe('P');
|
|
9
|
+
});
|
|
10
|
+
it('renders arbitrary slotted content, e.g. a link', async () => {
|
|
11
|
+
const { root } = await render(h("bs-ai-disclaimer", null, "AI can make mistakes. ", h("a", { href: "/policy" }, "Learn more")));
|
|
12
|
+
expect(root.querySelector('a')).not.toBeNull();
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
display: block;
|
|
3
|
+
--bs-ai-disclaimer-padding-x: var(--bs-spacing-200);
|
|
4
|
+
--bs-ai-disclaimer-text-color: var(--bs-text-secondary);
|
|
5
|
+
--bs-ai-disclaimer-font-size: var(--bs-font-size-sm);
|
|
6
|
+
--bs-ai-disclaimer-line-height: var(--bs-line-height-body-sm);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.bs-ai-disclaimer {
|
|
10
|
+
box-sizing: border-box;
|
|
11
|
+
display: flex;
|
|
12
|
+
align-items: center;
|
|
13
|
+
justify-content: center;
|
|
14
|
+
padding: 0 var(--bs-ai-disclaimer-padding-x);
|
|
15
|
+
font-family: inherit;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.bs-ai-disclaimer__text {
|
|
19
|
+
margin: 0;
|
|
20
|
+
flex: 1 0 0;
|
|
21
|
+
min-width: 0;
|
|
22
|
+
color: var(--bs-ai-disclaimer-text-color);
|
|
23
|
+
font-size: var(--bs-ai-disclaimer-font-size);
|
|
24
|
+
line-height: calc(var(--bs-ai-disclaimer-line-height) * 1px);
|
|
25
|
+
text-align: center;
|
|
26
|
+
word-break: break-word;
|
|
27
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { h } from "@stencil/core";
|
|
2
|
+
/**
|
|
3
|
+
* A centered caption disclaimer for Genie AI surfaces, e.g. "AI can make mistakes. Please verify
|
|
4
|
+
* important information."
|
|
5
|
+
*
|
|
6
|
+
* ## When to use
|
|
7
|
+
* - Below or above `bs-composer` in a Genie AI chat panel, to remind users AI output can be wrong.
|
|
8
|
+
*
|
|
9
|
+
* ## When not to use
|
|
10
|
+
* - A general-purpose caption/helper text — use plain text or `bs-input`'s description slot for
|
|
11
|
+
* non-AI-related helper copy.
|
|
12
|
+
*
|
|
13
|
+
* The default slot (rather than a fixed prop) is intentional: Figma only specifies plain text, but
|
|
14
|
+
* some consuming apps link out to a policy/help page from this copy, and a slot supports that
|
|
15
|
+
* without inventing an unconfirmed `href`/link prop.
|
|
16
|
+
*
|
|
17
|
+
* @slot - The disclaimer text/content, centered. Defaults to no content -- the consumer supplies
|
|
18
|
+
* the copy, e.g. "AI can make mistakes. Please verify important information."
|
|
19
|
+
* @part text - The disclaimer text container.
|
|
20
|
+
* @prop --bs-ai-disclaimer-padding-x - Horizontal padding. Aliased to `--bs-spacing-200`.
|
|
21
|
+
* @prop --bs-ai-disclaimer-text-color - Text color. Aliased to `--bs-text-secondary`.
|
|
22
|
+
* @prop --bs-ai-disclaimer-font-size - Text font size. Aliased to `--bs-font-size-sm`.
|
|
23
|
+
* @prop --bs-ai-disclaimer-line-height - Text line height. Aliased to `--bs-line-height-body-sm`.
|
|
24
|
+
*/
|
|
25
|
+
export class BsAiDisclaimer {
|
|
26
|
+
render() {
|
|
27
|
+
return (h("div", { key: 'c306fa7e8f7f9dca07642e1038708847847e2d7e', class: "bs-ai-disclaimer" }, h("p", { key: '7f42e2094e7baf287c886ce966a3813657a99a61', part: "text", class: "bs-ai-disclaimer__text" }, h("slot", { key: 'c5a66f6093b413274c20de59e7f82d4f7372b56c' }))));
|
|
28
|
+
}
|
|
29
|
+
static get is() { return "bs-ai-disclaimer"; }
|
|
30
|
+
static get encapsulation() { return "shadow"; }
|
|
31
|
+
static get originalStyleUrls() {
|
|
32
|
+
return {
|
|
33
|
+
"$": ["bs-ai-disclaimer.css"]
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
static get styleUrls() {
|
|
37
|
+
return {
|
|
38
|
+
"$": ["bs-ai-disclaimer.css"]
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { html } from "lit";
|
|
2
|
+
import { componentDescription } from "../../stories-utils";
|
|
3
|
+
const meta = {
|
|
4
|
+
title: 'Genie AI Components/bs-ai-disclaimer',
|
|
5
|
+
parameters: { docs: { description: { component: componentDescription('bs-ai-disclaimer') } } },
|
|
6
|
+
render: args => html ` <bs-ai-disclaimer>${args.text}</bs-ai-disclaimer> `,
|
|
7
|
+
argTypes: {
|
|
8
|
+
text: { control: 'text', description: 'Default slot: the disclaimer text/content.' },
|
|
9
|
+
},
|
|
10
|
+
args: {
|
|
11
|
+
text: 'AI can make mistakes. Please verify important information.',
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
export default meta;
|
|
15
|
+
export const Default = {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { render, h, describe, it, expect } from "@stencil/vitest";
|
|
2
|
+
describe('bs-ai-greeting', () => {
|
|
3
|
+
it('renders the default heading and a product-agnostic subtext', async () => {
|
|
4
|
+
const { root } = await render(h("bs-ai-greeting", null));
|
|
5
|
+
expect(root).toHaveTextContent("Hi. I'm Genie,");
|
|
6
|
+
expect(root).toHaveTextContent('your AI assistant.');
|
|
7
|
+
expect(root).toHaveTextContent('How can I help you today?');
|
|
8
|
+
});
|
|
9
|
+
it('uses a custom assistant name in the heading', async () => {
|
|
10
|
+
const { root } = await render(h("bs-ai-greeting", { "assistant-name": "Sasha" }));
|
|
11
|
+
expect(root).toHaveTextContent("Hi. I'm Sasha,");
|
|
12
|
+
});
|
|
13
|
+
it('mentions the product name in the subtext when provided', async () => {
|
|
14
|
+
const { root } = await render(h("bs-ai-greeting", { "product-name": "Brandsync" }));
|
|
15
|
+
expect(root).toHaveTextContent('How can I help you with Brandsync today?');
|
|
16
|
+
});
|
|
17
|
+
it('exposes heading and subtext parts', async () => {
|
|
18
|
+
const { root } = await render(h("bs-ai-greeting", null));
|
|
19
|
+
expect(root.shadowRoot.querySelector('[part="heading"]')).not.toBeNull();
|
|
20
|
+
expect(root.shadowRoot.querySelector('[part="subtext"]')).not.toBeNull();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
display: block;
|
|
3
|
+
--bs-ai-greeting-gap: var(--bs-spacing-200);
|
|
4
|
+
--bs-ai-greeting-max-width: 490px;
|
|
5
|
+
--bs-ai-greeting-heading-color: var(--bs-text-default);
|
|
6
|
+
--bs-ai-greeting-heading-font-size: var(--bs-font-size-4xl);
|
|
7
|
+
/* Figma specifies a 28px line-height for this heading, which doesn't match any
|
|
8
|
+
* --bs-line-height-heading-* token (h4 is 32) -- aliased directly to --bs-line-height-body-lg,
|
|
9
|
+
* the token that happens to carry the same numeric value. */
|
|
10
|
+
--bs-ai-greeting-heading-line-height: var(--bs-line-height-body-lg);
|
|
11
|
+
--bs-ai-greeting-heading-weight: var(--bs-font-weight-bold);
|
|
12
|
+
--bs-ai-greeting-heading-gap: var(--bs-spacing-200);
|
|
13
|
+
--bs-ai-greeting-subtext-color: var(--bs-text-secondary);
|
|
14
|
+
/* Figma specifies 20px, which doesn't match the semantic --bs-text-style-body-lg-size (18px) --
|
|
15
|
+
* aliased directly to the raw --bs-font-size-xl primitive instead. */
|
|
16
|
+
--bs-ai-greeting-subtext-font-size: var(--bs-font-size-xl);
|
|
17
|
+
--bs-ai-greeting-subtext-line-height: var(--bs-line-height-body-lg);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.bs-ai-greeting {
|
|
21
|
+
box-sizing: border-box;
|
|
22
|
+
display: flex;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
align-items: center;
|
|
25
|
+
justify-content: center;
|
|
26
|
+
gap: var(--bs-ai-greeting-gap);
|
|
27
|
+
max-width: var(--bs-ai-greeting-max-width);
|
|
28
|
+
margin: 0 auto;
|
|
29
|
+
text-align: center;
|
|
30
|
+
font-family: inherit;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.bs-ai-greeting__heading {
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
gap: var(--bs-ai-greeting-heading-gap);
|
|
37
|
+
color: var(--bs-ai-greeting-heading-color);
|
|
38
|
+
font-size: var(--bs-ai-greeting-heading-font-size);
|
|
39
|
+
font-weight: var(--bs-ai-greeting-heading-weight);
|
|
40
|
+
line-height: calc(var(--bs-ai-greeting-heading-line-height) * 1px);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.bs-ai-greeting__heading-line {
|
|
44
|
+
margin: 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.bs-ai-greeting__subtext {
|
|
48
|
+
margin: 0;
|
|
49
|
+
color: var(--bs-ai-greeting-subtext-color);
|
|
50
|
+
font-size: var(--bs-ai-greeting-subtext-font-size);
|
|
51
|
+
font-weight: var(--bs-font-weight-regular);
|
|
52
|
+
line-height: calc(var(--bs-ai-greeting-subtext-line-height) * 1px);
|
|
53
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { h } from "@stencil/core";
|
|
2
|
+
/**
|
|
3
|
+
* The centered welcome heading shown at the top of an empty Genie AI chat panel, e.g.
|
|
4
|
+
* "Hi. I'm Genie, your AI assistant." + "How can I help you with [product] today?"
|
|
5
|
+
*
|
|
6
|
+
* ## When to use
|
|
7
|
+
* - The empty/initial state of a Genie AI chat panel, before the user has sent a message.
|
|
8
|
+
*
|
|
9
|
+
* ## When not to use
|
|
10
|
+
* - Once a conversation has started -- this is a one-time empty-state greeting, not a persistent
|
|
11
|
+
* header (see `bs-chatbot-header` for that).
|
|
12
|
+
*
|
|
13
|
+
* `productName` is optional: Figma's copy has a `[product_name]` placeholder the consuming app is
|
|
14
|
+
* expected to fill in, but a component shouldn't force a product name to exist, so leaving it
|
|
15
|
+
* unset falls back to a product-agnostic "How can I help you today?".
|
|
16
|
+
*
|
|
17
|
+
* @part heading - The bold "Hi. I'm {assistantName}, your AI assistant." heading.
|
|
18
|
+
* @part subtext - The "How can I help you..." subtext.
|
|
19
|
+
* @prop --bs-ai-greeting-gap - Gap between heading and subtext. Aliased to `--bs-spacing-200`.
|
|
20
|
+
* @prop --bs-ai-greeting-max-width - Max width of the centered content block. Matches Figma's
|
|
21
|
+
* 490px.
|
|
22
|
+
* @prop --bs-ai-greeting-heading-color - Heading text color. Aliased to `--bs-text-default`.
|
|
23
|
+
* @prop --bs-ai-greeting-heading-font-size - Heading font size. Aliased to `--bs-font-size-4xl`.
|
|
24
|
+
* @prop --bs-ai-greeting-heading-line-height - Heading line height. Figma specifies 28px, which
|
|
25
|
+
* doesn't match any `--bs-line-height-heading-*` token (h4 is 32) -- aliased directly to
|
|
26
|
+
* `--bs-line-height-body-lg`, the token that happens to share the same numeric value.
|
|
27
|
+
* @prop --bs-ai-greeting-heading-weight - Heading font weight. Aliased to `--bs-font-weight-bold`.
|
|
28
|
+
* @prop --bs-ai-greeting-heading-gap - Gap between the two heading lines. Aliased to
|
|
29
|
+
* `--bs-spacing-200`.
|
|
30
|
+
* @prop --bs-ai-greeting-subtext-color - Subtext color. Aliased to `--bs-text-secondary`.
|
|
31
|
+
* @prop --bs-ai-greeting-subtext-font-size - Subtext font size. Figma specifies 20px, which
|
|
32
|
+
* doesn't match the semantic `--bs-text-style-body-lg-size` (18px) -- aliased directly to the
|
|
33
|
+
* raw `--bs-font-size-xl` primitive instead.
|
|
34
|
+
* @prop --bs-ai-greeting-subtext-line-height - Subtext line height. Aliased to
|
|
35
|
+
* `--bs-line-height-body-lg`.
|
|
36
|
+
*/
|
|
37
|
+
export class BsAiGreeting {
|
|
38
|
+
/** The assistant's name, used in the heading ("Hi. I'm {assistantName},"). */
|
|
39
|
+
assistantName = 'Genie';
|
|
40
|
+
/** The product name mentioned in the subtext. Omit to use a product-agnostic subtext. */
|
|
41
|
+
productName;
|
|
42
|
+
render() {
|
|
43
|
+
const subtext = this.productName
|
|
44
|
+
? `How can I help you with ${this.productName} today?`
|
|
45
|
+
: 'How can I help you today?';
|
|
46
|
+
return (h("div", { key: '7931e7404b70476a5488e31f07981c97617c1e5b', class: "bs-ai-greeting" }, h("div", { key: '1ba75538642eebb9fe7c24eae2aae9a4eed176cf', part: "heading", class: "bs-ai-greeting__heading" }, h("p", { key: '6cf5d97d81249298d02d3983a039e664a75fbb40', class: "bs-ai-greeting__heading-line" }, "Hi. I'm ", this.assistantName, ","), h("p", { key: 'f7a1b0235b5b32b1319bc7748e0073fae0defef0', class: "bs-ai-greeting__heading-line" }, "your AI assistant.")), h("p", { key: '5f07b44ca8d000c39204374f99c6608ecbfc22d3', part: "subtext", class: "bs-ai-greeting__subtext" }, subtext)));
|
|
47
|
+
}
|
|
48
|
+
static get is() { return "bs-ai-greeting"; }
|
|
49
|
+
static get encapsulation() { return "shadow"; }
|
|
50
|
+
static get originalStyleUrls() {
|
|
51
|
+
return {
|
|
52
|
+
"$": ["bs-ai-greeting.css"]
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
static get styleUrls() {
|
|
56
|
+
return {
|
|
57
|
+
"$": ["bs-ai-greeting.css"]
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
static get properties() {
|
|
61
|
+
return {
|
|
62
|
+
"assistantName": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"mutable": false,
|
|
65
|
+
"complexType": {
|
|
66
|
+
"original": "string",
|
|
67
|
+
"resolved": "string",
|
|
68
|
+
"references": {}
|
|
69
|
+
},
|
|
70
|
+
"required": false,
|
|
71
|
+
"optional": false,
|
|
72
|
+
"docs": {
|
|
73
|
+
"tags": [],
|
|
74
|
+
"text": "The assistant's name, used in the heading (\"Hi. I'm {assistantName},\")."
|
|
75
|
+
},
|
|
76
|
+
"getter": false,
|
|
77
|
+
"setter": false,
|
|
78
|
+
"reflect": false,
|
|
79
|
+
"attribute": "assistant-name",
|
|
80
|
+
"defaultValue": "'Genie'"
|
|
81
|
+
},
|
|
82
|
+
"productName": {
|
|
83
|
+
"type": "string",
|
|
84
|
+
"mutable": false,
|
|
85
|
+
"complexType": {
|
|
86
|
+
"original": "string",
|
|
87
|
+
"resolved": "string",
|
|
88
|
+
"references": {}
|
|
89
|
+
},
|
|
90
|
+
"required": false,
|
|
91
|
+
"optional": true,
|
|
92
|
+
"docs": {
|
|
93
|
+
"tags": [],
|
|
94
|
+
"text": "The product name mentioned in the subtext. Omit to use a product-agnostic subtext."
|
|
95
|
+
},
|
|
96
|
+
"getter": false,
|
|
97
|
+
"setter": false,
|
|
98
|
+
"reflect": false,
|
|
99
|
+
"attribute": "product-name"
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { html } from "lit";
|
|
2
|
+
import { componentDescription, propDescription } from "../../stories-utils";
|
|
3
|
+
const meta = {
|
|
4
|
+
title: 'Genie AI Components/bs-ai-greeting',
|
|
5
|
+
parameters: { docs: { description: { component: componentDescription('bs-ai-greeting') } } },
|
|
6
|
+
render: args => html `
|
|
7
|
+
<bs-ai-greeting assistant-name=${args.assistantName} product-name=${args.productName || undefined}></bs-ai-greeting>
|
|
8
|
+
`,
|
|
9
|
+
argTypes: {
|
|
10
|
+
assistantName: { control: 'text', description: propDescription('bs-ai-greeting', 'assistantName') },
|
|
11
|
+
productName: { control: 'text', description: propDescription('bs-ai-greeting', 'productName') },
|
|
12
|
+
},
|
|
13
|
+
args: {
|
|
14
|
+
assistantName: 'Genie',
|
|
15
|
+
productName: 'Brandsync',
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
export default meta;
|
|
19
|
+
export const Default = {};
|
|
20
|
+
export const WithoutProductName = {
|
|
21
|
+
name: 'Without product name',
|
|
22
|
+
args: { productName: '' },
|
|
23
|
+
};
|
|
@@ -29,7 +29,7 @@ export class BsAiThinking {
|
|
|
29
29
|
/** The status text shown next to the icon, e.g. "Retrieving", "Thinking", "Searching". */
|
|
30
30
|
label = 'Thinking';
|
|
31
31
|
render() {
|
|
32
|
-
return (h("div", { key: '
|
|
32
|
+
return (h("div", { key: 'b72bc5095cc94257821541517f3446bac960df49', class: "bs-ai-thinking", role: "status", "aria-live": "polite" }, h("img", { key: '6c41c71416fc77f7385505754a68786b5f3412fa', part: "icon", class: "bs-ai-thinking__icon", src: GENIE_MARK_ICON, alt: "", "aria-hidden": "true" }), h("span", { key: '8edef57f7b31a03e2add401e42acdb7b6525a432', part: "label", class: "bs-ai-thinking__label" }, this.label)));
|
|
33
33
|
}
|
|
34
34
|
static get is() { return "bs-ai-thinking"; }
|
|
35
35
|
static get encapsulation() { return "shadow"; }
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { render, h, describe, it, expect } from "@stencil/vitest";
|
|
2
|
+
describe('bs-attachment', () => {
|
|
3
|
+
it('renders an image thumbnail by default', async () => {
|
|
4
|
+
const { root } = await render(h("bs-attachment", { "image-src": "/photo.jpg", "image-alt": "A photo" }));
|
|
5
|
+
const thumbnail = root.shadowRoot.querySelector('[part="thumbnail"]');
|
|
6
|
+
expect(thumbnail).not.toBeNull();
|
|
7
|
+
const img = root.shadowRoot.querySelector('img');
|
|
8
|
+
expect(img.getAttribute('src')).toBe('/photo.jpg');
|
|
9
|
+
expect(img.getAttribute('alt')).toBe('A photo');
|
|
10
|
+
});
|
|
11
|
+
it('renders a filename card with a PDF badge for type="pdf"', async () => {
|
|
12
|
+
const { root } = await render(h("bs-attachment", { type: "pdf", "file-name": "report.pdf" }));
|
|
13
|
+
expect(root.shadowRoot.querySelector('[part="card"]')).not.toBeNull();
|
|
14
|
+
expect(root).toHaveTextContent('report.pdf');
|
|
15
|
+
expect(root.shadowRoot.querySelector('[part="badge"]').className).toContain('bs-attachment__badge--pdf');
|
|
16
|
+
});
|
|
17
|
+
it('renders a filename card with a document badge for type="document"', async () => {
|
|
18
|
+
const { root } = await render(h("bs-attachment", { type: "document", "file-name": "notes.docx" }));
|
|
19
|
+
expect(root.shadowRoot.querySelector('[part="badge"]').className).toContain('bs-attachment__badge--document');
|
|
20
|
+
});
|
|
21
|
+
it('shows a spinner in the badge instead of the file icon when loading', async () => {
|
|
22
|
+
const { root } = await render(h("bs-attachment", { type: "pdf", loading: true }));
|
|
23
|
+
const badge = root.shadowRoot.querySelector('[part="badge"]');
|
|
24
|
+
expect(badge.querySelector('svg')).toBeNull();
|
|
25
|
+
expect(badge.querySelector('[role="status"]')).not.toBeNull();
|
|
26
|
+
});
|
|
27
|
+
it('marks the host aria-busy when loading', async () => {
|
|
28
|
+
const { root } = await render(h("bs-attachment", { loading: true }));
|
|
29
|
+
expect(root.shadowRoot.querySelector('.bs-attachment').getAttribute('aria-busy')).toBe('true');
|
|
30
|
+
});
|
|
31
|
+
it('emits bsRemove when the remove button is clicked', async () => {
|
|
32
|
+
const { root, spyOnEvent } = await render(h("bs-attachment", null));
|
|
33
|
+
const removeSpy = spyOnEvent('bsRemove');
|
|
34
|
+
root.shadowRoot.querySelector('[part="remove"]').click();
|
|
35
|
+
expect(removeSpy).toHaveReceivedEventTimes(1);
|
|
36
|
+
});
|
|
37
|
+
it('does not render a remove button when removable is false', async () => {
|
|
38
|
+
const { root } = await render(h("bs-attachment", { removable: false }));
|
|
39
|
+
expect(root.shadowRoot.querySelector('[part="remove"]')).toBeNull();
|
|
40
|
+
});
|
|
41
|
+
});
|