@brandsync/wc 1.2.0 → 1.4.0

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 (281) hide show
  1. package/custom-elements.json +453 -91
  2. package/dist/brandsync-wc/brandsync-wc.esm.js +1 -1
  3. package/dist/brandsync-wc/{p-a35d5ea7.entry.js → p-03a8fbbf.entry.js} +1 -1
  4. package/dist/brandsync-wc/{p-41732f18.entry.js → p-0534d0a9.entry.js} +1 -1
  5. package/dist/brandsync-wc/{p-3e6d37a4.entry.js → p-07043faa.entry.js} +1 -1
  6. package/dist/brandsync-wc/{p-b6425ac2.entry.js → p-0c7f993e.entry.js} +1 -1
  7. package/dist/brandsync-wc/{p-c76ca89f.entry.js → p-1030c935.entry.js} +1 -1
  8. package/dist/brandsync-wc/{p-ce08c9d7.entry.js → p-10ad342b.entry.js} +1 -1
  9. package/dist/brandsync-wc/{p-03f9fd54.entry.js → p-113ed9df.entry.js} +1 -1
  10. package/dist/brandsync-wc/{p-f6fafbd6.entry.js → p-117a52dc.entry.js} +1 -1
  11. package/dist/brandsync-wc/{p-17dbd4b3.entry.js → p-17cef278.entry.js} +1 -1
  12. package/dist/brandsync-wc/{p-6970a24c.entry.js → p-1d50cff0.entry.js} +1 -1
  13. package/dist/brandsync-wc/{p-7f14660d.entry.js → p-2eb6db9f.entry.js} +1 -1
  14. package/dist/brandsync-wc/{p-a73bfd31.entry.js → p-3145cc00.entry.js} +1 -1
  15. package/dist/brandsync-wc/{p-1e9ceb9d.entry.js → p-31fe38dd.entry.js} +1 -1
  16. package/dist/brandsync-wc/{p-650b7eef.entry.js → p-3b3ef658.entry.js} +1 -1
  17. package/dist/brandsync-wc/{p-18e0cff4.entry.js → p-3c060d84.entry.js} +1 -1
  18. package/dist/brandsync-wc/{p-7091f130.entry.js → p-3eecd03e.entry.js} +1 -1
  19. package/dist/brandsync-wc/p-4567c1d0.entry.js +1 -0
  20. package/dist/brandsync-wc/{p-ca74c7d9.entry.js → p-4ba7690a.entry.js} +1 -1
  21. package/dist/brandsync-wc/{p-673546bf.entry.js → p-507b5c4b.entry.js} +1 -1
  22. package/dist/brandsync-wc/{p-a597dc2b.entry.js → p-5bf18d08.entry.js} +1 -1
  23. package/dist/brandsync-wc/{p-260e14de.entry.js → p-6b850a6c.entry.js} +1 -1
  24. package/dist/brandsync-wc/{p-ed704126.entry.js → p-6dc7fc4a.entry.js} +1 -1
  25. package/dist/brandsync-wc/{p-04d6aa95.entry.js → p-6fa6a576.entry.js} +1 -1
  26. package/dist/brandsync-wc/{p-0299e8e1.entry.js → p-700fb759.entry.js} +1 -1
  27. package/dist/brandsync-wc/{p-67bc2ec8.entry.js → p-826c08ac.entry.js} +1 -1
  28. package/dist/brandsync-wc/{p-cff188cb.entry.js → p-8dec61f7.entry.js} +1 -1
  29. package/dist/brandsync-wc/p-93984743.entry.js +1 -0
  30. package/dist/brandsync-wc/{p-f94449da.entry.js → p-984e9878.entry.js} +1 -1
  31. package/dist/brandsync-wc/p-9a2f986d.entry.js +1 -0
  32. package/dist/brandsync-wc/{p-aac6b59b.entry.js → p-9bc67188.entry.js} +1 -1
  33. package/dist/brandsync-wc/{p-CvfB8CQv.js → p-CcPfH1dJ.js} +2 -2
  34. package/dist/brandsync-wc/{p-c8480d21.entry.js → p-a6bc823e.entry.js} +1 -1
  35. package/dist/brandsync-wc/p-b1353da8.entry.js +1 -0
  36. package/dist/brandsync-wc/{p-718ce85f.entry.js → p-b176c547.entry.js} +1 -1
  37. package/dist/brandsync-wc/{p-2e7586dd.entry.js → p-b22038b2.entry.js} +1 -1
  38. package/dist/brandsync-wc/p-b5ebbc76.entry.js +1 -0
  39. package/dist/brandsync-wc/{p-fc9d52d4.entry.js → p-b6dba2bf.entry.js} +1 -1
  40. package/dist/brandsync-wc/{p-f652d79c.entry.js → p-ba650ca9.entry.js} +1 -1
  41. package/dist/brandsync-wc/p-baea8952.entry.js +1 -0
  42. package/dist/brandsync-wc/{p-8f2cfe31.entry.js → p-bbd238cd.entry.js} +1 -1
  43. package/dist/brandsync-wc/{p-0921ca0d.entry.js → p-bca1149c.entry.js} +1 -1
  44. package/dist/brandsync-wc/{p-72e02bd5.entry.js → p-c89ab519.entry.js} +1 -1
  45. package/dist/brandsync-wc/{p-2a7cc40c.entry.js → p-c8fabfd0.entry.js} +1 -1
  46. package/dist/brandsync-wc/{p-c7b9a5c7.entry.js → p-d5ea1b72.entry.js} +1 -1
  47. package/dist/brandsync-wc/{p-8b5f4ca7.entry.js → p-d7ce9505.entry.js} +1 -1
  48. package/dist/brandsync-wc/{p-b63362e7.entry.js → p-da6fa359.entry.js} +1 -1
  49. package/dist/brandsync-wc/p-dc974d62.entry.js +1 -0
  50. package/dist/brandsync-wc/p-df0fc514.entry.js +1 -0
  51. package/dist/brandsync-wc/{p-a16afeaa.entry.js → p-e5b1d254.entry.js} +1 -1
  52. package/dist/brandsync-wc/{p-205deb32.entry.js → p-f0df6653.entry.js} +1 -1
  53. package/dist/brandsync-wc/{p-7655e741.entry.js → p-fc52e0df.entry.js} +1 -1
  54. package/dist/cjs/brandsync-wc.cjs.js +2 -2
  55. package/dist/cjs/bs-ai-disclaimer.cjs.entry.js +2 -2
  56. package/dist/cjs/bs-ai-greeting.cjs.entry.js +2 -2
  57. package/dist/cjs/bs-ai-thinking.cjs.entry.js +2 -2
  58. package/dist/cjs/bs-attachment-list.cjs.entry.js +2 -2
  59. package/dist/cjs/bs-attachment.cjs.entry.js +1 -1
  60. package/dist/cjs/bs-avatar.cjs.entry.js +1 -1
  61. package/dist/cjs/bs-badge.cjs.entry.js +1 -1
  62. package/dist/cjs/bs-breadcrumb-overflow.cjs.entry.js +1 -1
  63. package/dist/cjs/bs-breadcrumb.cjs.entry.js +1 -1
  64. package/dist/cjs/bs-breadcrumbs.cjs.entry.js +2 -2
  65. package/dist/cjs/bs-button-skeleton.cjs.entry.js +2 -2
  66. package/dist/cjs/bs-button.cjs.entry.js +2 -2
  67. package/dist/cjs/bs-card.cjs.entry.js +1 -1
  68. package/dist/cjs/bs-chatbot-feedback.cjs.entry.js +2 -2
  69. package/dist/cjs/bs-chatbot-header.cjs.entry.js +2 -2
  70. package/dist/cjs/bs-chatbot-response-action.cjs.entry.js +2 -2
  71. package/dist/cjs/bs-chatbot-sources-drawer.cjs.entry.js +2 -2
  72. package/dist/cjs/bs-chatbot-suggestion-button.cjs.entry.js +2 -2
  73. package/dist/cjs/bs-checkbox-skeleton.cjs.entry.js +2 -2
  74. package/dist/cjs/bs-checkbox.cjs.entry.js +1 -1
  75. package/dist/cjs/bs-chip-filter.cjs.entry.js +10 -6
  76. package/dist/cjs/bs-chip-informative.cjs.entry.js +1 -1
  77. package/dist/cjs/bs-chip-input.cjs.entry.js +1 -1
  78. package/dist/cjs/bs-composer-status-banner.cjs.entry.js +1 -1
  79. package/dist/cjs/bs-composer.cjs.entry.js +26 -3
  80. package/dist/cjs/bs-data-table.cjs.entry.js +21 -4
  81. package/dist/cjs/bs-dialog.cjs.entry.js +1 -1
  82. package/dist/cjs/bs-icon-button.cjs.entry.js +3 -3
  83. package/dist/cjs/bs-inline-tab.cjs.entry.js +2 -2
  84. package/dist/cjs/bs-input.cjs.entry.js +3 -3
  85. package/dist/cjs/bs-logo.cjs.entry.js +1 -1
  86. package/dist/cjs/bs-menu-item.cjs.entry.js +2 -2
  87. package/dist/cjs/bs-menu.cjs.entry.js +2 -2
  88. package/dist/cjs/bs-navigation-drawer-item.cjs.entry.js +2 -2
  89. package/dist/cjs/bs-navigation-drawer.cjs.entry.js +3 -3
  90. package/dist/cjs/bs-navigation-header.cjs.entry.js +3 -3
  91. package/dist/cjs/bs-pagination.cjs.entry.js +2 -2
  92. package/dist/cjs/bs-progress-linear.cjs.entry.js +65 -0
  93. package/dist/cjs/bs-progress.cjs.entry.js +69 -0
  94. package/dist/cjs/bs-radio.cjs.entry.js +2 -2
  95. package/dist/cjs/bs-slider.cjs.entry.js +2 -2
  96. package/dist/cjs/bs-snackbar.cjs.entry.js +13 -3
  97. package/dist/cjs/bs-source-link.cjs.entry.js +3 -3
  98. package/dist/cjs/bs-stepper-step.cjs.entry.js +2 -2
  99. package/dist/cjs/bs-stepper.cjs.entry.js +2 -2
  100. package/dist/cjs/bs-switch.cjs.entry.js +2 -2
  101. package/dist/cjs/bs-tab.cjs.entry.js +2 -2
  102. package/dist/cjs/bs-tabs.cjs.entry.js +2 -2
  103. package/dist/cjs/bs-toast.cjs.entry.js +2 -2
  104. package/dist/cjs/bs-tooltip.cjs.entry.js +2 -2
  105. package/dist/cjs/{index-CdAh5BFg.js → index-Bj1mNOtg.js} +17 -0
  106. package/dist/cjs/loader.cjs.js +2 -2
  107. package/dist/collection/collection-manifest.json +2 -0
  108. package/dist/collection/components/bs-ai-disclaimer/bs-ai-disclaimer.js +1 -1
  109. package/dist/collection/components/bs-ai-greeting/bs-ai-greeting.js +1 -1
  110. package/dist/collection/components/bs-ai-thinking/bs-ai-thinking.js +1 -1
  111. package/dist/collection/components/bs-attachment-list/bs-attachment-list.js +1 -1
  112. package/dist/collection/components/bs-breadcrumb/bs-breadcrumbs/bs-breadcrumbs.js +1 -1
  113. package/dist/collection/components/bs-button/bs-button/bs-button.css +15 -5
  114. package/dist/collection/components/bs-button/bs-icon-button/bs-icon-button.css +15 -7
  115. package/dist/collection/components/bs-button/bs-icon-button/bs-icon-button.js +1 -1
  116. package/dist/collection/components/bs-button-skeleton/bs-button-skeleton.js +1 -1
  117. package/dist/collection/components/bs-chatbot-feedback/bs-chatbot-feedback.js +1 -1
  118. package/dist/collection/components/bs-chatbot-header/bs-chatbot-header.js +1 -1
  119. package/dist/collection/components/bs-chatbot-response-action/bs-chatbot-response-action.js +1 -1
  120. package/dist/collection/components/bs-chatbot-sources-drawer/bs-chatbot-sources-drawer.js +1 -1
  121. package/dist/collection/components/bs-chatbot-suggestion-button/bs-chatbot-suggestion-button.js +1 -1
  122. package/dist/collection/components/bs-checkbox/bs-checkbox-skeleton/bs-checkbox-skeleton.js +1 -1
  123. package/dist/collection/components/bs-chip/bs-chip-filter/bs-chip-filter.cmp.test.js +19 -5
  124. package/dist/collection/components/bs-chip/bs-chip-filter/bs-chip-filter.js +11 -7
  125. package/dist/collection/components/bs-composer/bs-composer.cmp.test.js +44 -0
  126. package/dist/collection/components/bs-composer/bs-composer.js +29 -6
  127. package/dist/collection/components/bs-data-table/bs-data-table.cmp.test.js +108 -0
  128. package/dist/collection/components/bs-data-table/bs-data-table.css +5 -3
  129. package/dist/collection/components/bs-data-table/bs-data-table.js +40 -2
  130. package/dist/collection/components/bs-input/bs-input.js +2 -2
  131. package/dist/collection/components/bs-menu/bs-menu.js +1 -1
  132. package/dist/collection/components/bs-menu-item/bs-menu-item.js +1 -1
  133. package/dist/collection/components/bs-pagination/bs-pagination.js +1 -1
  134. package/dist/collection/components/bs-progress/bs-progress.cmp.test.js +96 -0
  135. package/dist/collection/components/bs-progress/bs-progress.css +119 -0
  136. package/dist/collection/components/bs-progress/bs-progress.js +212 -0
  137. package/dist/collection/components/bs-progress/bs-progress.stories.js +72 -0
  138. package/dist/collection/components/bs-progress-linear/bs-progress-linear.cmp.test.js +92 -0
  139. package/dist/collection/components/bs-progress-linear/bs-progress-linear.css +108 -0
  140. package/dist/collection/components/bs-progress-linear/bs-progress-linear.js +192 -0
  141. package/dist/collection/components/bs-progress-linear/bs-progress-linear.stories.js +66 -0
  142. package/dist/collection/components/bs-radio/bs-radio.js +1 -1
  143. package/dist/collection/components/bs-slider/bs-slider.js +1 -1
  144. package/dist/collection/components/bs-snackbar/bs-snackbar.cmp.test.js +4 -1
  145. package/dist/collection/components/bs-snackbar/bs-snackbar.css +8 -155
  146. package/dist/collection/components/bs-snackbar/bs-snackbar.js +11 -1
  147. package/dist/collection/components/bs-source-link/bs-source-link.js +2 -2
  148. package/dist/collection/components/bs-stepper/bs-stepper/bs-stepper.js +1 -1
  149. package/dist/collection/components/bs-stepper/bs-stepper-step/bs-stepper-step.js +1 -1
  150. package/dist/collection/components/bs-switch/bs-switch.js +1 -1
  151. package/dist/collection/components/bs-tab/bs-inline-tab/bs-inline-tab.js +1 -1
  152. package/dist/collection/components/bs-tab/bs-tab/bs-tab.js +1 -1
  153. package/dist/collection/components/bs-tab/bs-tabs/bs-tabs.js +1 -1
  154. package/dist/collection/components/bs-toast/bs-toast.js +1 -1
  155. package/dist/collection/components/bs-tooltip/bs-tooltip.js +1 -1
  156. package/dist/collection/components/ui-shell/bs-navigation-drawer/bs-navigation-drawer/bs-navigation-drawer.cmp.test.js +6 -0
  157. package/dist/collection/components/ui-shell/bs-navigation-drawer/bs-navigation-drawer/bs-navigation-drawer.css +43 -1
  158. package/dist/collection/components/ui-shell/bs-navigation-drawer/bs-navigation-drawer/bs-navigation-drawer.js +1 -1
  159. package/dist/collection/components/ui-shell/bs-navigation-drawer/bs-navigation-drawer-item/bs-navigation-drawer-item.js +1 -1
  160. package/dist/collection/components/ui-shell/bs-navigation-header/bs-navigation-header/bs-navigation-header.css +25 -0
  161. package/dist/collection/components/ui-shell/bs-navigation-header/bs-navigation-header/bs-navigation-header.js +1 -1
  162. package/dist/components/bs-ai-disclaimer.js +1 -1
  163. package/dist/components/bs-ai-greeting.js +1 -1
  164. package/dist/components/bs-ai-thinking.js +1 -1
  165. package/dist/components/bs-attachment-list.js +1 -1
  166. package/dist/components/bs-attachment.js +1 -1
  167. package/dist/components/bs-breadcrumb-overflow.js +1 -1
  168. package/dist/components/bs-breadcrumbs.js +1 -1
  169. package/dist/components/bs-button-skeleton.js +1 -1
  170. package/dist/components/bs-button.js +1 -1
  171. package/dist/components/bs-chatbot-feedback.js +1 -1
  172. package/dist/components/bs-chatbot-header.js +1 -1
  173. package/dist/components/bs-chatbot-response-action.js +1 -1
  174. package/dist/components/bs-chatbot-sources-drawer.js +1 -1
  175. package/dist/components/bs-chatbot-suggestion-button.js +1 -1
  176. package/dist/components/bs-checkbox-skeleton.js +1 -1
  177. package/dist/components/bs-chip-filter.js +1 -1
  178. package/dist/components/bs-composer.js +1 -1
  179. package/dist/components/bs-data-table.js +1 -1
  180. package/dist/components/bs-dialog.js +1 -1
  181. package/dist/components/bs-icon-button.js +1 -1
  182. package/dist/components/bs-inline-tab.js +1 -1
  183. package/dist/components/bs-input.js +1 -1
  184. package/dist/components/bs-menu-item.js +1 -1
  185. package/dist/components/bs-menu.js +1 -1
  186. package/dist/components/bs-navigation-drawer-item.js +1 -1
  187. package/dist/components/bs-navigation-drawer.js +1 -1
  188. package/dist/components/bs-navigation-header.js +1 -1
  189. package/dist/components/bs-pagination.js +1 -1
  190. package/dist/components/bs-progress-linear.d.ts +11 -0
  191. package/dist/components/bs-progress-linear.js +1 -0
  192. package/dist/components/bs-progress.d.ts +11 -0
  193. package/dist/components/bs-progress.js +1 -0
  194. package/dist/components/bs-radio.js +1 -1
  195. package/dist/components/bs-slider.js +1 -1
  196. package/dist/components/bs-snackbar.js +1 -1
  197. package/dist/components/bs-source-link.js +1 -1
  198. package/dist/components/bs-stepper-step.js +1 -1
  199. package/dist/components/bs-stepper.js +1 -1
  200. package/dist/components/bs-switch.js +1 -1
  201. package/dist/components/bs-tab.js +1 -1
  202. package/dist/components/bs-tabs.js +1 -1
  203. package/dist/components/bs-toast.js +1 -1
  204. package/dist/components/bs-tooltip.js +1 -1
  205. package/dist/components/p-BQdQhCjF.js +1 -0
  206. package/dist/components/{p-Bg98eW9H.js → p-Bi4KsnwA.js} +1 -1
  207. package/dist/components/p-C5ducC76.js +1 -0
  208. package/dist/components/{p-BlCziuES.js → p-CKXzHFVu.js} +1 -1
  209. package/dist/components/{p-BOP5EJrQ.js → p-CbSuTCj1.js} +1 -1
  210. package/dist/esm/brandsync-wc.js +3 -3
  211. package/dist/esm/bs-ai-disclaimer.entry.js +2 -2
  212. package/dist/esm/bs-ai-greeting.entry.js +2 -2
  213. package/dist/esm/bs-ai-thinking.entry.js +2 -2
  214. package/dist/esm/bs-attachment-list.entry.js +2 -2
  215. package/dist/esm/bs-attachment.entry.js +1 -1
  216. package/dist/esm/bs-avatar.entry.js +1 -1
  217. package/dist/esm/bs-badge.entry.js +1 -1
  218. package/dist/esm/bs-breadcrumb-overflow.entry.js +1 -1
  219. package/dist/esm/bs-breadcrumb.entry.js +1 -1
  220. package/dist/esm/bs-breadcrumbs.entry.js +2 -2
  221. package/dist/esm/bs-button-skeleton.entry.js +2 -2
  222. package/dist/esm/bs-button.entry.js +2 -2
  223. package/dist/esm/bs-card.entry.js +1 -1
  224. package/dist/esm/bs-chatbot-feedback.entry.js +2 -2
  225. package/dist/esm/bs-chatbot-header.entry.js +2 -2
  226. package/dist/esm/bs-chatbot-response-action.entry.js +2 -2
  227. package/dist/esm/bs-chatbot-sources-drawer.entry.js +2 -2
  228. package/dist/esm/bs-chatbot-suggestion-button.entry.js +2 -2
  229. package/dist/esm/bs-checkbox-skeleton.entry.js +2 -2
  230. package/dist/esm/bs-checkbox.entry.js +1 -1
  231. package/dist/esm/bs-chip-filter.entry.js +10 -6
  232. package/dist/esm/bs-chip-informative.entry.js +1 -1
  233. package/dist/esm/bs-chip-input.entry.js +1 -1
  234. package/dist/esm/bs-composer-status-banner.entry.js +1 -1
  235. package/dist/esm/bs-composer.entry.js +26 -3
  236. package/dist/esm/bs-data-table.entry.js +21 -4
  237. package/dist/esm/bs-dialog.entry.js +1 -1
  238. package/dist/esm/bs-icon-button.entry.js +3 -3
  239. package/dist/esm/bs-inline-tab.entry.js +2 -2
  240. package/dist/esm/bs-input.entry.js +3 -3
  241. package/dist/esm/bs-logo.entry.js +1 -1
  242. package/dist/esm/bs-menu-item.entry.js +2 -2
  243. package/dist/esm/bs-menu.entry.js +2 -2
  244. package/dist/esm/bs-navigation-drawer-item.entry.js +2 -2
  245. package/dist/esm/bs-navigation-drawer.entry.js +3 -3
  246. package/dist/esm/bs-navigation-header.entry.js +3 -3
  247. package/dist/esm/bs-pagination.entry.js +2 -2
  248. package/dist/esm/bs-progress-linear.entry.js +63 -0
  249. package/dist/esm/bs-progress.entry.js +67 -0
  250. package/dist/esm/bs-radio.entry.js +2 -2
  251. package/dist/esm/bs-slider.entry.js +2 -2
  252. package/dist/esm/bs-snackbar.entry.js +13 -3
  253. package/dist/esm/bs-source-link.entry.js +3 -3
  254. package/dist/esm/bs-stepper-step.entry.js +2 -2
  255. package/dist/esm/bs-stepper.entry.js +2 -2
  256. package/dist/esm/bs-switch.entry.js +2 -2
  257. package/dist/esm/bs-tab.entry.js +2 -2
  258. package/dist/esm/bs-tabs.entry.js +2 -2
  259. package/dist/esm/bs-toast.entry.js +2 -2
  260. package/dist/esm/bs-tooltip.entry.js +2 -2
  261. package/dist/esm/{index-CvfB8CQv.js → index-CcPfH1dJ.js} +17 -0
  262. package/dist/esm/loader.js +3 -3
  263. package/dist/types/components/bs-chip/bs-chip-filter/bs-chip-filter.d.ts +7 -2
  264. package/dist/types/components/bs-composer/bs-composer.d.ts +15 -1
  265. package/dist/types/components/bs-data-table/bs-data-table.cmp.test.d.ts +1 -0
  266. package/dist/types/components/bs-data-table/bs-data-table.d.ts +5 -0
  267. package/dist/types/components/bs-progress/bs-progress.cmp.test.d.ts +1 -0
  268. package/dist/types/components/bs-progress/bs-progress.d.ts +46 -0
  269. package/dist/types/components/bs-progress/bs-progress.stories.d.ts +18 -0
  270. package/dist/types/components/bs-progress-linear/bs-progress-linear.cmp.test.d.ts +1 -0
  271. package/dist/types/components/bs-progress-linear/bs-progress-linear.d.ts +50 -0
  272. package/dist/types/components/bs-progress-linear/bs-progress-linear.stories.d.ts +17 -0
  273. package/dist/types/components.d.ts +251 -6
  274. package/package.json +1 -1
  275. package/dist/brandsync-wc/p-00d40aca.entry.js +0 -1
  276. package/dist/brandsync-wc/p-127d698d.entry.js +0 -1
  277. package/dist/brandsync-wc/p-1780224d.entry.js +0 -1
  278. package/dist/brandsync-wc/p-35bcb932.entry.js +0 -1
  279. package/dist/brandsync-wc/p-393efb5d.entry.js +0 -1
  280. package/dist/brandsync-wc/p-b2abd8d9.entry.js +0 -1
  281. package/dist/components/p-B8JpGodL.js +0 -1
@@ -46,8 +46,17 @@
46
46
  step family, matching --bs-button-neutral-container (--bs-color-neutral-container) itself. */
47
47
  --bs-button-neutral-hover: var(--bs-color-neutral-container-hover);
48
48
  --bs-button-neutral-pressed: var(--bs-color-neutral-container-pressed);
49
- --bs-button-outlined-border: var(--bs-border-primary);
50
- --bs-button-outlined-border-hover: var(--bs-border-primary-hover);
49
+ /* Verified against Figma node 2842:50233/50230/50227/50224 (Style=Outline, States=Enabled/
50
+ Hovered/Focused/Pressed): border/text colors step through brand-600 -> 700 -> 800 across
51
+ enabled -> hover -> pressed, NOT a single "hover" color reused for both hover and pressed
52
+ (that was this variant's previous bug -- hover and pressed were indistinguishable, and
53
+ neither matched the enabled color Figma actually specifies). Text color matches
54
+ --bs-text-action-hover (brand-700) on BOTH hover and pressed per the spec -- pressed does NOT
55
+ get its own darker text color, only the border does. */
56
+ --bs-button-outlined-border: var(--bs-color-primary-default);
57
+ --bs-button-outlined-border-hover: var(--bs-color-primary-hover);
58
+ --bs-button-outlined-border-pressed: var(--bs-color-primary-pressed);
59
+ --bs-button-outlined-text-hover: var(--bs-text-action-hover);
51
60
  --bs-button-outlined-focus: var(--bs-border-primary-focus);
52
61
  --bs-button-outlined-container: var(--bs-color-primary-container);
53
62
  }
@@ -231,16 +240,17 @@
231
240
  .bs-button--outlined {
232
241
  background: transparent;
233
242
  color: var(--bs-color-primary-default);
234
- border: 1.5px solid var(--bs-button-outlined-border);
243
+ border: 1px solid var(--bs-button-outlined-border);
235
244
  }
236
245
  .bs-button--outlined:hover:not(:disabled) {
237
246
  background: var(--bs-button-outlined-container);
238
247
  border-color: var(--bs-button-outlined-border-hover);
248
+ color: var(--bs-button-outlined-text-hover);
239
249
  }
240
250
  .bs-button--outlined:active:not(:disabled) {
241
251
  background: var(--bs-button-outlined-container);
242
- color: var(--bs-color-primary-pressed);
243
- border-color: var(--bs-button-outlined-border-hover);
252
+ color: var(--bs-button-outlined-text-hover);
253
+ border-color: var(--bs-button-outlined-border-pressed);
244
254
  }
245
255
  .bs-button--outlined:disabled {
246
256
  opacity: var(--bs-opacity-disabled);
@@ -25,8 +25,10 @@
25
25
  * @prop --bs-icon-button-subtle-hover: Background, variant="subtle", hover. Aliased to --bs-color-neutral-container.
26
26
  * @prop --bs-icon-button-subtle-pressed: Background, variant="subtle", pressed. Aliased to --bs-color-neutral-container-pressed.
27
27
  * @prop --bs-icon-button-subtle-focus: Focus ring color, variant="subtle". Aliased to --bs-border-primary-focus.
28
- * @prop --bs-icon-button-outlined-border: Border color, variant="outlined", default. Aliased to --bs-border-primary.
29
- * @prop --bs-icon-button-outlined-border-hover: Border color, variant="outlined", hover/pressed. Aliased to --bs-border-primary-hover.
28
+ * @prop --bs-icon-button-outlined-border: Border color, variant="outlined", default. Aliased to --bs-color-primary-default.
29
+ * @prop --bs-icon-button-outlined-border-hover: Border color, variant="outlined", hover. Aliased to --bs-color-primary-hover.
30
+ * @prop --bs-icon-button-outlined-border-pressed: Border color, variant="outlined", pressed. Aliased to --bs-color-primary-pressed.
31
+ * @prop --bs-icon-button-outlined-text-hover: Icon color, variant="outlined", hover/pressed. Aliased to --bs-text-action-hover.
30
32
  * @prop --bs-icon-button-outlined-container: Background, variant="outlined", hover/pressed. Aliased to --bs-color-primary-container.
31
33
  * @prop --bs-icon-button-outlined-focus: Focus ring color, variant="outlined". Aliased to --bs-border-primary-focus.
32
34
  * @prop --bs-icon-button-success-default: Background, variant="success", default. Aliased to --bs-color-success-default.
@@ -94,8 +96,13 @@
94
96
  --bs-icon-button-subtle-pressed: var(--bs-color-neutral-container-pressed);
95
97
  --bs-icon-button-subtle-focus: var(--bs-border-primary-focus);
96
98
 
97
- --bs-icon-button-outlined-border: var(--bs-border-primary);
98
- --bs-icon-button-outlined-border-hover: var(--bs-border-primary-hover);
99
+ /* Verified against Figma node 2842:50233/50230/50227/50224 (bs-button's Style=Outline states) --
100
+ border/text colors step through brand-600 -> 700 -> 800 across enabled -> hover -> pressed,
101
+ matching the fix applied to bs-button's own outlined variant. */
102
+ --bs-icon-button-outlined-border: var(--bs-color-primary-default);
103
+ --bs-icon-button-outlined-border-hover: var(--bs-color-primary-hover);
104
+ --bs-icon-button-outlined-border-pressed: var(--bs-color-primary-pressed);
105
+ --bs-icon-button-outlined-text-hover: var(--bs-text-action-hover);
99
106
  --bs-icon-button-outlined-container: var(--bs-color-primary-container);
100
107
  --bs-icon-button-outlined-focus: var(--bs-border-primary-focus);
101
108
 
@@ -326,16 +333,17 @@
326
333
  .bs-icon-button--outlined {
327
334
  background: transparent;
328
335
  color: var(--bs-color-primary-default);
329
- border: 1.5px solid var(--bs-icon-button-outlined-border);
336
+ border: 1px solid var(--bs-icon-button-outlined-border);
330
337
  }
331
338
  .bs-icon-button--outlined:hover:not(:disabled) {
332
339
  background: var(--bs-icon-button-outlined-container);
333
340
  border-color: var(--bs-icon-button-outlined-border-hover);
341
+ color: var(--bs-icon-button-outlined-text-hover);
334
342
  }
335
343
  .bs-icon-button--outlined:active:not(:disabled) {
336
344
  background: var(--bs-icon-button-outlined-container);
337
- color: var(--bs-color-primary-pressed);
338
- border-color: var(--bs-icon-button-outlined-border-hover);
345
+ color: var(--bs-icon-button-outlined-text-hover);
346
+ border-color: var(--bs-icon-button-outlined-border-pressed);
339
347
  }
340
348
  .bs-icon-button--outlined:disabled {
341
349
  opacity: var(--bs-opacity-disabled);
@@ -50,7 +50,7 @@ export class BsIconButton {
50
50
  */
51
51
  ariaLabel = null;
52
52
  render() {
53
- return (h("button", { key: '59709048e7339610a80a8c19ee55276d420a21db', class: `bs-icon-button bs-icon-button--${this.variant} bs-icon-button--${this.size}`, type: this.type, disabled: this.disabled, "aria-label": this.ariaLabel }, h("span", { key: '008f553d50091ba49f568d82de27a35871b9a66d', part: "icon", class: "bs-icon-button__icon" }, h("slot", { key: '5365a00665a7de5a64af0793862552a1057ac110' }))));
53
+ return (h("button", { key: '7332506653b523ec486608f744ae3d380c5189cb', class: `bs-icon-button bs-icon-button--${this.variant} bs-icon-button--${this.size}`, type: this.type, disabled: this.disabled, "aria-label": this.ariaLabel }, h("span", { key: 'd72b8d4db55a417473d894736adbae530ca65379', part: "icon", class: "bs-icon-button__icon" }, h("slot", { key: 'c218c13307f99d58274e4f377ad42fd925e25fc5' }))));
54
54
  }
55
55
  static get is() { return "bs-icon-button"; }
56
56
  static get encapsulation() { return "shadow"; }
@@ -25,7 +25,7 @@ export class BsButtonSkeleton {
25
25
  /** Sizing scale, matching the `bs-button` size it stands in for. */
26
26
  size = 'md';
27
27
  render() {
28
- return h("span", { key: '5f8f84b3b82e4c88a2308a9d9cfd0d8dfb50e876', part: "container", class: `bs-button-skeleton bs-button-skeleton--${this.size}`, role: "status", "aria-label": "Loading" });
28
+ return h("span", { key: '43450691678faace72f13fcec1358a8c0624e244', part: "container", class: `bs-button-skeleton bs-button-skeleton--${this.size}`, role: "status", "aria-label": "Loading" });
29
29
  }
30
30
  static get is() { return "bs-button-skeleton"; }
31
31
  static get encapsulation() { return "shadow"; }
@@ -123,7 +123,7 @@ export class BsChatbotFeedback {
123
123
  }
124
124
  render() {
125
125
  const stars = [1, 2, 3, 4, 5];
126
- return (h("div", { key: 'e2c53e479c52e5a7e21dd6b010863cfed34f523b', class: "bs-chatbot-feedback", role: "region", "aria-label": this.computedHeading() }, h("button", { key: '7ea071eb0f77718b1f41c2c40181c61e5114f339', type: "button", part: "close", class: "bs-chatbot-feedback__close", "aria-label": "Close", onClick: this.onCloseClick }, h(CloseIcon, { key: '39d490c84008bc1a949a497c6606ce3789c39701' })), h("div", { key: '0030328128dad8a52a5f9c8393d82c6522bc5543', class: "bs-chatbot-feedback__top" }, h("div", { key: '8e53604efefeb014a947ac6559574df74ce21293', class: "bs-chatbot-feedback__text" }, h("p", { key: '6a69d8d8d66802db883d6ca7c6a7c218cca9baa8', part: "heading", class: "bs-chatbot-feedback__heading" }, this.computedHeading()), h("p", { key: '6facf10badd690adeaf33058af4e2e5104ba92c8', part: "subtitle", class: "bs-chatbot-feedback__subtitle" }, this.computedSubtitle())), h("div", { key: 'c933517d5e5bafcdeae73d3a6b85e1bcee6955b2', class: "bs-chatbot-feedback__stars", role: "radiogroup", "aria-label": "Rating" }, stars.map(value => (h("button", { type: "button", part: "star", class: "bs-chatbot-feedback__star", role: "radio", "aria-checked": (this.rating >= value).toString(), "aria-label": `${value} star${value > 1 ? 's' : ''}`, disabled: this.submitted, onClick: () => this.onStarClick(value) }, h(StarIcon, { filled: this.rating >= value }))))), !this.submitted && (h("div", { key: '09872bfeb1d6df31149ead5c14befa27ed8a94cf', class: "bs-chatbot-feedback__field" }, h("label", { key: '5e45545e6c36ffeda32438689d43fd4f4cd57754', part: "label", class: "bs-chatbot-feedback__label", htmlFor: "bs-chatbot-feedback-comment" }, "Tell us what you think"), h("textarea", { key: 'db1eb08051b7d12c2397d91308a1ddc96a335686', part: "textarea", id: "bs-chatbot-feedback-comment", class: "bs-chatbot-feedback__textarea", placeholder: "e.g.The response was helpful ....", value: this.comment, onInput: this.onCommentInput }))), this.submitted && this.comment && (h("p", { key: '888f86568ba57fb93771150ff59952923af0ae4c', part: "comment", class: "bs-chatbot-feedback__comment" }, this.comment))), h("div", { key: '7027d27f3c5dcbac0fe97ad130c9e4bf424a9103', class: "bs-chatbot-feedback__actions" }, !this.submitted && (h("button", { key: 'c410bbe6a1dd85d9c03f689ac8921d90f5bd63e2', type: "button", part: "submit", class: "bs-chatbot-feedback__submit", disabled: this.rating === 0, onClick: this.onSubmitClick }, h(SendIcon, { key: '9a098a14cf2e04c73e02c4ef0f75da4e23529da4' }), "Submit feedback")), h("button", { key: '810c89a2b8b4b5b9c14aa5368ed2365c98b839a7', type: "button", part: "new-chat", class: `bs-chatbot-feedback__new-chat ${this.submitted ? 'bs-chatbot-feedback__new-chat--primary' : 'bs-chatbot-feedback__new-chat--outlined'}`, onClick: this.onNewChatClick }, h(EditIcon, { key: '7c86efd66631a8a0fdd7acc5c754dddd0f42aab8' }), "Start new chat"))));
126
+ return (h("div", { key: '7ce663d126eb30ed222c4744a04c8208504941b0', class: "bs-chatbot-feedback", role: "region", "aria-label": this.computedHeading() }, h("button", { key: 'f833bae45d9975adc2ada76bb2e9cea91dd02f67', type: "button", part: "close", class: "bs-chatbot-feedback__close", "aria-label": "Close", onClick: this.onCloseClick }, h(CloseIcon, { key: '570de12483be26f879049afddfa3f6f1797d097e' })), h("div", { key: '37d9790f2115b75a76aeb2bab12550dd1603c46f', class: "bs-chatbot-feedback__top" }, h("div", { key: '82f10bb7865e0bf0f265a944163df0d628abedbd', class: "bs-chatbot-feedback__text" }, h("p", { key: '76c633c71ddcc70d53a61b374b727afe050f6343', part: "heading", class: "bs-chatbot-feedback__heading" }, this.computedHeading()), h("p", { key: 'e6ea88567a8a25c47ffe2d64f23bd269101d4bea', part: "subtitle", class: "bs-chatbot-feedback__subtitle" }, this.computedSubtitle())), h("div", { key: 'd0d0cb36a349789af68449a2d70edce71a4496f6', class: "bs-chatbot-feedback__stars", role: "radiogroup", "aria-label": "Rating" }, stars.map(value => (h("button", { type: "button", part: "star", class: "bs-chatbot-feedback__star", role: "radio", "aria-checked": (this.rating >= value).toString(), "aria-label": `${value} star${value > 1 ? 's' : ''}`, disabled: this.submitted, onClick: () => this.onStarClick(value) }, h(StarIcon, { filled: this.rating >= value }))))), !this.submitted && (h("div", { key: '253f16ef5004d442cffa57e6804b32c388b3eecd', class: "bs-chatbot-feedback__field" }, h("label", { key: 'c857ccda541ac1cced46c072e89b855b228e85c1', part: "label", class: "bs-chatbot-feedback__label", htmlFor: "bs-chatbot-feedback-comment" }, "Tell us what you think"), h("textarea", { key: '1ec486839761292cda2e33b05ebd7e0d9b9d95aa', part: "textarea", id: "bs-chatbot-feedback-comment", class: "bs-chatbot-feedback__textarea", placeholder: "e.g.The response was helpful ....", value: this.comment, onInput: this.onCommentInput }))), this.submitted && this.comment && (h("p", { key: '4dc40cba99967af8f53f6ecaee6777523f9b48e0', part: "comment", class: "bs-chatbot-feedback__comment" }, this.comment))), h("div", { key: '0cfebfb6fa405cf19b9aceb3d0b37555cd95337d', class: "bs-chatbot-feedback__actions" }, !this.submitted && (h("button", { key: '6e81b8cb974427c5aef7b8a6cf53505dd85f830e', type: "button", part: "submit", class: "bs-chatbot-feedback__submit", disabled: this.rating === 0, onClick: this.onSubmitClick }, h(SendIcon, { key: '72b795b62594d42effa31e2b6b7ab1ea0539ca5d' }), "Submit feedback")), h("button", { key: '573bc780413b93864c8e67d76b6b08428aeb0fe3', type: "button", part: "new-chat", class: `bs-chatbot-feedback__new-chat ${this.submitted ? 'bs-chatbot-feedback__new-chat--primary' : 'bs-chatbot-feedback__new-chat--outlined'}`, onClick: this.onNewChatClick }, h(EditIcon, { key: '87fcee4e778b90b5c8b6c2a2c192bfc7dc6368b2' }), "Start new chat"))));
127
127
  }
128
128
  static get is() { return "bs-chatbot-feedback"; }
129
129
  static get encapsulation() { return "shadow"; }
@@ -74,7 +74,7 @@ export class BsChatbotHeader {
74
74
  this.bsClose.emit();
75
75
  };
76
76
  render() {
77
- return (h("div", { key: '5dfec82f3287604e96f4cedf88572c4e125c6a25', class: "bs-chatbot-header", role: "banner", "aria-label": this.heading }, h("div", { key: '0b6150aed7641ad4784f6da5c88310ebb4b697fb', part: "logo", class: "bs-chatbot-header__logo", role: "img", "aria-label": this.heading, innerHTML: GENIE_LOGO_SVG }), h("div", { key: '32f82e9f0a7caac8005270b8e7fddb51958db6ef', class: "bs-chatbot-header__actions" }, h("span", { key: '850e437877cc7a38d94fe915cdb36508823d6bb5', class: "bs-chatbot-header__tooltip-wrapper" }, h("button", { key: 'cc223071ce84b4279d383e9ed489af4cd29c5400', type: "button", part: "new-chat", class: "bs-chatbot-header__button", "aria-label": "New chat", onClick: this.onNewChatClick }, h("slot", { key: 'c1cf2e98f1fe70050c1cdc86626d818954987fd3', name: "new-chat-icon" }, h(NewChatIcon, { key: '3195d3c48fadb448eeed765bfc4634afa7259e58' }))), h("bs-tooltip", { key: 'e60f561f7837a4c2c6e3c660a0b42fbf760a9b45', class: "bs-chatbot-header__tooltip", placement: "top", "aria-hidden": "true" }, "New chat")), h("span", { key: 'b1892cec33d77a20f18b2f4d24a43bfa8960bccc', class: "bs-chatbot-header__tooltip-wrapper" }, h("button", { key: '8391cd76856dd02a27097f37ffc4988f7f22e0e9', type: "button", part: "history", class: "bs-chatbot-header__button", "aria-label": "History", onClick: this.onHistoryClick }, h("slot", { key: 'bdfa76904127ed12872b32b306de25f07e24b143', name: "history-icon" }, h(HistoryIcon, { key: '03a0274814c4ab48cfc1079ab7a68d23cc14cc2b' }))), h("bs-tooltip", { key: 'c24f6a546611a2d5eff5f1b8d6db36696f3247c6', class: "bs-chatbot-header__tooltip", placement: "top", "aria-hidden": "true" }, "History")), h("span", { key: '735bf2953d83ab2f64fc6d5f7a2b0e0fc615c1a3', class: "bs-chatbot-header__tooltip-wrapper" }, h("button", { key: '93ebb0b2211c9dab1caccc34d3d22630b77bbb35', type: "button", part: "expand", class: "bs-chatbot-header__button", "aria-label": this.expanded ? 'Collapse' : 'Expand', "aria-pressed": this.expanded ? 'true' : 'false', onClick: this.onExpandClick }, h("slot", { key: 'f33c3762fe0cb122a12fbdc6e82f2e6aa2b8dfd5', name: "expand-icon" }, h(ExpandIcon, { key: '29b06bcab56fc11322fa142a826f75740a737213' }))), h("bs-tooltip", { key: '771b316816cdab7f119f4e1c5bc86f3a7e3a5714', class: "bs-chatbot-header__tooltip", placement: "top", "aria-hidden": "true" }, this.expanded ? 'Collapse' : 'Expand')), h("span", { key: '7d2c13b669e54e81a5be120ed9f083742e507645', class: "bs-chatbot-header__tooltip-wrapper" }, h("button", { key: '37a176ca2b413927ceb89bb35c386d05ad3368e9', type: "button", part: "close", class: "bs-chatbot-header__button", "aria-label": "Close", onClick: this.onCloseClick }, h("slot", { key: 'ce00fb1c1e30e125fcbe50c7e936d929847aa176', name: "close-icon" }, h(CloseIcon, { key: '78cbf21b668cc7db478cb6a84383a734c00d790b' }))), h("bs-tooltip", { key: '298dceb184e4581c3b46da8197b59e84074e1dc8', class: "bs-chatbot-header__tooltip", placement: "top", "aria-hidden": "true" }, "Close")))));
77
+ return (h("div", { key: 'eb1869272c6e4e3f769a7db50aeab3bc6430c568', class: "bs-chatbot-header", role: "banner", "aria-label": this.heading }, h("div", { key: '885c7dd1281d942ecbedc19bd206d71bf4f318dc', part: "logo", class: "bs-chatbot-header__logo", role: "img", "aria-label": this.heading, innerHTML: GENIE_LOGO_SVG }), h("div", { key: '230753627632b68cd80cce5787d1dd727e6f983c', class: "bs-chatbot-header__actions" }, h("span", { key: '278c6c23496c57f485b4c2f20e311f47dd59d5b9', class: "bs-chatbot-header__tooltip-wrapper" }, h("button", { key: '161519508618cee3cc7de4193eed51f79a1e3d04', type: "button", part: "new-chat", class: "bs-chatbot-header__button", "aria-label": "New chat", onClick: this.onNewChatClick }, h("slot", { key: 'a914bb9346fcc941041d1ffddb2e5d6ae2ef8c87', name: "new-chat-icon" }, h(NewChatIcon, { key: 'c510836b89605d8ffce85e9908393688e42c274c' }))), h("bs-tooltip", { key: 'a852098d08983550e88a45c105f520a3a13df931', class: "bs-chatbot-header__tooltip", placement: "top", "aria-hidden": "true" }, "New chat")), h("span", { key: 'b3f6f0a9d9b136feeef1c248b768d67583773a34', class: "bs-chatbot-header__tooltip-wrapper" }, h("button", { key: '657c4449342ee03f8b3945dc156e2cd9e87c3e2c', type: "button", part: "history", class: "bs-chatbot-header__button", "aria-label": "History", onClick: this.onHistoryClick }, h("slot", { key: '2166286312406c8027b2929ce182e138ff5c9a69', name: "history-icon" }, h(HistoryIcon, { key: '986f5ad358889fca9a1eb3707d64552fabd43d73' }))), h("bs-tooltip", { key: 'cf47b5e52c844342283ec353e68ae44c849c4700', class: "bs-chatbot-header__tooltip", placement: "top", "aria-hidden": "true" }, "History")), h("span", { key: 'c53649c46dfbdb7131ffad4851347b74e36930b1', class: "bs-chatbot-header__tooltip-wrapper" }, h("button", { key: 'f9ea9ce41ed06d72bce86f9304d21e5617a6b74f', type: "button", part: "expand", class: "bs-chatbot-header__button", "aria-label": this.expanded ? 'Collapse' : 'Expand', "aria-pressed": this.expanded ? 'true' : 'false', onClick: this.onExpandClick }, h("slot", { key: 'b322d0d7ceab41872f4d8e8cc25c5b0bb0f80ef6', name: "expand-icon" }, h(ExpandIcon, { key: '82b5f89e9fe0860abe36b7fff55c1d033f7347fa' }))), h("bs-tooltip", { key: 'f4ba617724037b2bc038c66c474f436e49566987', class: "bs-chatbot-header__tooltip", placement: "top", "aria-hidden": "true" }, this.expanded ? 'Collapse' : 'Expand')), h("span", { key: '358776a595674bcb628d81969be1f04775514367', class: "bs-chatbot-header__tooltip-wrapper" }, h("button", { key: 'a22a03e497f6d254f37f666c09c46a32b52f9fea', type: "button", part: "close", class: "bs-chatbot-header__button", "aria-label": "Close", onClick: this.onCloseClick }, h("slot", { key: '02a6d784ff8b2f63c8b71912d62ad250a2fa3738', name: "close-icon" }, h(CloseIcon, { key: '716bddeb32669154197a59401e72c34c6e94f14e' }))), h("bs-tooltip", { key: '6649d7ab7192ac1e11995e90402b5936c1c6e638', class: "bs-chatbot-header__tooltip", placement: "top", "aria-hidden": "true" }, "Close")))));
78
78
  }
79
79
  static get is() { return "bs-chatbot-header"; }
80
80
  static get encapsulation() { return "shadow"; }
@@ -105,7 +105,7 @@ export class BsChatbotResponseAction {
105
105
  };
106
106
  render() {
107
107
  const hasSources = !!this.sourcesCount && this.sourcesCount > 0;
108
- return (h("div", { key: 'c15cc3a766e35be488da4b12bf723f03319eae99', class: "bs-chatbot-response-action" }, h("button", { key: 'bbe4c344d999149241bf01b59312e0067f4c506b', type: "button", part: "like", class: "bs-chatbot-response-action__button", "aria-label": "Like", onClick: this.onLikeClick }, h("slot", { key: '71305d3ca5a846f04e14d347a2a20df223476e72', name: "like-icon" }, h(ThumbsUpIcon, { key: '27bab65b5dcc421c073e5c6059ee93dcb9f240e5' }))), h("button", { key: '49fb53820c2897ea08ca02323d15c51eb01e8ee7', type: "button", part: "dislike", class: "bs-chatbot-response-action__button", "aria-label": "Dislike", onClick: this.onDislikeClick }, h("slot", { key: 'daefb77861d29f33489bde4d421586dc11cca122', name: "dislike-icon" }, h(ThumbsDownIcon, { key: '438a1002406f1a6275eb3b25dacb70aa102666b2' }))), h("button", { key: 'decf278674a50c0ff2916f7d6ee453789bd0446e', type: "button", part: "copy", class: "bs-chatbot-response-action__button", "aria-label": "Copy", onClick: this.onCopyClick }, h("slot", { key: '062eaa99d2f41f0f989939bc89266de8e54ed42d', name: "copy-icon" }, h(CopyIcon, { key: '98594b5cfba143d72d872c7a7a0e19c0d56085a4' }))), h("button", { key: '7b84279224fc9aa5ccb33b8254a777b934ebae06', type: "button", part: "regenerate", class: "bs-chatbot-response-action__button", "aria-label": "Regenerate", onClick: this.onRegenerateClick }, h("slot", { key: 'dd903ba58db6e7d15e5805c4a1d2e71d1ace2b9d', name: "regenerate-icon" }, h(RegenerateIcon, { key: 'e992a8c626bf5e47af8c8e5f6c815aa7f1400b11' }))), h("div", { key: 'd0f17f4dd1f0180a48fda6b58bd3f0c1f882ffd7', class: "bs-chatbot-response-action__menu-wrapper" }, h("button", { key: 'e0053f4919e3225d8718384d993272287f2b4127', type: "button", part: "menu", class: "bs-chatbot-response-action__button", "aria-label": "More options", "aria-haspopup": "menu", "aria-expanded": this.menuOpen ? 'true' : 'false', onClick: this.onMenuClick }, h("slot", { key: '2dd181588120f6fb53444687a802ab348e98ca10', name: "menu-icon" }, h(MenuIcon, { key: 'b283baf6f54bce2d521c7b557ebf72f69c91e3fe' }))), this.menuOpen && (h("div", { key: '751a5ccbc9ea79b4b350cb2406132751334260a9', class: "bs-chatbot-response-action__menu-popup" }, h("slot", { key: '2af8bdb559468514e300e3aa840f2021384de021', name: "menu" })))), hasSources && (h("button", { key: 'ca88da48fc486e77f9727aaa2f94df629dd97bb6', type: "button", part: "sources", class: "bs-chatbot-response-action__sources", onClick: this.onSourcesClick }, h("slot", { key: 'db1b6edddaa0e8ee12a71a08bea5b16701820947', name: "sources-icon" }, h(SourcesIcon, { key: 'ae3a163e2f280985baba92b9d4efc28129acf0e5' })), h("span", { key: '1b389177029e2f090e6aa78b5d8128b8dc7f2d3e', class: "bs-chatbot-response-action__sources-label" }, this.sourcesCount, " ", this.sourcesCount === 1 ? 'source' : 'sources')))));
108
+ return (h("div", { key: '532e40c28571d004133c3209dc4495b5861e0a1c', class: "bs-chatbot-response-action" }, h("button", { key: '94751f1e91f6dd502763aa8fa347a2a96680e691', type: "button", part: "like", class: "bs-chatbot-response-action__button", "aria-label": "Like", onClick: this.onLikeClick }, h("slot", { key: 'ebeae804bd521958538fe539304489721c326ac0', name: "like-icon" }, h(ThumbsUpIcon, { key: 'ebf5446f16a8bd8836ff81a56a71b7f8b01f86b8' }))), h("button", { key: 'f55439692b799199a3b93b98d10b6ab8338eae2b', type: "button", part: "dislike", class: "bs-chatbot-response-action__button", "aria-label": "Dislike", onClick: this.onDislikeClick }, h("slot", { key: '5c836e450855155c7a0ef48086ad5328972686a3', name: "dislike-icon" }, h(ThumbsDownIcon, { key: '452664dbcbb54a5ef07355a5c31b56c10d7b7a92' }))), h("button", { key: 'f97c483dbd6cc1a9892e4df8fd350c0b245643ac', type: "button", part: "copy", class: "bs-chatbot-response-action__button", "aria-label": "Copy", onClick: this.onCopyClick }, h("slot", { key: 'f7d8b19c0c4f962dc344e069bc1d2d1ff8dd8d3f', name: "copy-icon" }, h(CopyIcon, { key: 'ad7a2d9f1e6821e0b3c73b6be8566804d50a6f14' }))), h("button", { key: '7e56271188b55e1943d2150dc36a6ad1951ec784', type: "button", part: "regenerate", class: "bs-chatbot-response-action__button", "aria-label": "Regenerate", onClick: this.onRegenerateClick }, h("slot", { key: '1a800da6dc0d1ba570b82c4c1b973bbb5033f8ea', name: "regenerate-icon" }, h(RegenerateIcon, { key: '752607bbf68aa8427d141035a1aa3f463f60a3ae' }))), h("div", { key: 'a4a51c3a1b22cfada07978a9a6f5a536af54d220', class: "bs-chatbot-response-action__menu-wrapper" }, h("button", { key: 'c96c865aea4773efbf441992a1a3d1218c1efe28', type: "button", part: "menu", class: "bs-chatbot-response-action__button", "aria-label": "More options", "aria-haspopup": "menu", "aria-expanded": this.menuOpen ? 'true' : 'false', onClick: this.onMenuClick }, h("slot", { key: '5aa856322bdb5295e8d52c03931fcf734bb4606c', name: "menu-icon" }, h(MenuIcon, { key: '3fded797bdc3c19e3353b1703e8e20b59d2833d3' }))), this.menuOpen && (h("div", { key: 'a9848b1d6c93b11b28fd782ba53c270b47b515da', class: "bs-chatbot-response-action__menu-popup" }, h("slot", { key: 'a3ff06257fcb00941a0b7abffba29c63403519bb', name: "menu" })))), hasSources && (h("button", { key: '3862519b2af2ada55c51f683c8ef6fa7161b9879', type: "button", part: "sources", class: "bs-chatbot-response-action__sources", onClick: this.onSourcesClick }, h("slot", { key: '33521c0bf865f639973809f46afaf5e50f257f6b', name: "sources-icon" }, h(SourcesIcon, { key: '8995e91b856bb62c66226025afc660bde1698148' })), h("span", { key: '04220d48facffd829612c83ebd4c75717e25056f', class: "bs-chatbot-response-action__sources-label" }, this.sourcesCount, " ", this.sourcesCount === 1 ? 'source' : 'sources')))));
109
109
  }
110
110
  static get is() { return "bs-chatbot-response-action"; }
111
111
  static get encapsulation() { return "shadow"; }
@@ -57,7 +57,7 @@ export class BsChatbotSourcesDrawer {
57
57
  };
58
58
  render() {
59
59
  const displayCount = this.count ?? this.slottedCount;
60
- return (h("div", { key: '7e7d4e927e584807577e02ab2d6811b8eb26d850', class: "bs-chatbot-sources-drawer", role: "region", "aria-label": this.heading }, h("div", { key: '3feb972675a7472bfd49f0164c8af1767ce82af0', class: "bs-chatbot-sources-drawer__header" }, h("div", { key: '5b0f70d84ba6656fcb516cb53fbc63150d013059', class: "bs-chatbot-sources-drawer__title-group" }, h("h2", { key: '6913fb84bc901a8538f74096f74df98103a87b35', part: "heading", class: "bs-chatbot-sources-drawer__heading" }, this.heading), displayCount > 0 && (h("span", { key: '6eda1f962cd7bfc8bd120454988372590784458b', part: "count", class: "bs-chatbot-sources-drawer__count" }, displayCount))), h("button", { key: '7db71240b8e5150de1e4e8f68e0d9b0bce7788c5', type: "button", part: "collapse", class: "bs-chatbot-sources-drawer__collapse", "aria-label": "Collapse sources", onClick: this.onCollapseClick }, h("slot", { key: '79c14cfe115966d1e53e0f9c673393128211bb85', name: "collapse-icon" }, h(CaretRightIcon, { key: 'e5f316c75642b5ec23c46d3ae6361c97cabee2a7' })))), h("div", { key: 'fec3cbebcc8522f84fdb4ba20c8b463d322116c9', part: "list", class: "bs-chatbot-sources-drawer__list" }, h("slot", { key: '8c23cd4194267439fa5f903ff33bc090771007c4', onSlotchange: this.onSlotchange }))));
60
+ return (h("div", { key: 'cdfd3716db3d500d357314994aff14bb404a6572', class: "bs-chatbot-sources-drawer", role: "region", "aria-label": this.heading }, h("div", { key: '6db7d6c785ebdeecc337841a9247b787a6fca119', class: "bs-chatbot-sources-drawer__header" }, h("div", { key: 'a2c992059ab69fcc1c7e02d59349818101d067c9', class: "bs-chatbot-sources-drawer__title-group" }, h("h2", { key: 'b72108d341794d69a40cc00d61e05fbb5bc5a1ff', part: "heading", class: "bs-chatbot-sources-drawer__heading" }, this.heading), displayCount > 0 && (h("span", { key: '9a6fc6effd4f044c4237b12a032cd4dc0b67518c', part: "count", class: "bs-chatbot-sources-drawer__count" }, displayCount))), h("button", { key: '24748019d108acfdc4b9743e7a82142d072cd548', type: "button", part: "collapse", class: "bs-chatbot-sources-drawer__collapse", "aria-label": "Collapse sources", onClick: this.onCollapseClick }, h("slot", { key: 'cedf7ecd8006cd0c34fabaeb5230082b0d9df9d3', name: "collapse-icon" }, h(CaretRightIcon, { key: '73c9b27651ae8adf387ae0480a0174ac03467d10' })))), h("div", { key: 'f9197d1326305d89297cdddd10e14d78dc46248e', part: "list", class: "bs-chatbot-sources-drawer__list" }, h("slot", { key: 'aece928a19516645ec18c8ec1836861dca975366', onSlotchange: this.onSlotchange }))));
61
61
  }
62
62
  static get is() { return "bs-chatbot-sources-drawer"; }
63
63
  static get encapsulation() { return "shadow"; }
@@ -45,7 +45,7 @@ export class BsChatbotSuggestionButton {
45
45
  this.bsSelect.emit();
46
46
  };
47
47
  render() {
48
- return (h("button", { key: '0a980666835a143d72291370b4575d069964a477', type: "button", part: "button", class: "bs-chatbot-suggestion-button", disabled: this.disabled, onClick: this.onClick }, h("slot", { key: '76a4e8f5773259d52c34d46a6eb8a63b32bfc647' })));
48
+ return (h("button", { key: '92fa701db3f36e192af92ebe87d615825c2160dd', type: "button", part: "button", class: "bs-chatbot-suggestion-button", disabled: this.disabled, onClick: this.onClick }, h("slot", { key: 'eff01e89ea8293e6bf7cccb2c64ba2ba9dc49b7f' })));
49
49
  }
50
50
  static get is() { return "bs-chatbot-suggestion-button"; }
51
51
  static get encapsulation() { return "shadow"; }
@@ -33,7 +33,7 @@ export class BsCheckboxSkeleton {
33
33
  * (unusual) default `bs-checkbox` itself uses. */
34
34
  size = 'lg';
35
35
  render() {
36
- return (h("span", { key: '48c41b6a2367d0d25c2613bcb0a7351e4a6008c5', part: "container", class: "bs-checkbox-skeleton", role: "status", "aria-label": "Loading" }, h("span", { key: '9b70627ab11ab9488f3293c3773887e8517e67e5', part: "box", class: `bs-checkbox-skeleton__box bs-checkbox-skeleton__box--${this.size}` }), h("span", { key: 'e520369b9d4ced5c85089ae13ce97d42b4e7b344', part: "label", class: "bs-checkbox-skeleton__label" })));
36
+ return (h("span", { key: 'bbe085c38caf6b80e558868ff208d21c107cd3d3', part: "container", class: "bs-checkbox-skeleton", role: "status", "aria-label": "Loading" }, h("span", { key: '5d5a368f1e2c61991c7bde7398634084294cb503', part: "box", class: `bs-checkbox-skeleton__box bs-checkbox-skeleton__box--${this.size}` }), h("span", { key: 'c39d0ceace38a2f611f4b476d1a295372d220b81', part: "label", class: "bs-checkbox-skeleton__label" })));
37
37
  }
38
38
  static get is() { return "bs-checkbox-skeleton"; }
39
39
  static get encapsulation() { return "shadow"; }
@@ -13,20 +13,35 @@ describe('bs-chip-filter', () => {
13
13
  expect(button).toEqualAttribute('aria-pressed', 'true');
14
14
  expect(button).toHaveClass('bs-chip-filter--selected');
15
15
  });
16
- it('clicking toggles selected and emits bsChange with the new value', async () => {
16
+ it('clicking emits bsChange with the requested new value, without mutating selected itself', async () => {
17
17
  const { root, waitForChanges, spyOnEvent } = await render(h("bs-chip-filter", null, "Label"));
18
18
  const bsChangeSpy = spyOnEvent('bsChange');
19
19
  const button = root.shadowRoot.querySelector('button');
20
20
  button.click();
21
21
  await waitForChanges();
22
- expect(root.selected).toBe(true);
23
22
  expect(bsChangeSpy).toHaveReceivedEventTimes(1);
24
23
  expect(bsChangeSpy).toHaveReceivedEventDetail(true);
24
+ // The chip is controlled: it never flips its own `selected` prop on click.
25
+ expect(root.selected).toBe(false);
26
+ });
27
+ it('is a controlled component: if the parent does not update selected in response to bsChange, the chip stays at its current prop value', async () => {
28
+ const { root, waitForChanges, spyOnEvent } = await render(h("bs-chip-filter", { selected: false }, "Label"));
29
+ const bsChangeSpy = spyOnEvent('bsChange');
30
+ const button = root.shadowRoot.querySelector('button');
25
31
  button.click();
26
32
  await waitForChanges();
33
+ // Event requests the change...
34
+ expect(bsChangeSpy).toHaveReceivedEventDetail(true);
35
+ // ...but since the "parent" never updated the selected prop (simulating a rejected change),
36
+ // the chip's rendered/visual state must still match the prop, not drift into its own truth.
27
37
  expect(root.selected).toBe(false);
28
- expect(bsChangeSpy).toHaveReceivedEventTimes(2);
29
- expect(bsChangeSpy).toHaveReceivedEventDetail(false);
38
+ expect(button).toEqualAttribute('aria-pressed', 'false');
39
+ expect(button).not.toHaveClass('bs-chip-filter--selected');
40
+ // Only an explicit prop update (what a real controlled parent would do) changes the display.
41
+ root.selected = true;
42
+ await waitForChanges();
43
+ expect(button).toEqualAttribute('aria-pressed', 'true');
44
+ expect(button).toHaveClass('bs-chip-filter--selected');
30
45
  });
31
46
  describe('disabled', () => {
32
47
  it('sets the disabled attribute on the native button', async () => {
@@ -40,7 +55,6 @@ describe('bs-chip-filter', () => {
40
55
  const button = root.shadowRoot.querySelector('button');
41
56
  button.click();
42
57
  await waitForChanges();
43
- expect(root.selected).toBe(false);
44
58
  expect(bsChangeSpy).toHaveReceivedEventTimes(0);
45
59
  });
46
60
  });
@@ -24,8 +24,13 @@ export class BsChipFilter {
24
24
  /** Sizing scale. Controls the chip's height only -- icon size, gap, and font size stay
25
25
  * constant across sizes, matching the Figma spec exactly. */
26
26
  size = 'lg';
27
- /** Whether the chip reads as toggled on. Mutable so clicking it toggles directly, and
28
- * reflected so consumers can target `bs-chip-filter[selected]` via CSS. */
27
+ /** Whether the chip reads as toggled on. This is the single source of truth for the chip's
28
+ * visual state -- a controlled component, like a controlled `<input>`. Clicking the chip never
29
+ * mutates this prop itself; it only emits `bsChange` with the requested new value. If the
30
+ * consumer doesn't update `selected` in response (e.g. their own validation rejects the
31
+ * change), the chip's rendering stays exactly as `selected` says, rather than drifting into
32
+ * some internally-tracked truth. Reflected so consumers can target
33
+ * `bs-chip-filter[selected]` via CSS. */
29
34
  selected = false;
30
35
  /** Shows a trailing dropdown caret, signaling this chip opens a menu of further options.
31
36
  * Purely a visual affordance -- wire up the actual menu (e.g. `bs-menu`) yourself. */
@@ -57,8 +62,7 @@ export class BsChipFilter {
57
62
  this.hasIcon = ev.target.assignedNodes().length > 0;
58
63
  };
59
64
  onClick = () => {
60
- this.selected = !this.selected;
61
- this.bsChange.emit(this.selected);
65
+ this.bsChange.emit(!this.selected);
62
66
  };
63
67
  render() {
64
68
  // Matches the four Icon x Dropdown combinations verified against Figma (node 1905:9151):
@@ -66,7 +70,7 @@ export class BsChipFilter {
66
70
  // label-only edge gets more -- except when NEITHER edge has a glyph, where both edges use a
67
71
  // third, larger value rather than the label-only one (see bs-chip-filter.css's own comment).
68
72
  const paddingVariant = this.hasIcon && this.dropdown ? 'icon-dropdown' : this.hasIcon ? 'icon-only' : this.dropdown ? 'dropdown-only' : 'text-only';
69
- return (h("button", { key: 'c585746cca27a4d60d2a0c242e26e19ba8b41677', type: "button", class: `bs-chip-filter bs-chip-filter--${this.size} bs-chip-filter--${paddingVariant} ${this.selected ? 'bs-chip-filter--selected' : ''}`, disabled: this.disabled, "aria-pressed": String(this.selected), "aria-label": this.ariaLabel, onClick: this.onClick }, h("span", { key: 'f62eda39d506b130e5cfe0881bfa80dd0241e1cf', part: "icon", class: `bs-chip-filter__icon ${this.hasIcon ? 'bs-chip-filter__icon--visible' : ''}` }, h("slot", { key: '233f80cba2500aa4fed6e1ccdb6d19f14fb64384', name: "icon", onSlotchange: this.onIconSlotchange })), h("span", { key: '74d101de8d1dd20bda1fbc789733282ae1a3784a', part: "label", class: "bs-chip-filter__label" }, h("slot", { key: '15db7eea134a9d3eac56a159c920141daed4e467' })), this.dropdown && (h("span", { key: 'e070c37932fa4bdc4f494472f361870e2f3d6b22', part: "caret", class: "bs-chip-filter__caret", "aria-hidden": "true" }, h(ChevronDownIcon, { key: '642401f2ddc833731875cfdd3b7d5d96f2272167' })))));
73
+ return (h("button", { key: '5ed45b30aa94816ea44c6bc4824d5e9854971607', type: "button", class: `bs-chip-filter bs-chip-filter--${this.size} bs-chip-filter--${paddingVariant} ${this.selected ? 'bs-chip-filter--selected' : ''}`, disabled: this.disabled, "aria-pressed": String(this.selected), "aria-label": this.ariaLabel, onClick: this.onClick }, h("span", { key: '8bbbcb477640c5d34136b7507b8faa63fd2bcbed', part: "icon", class: `bs-chip-filter__icon ${this.hasIcon ? 'bs-chip-filter__icon--visible' : ''}` }, h("slot", { key: 'b15f49e78ed83f9dd25c45de35cec754d2e01606', name: "icon", onSlotchange: this.onIconSlotchange })), h("span", { key: '5d62b8b0500ce995cf3c1f4710b0b7f535bf228d', part: "label", class: "bs-chip-filter__label" }, h("slot", { key: '0e8a6434bbd31308034fcb19f7d1b9df210c7a1b' })), this.dropdown && (h("span", { key: 'cb11b64425dc06173389bc6c50f259d5c880006a', part: "caret", class: "bs-chip-filter__caret", "aria-hidden": "true" }, h(ChevronDownIcon, { key: '27d7ac0eecbdbfc22d37f295cdda776c2cfbf346' })))));
70
74
  }
71
75
  static get is() { return "bs-chip-filter"; }
72
76
  static get encapsulation() { return "shadow"; }
@@ -111,7 +115,7 @@ export class BsChipFilter {
111
115
  },
112
116
  "selected": {
113
117
  "type": "boolean",
114
- "mutable": true,
118
+ "mutable": false,
115
119
  "complexType": {
116
120
  "original": "boolean",
117
121
  "resolved": "boolean",
@@ -121,7 +125,7 @@ export class BsChipFilter {
121
125
  "optional": false,
122
126
  "docs": {
123
127
  "tags": [],
124
- "text": "Whether the chip reads as toggled on. Mutable so clicking it toggles directly, and\nreflected so consumers can target `bs-chip-filter[selected]` via CSS."
128
+ "text": "Whether the chip reads as toggled on. This is the single source of truth for the chip's\nvisual state -- a controlled component, like a controlled `<input>`. Clicking the chip never\nmutates this prop itself; it only emits `bsChange` with the requested new value. If the\nconsumer doesn't update `selected` in response (e.g. their own validation rejects the\nchange), the chip's rendering stays exactly as `selected` says, rather than drifting into\nsome internally-tracked truth. Reflected so consumers can target\n`bs-chip-filter[selected]` via CSS."
125
129
  },
126
130
  "getter": false,
127
131
  "setter": false,
@@ -65,6 +65,27 @@ describe('bs-composer', () => {
65
65
  expect(spy).toHaveReceivedEventTimes(1);
66
66
  expect(spy).toHaveReceivedEventDetail('a');
67
67
  });
68
+ describe('value prop sync', () => {
69
+ it('keeps the value prop in sync with what was typed, not stuck at the initial value', async () => {
70
+ const { root } = await render(h("bs-composer", null));
71
+ const element = root;
72
+ const textarea = root.shadowRoot.querySelector('textarea');
73
+ textarea.value = 'hello';
74
+ textarea.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
75
+ expect(element.value).toBe('hello');
76
+ });
77
+ it('clears the textarea when value is programmatically reset to "" after the user typed something', async () => {
78
+ const { root, setProps, waitForChanges } = await render(h("bs-composer", null));
79
+ const textarea = root.shadowRoot.querySelector('textarea');
80
+ textarea.value = 'hello';
81
+ textarea.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
82
+ await waitForChanges();
83
+ expect(textarea.value).toBe('hello');
84
+ await setProps({ value: '' });
85
+ await waitForChanges();
86
+ expect(textarea.value).toBe('');
87
+ });
88
+ });
68
89
  describe('auto-grow', () => {
69
90
  it('grows taller as multi-line content is typed', async () => {
70
91
  const { root } = await render(h("bs-composer", null));
@@ -131,6 +152,22 @@ describe('bs-composer', () => {
131
152
  root.shadowRoot.querySelector('[part="mic"]').click();
132
153
  expect(spy).toHaveReceivedEventTimes(1);
133
154
  });
155
+ it('emits bsSubmit when Enter alone is pressed in the text field', async () => {
156
+ const { root, spyOnEvent } = await render(h("bs-composer", { state: "idle" }));
157
+ const spy = spyOnEvent('bsSubmit');
158
+ const textarea = root.shadowRoot.querySelector('textarea');
159
+ textarea.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, composed: true, cancelable: true }));
160
+ expect(spy).toHaveReceivedEventTimes(1);
161
+ });
162
+ it('does not emit bsSubmit and inserts a newline when Shift+Enter is pressed', async () => {
163
+ const { root, spyOnEvent } = await render(h("bs-composer", { state: "idle" }));
164
+ const spy = spyOnEvent('bsSubmit');
165
+ const textarea = root.shadowRoot.querySelector('textarea');
166
+ const ev = new KeyboardEvent('keydown', { key: 'Enter', shiftKey: true, bubbles: true, composed: true, cancelable: true });
167
+ textarea.dispatchEvent(ev);
168
+ expect(spy.length).toBe(0);
169
+ expect(ev.defaultPrevented).toBe(false);
170
+ });
134
171
  });
135
172
  describe('state="generating"', () => {
136
173
  it('shows an enabled action button and emits bsStop (not bsSubmit) on click', async () => {
@@ -195,4 +232,11 @@ describe('bs-composer', () => {
195
232
  const { root } = await render(h("bs-composer", { state: "idle" }));
196
233
  expect(root.shadowRoot.querySelector('.bs-composer__waveform')).toBeNull();
197
234
  });
235
+ it('reflects the state prop to a host attribute', async () => {
236
+ const { root, setProps, waitForChanges } = await render(h("bs-composer", { state: "idle" }));
237
+ expect(root).toEqualAttribute('state', 'idle');
238
+ await setProps({ state: 'recording' });
239
+ await waitForChanges();
240
+ expect(root).toEqualAttribute('state', 'recording');
241
+ });
198
242
  });
@@ -77,12 +77,21 @@ export class BsComposer {
77
77
  * The field is a `<textarea>` (not a single-line `<input>`) that grows with its content, up to
78
78
  * `--bs-composer-input-max-lines` (10 by default) -- beyond that it scrolls internally instead
79
79
  * of growing further. Setting `value` as a prop (not just typing) also re-triggers the resize,
80
- * so e.g. programmatically clearing the field after submit correctly shrinks it back down. */
80
+ * so e.g. programmatically clearing the field after submit correctly shrinks it back down.
81
+ *
82
+ * Mutable: kept in sync with the real `<textarea>`'s content on every keystroke (see `onInput`),
83
+ * not pushed one-way from the outside only. Without this, typing alone never updates this prop,
84
+ * so a consumer re-setting `value` to e.g. `''` after the user had typed something would be a
85
+ * no-op (same as the never-updated internal value) and silently fail to clear the field. */
81
86
  value = '';
82
87
  /**
83
88
  * Which of the four mutually-exclusive composer states to render: `idle` (send, enabled),
84
89
  * `generating` (stop, while the AI is responding), `disabled` (send, but not interactive), or
85
90
  * `recording` (voice input in progress -- shows a waveform and a confirm action).
91
+ *
92
+ * Reflects to a `state` attribute on the host, so a consumer can target a specific state from
93
+ * outside via a CSS attribute selector (e.g. `bs-composer[state="recording"]`) or by querying
94
+ * for it in JS, the same way `bs-input`'s `open` prop reflects.
86
95
  */
87
96
  state = 'idle';
88
97
  /**
@@ -145,9 +154,23 @@ export class BsComposer {
145
154
  };
146
155
  onInput = (ev) => {
147
156
  const value = ev.target.value;
157
+ // Keep the `value` prop in sync with what was actually typed -- see `value`'s doc comment for
158
+ // why this is required for an external `value` prop change (e.g. clearing after submit) to
159
+ // reliably take effect afterwards.
160
+ this.value = value;
148
161
  this.resizeInput();
149
162
  this.bsInput.emit(value);
150
163
  };
164
+ /** Enter alone sends (re-using the exact same per-state action the primary button's own click
165
+ * handler performs), Shift+Enter inserts a normal newline -- standard chat-composer convention.
166
+ * No-ops while `disabled` (the native `disabled` attribute already blocks all input, but this
167
+ * guards the emit here too, for symmetry with the action button's own disabled check). */
168
+ onInputKeydown = (ev) => {
169
+ if (ev.key !== 'Enter' || ev.shiftKey || this.state === 'disabled')
170
+ return;
171
+ ev.preventDefault();
172
+ this.onActionClick();
173
+ };
151
174
  onAttachClick = () => {
152
175
  this.bsAttach.emit();
153
176
  };
@@ -183,7 +206,7 @@ export class BsComposer {
183
206
  const placeholder = this.placeholder ?? DEFAULT_PLACEHOLDERS[this.variant];
184
207
  const disabled = this.state === 'disabled';
185
208
  const recording = this.state === 'recording';
186
- return (h("div", { key: 'f4676a3c110cd683f745e3b0e4d37d8abcab06c5', class: `bs-composer bs-composer--${this.state} bs-composer--${this.variant}` }, h("div", { key: '7970d493b0c0f9ef19f00fea2d33b58085f589e6', part: "attachments", class: `bs-composer__attachments-row ${this.hasAttachments ? 'bs-composer__attachments-row--visible' : ''}` }, h("slot", { key: '4b53a6cfd1d7d0e7cf0fa0d5e4f37fb551f4bcd4', name: "attachments", onSlotchange: this.onAttachmentsSlotchange })), h("div", { key: '44fa49b002b657accd21a01e75cd5458dba337a8', class: "bs-composer__text-row" }, h("textarea", { key: '8fde6e735be83c28a38a59437ad9b2453bc6d074', ref: el => (this.inputEl = el), part: "input", class: "bs-composer__input", rows: 1, value: this.value, placeholder: placeholder, disabled: disabled, "aria-label": this.ariaLabel, onInput: this.onInput })), h("div", { key: '6f7a9e1a33d642e3ce847c8df03bc7e119696bbe', class: "bs-composer__controls-row" }, h("button", { key: '3b98d1c4e50373318b64d91e259e22d54cced5a7', type: "button", part: "attach", class: "bs-composer__attach", "aria-label": "Attach", onClick: this.onAttachClick }, h(PlusIcon, { key: 'e80e96ec1ea18d5eec08f77d9601c174382aafbd' })), 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: '6dc198b201f3df52a9646146ea4ddfc3d921ca72', 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: 'a7e626d35aa9cc0b9e2bd67ced5961671cdd7850', 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: '3f81510829b313a0088b7a4ea6f70c41dce16e77', name: "actions-end" }))));
209
+ return (h("div", { key: '3174350ad304e38046eafeaee35d02967353f15e', class: `bs-composer bs-composer--${this.state} bs-composer--${this.variant}` }, h("div", { key: 'fc87d604bcdce8ac0f32ce61d74373349bebb1a1', part: "attachments", class: `bs-composer__attachments-row ${this.hasAttachments ? 'bs-composer__attachments-row--visible' : ''}` }, h("slot", { key: '180a6243b0073926464db98fcaf8c055c759cec1', name: "attachments", onSlotchange: this.onAttachmentsSlotchange })), h("div", { key: '8dde3d4aafba78bc975635339c432526d6150228', class: "bs-composer__text-row" }, h("textarea", { key: '83cff2a497c6f9625a3111882bb232b2ed007ec8', ref: el => (this.inputEl = el), part: "input", class: "bs-composer__input", rows: 1, value: this.value, placeholder: placeholder, disabled: disabled, "aria-label": this.ariaLabel, onInput: this.onInput, onKeyDown: this.onInputKeydown })), h("div", { key: 'dbcca68b952b2d6945dc8ba912d13888d2460661', class: "bs-composer__controls-row" }, h("button", { key: '2e28ba84020fa9982ca531e5590abc757c4974de', type: "button", part: "attach", class: "bs-composer__attach", "aria-label": "Attach", onClick: this.onAttachClick }, h(PlusIcon, { key: '205351174ac718872ef0e088359c4005834f33e9' })), 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: 'ad9f28bf859112f5f3570ecd21dbb154feaf87a7', 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: '72c0abd1da7c5e0495e5a40bfc067680bd6b6ca5', 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: '09ee67b7a7aaa4a1a608b6d1b603b941ca94a02f', name: "actions-end" }))));
187
210
  }
188
211
  static get is() { return "bs-composer"; }
189
212
  static get encapsulation() { return "shadow"; }
@@ -247,7 +270,7 @@ export class BsComposer {
247
270
  },
248
271
  "value": {
249
272
  "type": "string",
250
- "mutable": false,
273
+ "mutable": true,
251
274
  "complexType": {
252
275
  "original": "string",
253
276
  "resolved": "string",
@@ -257,7 +280,7 @@ export class BsComposer {
257
280
  "optional": false,
258
281
  "docs": {
259
282
  "tags": [],
260
- "text": "Current text value. Native `input` events don't cross the Shadow DOM boundary, so this\ncomponent re-dispatches them as a `bsInput` custom event instead.\n\nThe field is a `<textarea>` (not a single-line `<input>`) that grows with its content, up to\n`--bs-composer-input-max-lines` (10 by default) -- beyond that it scrolls internally instead\nof growing further. Setting `value` as a prop (not just typing) also re-triggers the resize,\nso e.g. programmatically clearing the field after submit correctly shrinks it back down."
283
+ "text": "Current text value. Native `input` events don't cross the Shadow DOM boundary, so this\ncomponent re-dispatches them as a `bsInput` custom event instead.\n\nThe field is a `<textarea>` (not a single-line `<input>`) that grows with its content, up to\n`--bs-composer-input-max-lines` (10 by default) -- beyond that it scrolls internally instead\nof growing further. Setting `value` as a prop (not just typing) also re-triggers the resize,\nso e.g. programmatically clearing the field after submit correctly shrinks it back down.\n\nMutable: kept in sync with the real `<textarea>`'s content on every keystroke (see `onInput`),\nnot pushed one-way from the outside only. Without this, typing alone never updates this prop,\nso a consumer re-setting `value` to e.g. `''` after the user had typed something would be a\nno-op (same as the never-updated internal value) and silently fail to clear the field."
261
284
  },
262
285
  "getter": false,
263
286
  "setter": false,
@@ -283,11 +306,11 @@ export class BsComposer {
283
306
  "optional": false,
284
307
  "docs": {
285
308
  "tags": [],
286
- "text": "Which of the four mutually-exclusive composer states to render: `idle` (send, enabled),\n`generating` (stop, while the AI is responding), `disabled` (send, but not interactive), or\n`recording` (voice input in progress -- shows a waveform and a confirm action)."
309
+ "text": "Which of the four mutually-exclusive composer states to render: `idle` (send, enabled),\n`generating` (stop, while the AI is responding), `disabled` (send, but not interactive), or\n`recording` (voice input in progress -- shows a waveform and a confirm action).\n\nReflects to a `state` attribute on the host, so a consumer can target a specific state from\noutside via a CSS attribute selector (e.g. `bs-composer[state=\"recording\"]`) or by querying\nfor it in JS, the same way `bs-input`'s `open` prop reflects."
287
310
  },
288
311
  "getter": false,
289
312
  "setter": false,
290
- "reflect": false,
313
+ "reflect": true,
291
314
  "attribute": "state",
292
315
  "defaultValue": "'idle'"
293
316
  },
@@ -0,0 +1,108 @@
1
+ import { render, h, describe, it, expect } from "@stencil/vitest";
2
+ const columns = [
3
+ { key: 'name', label: 'Name' },
4
+ { key: 'status', label: 'Status' },
5
+ ];
6
+ const rows = [
7
+ { id: 1, name: 'Amelia', status: 'Active' },
8
+ { id: 2, name: 'Noah', status: 'Active' },
9
+ { id: 3, name: 'Priya', status: 'On leave' },
10
+ ];
11
+ describe('bs-data-table', () => {
12
+ describe('select-all checkbox', () => {
13
+ it('renders a select-all checkbox in the header when selectable', async () => {
14
+ const { root } = await render(h("bs-data-table", { selectable: true, columns: columns, rows: rows }));
15
+ const selectAll = root.shadowRoot.querySelector('thead input[type="checkbox"]');
16
+ expect(selectAll).not.toBeNull();
17
+ expect(selectAll.checked).toBe(false);
18
+ expect(selectAll.indeterminate).toBe(false);
19
+ });
20
+ it('does not render a select-all checkbox when not selectable', async () => {
21
+ const { root } = await render(h("bs-data-table", { columns: columns, rows: rows }));
22
+ expect(root.shadowRoot.querySelector('thead input[type="checkbox"]')).toBeNull();
23
+ });
24
+ it('becomes indeterminate when some but not all rows are selected', async () => {
25
+ const { root, waitForChanges } = await render(h("bs-data-table", { selectable: true, columns: columns, rows: rows }));
26
+ const rowCheckbox = root.shadowRoot.querySelector('tbody input[type="checkbox"]');
27
+ rowCheckbox.checked = true;
28
+ rowCheckbox.dispatchEvent(new Event('change'));
29
+ await waitForChanges();
30
+ const selectAll = root.shadowRoot.querySelector('thead input[type="checkbox"]');
31
+ expect(selectAll.indeterminate).toBe(true);
32
+ expect(selectAll.checked).toBe(false);
33
+ });
34
+ it('is checked when every row is selected', async () => {
35
+ const { root, waitForChanges } = await render(h("bs-data-table", { selectable: true, columns: columns, rows: rows }));
36
+ const rowCheckboxes = Array.from(root.shadowRoot.querySelectorAll('tbody input[type="checkbox"]'));
37
+ for (const checkbox of rowCheckboxes) {
38
+ checkbox.checked = true;
39
+ checkbox.dispatchEvent(new Event('change'));
40
+ }
41
+ await waitForChanges();
42
+ const selectAll = root.shadowRoot.querySelector('thead input[type="checkbox"]');
43
+ expect(selectAll.checked).toBe(true);
44
+ expect(selectAll.indeterminate).toBe(false);
45
+ });
46
+ it('selects all rows and emits bsRowSelect for each row when clicked', async () => {
47
+ const { root, waitForChanges, spyOnEvent } = await render(h("bs-data-table", { selectable: true, columns: columns, rows: rows }));
48
+ const selectSpy = spyOnEvent('bsRowSelect');
49
+ const selectAll = root.shadowRoot.querySelector('thead input[type="checkbox"]');
50
+ selectAll.checked = true;
51
+ selectAll.dispatchEvent(new Event('change'));
52
+ await waitForChanges();
53
+ expect(selectSpy).toHaveReceivedEventTimes(3);
54
+ const rowCheckboxes = Array.from(root.shadowRoot.querySelectorAll('tbody input[type="checkbox"]'));
55
+ expect(rowCheckboxes.every(checkbox => checkbox.checked)).toBe(true);
56
+ });
57
+ it('deselects all rows when unchecked', async () => {
58
+ const { root, waitForChanges, spyOnEvent } = await render(h("bs-data-table", { selectable: true, columns: columns, rows: rows }));
59
+ const selectAll = root.shadowRoot.querySelector('thead input[type="checkbox"]');
60
+ selectAll.checked = true;
61
+ selectAll.dispatchEvent(new Event('change'));
62
+ await waitForChanges();
63
+ const selectSpy = spyOnEvent('bsRowSelect');
64
+ selectAll.checked = false;
65
+ selectAll.dispatchEvent(new Event('change'));
66
+ await waitForChanges();
67
+ expect(selectSpy).toHaveReceivedEventTimes(3);
68
+ const rowCheckboxes = Array.from(root.shadowRoot.querySelectorAll('tbody input[type="checkbox"]'));
69
+ expect(rowCheckboxes.every(checkbox => !checkbox.checked)).toBe(true);
70
+ });
71
+ });
72
+ describe('clearSelection()', () => {
73
+ it('resets selection state and emits bsRowSelect for previously selected rows', async () => {
74
+ const { root, waitForChanges, spyOnEvent } = await render(h("bs-data-table", { selectable: true, columns: columns, rows: rows }));
75
+ const rowCheckbox = root.shadowRoot.querySelector('tbody input[type="checkbox"]');
76
+ rowCheckbox.checked = true;
77
+ rowCheckbox.dispatchEvent(new Event('change'));
78
+ await waitForChanges();
79
+ const selectSpy = spyOnEvent('bsRowSelect');
80
+ await root.clearSelection();
81
+ await waitForChanges();
82
+ expect(selectSpy).toHaveReceivedEventTimes(1);
83
+ expect(selectSpy).toHaveReceivedEventDetail({ id: 1, selected: false });
84
+ const checkboxesAfterClear = Array.from(root.shadowRoot.querySelectorAll('tbody input[type="checkbox"]'));
85
+ expect(checkboxesAfterClear.every(checkbox => !checkbox.checked)).toBe(true);
86
+ });
87
+ it('emits no event when nothing was selected', async () => {
88
+ const { root, spyOnEvent } = await render(h("bs-data-table", { selectable: true, columns: columns, rows: rows }));
89
+ const selectSpy = spyOnEvent('bsRowSelect');
90
+ await root.clearSelection();
91
+ expect(selectSpy).toHaveReceivedEventTimes(0);
92
+ });
93
+ });
94
+ describe('cellRenderer', () => {
95
+ it('renders default cell values as escaped text, never interpreted as HTML', async () => {
96
+ const maliciousRows = [{ id: 1, name: '<img src=x onerror="window.__xss = true">', status: 'Active' }];
97
+ const { root } = await render(h("bs-data-table", { columns: columns, rows: maliciousRows }));
98
+ const cell = root.shadowRoot.querySelector('tbody td');
99
+ expect(cell.querySelector('img')).toBeNull();
100
+ expect(cell.textContent).toBe('<img src=x onerror="window.__xss = true">');
101
+ });
102
+ it('still allows cellRenderer to render trusted custom HTML when explicitly supplied', async () => {
103
+ const { root } = await render(h("bs-data-table", { columns: columns, rows: rows, cellRenderer: () => '<button type="button">Edit</button>' }));
104
+ const cell = root.shadowRoot.querySelector('tbody td');
105
+ expect(cell.querySelector('button')).not.toBeNull();
106
+ });
107
+ });
108
+ });