@brandsync/wc 0.0.2 → 0.0.4
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 +297 -1
- package/dist/brandsync-wc/brandsync-wc.esm.js +1 -1
- package/dist/brandsync-wc/{p-e38a9744.entry.js → p-27288299.entry.js} +1 -1
- package/dist/brandsync-wc/{p-c2cc0d6f.entry.js → p-2742ecef.entry.js} +1 -1
- package/dist/brandsync-wc/p-4ce458bf.entry.js +1 -0
- package/dist/brandsync-wc/p-6c1fa4da.entry.js +1 -0
- package/dist/brandsync-wc/{p-da11e421.entry.js → p-880ea3f8.entry.js} +1 -1
- package/dist/brandsync-wc/{p-2c4df28d.entry.js → p-9e5d2211.entry.js} +1 -1
- package/dist/brandsync-wc/{p-3134f5f5.entry.js → p-ab5cc7af.entry.js} +1 -1
- package/dist/brandsync-wc/p-b24c455f.entry.js +1 -0
- package/dist/brandsync-wc/{p-5739acaf.entry.js → p-cfc3421b.entry.js} +1 -1
- package/dist/brandsync-wc/{p-db3934d2.entry.js → p-ea705742.entry.js} +1 -1
- package/dist/brandsync-wc/{p-BOj_41o9.js → p-nLORuTUY.js} +2 -2
- package/dist/cjs/brandsync-wc.cjs.js +2 -2
- package/dist/cjs/bs-badge.cjs.entry.js +1 -1
- package/dist/cjs/bs-button-skeleton.cjs.entry.js +2 -2
- 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-header.cjs.entry.js +144 -0
- package/dist/cjs/bs-chatbot-response-action.cjs.entry.js +66 -0
- package/dist/cjs/bs-composer.cjs.entry.js +2 -2
- package/dist/cjs/bs-data-table.cjs.entry.js +3 -3
- package/dist/cjs/bs-input.cjs.entry.js +3 -3
- package/dist/cjs/bs-modal.cjs.entry.js +1 -1
- package/dist/cjs/{index-nyOcuVbF.js → index-CVh-sqA_.js} +3 -0
- package/dist/cjs/loader.cjs.js +2 -2
- package/dist/collection/collection-manifest.json +2 -0
- package/dist/collection/components/bs-button-skeleton/bs-button-skeleton.js +1 -1
- package/dist/collection/components/bs-chatbot-header/bs-chatbot-header.cmp.test.js +94 -0
- package/dist/collection/components/bs-chatbot-header/bs-chatbot-header.css +81 -0
- package/dist/collection/components/bs-chatbot-header/bs-chatbot-header.js +194 -0
- package/dist/collection/components/bs-chatbot-header/bs-chatbot-header.stories.js +53 -0
- package/dist/collection/components/bs-chatbot-header/genie-logo.js +86 -0
- package/dist/collection/components/bs-chatbot-response-action/bs-chatbot-response-action.cmp.test.js +133 -0
- package/dist/collection/components/bs-chatbot-response-action/bs-chatbot-response-action.css +107 -0
- package/dist/collection/components/bs-chatbot-response-action/bs-chatbot-response-action.js +216 -0
- package/dist/collection/components/bs-chatbot-response-action/bs-chatbot-response-action.stories.js +33 -0
- package/dist/collection/components/bs-composer/bs-composer.cmp.test.js +13 -0
- package/dist/collection/components/bs-composer/bs-composer.js +11 -1
- package/dist/collection/components/bs-data-table/bs-data-table.js +2 -2
- package/dist/collection/components/bs-input/bs-input.js +2 -2
- 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-header.d.ts +11 -0
- package/dist/components/bs-chatbot-header.js +1 -0
- package/dist/components/bs-chatbot-response-action.d.ts +11 -0
- package/dist/components/bs-chatbot-response-action.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-modal.js +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/{p-Cu4gTknX.js → p-BpvhHQSw.js} +1 -1
- package/dist/esm/brandsync-wc.js +3 -3
- package/dist/esm/bs-badge.entry.js +1 -1
- package/dist/esm/bs-button-skeleton.entry.js +2 -2
- package/dist/esm/bs-button.entry.js +1 -1
- package/dist/esm/bs-card.entry.js +1 -1
- package/dist/esm/bs-chatbot-header.entry.js +142 -0
- package/dist/esm/bs-chatbot-response-action.entry.js +64 -0
- package/dist/esm/bs-composer.entry.js +2 -2
- package/dist/esm/bs-data-table.entry.js +3 -3
- package/dist/esm/bs-input.entry.js +3 -3
- package/dist/esm/bs-modal.entry.js +1 -1
- package/dist/esm/{index-BOj_41o9.js → index-nLORuTUY.js} +3 -0
- package/dist/esm/loader.js +3 -3
- package/dist/types/components/bs-chatbot-header/bs-chatbot-header.cmp.test.d.ts +1 -0
- package/dist/types/components/bs-chatbot-header/bs-chatbot-header.d.ts +59 -0
- package/dist/types/components/bs-chatbot-header/bs-chatbot-header.stories.d.ts +9 -0
- package/dist/types/components/bs-chatbot-header/genie-logo.d.ts +1 -0
- package/dist/types/components/bs-chatbot-response-action/bs-chatbot-response-action.cmp.test.d.ts +1 -0
- package/dist/types/components/bs-chatbot-response-action/bs-chatbot-response-action.d.ts +67 -0
- package/dist/types/components/bs-chatbot-response-action/bs-chatbot-response-action.stories.d.ts +10 -0
- package/dist/types/components/bs-composer/bs-composer.d.ts +10 -0
- package/dist/types/components.d.ts +335 -0
- package/package.json +2 -1
- package/readme.md +38 -0
- package/dist/brandsync-wc/p-042ad15a.entry.js +0 -1
package/dist/collection/components/bs-chatbot-response-action/bs-chatbot-response-action.cmp.test.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { render, h, describe, it, expect } from "@stencil/vitest";
|
|
2
|
+
describe('bs-chatbot-response-action', () => {
|
|
3
|
+
it('renders all five icon buttons with the correct parts, and no sources button by default', async () => {
|
|
4
|
+
const { root } = await render(h("bs-chatbot-response-action", null));
|
|
5
|
+
expect(root.shadowRoot.querySelector('[part="like"]')).not.toBeNull();
|
|
6
|
+
expect(root.shadowRoot.querySelector('[part="dislike"]')).not.toBeNull();
|
|
7
|
+
expect(root.shadowRoot.querySelector('[part="copy"]')).not.toBeNull();
|
|
8
|
+
expect(root.shadowRoot.querySelector('[part="regenerate"]')).not.toBeNull();
|
|
9
|
+
expect(root.shadowRoot.querySelector('[part="menu"]')).not.toBeNull();
|
|
10
|
+
expect(root.shadowRoot.querySelector('[part="sources"]')).toBeNull();
|
|
11
|
+
});
|
|
12
|
+
it('does not render the sources button when sourcesCount is 0', async () => {
|
|
13
|
+
const { root } = await render(h("bs-chatbot-response-action", { sourcesCount: 0 }));
|
|
14
|
+
expect(root.shadowRoot.querySelector('[part="sources"]')).toBeNull();
|
|
15
|
+
});
|
|
16
|
+
it('renders the sources button with singular text when sourcesCount is 1', async () => {
|
|
17
|
+
const { root } = await render(h("bs-chatbot-response-action", { sourcesCount: 1 }));
|
|
18
|
+
const sources = root.shadowRoot.querySelector('[part="sources"]');
|
|
19
|
+
expect(sources).not.toBeNull();
|
|
20
|
+
expect(sources).toHaveTextContent('1 source');
|
|
21
|
+
});
|
|
22
|
+
it('renders the sources button with plural text when sourcesCount is greater than 1', async () => {
|
|
23
|
+
const { root } = await render(h("bs-chatbot-response-action", { sourcesCount: 3 }));
|
|
24
|
+
const sources = root.shadowRoot.querySelector('[part="sources"]');
|
|
25
|
+
expect(sources).not.toBeNull();
|
|
26
|
+
expect(sources).toHaveTextContent('3 sources');
|
|
27
|
+
});
|
|
28
|
+
it('emits bsLike when the like button is clicked, and not the other events', async () => {
|
|
29
|
+
const { root, spyOnEvent } = await render(h("bs-chatbot-response-action", { sourcesCount: 3 }));
|
|
30
|
+
const likeSpy = spyOnEvent('bsLike');
|
|
31
|
+
const dislikeSpy = spyOnEvent('bsDislike');
|
|
32
|
+
const copySpy = spyOnEvent('bsCopy');
|
|
33
|
+
const regenerateSpy = spyOnEvent('bsRegenerate');
|
|
34
|
+
const menuSpy = spyOnEvent('bsMenuOpen');
|
|
35
|
+
const sourcesSpy = spyOnEvent('bsSourcesClick');
|
|
36
|
+
root.shadowRoot.querySelector('[part="like"]').click();
|
|
37
|
+
expect(likeSpy).toHaveReceivedEventTimes(1);
|
|
38
|
+
expect(dislikeSpy.length).toBe(0);
|
|
39
|
+
expect(copySpy.length).toBe(0);
|
|
40
|
+
expect(regenerateSpy.length).toBe(0);
|
|
41
|
+
expect(menuSpy.length).toBe(0);
|
|
42
|
+
expect(sourcesSpy.length).toBe(0);
|
|
43
|
+
});
|
|
44
|
+
it('emits bsDislike when the dislike button is clicked, and not the other events', async () => {
|
|
45
|
+
const { root, spyOnEvent } = await render(h("bs-chatbot-response-action", { sourcesCount: 3 }));
|
|
46
|
+
const likeSpy = spyOnEvent('bsLike');
|
|
47
|
+
const dislikeSpy = spyOnEvent('bsDislike');
|
|
48
|
+
const copySpy = spyOnEvent('bsCopy');
|
|
49
|
+
const regenerateSpy = spyOnEvent('bsRegenerate');
|
|
50
|
+
const menuSpy = spyOnEvent('bsMenuOpen');
|
|
51
|
+
const sourcesSpy = spyOnEvent('bsSourcesClick');
|
|
52
|
+
root.shadowRoot.querySelector('[part="dislike"]').click();
|
|
53
|
+
expect(dislikeSpy).toHaveReceivedEventTimes(1);
|
|
54
|
+
expect(likeSpy.length).toBe(0);
|
|
55
|
+
expect(copySpy.length).toBe(0);
|
|
56
|
+
expect(regenerateSpy.length).toBe(0);
|
|
57
|
+
expect(menuSpy.length).toBe(0);
|
|
58
|
+
expect(sourcesSpy.length).toBe(0);
|
|
59
|
+
});
|
|
60
|
+
it('emits bsCopy when the copy button is clicked, and not the other events', async () => {
|
|
61
|
+
const { root, spyOnEvent } = await render(h("bs-chatbot-response-action", { sourcesCount: 3 }));
|
|
62
|
+
const likeSpy = spyOnEvent('bsLike');
|
|
63
|
+
const dislikeSpy = spyOnEvent('bsDislike');
|
|
64
|
+
const copySpy = spyOnEvent('bsCopy');
|
|
65
|
+
const regenerateSpy = spyOnEvent('bsRegenerate');
|
|
66
|
+
const menuSpy = spyOnEvent('bsMenuOpen');
|
|
67
|
+
const sourcesSpy = spyOnEvent('bsSourcesClick');
|
|
68
|
+
root.shadowRoot.querySelector('[part="copy"]').click();
|
|
69
|
+
expect(copySpy).toHaveReceivedEventTimes(1);
|
|
70
|
+
expect(likeSpy.length).toBe(0);
|
|
71
|
+
expect(dislikeSpy.length).toBe(0);
|
|
72
|
+
expect(regenerateSpy.length).toBe(0);
|
|
73
|
+
expect(menuSpy.length).toBe(0);
|
|
74
|
+
expect(sourcesSpy.length).toBe(0);
|
|
75
|
+
});
|
|
76
|
+
it('emits bsRegenerate when the regenerate button is clicked, and not the other events', async () => {
|
|
77
|
+
const { root, spyOnEvent } = await render(h("bs-chatbot-response-action", { sourcesCount: 3 }));
|
|
78
|
+
const likeSpy = spyOnEvent('bsLike');
|
|
79
|
+
const dislikeSpy = spyOnEvent('bsDislike');
|
|
80
|
+
const copySpy = spyOnEvent('bsCopy');
|
|
81
|
+
const regenerateSpy = spyOnEvent('bsRegenerate');
|
|
82
|
+
const menuSpy = spyOnEvent('bsMenuOpen');
|
|
83
|
+
const sourcesSpy = spyOnEvent('bsSourcesClick');
|
|
84
|
+
root.shadowRoot.querySelector('[part="regenerate"]').click();
|
|
85
|
+
expect(regenerateSpy).toHaveReceivedEventTimes(1);
|
|
86
|
+
expect(likeSpy.length).toBe(0);
|
|
87
|
+
expect(dislikeSpy.length).toBe(0);
|
|
88
|
+
expect(copySpy.length).toBe(0);
|
|
89
|
+
expect(menuSpy.length).toBe(0);
|
|
90
|
+
expect(sourcesSpy.length).toBe(0);
|
|
91
|
+
});
|
|
92
|
+
it('emits bsMenuOpen when the more-options button is clicked, and not the other events', async () => {
|
|
93
|
+
const { root, spyOnEvent } = await render(h("bs-chatbot-response-action", { sourcesCount: 3 }));
|
|
94
|
+
const likeSpy = spyOnEvent('bsLike');
|
|
95
|
+
const dislikeSpy = spyOnEvent('bsDislike');
|
|
96
|
+
const copySpy = spyOnEvent('bsCopy');
|
|
97
|
+
const regenerateSpy = spyOnEvent('bsRegenerate');
|
|
98
|
+
const menuSpy = spyOnEvent('bsMenuOpen');
|
|
99
|
+
const sourcesSpy = spyOnEvent('bsSourcesClick');
|
|
100
|
+
root.shadowRoot.querySelector('[part="menu"]').click();
|
|
101
|
+
expect(menuSpy).toHaveReceivedEventTimes(1);
|
|
102
|
+
expect(likeSpy.length).toBe(0);
|
|
103
|
+
expect(dislikeSpy.length).toBe(0);
|
|
104
|
+
expect(copySpy.length).toBe(0);
|
|
105
|
+
expect(regenerateSpy.length).toBe(0);
|
|
106
|
+
expect(sourcesSpy.length).toBe(0);
|
|
107
|
+
});
|
|
108
|
+
it('emits bsSourcesClick when the sources button is clicked, and not the other events', async () => {
|
|
109
|
+
const { root, spyOnEvent } = await render(h("bs-chatbot-response-action", { sourcesCount: 3 }));
|
|
110
|
+
const likeSpy = spyOnEvent('bsLike');
|
|
111
|
+
const dislikeSpy = spyOnEvent('bsDislike');
|
|
112
|
+
const copySpy = spyOnEvent('bsCopy');
|
|
113
|
+
const regenerateSpy = spyOnEvent('bsRegenerate');
|
|
114
|
+
const menuSpy = spyOnEvent('bsMenuOpen');
|
|
115
|
+
const sourcesSpy = spyOnEvent('bsSourcesClick');
|
|
116
|
+
root.shadowRoot.querySelector('[part="sources"]').click();
|
|
117
|
+
expect(sourcesSpy).toHaveReceivedEventTimes(1);
|
|
118
|
+
expect(likeSpy.length).toBe(0);
|
|
119
|
+
expect(dislikeSpy.length).toBe(0);
|
|
120
|
+
expect(copySpy.length).toBe(0);
|
|
121
|
+
expect(regenerateSpy.length).toBe(0);
|
|
122
|
+
expect(menuSpy.length).toBe(0);
|
|
123
|
+
});
|
|
124
|
+
it('renders consumer-supplied content in the like-icon slot instead of the default icon', async () => {
|
|
125
|
+
const { root } = await render(h("bs-chatbot-response-action", null, h("span", { slot: "like-icon" }, "CUSTOM")));
|
|
126
|
+
const likeButton = root.shadowRoot.querySelector('[part="like"]');
|
|
127
|
+
const slot = likeButton.querySelector('slot[name="like-icon"]');
|
|
128
|
+
expect(slot).not.toBeNull();
|
|
129
|
+
const assigned = slot.assignedElements();
|
|
130
|
+
expect(assigned).toHaveLength(1);
|
|
131
|
+
expect(assigned[0]).toHaveTextContent('CUSTOM');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
display: block;
|
|
3
|
+
--bs-chatbot-response-action-gap: var(--bs-spacing-100);
|
|
4
|
+
--bs-chatbot-response-action-padding-top: var(--bs-spacing-150);
|
|
5
|
+
--bs-chatbot-response-action-padding-bottom: var(--bs-spacing-50);
|
|
6
|
+
--bs-chatbot-response-action-button-size: var(--bs-spacing-400);
|
|
7
|
+
--bs-chatbot-response-action-button-radius: var(--bs-border-radius-100);
|
|
8
|
+
--bs-chatbot-response-action-button-hover: var(--bs-color-neutral-container);
|
|
9
|
+
--bs-chatbot-response-action-button-pressed: var(--bs-color-neutral-container-pressed);
|
|
10
|
+
--bs-chatbot-response-action-icon: var(--bs-icon-neutral-default);
|
|
11
|
+
--bs-chatbot-response-action-sources-gap: var(--bs-spacing-50);
|
|
12
|
+
--bs-chatbot-response-action-sources-padding-left: var(--bs-spacing-100);
|
|
13
|
+
--bs-chatbot-response-action-sources-padding-right: var(--bs-spacing-150);
|
|
14
|
+
--bs-chatbot-response-action-sources-color: var(--bs-text-neutral-default);
|
|
15
|
+
--bs-chatbot-response-action-sources-font-size: var(--bs-font-size-sm);
|
|
16
|
+
--bs-chatbot-response-action-sources-line-height: var(--bs-line-height-body-sm);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.bs-chatbot-response-action {
|
|
20
|
+
box-sizing: border-box;
|
|
21
|
+
display: flex;
|
|
22
|
+
align-items: center;
|
|
23
|
+
gap: var(--bs-chatbot-response-action-gap);
|
|
24
|
+
padding-top: var(--bs-chatbot-response-action-padding-top);
|
|
25
|
+
padding-bottom: var(--bs-chatbot-response-action-padding-bottom);
|
|
26
|
+
background: transparent;
|
|
27
|
+
font-family: inherit;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.bs-chatbot-response-action__button {
|
|
31
|
+
display: inline-flex;
|
|
32
|
+
align-items: center;
|
|
33
|
+
justify-content: center;
|
|
34
|
+
box-sizing: border-box;
|
|
35
|
+
border: none;
|
|
36
|
+
padding: 0;
|
|
37
|
+
cursor: pointer;
|
|
38
|
+
background: transparent;
|
|
39
|
+
color: var(--bs-chatbot-response-action-icon);
|
|
40
|
+
font-family: inherit;
|
|
41
|
+
border-radius: var(--bs-chatbot-response-action-button-radius);
|
|
42
|
+
width: var(--bs-chatbot-response-action-button-size);
|
|
43
|
+
height: var(--bs-chatbot-response-action-button-size);
|
|
44
|
+
flex-shrink: 0;
|
|
45
|
+
transition: background-color var(--bs-duration-fast) var(--bs-easing-standard);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.bs-chatbot-response-action__button:focus-visible {
|
|
49
|
+
outline: 2px solid var(--bs-border-neutral-focus);
|
|
50
|
+
outline-offset: 2px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.bs-chatbot-response-action__button svg {
|
|
54
|
+
width: 20px;
|
|
55
|
+
height: 20px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.bs-chatbot-response-action__button:hover {
|
|
59
|
+
background: var(--bs-chatbot-response-action-button-hover);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.bs-chatbot-response-action__button:active {
|
|
63
|
+
background: var(--bs-chatbot-response-action-button-pressed);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.bs-chatbot-response-action__sources {
|
|
67
|
+
display: inline-flex;
|
|
68
|
+
align-items: center;
|
|
69
|
+
box-sizing: border-box;
|
|
70
|
+
border: none;
|
|
71
|
+
cursor: pointer;
|
|
72
|
+
background: transparent;
|
|
73
|
+
color: var(--bs-chatbot-response-action-sources-color);
|
|
74
|
+
font-family: inherit;
|
|
75
|
+
font-size: var(--bs-chatbot-response-action-sources-font-size);
|
|
76
|
+
line-height: calc(var(--bs-chatbot-response-action-sources-line-height) * 1px);
|
|
77
|
+
gap: var(--bs-chatbot-response-action-sources-gap);
|
|
78
|
+
border-radius: var(--bs-chatbot-response-action-button-radius);
|
|
79
|
+
height: var(--bs-chatbot-response-action-button-size);
|
|
80
|
+
padding-left: var(--bs-chatbot-response-action-sources-padding-left);
|
|
81
|
+
padding-right: var(--bs-chatbot-response-action-sources-padding-right);
|
|
82
|
+
flex-shrink: 0;
|
|
83
|
+
transition: background-color var(--bs-duration-fast) var(--bs-easing-standard);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.bs-chatbot-response-action__sources:focus-visible {
|
|
87
|
+
outline: 2px solid var(--bs-border-neutral-focus);
|
|
88
|
+
outline-offset: 2px;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.bs-chatbot-response-action__sources svg {
|
|
92
|
+
width: 20px;
|
|
93
|
+
height: 20px;
|
|
94
|
+
flex-shrink: 0;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.bs-chatbot-response-action__sources:hover {
|
|
98
|
+
background: var(--bs-chatbot-response-action-button-hover);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.bs-chatbot-response-action__sources:active {
|
|
102
|
+
background: var(--bs-chatbot-response-action-button-pressed);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.bs-chatbot-response-action__sources-label {
|
|
106
|
+
white-space: nowrap;
|
|
107
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { h } from "@stencil/core";
|
|
2
|
+
/**
|
|
3
|
+
* The row of action buttons that appears below an AI response message in a Genie chat panel:
|
|
4
|
+
* like, dislike, copy, regenerate, and more-options icon buttons, plus an optional "N sources"
|
|
5
|
+
* button.
|
|
6
|
+
*
|
|
7
|
+
* ## When to use
|
|
8
|
+
* - Directly below an AI-generated response message in a Genie chat panel.
|
|
9
|
+
*
|
|
10
|
+
* ## When not to use
|
|
11
|
+
* - Below a user's own message -- these actions (regenerate, like/dislike a response, etc.) only
|
|
12
|
+
* make sense for AI-generated content.
|
|
13
|
+
*
|
|
14
|
+
* @slot like-icon - Overrides the default "Like" button icon.
|
|
15
|
+
* @slot dislike-icon - Overrides the default "Dislike" button icon.
|
|
16
|
+
* @slot copy-icon - Overrides the default "Copy" button icon.
|
|
17
|
+
* @slot regenerate-icon - Overrides the default "Regenerate" button icon.
|
|
18
|
+
* @slot menu-icon - Overrides the default "More options" button icon.
|
|
19
|
+
* @slot sources-icon - Overrides the default icon in the "N sources" button.
|
|
20
|
+
* @part like - The "Like" icon button.
|
|
21
|
+
* @part dislike - The "Dislike" icon button.
|
|
22
|
+
* @part copy - The "Copy" icon button.
|
|
23
|
+
* @part regenerate - The "Regenerate" icon button.
|
|
24
|
+
* @part menu - The "More options" icon button.
|
|
25
|
+
* @part sources - The "N sources" button (only rendered when `sourcesCount` is set).
|
|
26
|
+
* @prop --bs-chatbot-response-action-gap - Gap between all buttons in the row. Aliased to `--bs-spacing-100`.
|
|
27
|
+
* @prop --bs-chatbot-response-action-padding-top - Aliased to `--bs-spacing-150`.
|
|
28
|
+
* @prop --bs-chatbot-response-action-padding-bottom - Aliased to `--bs-spacing-50`.
|
|
29
|
+
* @prop --bs-chatbot-response-action-button-size - Width/height of each icon button. Aliased to `--bs-spacing-400`.
|
|
30
|
+
* @prop --bs-chatbot-response-action-button-radius - Corner radius of each button. Aliased to `--bs-border-radius-100`.
|
|
31
|
+
* @prop --bs-chatbot-response-action-button-hover - Button background on hover. Aliased to `--bs-color-neutral-container`.
|
|
32
|
+
* @prop --bs-chatbot-response-action-button-pressed - Button background when pressed. Aliased to `--bs-color-neutral-container-pressed`.
|
|
33
|
+
* @prop --bs-chatbot-response-action-icon - Icon color. Aliased to `--bs-icon-neutral-default`.
|
|
34
|
+
* @prop --bs-chatbot-response-action-sources-gap - Gap between the sources icon and its label. Aliased to `--bs-spacing-50`.
|
|
35
|
+
* @prop --bs-chatbot-response-action-sources-padding-left - Aliased to `--bs-spacing-100`.
|
|
36
|
+
* @prop --bs-chatbot-response-action-sources-padding-right - Aliased to `--bs-spacing-150`.
|
|
37
|
+
* @prop --bs-chatbot-response-action-sources-color - Text color of the sources label. Aliased to `--bs-text-neutral-default`.
|
|
38
|
+
* @prop --bs-chatbot-response-action-sources-font-size - Aliased to `--bs-font-size-sm`.
|
|
39
|
+
* @prop --bs-chatbot-response-action-sources-line-height - Aliased to `--bs-line-height-body-sm`.
|
|
40
|
+
*/
|
|
41
|
+
export class BsChatbotResponseAction {
|
|
42
|
+
/**
|
|
43
|
+
* Number of sources backing the response. When set to a positive number, renders the "N
|
|
44
|
+
* sources" button (singular "1 source" / plural "N sources"). When unset or `0`, the button is
|
|
45
|
+
* not rendered at all.
|
|
46
|
+
*/
|
|
47
|
+
sourcesCount;
|
|
48
|
+
/** Fires when the "Like" button is clicked. */
|
|
49
|
+
bsLike;
|
|
50
|
+
/** Fires when the "Dislike" button is clicked. */
|
|
51
|
+
bsDislike;
|
|
52
|
+
/** Fires when the "Copy" button is clicked. */
|
|
53
|
+
bsCopy;
|
|
54
|
+
/** Fires when the "Regenerate" button is clicked. */
|
|
55
|
+
bsRegenerate;
|
|
56
|
+
/** Fires when the "More options" button is clicked. */
|
|
57
|
+
bsMenuOpen;
|
|
58
|
+
/** Fires when the "N sources" button is clicked. */
|
|
59
|
+
bsSourcesClick;
|
|
60
|
+
onLikeClick = () => {
|
|
61
|
+
this.bsLike.emit();
|
|
62
|
+
};
|
|
63
|
+
onDislikeClick = () => {
|
|
64
|
+
this.bsDislike.emit();
|
|
65
|
+
};
|
|
66
|
+
onCopyClick = () => {
|
|
67
|
+
this.bsCopy.emit();
|
|
68
|
+
};
|
|
69
|
+
onRegenerateClick = () => {
|
|
70
|
+
this.bsRegenerate.emit();
|
|
71
|
+
};
|
|
72
|
+
onMenuClick = () => {
|
|
73
|
+
this.bsMenuOpen.emit();
|
|
74
|
+
};
|
|
75
|
+
onSourcesClick = () => {
|
|
76
|
+
this.bsSourcesClick.emit();
|
|
77
|
+
};
|
|
78
|
+
render() {
|
|
79
|
+
const hasSources = !!this.sourcesCount && this.sourcesCount > 0;
|
|
80
|
+
return (h("div", { key: '61a46c51ffba5e1256a94cbab87ce6e06e45941f', class: "bs-chatbot-response-action" }, h("button", { key: '33e8e29235191bc2a4128074d5df08cc304dbefb', type: "button", part: "like", class: "bs-chatbot-response-action__button", "aria-label": "Like", onClick: this.onLikeClick }, h("slot", { key: '2337aa07fec93d12e6706ded394248f0353b91e6', name: "like-icon" }, h(ThumbsUpIcon, { key: '9be56ca48cbb7027ba608ea9f8e89c2c14f98eee' }))), h("button", { key: 'fcdd8f3d4028a0e91cd5e10525ac97febf2261b6', type: "button", part: "dislike", class: "bs-chatbot-response-action__button", "aria-label": "Dislike", onClick: this.onDislikeClick }, h("slot", { key: 'bc219702b5e935659aa7824596511e8b01d2014f', name: "dislike-icon" }, h(ThumbsDownIcon, { key: '5ec9da81d5a89d1d2a35dbfe88682214178204cb' }))), h("button", { key: '59d6b3032d141092537d9e56ced8e3045b40384f', type: "button", part: "copy", class: "bs-chatbot-response-action__button", "aria-label": "Copy", onClick: this.onCopyClick }, h("slot", { key: 'e5bd9fbc4774ae9d67707803819697b56c516984', name: "copy-icon" }, h(CopyIcon, { key: 'e7f8f643920bad3f88c597bb183cfc71f8319c46' }))), h("button", { key: 'a6bd1be8be7f0f70157a5a5e37bc18d2c94462fc', type: "button", part: "regenerate", class: "bs-chatbot-response-action__button", "aria-label": "Regenerate", onClick: this.onRegenerateClick }, h("slot", { key: '7d35981706ea38ae1e613047945dde9d67a94c62', name: "regenerate-icon" }, h(RegenerateIcon, { key: '1d2dacd4bba68fcd120317bb207e7aa25bc0f62f' }))), h("button", { key: '32f3f790f4024cd7b58ba6f291d32b3f5f0dbbc8', type: "button", part: "menu", class: "bs-chatbot-response-action__button", "aria-label": "More options", onClick: this.onMenuClick }, h("slot", { key: '0aaf67bbc34bdf5d12247f9ab264a75dad63f996', name: "menu-icon" }, h(MenuIcon, { key: 'c32d76d1e6f73cd9a82bbf4371a4d047b807b80c' }))), hasSources && (h("button", { key: '240f26ed6ec5faded1efe1f171da10e4a292011e', type: "button", part: "sources", class: "bs-chatbot-response-action__sources", onClick: this.onSourcesClick }, h("slot", { key: 'e97e26840df27d2ff281882823bae7556d53bdc6', name: "sources-icon" }, h(SourcesIcon, { key: '5dd3538a28ee3cf22b2801258024386827b9c774' })), h("span", { key: 'acf07f2bba262a08c3f2d9650b9fd09fab51d172', class: "bs-chatbot-response-action__sources-label" }, this.sourcesCount, " ", this.sourcesCount === 1 ? 'source' : 'sources')))));
|
|
81
|
+
}
|
|
82
|
+
static get is() { return "bs-chatbot-response-action"; }
|
|
83
|
+
static get encapsulation() { return "shadow"; }
|
|
84
|
+
static get originalStyleUrls() {
|
|
85
|
+
return {
|
|
86
|
+
"$": ["bs-chatbot-response-action.css"]
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
static get styleUrls() {
|
|
90
|
+
return {
|
|
91
|
+
"$": ["bs-chatbot-response-action.css"]
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
static get properties() {
|
|
95
|
+
return {
|
|
96
|
+
"sourcesCount": {
|
|
97
|
+
"type": "number",
|
|
98
|
+
"mutable": false,
|
|
99
|
+
"complexType": {
|
|
100
|
+
"original": "number",
|
|
101
|
+
"resolved": "number",
|
|
102
|
+
"references": {}
|
|
103
|
+
},
|
|
104
|
+
"required": false,
|
|
105
|
+
"optional": true,
|
|
106
|
+
"docs": {
|
|
107
|
+
"tags": [],
|
|
108
|
+
"text": "Number of sources backing the response. When set to a positive number, renders the \"N\nsources\" button (singular \"1 source\" / plural \"N sources\"). When unset or `0`, the button is\nnot rendered at all."
|
|
109
|
+
},
|
|
110
|
+
"getter": false,
|
|
111
|
+
"setter": false,
|
|
112
|
+
"reflect": false,
|
|
113
|
+
"attribute": "sources-count"
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
static get events() {
|
|
118
|
+
return [{
|
|
119
|
+
"method": "bsLike",
|
|
120
|
+
"name": "bsLike",
|
|
121
|
+
"bubbles": true,
|
|
122
|
+
"cancelable": true,
|
|
123
|
+
"composed": true,
|
|
124
|
+
"docs": {
|
|
125
|
+
"tags": [],
|
|
126
|
+
"text": "Fires when the \"Like\" button is clicked."
|
|
127
|
+
},
|
|
128
|
+
"complexType": {
|
|
129
|
+
"original": "void",
|
|
130
|
+
"resolved": "void",
|
|
131
|
+
"references": {}
|
|
132
|
+
}
|
|
133
|
+
}, {
|
|
134
|
+
"method": "bsDislike",
|
|
135
|
+
"name": "bsDislike",
|
|
136
|
+
"bubbles": true,
|
|
137
|
+
"cancelable": true,
|
|
138
|
+
"composed": true,
|
|
139
|
+
"docs": {
|
|
140
|
+
"tags": [],
|
|
141
|
+
"text": "Fires when the \"Dislike\" button is clicked."
|
|
142
|
+
},
|
|
143
|
+
"complexType": {
|
|
144
|
+
"original": "void",
|
|
145
|
+
"resolved": "void",
|
|
146
|
+
"references": {}
|
|
147
|
+
}
|
|
148
|
+
}, {
|
|
149
|
+
"method": "bsCopy",
|
|
150
|
+
"name": "bsCopy",
|
|
151
|
+
"bubbles": true,
|
|
152
|
+
"cancelable": true,
|
|
153
|
+
"composed": true,
|
|
154
|
+
"docs": {
|
|
155
|
+
"tags": [],
|
|
156
|
+
"text": "Fires when the \"Copy\" button is clicked."
|
|
157
|
+
},
|
|
158
|
+
"complexType": {
|
|
159
|
+
"original": "void",
|
|
160
|
+
"resolved": "void",
|
|
161
|
+
"references": {}
|
|
162
|
+
}
|
|
163
|
+
}, {
|
|
164
|
+
"method": "bsRegenerate",
|
|
165
|
+
"name": "bsRegenerate",
|
|
166
|
+
"bubbles": true,
|
|
167
|
+
"cancelable": true,
|
|
168
|
+
"composed": true,
|
|
169
|
+
"docs": {
|
|
170
|
+
"tags": [],
|
|
171
|
+
"text": "Fires when the \"Regenerate\" button is clicked."
|
|
172
|
+
},
|
|
173
|
+
"complexType": {
|
|
174
|
+
"original": "void",
|
|
175
|
+
"resolved": "void",
|
|
176
|
+
"references": {}
|
|
177
|
+
}
|
|
178
|
+
}, {
|
|
179
|
+
"method": "bsMenuOpen",
|
|
180
|
+
"name": "bsMenuOpen",
|
|
181
|
+
"bubbles": true,
|
|
182
|
+
"cancelable": true,
|
|
183
|
+
"composed": true,
|
|
184
|
+
"docs": {
|
|
185
|
+
"tags": [],
|
|
186
|
+
"text": "Fires when the \"More options\" button is clicked."
|
|
187
|
+
},
|
|
188
|
+
"complexType": {
|
|
189
|
+
"original": "void",
|
|
190
|
+
"resolved": "void",
|
|
191
|
+
"references": {}
|
|
192
|
+
}
|
|
193
|
+
}, {
|
|
194
|
+
"method": "bsSourcesClick",
|
|
195
|
+
"name": "bsSourcesClick",
|
|
196
|
+
"bubbles": true,
|
|
197
|
+
"cancelable": true,
|
|
198
|
+
"composed": true,
|
|
199
|
+
"docs": {
|
|
200
|
+
"tags": [],
|
|
201
|
+
"text": "Fires when the \"N sources\" button is clicked."
|
|
202
|
+
},
|
|
203
|
+
"complexType": {
|
|
204
|
+
"original": "void",
|
|
205
|
+
"resolved": "void",
|
|
206
|
+
"references": {}
|
|
207
|
+
}
|
|
208
|
+
}];
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const ThumbsUpIcon = () => (h("svg", { viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true" }, h("path", { d: "M2.5 8.125H6.25V16.25H2.5C2.33424 16.25 2.17527 16.1842 2.05806 16.0669C1.94085 15.9497 1.875 15.7908 1.875 15.625V8.75C1.875 8.58424 1.94085 8.42527 2.05806 8.30806C2.17527 8.19085 2.33424 8.125 2.5 8.125Z", stroke: "currentColor", "stroke-width": "1.66667", "stroke-linecap": "round", "stroke-linejoin": "round" }), h("path", { d: "M6.25 8.125L9.375 1.875C10.038 1.875 10.6739 2.13839 11.1428 2.60723C11.6116 3.07607 11.875 3.71196 11.875 4.375V6.25H16.875C17.0523 6.25005 17.2276 6.28782 17.3892 6.36081C17.5508 6.4338 17.695 6.54033 17.8123 6.67333C17.9295 6.80634 18.0172 6.96277 18.0693 7.13223C18.1215 7.3017 18.137 7.48033 18.1148 7.65625L17.1773 15.1562C17.1393 15.4583 16.9923 15.736 16.7641 15.9374C16.5358 16.1388 16.2419 16.2499 15.9375 16.25H6.25", stroke: "currentColor", "stroke-width": "1.66667", "stroke-linecap": "round", "stroke-linejoin": "round" })));
|
|
212
|
+
const ThumbsDownIcon = () => (h("svg", { viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true" }, h("path", { d: "M2.5 3.75H6.25V11.875H2.5C2.33424 11.875 2.17527 11.8092 2.05806 11.6919C1.94085 11.5747 1.875 11.4158 1.875 11.25V4.375C1.875 4.20924 1.94085 4.05027 2.05806 3.93306C2.17527 3.81585 2.33424 3.75 2.5 3.75Z", stroke: "currentColor", "stroke-width": "1.66667", "stroke-linecap": "round", "stroke-linejoin": "round" }), h("path", { d: "M6.25 11.875L9.375 18.125C10.038 18.125 10.6739 17.8616 11.1428 17.3928C11.6116 16.9239 11.875 16.288 11.875 15.625V13.75H16.875C17.0523 13.75 17.2276 13.7122 17.3892 13.6392C17.5508 13.5662 17.695 13.4597 17.8123 13.3267C17.9295 13.1937 18.0172 13.0372 18.0693 12.8678C18.1215 12.6983 18.137 12.5197 18.1148 12.3438L17.1773 4.84375C17.1393 4.54174 16.9923 4.26399 16.7641 4.06262C16.5358 3.86124 16.2419 3.75009 15.9375 3.75H6.25", stroke: "currentColor", "stroke-width": "1.66667", "stroke-linecap": "round", "stroke-linejoin": "round" })));
|
|
213
|
+
const CopyIcon = () => (h("svg", { viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true" }, h("path", { d: "M13.125 13.125H16.875V3.125H6.875V6.875", stroke: "currentColor", "stroke-width": "1.66667", "stroke-linecap": "round", "stroke-linejoin": "round" }), h("path", { d: "M13.125 6.875H3.125V16.875H13.125V6.875Z", stroke: "currentColor", "stroke-width": "1.66667", "stroke-linecap": "round", "stroke-linejoin": "round" })));
|
|
214
|
+
const RegenerateIcon = () => (h("svg", { viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true" }, h("path", { d: "M13.125 7.5H16.875V3.75", stroke: "currentColor", "stroke-width": "1.66667", "stroke-linecap": "round", "stroke-linejoin": "round" }), h("path", { d: "M16.875 7.5L14.6656 5.29063C13.3861 4.01117 11.6538 3.28772 9.84437 3.27719C8.03494 3.26666 6.29431 3.9699 5 5.23438", stroke: "currentColor", "stroke-width": "1.66667", "stroke-linecap": "round", "stroke-linejoin": "round" }), h("path", { d: "M6.875 12.5H3.125V16.25", stroke: "currentColor", "stroke-width": "1.66667", "stroke-linecap": "round", "stroke-linejoin": "round" }), h("path", { d: "M3.125 12.5L5.33437 14.7094C6.61388 15.9888 8.34621 16.7123 10.1556 16.7228C11.9651 16.7333 13.7057 16.0301 15 14.7656", stroke: "currentColor", "stroke-width": "1.66667", "stroke-linecap": "round", "stroke-linejoin": "round" })));
|
|
215
|
+
const MenuIcon = () => (h("svg", { viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true" }, h("path", { d: "M10 9.11426C10.489 9.11426 10.8857 9.511 10.8857 10C10.8857 10.489 10.489 10.8857 10 10.8857C9.511 10.8857 9.11426 10.489 9.11426 10C9.11426 9.511 9.511 9.11426 10 9.11426Z", fill: "currentColor", stroke: "currentColor", "stroke-width": "0.104167" }), h("path", { d: "M10 3.80176C10.489 3.80176 10.8857 4.1985 10.8857 4.6875C10.8857 5.1765 10.489 5.57324 10 5.57324C9.511 5.57324 9.11426 5.1765 9.11426 4.6875C9.11426 4.1985 9.511 3.80176 10 3.80176Z", fill: "currentColor", stroke: "currentColor", "stroke-width": "0.104167" }), h("path", { d: "M10 16.25C10.5178 16.25 10.9375 15.8303 10.9375 15.3125C10.9375 14.7947 10.5178 14.375 10 14.375C9.48223 14.375 9.0625 14.7947 9.0625 15.3125C9.0625 15.8303 9.48223 16.25 10 16.25Z", fill: "currentColor" })));
|
|
216
|
+
const SourcesIcon = () => (h("svg", { viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true" }, h("path", { d: "M13.125 17.5H4.375C4.20924 17.5 4.05027 17.4342 3.93306 17.3169C3.81585 17.1997 3.75 17.0408 3.75 16.875V5.625C3.75 5.45924 3.81585 5.30027 3.93306 5.18306C4.05027 5.06585 4.20924 5 4.375 5H10.625L13.75 8.125V16.875C13.75 17.0408 13.6842 17.1997 13.5669 17.3169C13.4497 17.4342 13.2908 17.5 13.125 17.5Z", stroke: "currentColor", "stroke-width": "1.66667", "stroke-linecap": "round", "stroke-linejoin": "round" }), h("path", { d: "M6.25 5V3.125C6.25 2.95924 6.31585 2.80027 6.43306 2.68306C6.55027 2.56585 6.70924 2.5 6.875 2.5H13.125L16.25 5.625V14.375C16.25 14.5408 16.1842 14.6997 16.0669 14.8169C15.9497 14.9342 15.7908 15 15.625 15H13.75", stroke: "currentColor", "stroke-width": "1.66667", "stroke-linecap": "round", "stroke-linejoin": "round" }), h("path", { d: "M6.875 11.875H10.625", stroke: "currentColor", "stroke-width": "1.66667", "stroke-linecap": "round", "stroke-linejoin": "round" }), h("path", { d: "M6.875 14.375H10.625", stroke: "currentColor", "stroke-width": "1.66667", "stroke-linecap": "round", "stroke-linejoin": "round" })));
|
package/dist/collection/components/bs-chatbot-response-action/bs-chatbot-response-action.stories.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { html } from "lit";
|
|
2
|
+
import { componentDescription, propDescription } from "../../stories-utils";
|
|
3
|
+
const meta = {
|
|
4
|
+
title: 'Genie AI Components/bs-chatbot-response-action',
|
|
5
|
+
parameters: { docs: { description: { component: componentDescription('bs-chatbot-response-action') } } },
|
|
6
|
+
render: args => html ` <bs-chatbot-response-action sources-count=${args.sourcesCount || undefined}></bs-chatbot-response-action> `,
|
|
7
|
+
argTypes: {
|
|
8
|
+
sourcesCount: { control: 'number', description: propDescription('bs-chatbot-response-action', 'sources-count') },
|
|
9
|
+
},
|
|
10
|
+
args: {
|
|
11
|
+
sourcesCount: 3,
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
export default meta;
|
|
15
|
+
export const Default = {};
|
|
16
|
+
export const NoSources = {
|
|
17
|
+
name: 'Without sources',
|
|
18
|
+
args: {
|
|
19
|
+
sourcesCount: 0,
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
export const InResponseMessage = {
|
|
23
|
+
name: 'In an AI response message',
|
|
24
|
+
render: () => html `
|
|
25
|
+
<div style="max-width: 480px; font-family: sans-serif;">
|
|
26
|
+
<p style="margin: 0; color: #1a1a1a; font-size: 14px; line-height: 20px;">
|
|
27
|
+
This is a placeholder AI response message. It demonstrates how the action row sits directly below the
|
|
28
|
+
response text, aligned to the left edge of the message.
|
|
29
|
+
</p>
|
|
30
|
+
<bs-chatbot-response-action sources-count="3"></bs-chatbot-response-action>
|
|
31
|
+
</div>
|
|
32
|
+
`,
|
|
33
|
+
};
|
|
@@ -31,6 +31,19 @@ describe('bs-composer', () => {
|
|
|
31
31
|
const input = root.shadowRoot.querySelector('input');
|
|
32
32
|
expect(input).toEqualAttribute('aria-label', 'Message');
|
|
33
33
|
});
|
|
34
|
+
it('renders consumer-supplied content in the actions-end slot, after the primary action button', async () => {
|
|
35
|
+
const { root } = await render(h("bs-composer", null, h("button", { slot: "actions-end", "aria-label": "Tools" }, "Tools")));
|
|
36
|
+
const slot = root.shadowRoot.querySelector('slot[name="actions-end"]');
|
|
37
|
+
expect(slot).not.toBeNull();
|
|
38
|
+
const assigned = slot.assignedElements();
|
|
39
|
+
expect(assigned).toHaveLength(1);
|
|
40
|
+
expect(assigned[0]).toEqualAttribute('aria-label', 'Tools');
|
|
41
|
+
const controlsRow = root.shadowRoot.querySelector('.bs-composer__controls-row');
|
|
42
|
+
const children = Array.from(controlsRow.children);
|
|
43
|
+
const slotIndex = children.indexOf(slot);
|
|
44
|
+
const actionIndex = children.findIndex(el => el.getAttribute('part') === 'action');
|
|
45
|
+
expect(slotIndex).toBeGreaterThan(actionIndex);
|
|
46
|
+
});
|
|
34
47
|
it('emits bsInput with the current value as the user types', async () => {
|
|
35
48
|
const { root, spyOnEvent } = await render(h("bs-composer", null));
|
|
36
49
|
const spy = spyOnEvent('bsInput');
|
|
@@ -22,6 +22,16 @@ const WAVEFORM_BAR_HEIGHTS = [
|
|
|
22
22
|
* - A general-purpose text field — use `bs-input` instead; this component's layout and states are
|
|
23
23
|
* purpose-built for a chat composer, not a generic form field.
|
|
24
24
|
*
|
|
25
|
+
* ## Focus
|
|
26
|
+
* Uses `shadow: { delegatesFocus: true }`, so calling `.focus()` on the `<bs-composer>` host
|
|
27
|
+
* element itself (not just its internal `<input>`) moves focus into the shadow-DOM text field --
|
|
28
|
+
* useful for e.g. focusing the composer after a parent view mounts, without reaching into its
|
|
29
|
+
* shadow root.
|
|
30
|
+
*
|
|
31
|
+
* @slot actions-end - Extra consumer-supplied controls appended after the primary action button
|
|
32
|
+
* in the controls row (e.g. a product-specific "Tools" button). Slotted content is placed
|
|
33
|
+
* inline in the same flex row as attach/mic/action, so a slotted element should size itself to
|
|
34
|
+
* roughly match `--bs-composer-button-size` to align visually.
|
|
25
35
|
* @part attach - The "+" attach button.
|
|
26
36
|
* @part input - The native text `<input>`.
|
|
27
37
|
* @part mic - The secondary icon button (microphone, or the stop-recording square while `state="recording"`).
|
|
@@ -121,7 +131,7 @@ export class BsComposer {
|
|
|
121
131
|
const placeholder = this.placeholder ?? DEFAULT_PLACEHOLDERS[this.variant];
|
|
122
132
|
const disabled = this.state === 'disabled';
|
|
123
133
|
const recording = this.state === 'recording';
|
|
124
|
-
return (h("div", { key: '
|
|
134
|
+
return (h("div", { key: '04c250520759948faa89bd625646a62c79cc6cee', class: `bs-composer bs-composer--${this.state} bs-composer--${this.variant}` }, h("div", { key: '8d5d99b90141d3dbeff1b31851cbbb5eaae3d920', class: "bs-composer__text-row" }, h("input", { key: '4eb1ef1b51a41de86da466c8a2c9ea93a7746b43', part: "input", class: "bs-composer__input", type: "text", value: this.value, placeholder: placeholder, disabled: disabled, "aria-label": this.ariaLabel, onInput: this.onInput })), h("div", { key: '8a733762c56ae3f4de7f2af1d89fb05d521b1d17', class: "bs-composer__controls-row" }, h("button", { key: 'b4cd13546ec447f2650a02f43dc2fc0b6d65c8ef', type: "button", part: "attach", class: "bs-composer__attach", "aria-label": "Attach", onClick: this.onAttachClick }, h(PlusIcon, { key: 'af8da06a2550d5c37d3737b145ad70c006e1ce66' })), recording ? (h("span", { class: "bs-composer__waveform", "aria-hidden": "true" }, WAVEFORM_BAR_HEIGHTS.map(height => (h("span", { class: "bs-composer__waveform-bar", style: { '--bs-composer-bar-height': `${height}px` } }))))) : (h("span", { class: "bs-composer__spacer" })), h("button", { key: '18b81bf7dd6057c3954566cd12994bb8589ff4ee', type: "button", part: "mic", class: `bs-composer__mic ${recording ? 'bs-composer__mic--recording' : ''}`, "aria-label": recording ? 'Stop recording' : 'Start voice input', disabled: disabled, onClick: this.onMicClick }, recording ? h(StopIcon, null) : h(MicIcon, null)), h("button", { key: 'a1cf9435fa7dc8e52db7ae148e07fde06971f27c', type: "button", part: "action", class: `bs-composer__action bs-composer__action--${this.state}`, "aria-label": this.actionLabel(), disabled: disabled, onClick: this.onActionClick }, this.renderActionIcon()), h("slot", { key: '6779413b48314161a75ec75be273e72fe4d622c3', name: "actions-end" }))));
|
|
125
135
|
}
|
|
126
136
|
static get is() { return "bs-composer"; }
|
|
127
137
|
static get encapsulation() { return "shadow"; }
|
|
@@ -54,11 +54,11 @@ export class BsDataTable {
|
|
|
54
54
|
this.bsRowSelect.emit({ id: row.id, selected });
|
|
55
55
|
};
|
|
56
56
|
render() {
|
|
57
|
-
return (h("table", { key: '
|
|
57
|
+
return (h("table", { key: '8276a72f6539690dd8189cd29e42993c3d61862c', part: "table", class: "bs-data-table" }, h("thead", { key: '2d3e42222eec0bcbe3d06f26f7a3ae53dd5ccdc0', part: "head" }, h("tr", { key: '45994ea59d9a1a347bb8abdf25d7b1b919822a61' }, this.selectable && h("th", { key: '05d5efa74feee1545e1c4b9dfc45acd7ffd10e6a', class: "bs-data-table__select-col" }), this.columns.map(column => {
|
|
58
58
|
const isSorted = this.sortColumn === column.key;
|
|
59
59
|
const ariaSort = column.sortable ? (isSorted ? (this.sortDirection === 'asc' ? 'ascending' : 'descending') : 'none') : undefined;
|
|
60
60
|
return (h("th", { part: "header-cell", class: "bs-data-table__header-cell", "aria-sort": ariaSort }, column.sortable ? (h("button", { type: "button", class: "bs-data-table__sort-button", onClick: () => this.onHeaderClick(column) }, column.label, isSorted && h("span", { class: "bs-data-table__sort-indicator" }, this.sortDirection === 'asc' ? ' ▲' : ' ▼'))) : (column.label)));
|
|
61
|
-
}))), h("tbody", { key: '
|
|
61
|
+
}))), h("tbody", { key: '9c1dc006341b63e5d22df655836f326ba27e7b9d', part: "body" }, this.rows.map(row => (h("tr", { part: "row", class: "bs-data-table__row" }, this.selectable && (h("td", { class: "bs-data-table__select-col" }, h("input", { type: "checkbox", checked: this.selectedIds.has(row.id), onChange: ev => this.onRowCheckboxChange(row, ev) }))), this.columns.map(column => this.cellRenderer ? (
|
|
62
62
|
// cellRenderer is a developer-supplied, trusted function (JS-property-only, never
|
|
63
63
|
// derived from untrusted input) -- its HTML output is intentionally not escaped,
|
|
64
64
|
// same trust model as React's dangerouslySetInnerHTML.
|
|
@@ -36,10 +36,10 @@ export class BsInput {
|
|
|
36
36
|
this.bsChange.emit(value);
|
|
37
37
|
};
|
|
38
38
|
render() {
|
|
39
|
-
return (h("div", { key: '
|
|
39
|
+
return (h("div", { key: '53b4d56fb2c955f061ac113b7dc2dbe8548a85d1', class: `bs-input ${this.error ? 'bs-input--error' : ''}` }, this.label && (
|
|
40
40
|
// "control" is a fixed id, not a generated one -- safe because Shadow DOM scopes ids
|
|
41
41
|
// to this instance's own shadow root, so it can never collide with another bs-input.
|
|
42
|
-
h("label", { key: '
|
|
42
|
+
h("label", { key: '60ac25b59a78410843dbe9416398d4e0ec15c976', part: "label", class: "bs-input__label", htmlFor: "control" }, this.label)), h("input", { key: 'a9f801b2a7e16550c5d22c1301435e7a7082b362', id: "control", part: "control", class: "bs-input__control", type: this.type, value: this.value, placeholder: this.placeholder, disabled: this.disabled, "aria-describedby": this.error || this.description ? 'description-or-error' : undefined, "aria-invalid": this.error ? 'true' : undefined, onInput: this.onInput, onChange: this.onChange }), this.error ? (h("span", { id: "description-or-error", part: "error", class: "bs-input__error" }, this.error)) : this.description ? (h("span", { id: "description-or-error", part: "description", class: "bs-input__description" }, this.description)) : null));
|
|
43
43
|
}
|
|
44
44
|
static get is() { return "bs-input"; }
|
|
45
45
|
static get encapsulation() { return "shadow"; }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e,p as a,H as r,h as b}from"./p-
|
|
1
|
+
import{t as e,p as a,H as r,h as b}from"./p-BpvhHQSw.js";const s=a(class extends r{constructor(e){super(),!1!==e&&this.__registerHost(),this.__attachShadow()}variant="default";render(){return b("span",{key:"9cc06bddba11f57edf97209456e25141a3b80bea",part:"container",class:"bs-badge bs-badge--"+this.variant},b("slot",{key:"7c0e4054e99a3dedc94f2a7250075fcb76c115b6"}))}static get style(){return":host{display:inline-block}.bs-badge{display:inline-flex;align-items:center;height:var(--bs-spacing-400);padding:0 var(--bs-spacing-200);border-radius:var(--bs-border-radius-full);font-size:var(--bs-font-size-xs);font-weight:var(--bs-font-weight-medium);font-family:inherit;white-space:nowrap}.bs-badge--default{background:var(--bs-badge-bg-default);color:var(--bs-badge-text-default)}.bs-badge--primary{background:var(--bs-badge-bg-primary-container);color:var(--bs-badge-text-primary)}.bs-badge--success{background:var(--bs-badge-bg-success-container);color:var(--bs-badge-text-success)}.bs-badge--warning{background:var(--bs-badge-bg-warning-container);color:var(--bs-badge-text-warning)}.bs-badge--info{background:var(--bs-badge-bg-info-container);color:var(--bs-badge-text-info)}.bs-badge--error{background:var(--bs-badge-bg-error-container);color:var(--bs-badge-text-error)}.bs-badge--neutral{background:var(--bs-badge-bg-neutral-container);color:var(--bs-badge-text-neutral)}.bs-badge--inverse{background:var(--bs-badge-bg-inverse);color:var(--bs-badge-text-inverse)}"}},[769,"bs-badge",{variant:[1]}]);function t(){"undefined"!=typeof customElements&&["bs-badge"].forEach((a=>{"bs-badge"===a&&(customElements.get(e(a))||customElements.define(e(a),s))}))}t();const n=s,d=t;export{n as BsBadge,d as defineCustomElement}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t,p as e,H as s,h as n}from"./p-
|
|
1
|
+
import{t,p as e,H as s,h as n}from"./p-BpvhHQSw.js";const o=e(class extends s{constructor(t){super(),!1!==t&&this.__registerHost(),this.__attachShadow()}size="md";render(){return n("span",{key:"5b51879877adc5abbe6f28d79f27a1f33654a1a4",part:"container",class:"bs-button-skeleton bs-button-skeleton--"+this.size,role:"status","aria-label":"Loading"})}static get style(){return":host{display:inline-block;--bs-button-skeleton-height-sm:var(--bs-spacing-500);--bs-button-skeleton-height-md:var(--bs-spacing-600);--bs-button-skeleton-height-lg:var(--bs-spacing-700);--bs-button-skeleton-width:96px}.bs-button-skeleton{display:inline-block;border-radius:var(--bs-border-radius-100);width:var(--bs-button-skeleton-width);background:var(--bs-color-neutral-container);animation:bs-button-skeleton-pulse 1.5s ease-in-out infinite}.bs-button-skeleton--sm{height:var(--bs-button-skeleton-height-sm)}.bs-button-skeleton--md{height:var(--bs-button-skeleton-height-md)}.bs-button-skeleton--lg{height:var(--bs-button-skeleton-height-lg)}@keyframes bs-button-skeleton-pulse{0%,100%{opacity:1}50%{opacity:0.5}}@media (prefers-reduced-motion: reduce){.bs-button-skeleton{animation:none}}"}},[513,"bs-button-skeleton",{size:[1]}]);function b(){"undefined"!=typeof customElements&&["bs-button-skeleton"].forEach((e=>{"bs-button-skeleton"===e&&(customElements.get(t(e))||customElements.define(t(e),o))}))}b();const i=o,a=b;export{i as BsButtonSkeleton,a as defineCustomElement}
|