@brandsync/wc 0.0.1

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.
Files changed (134) hide show
  1. package/LICENSE +21 -0
  2. package/custom-elements.json +1138 -0
  3. package/dist/brandsync-wc/brandsync-wc.css +1730 -0
  4. package/dist/brandsync-wc/brandsync-wc.esm.js +1 -0
  5. package/dist/brandsync-wc/brandsync-wc.esm.js.map +1 -0
  6. package/dist/brandsync-wc/index-Cqxk7LcP.js.map +1 -0
  7. package/dist/brandsync-wc/index.esm.js +1 -0
  8. package/dist/brandsync-wc/index.esm.js.map +1 -0
  9. package/dist/brandsync-wc/p-042ad15a.entry.js +1 -0
  10. package/dist/brandsync-wc/p-2c4df28d.entry.js +1 -0
  11. package/dist/brandsync-wc/p-3134f5f5.entry.js +1 -0
  12. package/dist/brandsync-wc/p-5739acaf.entry.js +1 -0
  13. package/dist/brandsync-wc/p-BOj_41o9.js +3 -0
  14. package/dist/brandsync-wc/p-c2cc0d6f.entry.js +1 -0
  15. package/dist/brandsync-wc/p-da11e421.entry.js +1 -0
  16. package/dist/brandsync-wc/p-db3934d2.entry.js +1 -0
  17. package/dist/brandsync-wc/p-e38a9744.entry.js +1 -0
  18. package/dist/cjs/brandsync-wc.cjs.js +24 -0
  19. package/dist/cjs/bs-badge.cjs.entry.js +19 -0
  20. package/dist/cjs/bs-button-skeleton.cjs.entry.js +19 -0
  21. package/dist/cjs/bs-button.cjs.entry.js +88 -0
  22. package/dist/cjs/bs-card.cjs.entry.js +20 -0
  23. package/dist/cjs/bs-composer.cjs.entry.js +116 -0
  24. package/dist/cjs/bs-data-table.cjs.entry.js +62 -0
  25. package/dist/cjs/bs-input.cjs.entry.js +42 -0
  26. package/dist/cjs/bs-modal.cjs.entry.js +69 -0
  27. package/dist/cjs/index-nyOcuVbF.js +1710 -0
  28. package/dist/cjs/index.cjs.js +7 -0
  29. package/dist/cjs/loader.cjs.js +12 -0
  30. package/dist/collection/collection-manifest.json +20 -0
  31. package/dist/collection/components/bs-badge/bs-badge.cmp.test.js +30 -0
  32. package/dist/collection/components/bs-badge/bs-badge.css +55 -0
  33. package/dist/collection/components/bs-badge/bs-badge.js +64 -0
  34. package/dist/collection/components/bs-badge/bs-badge.stories.js +75 -0
  35. package/dist/collection/components/bs-button/bs-button.cmp.test.js +81 -0
  36. package/dist/collection/components/bs-button/bs-button.css +247 -0
  37. package/dist/collection/components/bs-button/bs-button.js +242 -0
  38. package/dist/collection/components/bs-button/bs-button.stories.js +145 -0
  39. package/dist/collection/components/bs-button-skeleton/bs-button-skeleton.cmp.test.js +18 -0
  40. package/dist/collection/components/bs-button-skeleton/bs-button-skeleton.css +46 -0
  41. package/dist/collection/components/bs-button-skeleton/bs-button-skeleton.js +73 -0
  42. package/dist/collection/components/bs-button-skeleton/bs-button-skeleton.stories.js +25 -0
  43. package/dist/collection/components/bs-card/bs-card.cmp.test.js +42 -0
  44. package/dist/collection/components/bs-card/bs-card.css +31 -0
  45. package/dist/collection/components/bs-card/bs-card.js +70 -0
  46. package/dist/collection/components/bs-card/bs-card.stories.js +27 -0
  47. package/dist/collection/components/bs-composer/bs-composer.cmp.test.js +132 -0
  48. package/dist/collection/components/bs-composer/bs-composer.css +185 -0
  49. package/dist/collection/components/bs-composer/bs-composer.js +353 -0
  50. package/dist/collection/components/bs-composer/bs-composer.stories.js +66 -0
  51. package/dist/collection/components/bs-data-table/bs-data-table.css +56 -0
  52. package/dist/collection/components/bs-data-table/bs-data-table.js +259 -0
  53. package/dist/collection/components/bs-data-table/bs-data-table.stories.js +55 -0
  54. package/dist/collection/components/bs-input/bs-input.cmp.test.js +101 -0
  55. package/dist/collection/components/bs-input/bs-input.css +64 -0
  56. package/dist/collection/components/bs-input/bs-input.js +230 -0
  57. package/dist/collection/components/bs-input/bs-input.stories.js +40 -0
  58. package/dist/collection/components/bs-modal/bs-modal.cmp.test.js +112 -0
  59. package/dist/collection/components/bs-modal/bs-modal.css +66 -0
  60. package/dist/collection/components/bs-modal/bs-modal.js +198 -0
  61. package/dist/collection/components/bs-modal/bs-modal.stories.js +38 -0
  62. package/dist/collection/index.js +10 -0
  63. package/dist/collection/stories-utils.js +25 -0
  64. package/dist/collection/utils/utils.js +3 -0
  65. package/dist/collection/utils/utils.unit.test.js +16 -0
  66. package/dist/components/bs-badge.d.ts +11 -0
  67. package/dist/components/bs-badge.js +1 -0
  68. package/dist/components/bs-button-skeleton.d.ts +11 -0
  69. package/dist/components/bs-button-skeleton.js +1 -0
  70. package/dist/components/bs-button.d.ts +11 -0
  71. package/dist/components/bs-button.js +1 -0
  72. package/dist/components/bs-card.d.ts +11 -0
  73. package/dist/components/bs-card.js +1 -0
  74. package/dist/components/bs-composer.d.ts +11 -0
  75. package/dist/components/bs-composer.js +1 -0
  76. package/dist/components/bs-data-table.d.ts +11 -0
  77. package/dist/components/bs-data-table.js +1 -0
  78. package/dist/components/bs-input.d.ts +11 -0
  79. package/dist/components/bs-input.js +1 -0
  80. package/dist/components/bs-modal.d.ts +11 -0
  81. package/dist/components/bs-modal.js +1 -0
  82. package/dist/components/index.d.ts +35 -0
  83. package/dist/components/index.js +1 -0
  84. package/dist/components/p-Cu4gTknX.js +1 -0
  85. package/dist/esm/brandsync-wc.js +20 -0
  86. package/dist/esm/bs-badge.entry.js +17 -0
  87. package/dist/esm/bs-button-skeleton.entry.js +17 -0
  88. package/dist/esm/bs-button.entry.js +86 -0
  89. package/dist/esm/bs-card.entry.js +18 -0
  90. package/dist/esm/bs-composer.entry.js +114 -0
  91. package/dist/esm/bs-data-table.entry.js +60 -0
  92. package/dist/esm/bs-input.entry.js +40 -0
  93. package/dist/esm/bs-modal.entry.js +67 -0
  94. package/dist/esm/index-BOj_41o9.js +1701 -0
  95. package/dist/esm/index.js +5 -0
  96. package/dist/esm/loader.js +10 -0
  97. package/dist/index.cjs.js +1 -0
  98. package/dist/index.js +1 -0
  99. package/dist/types/components/bs-badge/bs-badge.cmp.test.d.ts +1 -0
  100. package/dist/types/components/bs-badge/bs-badge.d.ts +20 -0
  101. package/dist/types/components/bs-badge/bs-badge.stories.d.ts +19 -0
  102. package/dist/types/components/bs-button/bs-button.cmp.test.d.ts +1 -0
  103. package/dist/types/components/bs-button/bs-button.d.ts +84 -0
  104. package/dist/types/components/bs-button/bs-button.stories.d.ts +29 -0
  105. package/dist/types/components/bs-button-skeleton/bs-button-skeleton.cmp.test.d.ts +1 -0
  106. package/dist/types/components/bs-button-skeleton/bs-button-skeleton.d.ts +28 -0
  107. package/dist/types/components/bs-button-skeleton/bs-button-skeleton.stories.d.ts +10 -0
  108. package/dist/types/components/bs-card/bs-card.cmp.test.d.ts +1 -0
  109. package/dist/types/components/bs-card/bs-card.d.ts +26 -0
  110. package/dist/types/components/bs-card/bs-card.stories.d.ts +10 -0
  111. package/dist/types/components/bs-composer/bs-composer.cmp.test.d.ts +1 -0
  112. package/dist/types/components/bs-composer/bs-composer.d.ts +83 -0
  113. package/dist/types/components/bs-composer/bs-composer.stories.d.ts +17 -0
  114. package/dist/types/components/bs-data-table/bs-data-table.d.ts +55 -0
  115. package/dist/types/components/bs-data-table/bs-data-table.stories.d.ts +7 -0
  116. package/dist/types/components/bs-input/bs-input.cmp.test.d.ts +1 -0
  117. package/dist/types/components/bs-input/bs-input.d.ts +33 -0
  118. package/dist/types/components/bs-input/bs-input.stories.d.ts +15 -0
  119. package/dist/types/components/bs-modal/bs-modal.cmp.test.d.ts +1 -0
  120. package/dist/types/components/bs-modal/bs-modal.d.ts +45 -0
  121. package/dist/types/components/bs-modal/bs-modal.stories.d.ts +9 -0
  122. package/dist/types/components.d.ts +962 -0
  123. package/dist/types/index.d.ts +11 -0
  124. package/dist/types/stencil-public-runtime.d.ts +1872 -0
  125. package/dist/types/stories-utils.d.ts +8 -0
  126. package/dist/types/utils/utils.d.ts +1 -0
  127. package/dist/types/utils/utils.unit.test.d.ts +1 -0
  128. package/loader/cdn.js +1 -0
  129. package/loader/index.cjs.js +1 -0
  130. package/loader/index.d.ts +24 -0
  131. package/loader/index.es2017.js +1 -0
  132. package/loader/index.js +2 -0
  133. package/package.json +67 -0
  134. package/readme.md +48 -0
@@ -0,0 +1,70 @@
1
+ import { h } from "@stencil/core";
2
+ /**
3
+ * A bounded surface for grouping related content — a summary, a form section, a list item.
4
+ *
5
+ * ## When to use
6
+ * - Grouping a self-contained piece of content that needs visual separation from the page
7
+ * background (e.g. a booking summary, a settings section).
8
+ *
9
+ * ## When not to use
10
+ * - As the only structural element on a page — cards group content, they don't replace layout.
11
+ * - For a dismissible/transient message — use a modal or a dedicated notification component.
12
+ *
13
+ * @slot header - Optional heading content above the body.
14
+ * @slot - Default slot: the card's main body content.
15
+ * @slot footer - Optional actions/content below the body (e.g. a button).
16
+ * @part container - The outer bordered surface element.
17
+ * @part header - The header wrapper.
18
+ * @part body - The body wrapper.
19
+ * @part footer - The footer wrapper.
20
+ */
21
+ export class BsCard {
22
+ /** Maps to the brandsync-tokens `--bs-paper-bg-*` set — Brandsync's tokens don't have a
23
+ * dedicated "card" component yet, so this reuses the existing Paper surface tokens. */
24
+ surface = 'raised';
25
+ render() {
26
+ return (h("div", { key: '6c74e846c97f02a39ce1f2b215c87fbb9cd42055', part: "container", class: `bs-card bs-card--${this.surface}` }, h("div", { key: 'ef89eb6ea19be13daf403b010a93e1f5a82691d4', part: "header", class: "bs-card__header" }, h("slot", { key: '4627d1f598def9298e0b7d251a523892bb0b97cf', name: "header" })), h("div", { key: 'a599746c11f92d2a535985abdcadbc9cc3036fdd', part: "body", class: "bs-card__body" }, h("slot", { key: 'f8d46c5f6aefeb870796c4efa37663e698fdd5c7' })), h("div", { key: '7f928a259fb159b6eb7d742cbfe6c1aacbef6e36', part: "footer", class: "bs-card__footer" }, h("slot", { key: 'fddc69aedbc10f4397bb1db62265c657ec2642ab', name: "footer" }))));
27
+ }
28
+ static get is() { return "bs-card"; }
29
+ static get encapsulation() { return "shadow"; }
30
+ static get originalStyleUrls() {
31
+ return {
32
+ "$": ["bs-card.css"]
33
+ };
34
+ }
35
+ static get styleUrls() {
36
+ return {
37
+ "$": ["bs-card.css"]
38
+ };
39
+ }
40
+ static get properties() {
41
+ return {
42
+ "surface": {
43
+ "type": "string",
44
+ "mutable": false,
45
+ "complexType": {
46
+ "original": "BsCardSurface",
47
+ "resolved": "\"base\" | \"container\" | \"raised\"",
48
+ "references": {
49
+ "BsCardSurface": {
50
+ "location": "local",
51
+ "path": "/Users/vivka/brandsync-web-components/src/components/bs-card/bs-card.tsx",
52
+ "id": "src/components/bs-card/bs-card.tsx::BsCardSurface"
53
+ }
54
+ }
55
+ },
56
+ "required": false,
57
+ "optional": false,
58
+ "docs": {
59
+ "tags": [],
60
+ "text": "Maps to the brandsync-tokens `--bs-paper-bg-*` set \u2014 Brandsync's tokens don't have a\ndedicated \"card\" component yet, so this reuses the existing Paper surface tokens."
61
+ },
62
+ "getter": false,
63
+ "setter": false,
64
+ "reflect": false,
65
+ "attribute": "surface",
66
+ "defaultValue": "'raised'"
67
+ }
68
+ };
69
+ }
70
+ }
@@ -0,0 +1,27 @@
1
+ import { html } from "lit";
2
+ import { componentDescription, propDescription } from "../../stories-utils";
3
+ const meta = {
4
+ title: 'Components/bs-card',
5
+ parameters: { docs: { description: { component: componentDescription('bs-card') } } },
6
+ render: args => html `
7
+ <bs-card surface=${args.surface} style="max-width: 320px;">
8
+ <strong slot="header">Booking confirmed</strong>
9
+ <p>Meeting Room 4B is reserved for 2:00pm - 3:00pm.</p>
10
+ <bs-button slot="footer" size="sm">View details</bs-button>
11
+ </bs-card>
12
+ `,
13
+ argTypes: {
14
+ surface: { control: 'select', options: ['base', 'raised', 'container'], description: propDescription('bs-card', 'surface') },
15
+ },
16
+ args: {
17
+ surface: 'raised',
18
+ },
19
+ };
20
+ export default meta;
21
+ export const Raised = {};
22
+ export const Base = {
23
+ args: { surface: 'base' },
24
+ };
25
+ export const Container = {
26
+ args: { surface: 'container' },
27
+ };
@@ -0,0 +1,132 @@
1
+ import { render, h, describe, it, expect } from "@stencil/vitest";
2
+ describe('bs-composer', () => {
3
+ it('renders with idle state defaults: ai variant placeholder, enabled mic/action buttons', async () => {
4
+ const { root } = await render(h("bs-composer", null));
5
+ const input = root.shadowRoot.querySelector('input');
6
+ expect(input).toEqualAttribute('placeholder', 'Ask Genie something...');
7
+ expect(input).not.toHaveAttribute('disabled');
8
+ const mic = root.shadowRoot.querySelector('[part="mic"]');
9
+ const action = root.shadowRoot.querySelector('[part="action"]');
10
+ expect(mic).not.toHaveAttribute('disabled');
11
+ expect(action).not.toHaveAttribute('disabled');
12
+ expect(action).toEqualAttribute('aria-label', 'Send');
13
+ });
14
+ it('uses the human variant default placeholder', async () => {
15
+ const { root } = await render(h("bs-composer", { variant: "human" }));
16
+ const input = root.shadowRoot.querySelector('input');
17
+ expect(input).toEqualAttribute('placeholder', 'Message your support agent...');
18
+ });
19
+ it('overrides the variant default placeholder when placeholder is set', async () => {
20
+ const { root } = await render(h("bs-composer", { variant: "ai", placeholder: "Custom prompt" }));
21
+ const input = root.shadowRoot.querySelector('input');
22
+ expect(input).toEqualAttribute('placeholder', 'Custom prompt');
23
+ });
24
+ it('reflects the value prop to the native input', async () => {
25
+ const { root } = await render(h("bs-composer", { value: "hello there" }));
26
+ const input = root.shadowRoot.querySelector('input');
27
+ expect(input.value).toBe('hello there');
28
+ });
29
+ it('sets aria-label on the input from the ariaLabel prop', async () => {
30
+ const { root } = await render(h("bs-composer", { ariaLabel: "Message" }));
31
+ const input = root.shadowRoot.querySelector('input');
32
+ expect(input).toEqualAttribute('aria-label', 'Message');
33
+ });
34
+ it('emits bsInput with the current value as the user types', async () => {
35
+ const { root, spyOnEvent } = await render(h("bs-composer", null));
36
+ const spy = spyOnEvent('bsInput');
37
+ const input = root.shadowRoot.querySelector('input');
38
+ input.value = 'a';
39
+ input.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
40
+ expect(spy).toHaveReceivedEventTimes(1);
41
+ expect(spy).toHaveReceivedEventDetail('a');
42
+ });
43
+ it('emits bsAttach when the attach button is clicked', async () => {
44
+ const { root, spyOnEvent } = await render(h("bs-composer", null));
45
+ const spy = spyOnEvent('bsAttach');
46
+ root.shadowRoot.querySelector('[part="attach"]').click();
47
+ expect(spy).toHaveReceivedEventTimes(1);
48
+ });
49
+ describe('state="idle"', () => {
50
+ it('shows the send icon and enabled action/mic buttons, and emits bsSubmit on action click', async () => {
51
+ const { root, spyOnEvent } = await render(h("bs-composer", { state: "idle" }));
52
+ const submitSpy = spyOnEvent('bsSubmit');
53
+ const stopSpy = spyOnEvent('bsStop');
54
+ const confirmSpy = spyOnEvent('bsVoiceConfirm');
55
+ const action = root.shadowRoot.querySelector('[part="action"]');
56
+ expect(action).not.toHaveAttribute('disabled');
57
+ action.click();
58
+ expect(submitSpy).toHaveReceivedEventTimes(1);
59
+ expect(stopSpy.length).toBe(0);
60
+ expect(confirmSpy.length).toBe(0);
61
+ });
62
+ it('emits bsMicToggle when the mic button is clicked', async () => {
63
+ const { root, spyOnEvent } = await render(h("bs-composer", { state: "idle" }));
64
+ const spy = spyOnEvent('bsMicToggle');
65
+ root.shadowRoot.querySelector('[part="mic"]').click();
66
+ expect(spy).toHaveReceivedEventTimes(1);
67
+ });
68
+ });
69
+ describe('state="generating"', () => {
70
+ it('shows an enabled action button and emits bsStop (not bsSubmit) on click', async () => {
71
+ const { root, spyOnEvent } = await render(h("bs-composer", { state: "generating" }));
72
+ const submitSpy = spyOnEvent('bsSubmit');
73
+ const stopSpy = spyOnEvent('bsStop');
74
+ const action = root.shadowRoot.querySelector('[part="action"]');
75
+ expect(action).not.toHaveAttribute('disabled');
76
+ expect(action).toEqualAttribute('aria-label', 'Stop');
77
+ action.click();
78
+ expect(stopSpy).toHaveReceivedEventTimes(1);
79
+ expect(submitSpy.length).toBe(0);
80
+ });
81
+ });
82
+ describe('state="disabled"', () => {
83
+ it('natively disables both the mic and action buttons and the text input', async () => {
84
+ const { root } = await render(h("bs-composer", { state: "disabled" }));
85
+ expect(root.shadowRoot.querySelector('input')).toHaveAttribute('disabled');
86
+ expect(root.shadowRoot.querySelector('[part="mic"]')).toHaveAttribute('disabled');
87
+ expect(root.shadowRoot.querySelector('[part="action"]')).toHaveAttribute('disabled');
88
+ });
89
+ it('does not emit bsSubmit, bsStop, or bsVoiceConfirm when the disabled action button is clicked', async () => {
90
+ const { root, spyOnEvent } = await render(h("bs-composer", { state: "disabled" }));
91
+ const submitSpy = spyOnEvent('bsSubmit');
92
+ const stopSpy = spyOnEvent('bsStop');
93
+ const confirmSpy = spyOnEvent('bsVoiceConfirm');
94
+ root.shadowRoot.querySelector('[part="action"]').click();
95
+ expect(submitSpy.length).toBe(0);
96
+ expect(stopSpy.length).toBe(0);
97
+ expect(confirmSpy.length).toBe(0);
98
+ });
99
+ it('does not emit bsMicToggle when the disabled mic button is clicked', async () => {
100
+ const { root, spyOnEvent } = await render(h("bs-composer", { state: "disabled" }));
101
+ const spy = spyOnEvent('bsMicToggle');
102
+ root.shadowRoot.querySelector('[part="mic"]').click();
103
+ expect(spy.length).toBe(0);
104
+ });
105
+ });
106
+ describe('state="recording"', () => {
107
+ it('renders the waveform visualization and an enabled confirm action button', async () => {
108
+ const { root, spyOnEvent } = await render(h("bs-composer", { state: "recording", value: "already typed" }));
109
+ const confirmSpy = spyOnEvent('bsVoiceConfirm');
110
+ const submitSpy = spyOnEvent('bsSubmit');
111
+ expect(root.shadowRoot.querySelector('.bs-composer__waveform')).not.toBeNull();
112
+ const action = root.shadowRoot.querySelector('[part="action"]');
113
+ expect(action).not.toHaveAttribute('disabled');
114
+ expect(action).toEqualAttribute('aria-label', 'Confirm');
115
+ action.click();
116
+ expect(confirmSpy).toHaveReceivedEventTimes(1);
117
+ expect(submitSpy.length).toBe(0);
118
+ });
119
+ it('emits bsMicToggle when the stop-recording button is clicked', async () => {
120
+ const { root, spyOnEvent } = await render(h("bs-composer", { state: "recording" }));
121
+ const spy = spyOnEvent('bsMicToggle');
122
+ const mic = root.shadowRoot.querySelector('[part="mic"]');
123
+ expect(mic).toEqualAttribute('aria-label', 'Stop recording');
124
+ mic.click();
125
+ expect(spy).toHaveReceivedEventTimes(1);
126
+ });
127
+ });
128
+ it('does not render the waveform outside of the recording state', async () => {
129
+ const { root } = await render(h("bs-composer", { state: "idle" }));
130
+ expect(root.shadowRoot.querySelector('.bs-composer__waveform')).toBeNull();
131
+ });
132
+ });
@@ -0,0 +1,185 @@
1
+ :host {
2
+ display: block;
3
+ --bs-composer-radius: var(--bs-border-radius-150);
4
+ --bs-composer-button-radius: var(--bs-border-radius-100);
5
+ --bs-composer-button-size: var(--bs-spacing-600);
6
+ --bs-composer-bg: var(--bs-input-bg-default);
7
+ --bs-composer-border: var(--bs-input-border-default);
8
+ --bs-composer-border-focus: var(--bs-input-border-focus);
9
+
10
+ --bs-composer-action-bg: var(--bs-color-primary-default);
11
+ --bs-composer-action-bg-hover: var(--bs-color-primary-hover);
12
+ --bs-composer-action-bg-pressed: var(--bs-color-primary-pressed);
13
+ --bs-composer-action-bg-disabled: var(--bs-surface-action-disabled);
14
+ --bs-composer-action-icon: var(--bs-text-on-action);
15
+ --bs-composer-action-icon-disabled: var(--bs-text-on-disabled);
16
+
17
+ --bs-composer-attach-icon: var(--bs-icon-default);
18
+ --bs-composer-mic-icon: var(--bs-icon-default);
19
+ --bs-composer-mic-icon-disabled: var(--bs-icon-disabled);
20
+ --bs-composer-mic-recording-icon: var(--bs-icon-default);
21
+ --bs-composer-subtle-hover: var(--bs-color-neutral-container);
22
+ --bs-composer-subtle-pressed: var(--bs-color-neutral-container-pressed);
23
+
24
+ --bs-composer-waveform-color: var(--bs-border-default);
25
+ }
26
+
27
+ .bs-composer {
28
+ box-sizing: border-box;
29
+ display: flex;
30
+ flex-direction: column;
31
+ border: 1px solid var(--bs-composer-border);
32
+ border-radius: var(--bs-composer-radius);
33
+ background: var(--bs-composer-bg);
34
+ font-family: inherit;
35
+ }
36
+
37
+ .bs-composer--human {
38
+ border-style: dashed;
39
+ }
40
+
41
+ .bs-composer:focus-within {
42
+ border-color: var(--bs-composer-border-focus);
43
+ }
44
+
45
+ .bs-composer__text-row {
46
+ display: flex;
47
+ align-items: center;
48
+ gap: var(--bs-spacing-150);
49
+ padding: var(--bs-spacing-150);
50
+ }
51
+
52
+ .bs-composer__input {
53
+ flex: 1;
54
+ min-width: 0;
55
+ border: none;
56
+ outline: none;
57
+ background: transparent;
58
+ color: var(--bs-input-text);
59
+ font-family: inherit;
60
+ font-size: var(--bs-font-size-md);
61
+ }
62
+
63
+ .bs-composer__input::placeholder {
64
+ color: var(--bs-input-placeholder);
65
+ }
66
+
67
+ .bs-composer__input:disabled {
68
+ color: var(--bs-input-text-disabled);
69
+ cursor: not-allowed;
70
+ }
71
+
72
+ .bs-composer__waveform {
73
+ display: inline-flex;
74
+ flex: 1;
75
+ min-width: 0;
76
+ align-items: center;
77
+ justify-content: center;
78
+ gap: 3px;
79
+ overflow: hidden;
80
+ }
81
+
82
+ .bs-composer__waveform-bar {
83
+ display: inline-block;
84
+ flex-shrink: 0;
85
+ width: 2.5px;
86
+ border-radius: 1.5px;
87
+ background: var(--bs-composer-waveform-color);
88
+ /* Static, non-animated placeholder audio-level visualization -- a real analyzer would drive
89
+ * height from actual audio input. */
90
+ height: var(--bs-composer-bar-height, 6px);
91
+ }
92
+
93
+ .bs-composer__controls-row {
94
+ display: flex;
95
+ align-items: center;
96
+ gap: var(--bs-spacing-200);
97
+ padding: var(--bs-spacing-150);
98
+ }
99
+
100
+ .bs-composer__spacer {
101
+ flex: 1;
102
+ }
103
+
104
+ .bs-composer__attach,
105
+ .bs-composer__mic,
106
+ .bs-composer__action {
107
+ display: inline-flex;
108
+ align-items: center;
109
+ justify-content: center;
110
+ box-sizing: border-box;
111
+ border: none;
112
+ padding: 0;
113
+ cursor: pointer;
114
+ font-family: inherit;
115
+ border-radius: var(--bs-composer-button-radius);
116
+ width: var(--bs-composer-button-size);
117
+ height: var(--bs-composer-button-size);
118
+ flex-shrink: 0;
119
+ transition: background-color var(--bs-duration-fast) var(--bs-easing-standard);
120
+ }
121
+
122
+ .bs-composer__attach:focus-visible,
123
+ .bs-composer__mic:focus-visible,
124
+ .bs-composer__action:focus-visible {
125
+ outline: 2px solid var(--bs-border-neutral-focus);
126
+ outline-offset: 2px;
127
+ }
128
+
129
+ .bs-composer__attach svg,
130
+ .bs-composer__mic svg,
131
+ .bs-composer__action svg {
132
+ width: 24px;
133
+ height: 24px;
134
+ }
135
+
136
+ .bs-composer__attach,
137
+ .bs-composer__mic {
138
+ background: transparent;
139
+ }
140
+
141
+ .bs-composer__attach:hover:not(:disabled),
142
+ .bs-composer__mic:hover:not(:disabled) {
143
+ background: var(--bs-composer-subtle-hover);
144
+ }
145
+
146
+ .bs-composer__attach:active:not(:disabled),
147
+ .bs-composer__mic:active:not(:disabled) {
148
+ background: var(--bs-composer-subtle-pressed);
149
+ }
150
+
151
+ .bs-composer__attach {
152
+ color: var(--bs-composer-attach-icon);
153
+ }
154
+
155
+ .bs-composer__mic {
156
+ color: var(--bs-composer-mic-icon);
157
+ }
158
+
159
+ .bs-composer__mic--recording {
160
+ color: var(--bs-composer-mic-recording-icon);
161
+ }
162
+
163
+ .bs-composer__mic:disabled {
164
+ color: var(--bs-composer-mic-icon-disabled);
165
+ cursor: not-allowed;
166
+ }
167
+
168
+ .bs-composer__action {
169
+ background: var(--bs-composer-action-bg);
170
+ color: var(--bs-composer-action-icon);
171
+ }
172
+
173
+ .bs-composer__action:hover:not(:disabled) {
174
+ background: var(--bs-composer-action-bg-hover);
175
+ }
176
+
177
+ .bs-composer__action:active:not(:disabled) {
178
+ background: var(--bs-composer-action-bg-pressed);
179
+ }
180
+
181
+ .bs-composer__action:disabled {
182
+ background: var(--bs-composer-action-bg-disabled);
183
+ color: var(--bs-composer-action-icon-disabled);
184
+ cursor: not-allowed;
185
+ }