@adyen/bento-mcp 0.10.0 → 0.12.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 (429) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +24 -2
  3. package/SKILL.md +37 -7
  4. package/dist/assets/components/accordion/accordion.stories.ts +1 -1
  5. package/dist/assets/components/accordion/components/accordion-item.stories.ts +1 -1
  6. package/dist/assets/components/accordion/components/accordion-item.vue +1 -1
  7. package/dist/assets/components/action-bar/action-bar.docs.mdx +10 -3
  8. package/dist/assets/components/action-bar/action-bar.internal.types.ts +1 -0
  9. package/dist/assets/components/action-bar/action-bar.stories.ts +1 -1
  10. package/dist/assets/components/action-bar/action-bar.types.ts +1 -1
  11. package/dist/assets/components/action-bar/action-bar.vue +1 -1
  12. package/dist/assets/components/ai-tag/ai-tag.stories.ts +1 -1
  13. package/dist/assets/components/ai-tag/ai-tag.vue +1 -1
  14. package/dist/assets/components/alert/alert.stories.ts +1 -1
  15. package/dist/assets/components/alert/alert.types.ts +1 -1
  16. package/dist/assets/components/anchor-scroller/anchor-scroller.stories.ts +1 -1
  17. package/dist/assets/components/anchor-scroller/anchor-scroller.vue +1 -1
  18. package/dist/assets/components/avatar/avatar.internal.types.ts +1 -0
  19. package/dist/assets/components/avatar/avatar.stories.ts +1 -1
  20. package/dist/assets/components/avatar/avatar.types.ts +1 -1
  21. package/dist/assets/components/button/button.docs.mdx +4 -3
  22. package/dist/assets/components/button/button.stories.ts +1 -1
  23. package/dist/assets/components/button/button.types.ts +1 -1
  24. package/dist/assets/components/button/components/ai-button/ai-button.stories.ts +1 -1
  25. package/dist/assets/components/button/components/ai-button/ai-button.vue +1 -1
  26. package/dist/assets/components/button/components/button-actions/button-actions.docs.mdx +3 -0
  27. package/dist/assets/components/button/components/button-actions/button-actions.internal.types.ts +1 -0
  28. package/dist/assets/components/button/components/button-actions/button-actions.stories.ts +1 -1
  29. package/dist/assets/components/button/components/button-actions/button-actions.types.ts +1 -1
  30. package/dist/assets/components/button/components/button-actions/button-actions.vue +1 -1
  31. package/dist/assets/components/button/components/loading-button/loading-button.docs.mdx +26 -23
  32. package/dist/assets/components/button/components/loading-button/loading-button.stories.ts +1 -1
  33. package/dist/assets/components/button/components/loading-button/loading-button.vue +1 -1
  34. package/dist/assets/components/button/components/toggle-button/toggle-button.stories.ts +1 -1
  35. package/dist/assets/components/card/card.docs.mdx +18 -1
  36. package/dist/assets/components/card/card.stories.ts +1 -1
  37. package/dist/assets/components/card/card.types.ts +1 -1
  38. package/dist/assets/components/card/card.vue +1 -1
  39. package/dist/assets/components/checkbox/checkbox.stories.ts +1 -1
  40. package/dist/assets/components/checkbox/checkbox.types.ts +1 -1
  41. package/dist/assets/components/checkbox/checkbox.vue +1 -1
  42. package/dist/assets/components/checkbox/components/checkbox-group/checkbox-group.docs.mdx +9 -14
  43. package/dist/assets/components/checkbox/components/checkbox-group/checkbox-group.stories.ts +1 -1
  44. package/dist/assets/components/checkbox/components/checkbox-group/checkbox-group.types.ts +1 -1
  45. package/dist/assets/components/checkbox/components/checkbox-group/checkbox-group.vue +1 -1
  46. package/dist/assets/components/chip/chip.stories.ts +1 -1
  47. package/dist/assets/components/chip/chip.vue +1 -1
  48. package/dist/assets/components/click-outside/click-outside.stories.ts +1 -1
  49. package/dist/assets/components/code-snippet/code-snippet.types.ts +1 -1
  50. package/dist/assets/components/code-snippet/code-snippet.vue +1 -1
  51. package/dist/assets/components/country/country.stories.ts +1 -1
  52. package/dist/assets/components/country/country.types.ts +1 -1
  53. package/dist/assets/components/country/country.vue +1 -1
  54. package/dist/assets/components/currency/currency.stories.ts +1 -1
  55. package/dist/assets/components/currency/currency.vue +1 -1
  56. package/dist/assets/components/dashed-underline/dashed-underline.stories.ts +1 -1
  57. package/dist/assets/components/data-grid/components/data-grid-cell-actions/data-grid-cell-actions.types.ts +1 -1
  58. package/dist/assets/components/data-grid/components/data-grid-cell-actions/data-grid-cell-actions.vue +1 -1
  59. package/dist/assets/components/data-grid/components/data-grid-config-settings/data-grid-config-settings.vue +1 -1
  60. package/dist/assets/components/data-grid/components/data-grid-row/data-grid-row.vue +1 -1
  61. package/dist/assets/components/data-grid/components/data-grid-static-icon/data-grid-static-icon.stories.ts +1 -1
  62. package/dist/assets/components/data-grid/components/data-grid-summary-cell/data-grid-summary-cell.stories.ts +1 -1
  63. package/dist/assets/components/data-grid/components/data-grid-summary-cell/data-grid-summary-cell.vue +1 -1
  64. package/dist/assets/components/data-grid/components/data-grid-tag-with-text-cell/data-grid-tag-with-text-cell.stories.ts +1 -1
  65. package/dist/assets/components/data-grid/components/data-grid-trend-cell/data-grid-trend-cell.stories.ts +1 -1
  66. package/dist/assets/components/data-grid/components/data-grid-trend-cell/data-grid-trend-cell.vue +1 -1
  67. package/dist/assets/components/data-grid/data-grid.docs.mdx +3 -60
  68. package/dist/assets/components/data-grid/data-grid.stories.ts +1 -1
  69. package/dist/assets/components/data-grid/data-grid.vue +1 -1
  70. package/dist/assets/components/date/date.stories.ts +1 -1
  71. package/dist/assets/components/date-picker/date-picker.stories.ts +1 -1
  72. package/dist/assets/components/date-picker/date-picker.types.ts +1 -1
  73. package/dist/assets/components/date-picker/date-picker.vue +1 -1
  74. package/dist/assets/components/date-range-picker/components/date-range-picker-calendar/date-range-picker-calendar.vue +1 -1
  75. package/dist/assets/components/date-range-picker/components/date-time-input/date-time-input.types.ts +1 -1
  76. package/dist/assets/components/date-range-picker/components/date-time-input/date-time-input.vue +1 -1
  77. package/dist/assets/components/date-range-picker/date-range-picker.docs.mdx +31 -6
  78. package/dist/assets/components/date-range-picker/date-range-picker.stories.ts +1 -1
  79. package/dist/assets/components/date-range-picker/date-range-picker.types.ts +1 -1
  80. package/dist/assets/components/date-range-picker/date-range-picker.vue +1 -1
  81. package/dist/assets/components/date-time-picker/date-time-picker.stories.ts +1 -1
  82. package/dist/assets/components/date-time-picker/date-time-picker.types.ts +1 -1
  83. package/dist/assets/components/divider/divider.internal.types.ts +1 -0
  84. package/dist/assets/components/divider/divider.stories.ts +1 -1
  85. package/dist/assets/components/divider/divider.types.ts +1 -1
  86. package/dist/assets/components/divider/divider.vue +1 -1
  87. package/dist/assets/components/draggable/components/draggable-handle/draggable-handle.stories.ts +1 -1
  88. package/dist/assets/components/draggable/draggable.stories.ts +1 -1
  89. package/dist/assets/components/draggable/draggable.vue +1 -1
  90. package/dist/assets/components/drawer/drawer.stories.ts +1 -1
  91. package/dist/assets/components/dropdown/components/dropdown-base-textbox/dropdown-base-textbox.internal.types.ts +1 -0
  92. package/dist/assets/components/dropdown/components/dropdown-base-textbox/dropdown-base-textbox.types.ts +1 -1
  93. package/dist/assets/components/dropdown/components/dropdown-base-textbox/dropdown-base-textbox.vue +1 -1
  94. package/dist/assets/components/dropdown/components/dropdown-default-textbox/dropdown-default-textbox.vue +1 -1
  95. package/dist/assets/components/dropdown/components/dropdown-options-container/dropdown-options-container.vue +1 -1
  96. package/dist/assets/components/dropdown/components/dropdown-small-textbox/dropdown-small-textbox.vue +1 -1
  97. package/dist/assets/components/dropdown/components/variants/dropdown-avatar/dropdown-avatar.stories.ts +1 -1
  98. package/dist/assets/components/dropdown/components/variants/dropdown-avatar/dropdown-avatar.types.ts +1 -1
  99. package/dist/assets/components/dropdown/components/variants/dropdown-avatar/dropdown-avatar.vue +1 -1
  100. package/dist/assets/components/dropdown/components/variants/dropdown-country/dropdown-country.stories.ts +1 -1
  101. package/dist/assets/components/dropdown/components/variants/dropdown-country/dropdown-country.types.ts +1 -1
  102. package/dist/assets/components/dropdown/components/variants/dropdown-country/dropdown-country.vue +1 -1
  103. package/dist/assets/components/dropdown/components/variants/dropdown-currency/dropdown-currency.stories.ts +1 -1
  104. package/dist/assets/components/dropdown/components/variants/dropdown-currency/dropdown-currency.types.ts +1 -1
  105. package/dist/assets/components/dropdown/components/variants/dropdown-currency/dropdown-currency.vue +1 -1
  106. package/dist/assets/components/dropdown/components/variants/dropdown-payment-method/dropdown-payment-method.stories.ts +1 -1
  107. package/dist/assets/components/dropdown/components/variants/dropdown-payment-method/dropdown-payment-method.types.ts +1 -1
  108. package/dist/assets/components/dropdown/components/variants/dropdown-payment-method/dropdown-payment-method.vue +1 -1
  109. package/dist/assets/components/dropdown/components/variants/dropdown-tag/dropdown-tag.stories.ts +1 -1
  110. package/dist/assets/components/dropdown/components/variants/dropdown-tag/dropdown-tag.types.ts +1 -1
  111. package/dist/assets/components/dropdown/components/variants/dropdown-tag/dropdown-tag.vue +1 -1
  112. package/dist/assets/components/dropdown/dropdown.docs.mdx +4 -40
  113. package/dist/assets/components/dropdown/dropdown.internal.types.ts +1 -0
  114. package/dist/assets/components/dropdown/dropdown.stories.ts +1 -1
  115. package/dist/assets/components/dropdown/dropdown.types.ts +1 -1
  116. package/dist/assets/components/dropdown/dropdown.vue +1 -1
  117. package/dist/assets/components/empty-state/empty-state.stories.ts +1 -1
  118. package/dist/assets/components/empty-state/empty-state.types.ts +1 -1
  119. package/dist/assets/components/file-uploader/components/file-uploader-file-card/file-uploader-file-card.stories.ts +1 -1
  120. package/dist/assets/components/file-uploader/components/file-uploader-file-card/file-uploader-file-card.types.ts +1 -1
  121. package/dist/assets/components/file-uploader/components/file-uploader-file-card/file-uploader-file-card.vue +1 -1
  122. package/dist/assets/components/file-uploader/components/file-uploader-restrictions/file-uploader-restrictions.types.ts +1 -1
  123. package/dist/assets/components/file-uploader/components/file-uploader-restrictions/file-uploader-restrictions.vue +1 -1
  124. package/dist/assets/components/file-uploader/file-uploader.internal.types.ts +1 -0
  125. package/dist/assets/components/file-uploader/file-uploader.stories.ts +1 -1
  126. package/dist/assets/components/file-uploader/file-uploader.types.ts +1 -1
  127. package/dist/assets/components/file-uploader/file-uploader.vue +1 -1
  128. package/dist/assets/components/filter-bar/components/all-filters-modal/all-filters-modal.stories.ts +1 -1
  129. package/dist/assets/components/filter-bar/components/all-filters-modal/all-filters-modal.types.ts +1 -1
  130. package/dist/assets/components/filter-bar/components/all-filters-modal/all-filters-modal.vue +1 -1
  131. package/dist/assets/components/filter-bar/components/all-filters-modal/components/all-filters-modal-filter-selection/all-filters-modal-filter-selection.types.ts +1 -0
  132. package/dist/assets/components/filter-bar/components/all-filters-modal/components/all-filters-modal-filter-selection/all-filters-modal-filter-selection.vue +1 -0
  133. package/dist/assets/components/filter-bar/components/all-filters-modal/components/all-filters-modal-selected-filter/all-filters-modal-selected-filter.vue +1 -0
  134. package/dist/assets/components/filter-bar/components/base-filter/base-filter.internal.types.ts +1 -0
  135. package/dist/assets/components/filter-bar/components/base-filter/base-filter.types.ts +1 -1
  136. package/dist/assets/components/filter-bar/components/base-filter/base-filter.vue +1 -1
  137. package/dist/assets/components/filter-bar/components/boolean-filter/boolean-filter.vue +1 -1
  138. package/dist/assets/components/filter-bar/components/date-filter/date-filter.vue +1 -1
  139. package/dist/assets/components/filter-bar/components/date-range-filter/date-range-filter.vue +1 -1
  140. package/dist/assets/components/filter-bar/components/input-filter/input-filter.types.ts +1 -1
  141. package/dist/assets/components/filter-bar/components/input-filter/input-filter.vue +1 -1
  142. package/dist/assets/components/filter-bar/components/input-with-dropdown-filter/input-with-dropdown-filter.stories.ts +1 -1
  143. package/dist/assets/components/filter-bar/components/input-with-dropdown-filter/input-with-dropdown-filter.vue +1 -1
  144. package/dist/assets/components/filter-bar/components/select-filter/components/select-filter-button/select-filter-button.vue +1 -1
  145. package/dist/assets/components/filter-bar/components/select-filter/select-filter.vue +1 -1
  146. package/dist/assets/components/filter-bar/components/select-filter/variants/select-avatar-filter/select-avatar-filter.stories.ts +1 -1
  147. package/dist/assets/components/filter-bar/components/select-filter/variants/select-country-filter/select-country-filter.stories.ts +1 -1
  148. package/dist/assets/components/filter-bar/components/select-filter/variants/select-country-filter/select-country-filter.vue +1 -1
  149. package/dist/assets/components/filter-bar/components/toggle-filter/toggle-filter.vue +1 -1
  150. package/dist/assets/components/filter-bar/filter-bar.docs.mdx +4 -62
  151. package/dist/assets/components/filter-bar/filter-bar.stories.ts +1 -1
  152. package/dist/assets/components/filter-bar/filter-bar.types.ts +1 -1
  153. package/dist/assets/components/filter-bar/filter-bar.vue +1 -1
  154. package/dist/assets/components/form-layout/form-layout.docs.mdx +0 -23
  155. package/dist/assets/components/form-layout/form-layout.stories.ts +1 -1
  156. package/dist/assets/components/header/header.stories.ts +1 -1
  157. package/dist/assets/components/header/header.types.ts +1 -1
  158. package/dist/assets/components/header/header.vue +1 -1
  159. package/dist/assets/components/header-with-views/components/header-with-views-all-views/header-with-views-all-views.vue +1 -1
  160. package/dist/assets/components/header-with-views/components/header-with-views-item-edit-form/header-with-views-edit-form.types.ts +1 -1
  161. package/dist/assets/components/header-with-views/components/header-with-views-item-edit-form/header-with-views-edit-form.vue +1 -1
  162. package/dist/assets/components/header-with-views/header-with-views.internal.types.ts +1 -0
  163. package/dist/assets/components/header-with-views/header-with-views.stories.ts +1 -1
  164. package/dist/assets/components/header-with-views/header-with-views.types.ts +1 -1
  165. package/dist/assets/components/header-with-views/header-with-views.vue +1 -1
  166. package/dist/assets/components/image/image.stories.ts +1 -1
  167. package/dist/assets/components/info-icon/info-icon.stories.ts +1 -1
  168. package/dist/assets/components/input-field/input-field.docs.mdx +1 -13
  169. package/dist/assets/components/input-field/input-field.stories.ts +1 -1
  170. package/dist/assets/components/input-field/input-field.types.ts +1 -1
  171. package/dist/assets/components/input-field/input-field.vue +1 -1
  172. package/dist/assets/components/input-field-password/input-field-password.internal.types.ts +1 -0
  173. package/dist/assets/components/input-field-password/input-field-password.stories.ts +1 -1
  174. package/dist/assets/components/input-field-password/input-field-password.types.ts +1 -1
  175. package/dist/assets/components/input-field-password/input-field-password.vue +1 -1
  176. package/dist/assets/components/input-field-phone-number/input-field-phone-number.stories.ts +1 -1
  177. package/dist/assets/components/input-field-phone-number/input-field-phone-number.types.ts +1 -1
  178. package/dist/assets/components/input-field-phone-number/input-field-phone-number.vue +1 -1
  179. package/dist/assets/components/input-time/input-time.docs.mdx +17 -0
  180. package/dist/assets/components/input-time/input-time.stories.ts +1 -1
  181. package/dist/assets/components/input-time/input-time.types.ts +1 -1
  182. package/dist/assets/components/input-time/input-time.vue +1 -1
  183. package/dist/assets/components/inspector/inspector.stories.ts +1 -1
  184. package/dist/assets/components/inspector/inspector.vue +1 -1
  185. package/dist/assets/components/layout/components/layout-row/layout-row.stories.ts +1 -1
  186. package/dist/assets/components/layout/components/layout-row/layout-row.vue +1 -1
  187. package/dist/assets/components/layout/layout.docs.mdx +10 -0
  188. package/dist/assets/components/layout/layout.internal.types.ts +1 -0
  189. package/dist/assets/components/layout/layout.stories.ts +1 -1
  190. package/dist/assets/components/layout/layout.types.ts +1 -1
  191. package/dist/assets/components/link/link.stories.ts +1 -1
  192. package/dist/assets/components/link/link.types.ts +1 -1
  193. package/dist/assets/components/link/link.vue +1 -1
  194. package/dist/assets/components/list/list.stories.ts +1 -1
  195. package/dist/assets/components/loading-indicator/loading-indicator.stories.ts +1 -1
  196. package/dist/assets/components/menu/components/menu-item/menu-item.types.ts +1 -1
  197. package/dist/assets/components/menu/components/menu-item/menu-item.vue +1 -1
  198. package/dist/assets/components/menu/components/menu-item-list/menu-item-list.vue +1 -1
  199. package/dist/assets/components/menu/components/sub-menu-item-list/sub-menu-item-list.vue +1 -1
  200. package/dist/assets/components/menu/menu.docs.mdx +17 -7
  201. package/dist/assets/components/menu/menu.stories.ts +1 -1
  202. package/dist/assets/components/menu/menu.types.ts +1 -1
  203. package/dist/assets/components/menu/menu.vue +1 -1
  204. package/dist/assets/components/modal/components/base-modal/base-modal.vue +1 -1
  205. package/dist/assets/components/modal/components/modal-page/modal-page.vue +1 -1
  206. package/dist/assets/components/modal/modal.internal.types.ts +1 -0
  207. package/dist/assets/components/modal/modal.stories.ts +1 -1
  208. package/dist/assets/components/modal/modal.types.ts +1 -1
  209. package/dist/assets/components/modal/modal.vue +1 -1
  210. package/dist/assets/components/modal-fullscreen/components/modal-fullscreen-page.vue +1 -1
  211. package/dist/assets/components/modal-fullscreen/modal-fullscreen.stories.ts +1 -1
  212. package/dist/assets/components/modal-fullscreen/modal-fullscreen.vue +1 -1
  213. package/dist/assets/components/navigation-menu/components/navigation-menu-group/navigation-menu-group.internal.types.ts +1 -0
  214. package/dist/assets/components/navigation-menu/components/navigation-menu-group/navigation-menu-group.types.ts +1 -1
  215. package/dist/assets/components/navigation-menu/components/navigation-menu-group/navigation-menu-group.vue +1 -1
  216. package/dist/assets/components/navigation-menu/components/navigation-menu-item/navigation-menu-item.vue +1 -1
  217. package/dist/assets/components/navigation-menu/navigation-menu.internal.types.ts +1 -0
  218. package/dist/assets/components/navigation-menu/navigation-menu.stories.ts +1 -1
  219. package/dist/assets/components/navigation-menu/navigation-menu.types.ts +1 -1
  220. package/dist/assets/components/navigation-menu/navigation-menu.vue +1 -1
  221. package/dist/assets/components/pagination/components/pagination-context/pagination-context.vue +1 -1
  222. package/dist/assets/components/pagination/components/pagination-results-per-page/pagination-results-per-page.vue +1 -1
  223. package/dist/assets/components/pagination/pagination.stories.ts +1 -1
  224. package/dist/assets/components/pagination/pagination.types.ts +1 -1
  225. package/dist/assets/components/pagination/pagination.vue +1 -1
  226. package/dist/assets/components/payment-method/payment-method.stories.ts +1 -1
  227. package/dist/assets/components/payment-method/payment-method.types.ts +1 -1
  228. package/dist/assets/components/popover/popover.docs.mdx +32 -9
  229. package/dist/assets/components/popover/popover.stories.ts +1 -1
  230. package/dist/assets/components/popover/popover.types.ts +1 -1
  231. package/dist/assets/components/popover/popover.vue +1 -1
  232. package/dist/assets/components/popper-container/popper-container.types.ts +1 -1
  233. package/dist/assets/components/popper-container/popper-container.vue +1 -1
  234. package/dist/assets/components/progress-bar/progress-bar.docs.mdx +102 -0
  235. package/dist/assets/components/progress-bar/progress-bar.stories.ts +1 -0
  236. package/dist/assets/components/progress-bar/progress-bar.types.ts +1 -0
  237. package/dist/assets/components/progress-bar/progress-bar.vue +1 -0
  238. package/dist/assets/components/promo-banner/promo-banner.stories.ts +1 -1
  239. package/dist/assets/components/promo-banner/promo-banner.types.ts +1 -1
  240. package/dist/assets/components/promo-banner/promo-banner.vue +1 -1
  241. package/dist/assets/components/radio-group/components/radio-button/radio-button.vue +1 -1
  242. package/dist/assets/components/radio-group/radio-group.docs.mdx +1 -6
  243. package/dist/assets/components/radio-group/radio-group.stories.ts +1 -1
  244. package/dist/assets/components/radio-group/radio-group.types.ts +1 -1
  245. package/dist/assets/components/radio-group/radio-group.vue +1 -1
  246. package/dist/assets/components/rich-text-editor/rich-text-editor.internal.types.ts +1 -0
  247. package/dist/assets/components/rich-text-editor/rich-text-editor.stories.ts +1 -1
  248. package/dist/assets/components/rich-text-editor/rich-text-editor.types.ts +1 -1
  249. package/dist/assets/components/rich-text-editor/rich-text-editor.vue +1 -1
  250. package/dist/assets/components/search-bar/search-bar.stories.ts +1 -1
  251. package/dist/assets/components/search-bar/search-bar.vue +1 -1
  252. package/dist/assets/components/secondary-nav/components/secondary-nav-item/secondary-nav-item.vue +1 -1
  253. package/dist/assets/components/secondary-nav/secondary-nav.stories.ts +1 -1
  254. package/dist/assets/components/secondary-nav/secondary-nav.vue +1 -1
  255. package/dist/assets/components/segmented-control/components/segmented-control-button/segmented-control-button.vue +1 -1
  256. package/dist/assets/components/segmented-control/segmented-control.stories.ts +1 -1
  257. package/dist/assets/components/segmented-control/segmented-control.types.ts +1 -1
  258. package/dist/assets/components/segmented-control/segmented-control.vue +1 -1
  259. package/dist/assets/components/selection-card/components/selection-card-group/selection-card-group.docs.mdx +12 -13
  260. package/dist/assets/components/selection-card/components/selection-card-group/selection-card-group.stories.ts +1 -1
  261. package/dist/assets/components/selection-card/components/selection-card-group/selection-card-group.vue +1 -1
  262. package/dist/assets/components/selection-card/selection-card.stories.ts +1 -1
  263. package/dist/assets/components/selection-card/selection-card.types.ts +1 -1
  264. package/dist/assets/components/selection-card/selection-card.vue +1 -1
  265. package/dist/assets/components/sidepanel/sidepanel.docs.mdx +1 -1
  266. package/dist/assets/components/sidepanel/sidepanel.stories.ts +1 -1
  267. package/dist/assets/components/sidepanel/sidepanel.vue +1 -1
  268. package/dist/assets/components/status/status.stories.ts +1 -1
  269. package/dist/assets/components/status/status.types.ts +1 -1
  270. package/dist/assets/components/stepper/components/step/step.vue +1 -1
  271. package/dist/assets/components/stepper/stepper.stories.ts +1 -1
  272. package/dist/assets/components/stepper/stepper.vue +1 -1
  273. package/dist/assets/components/structured-list/structured-list.stories.ts +1 -1
  274. package/dist/assets/components/structured-list/structured-list.vue +1 -1
  275. package/dist/assets/components/summary-grid/components/summary-grid-item/summary-grid-item.types.ts +1 -1
  276. package/dist/assets/components/summary-grid/summary-grid.stories.ts +1 -1
  277. package/dist/assets/components/summary-grid/summary-grid.types.ts +1 -1
  278. package/dist/assets/components/table-of-contents/components/table-of-contents-list/table-of-contents-list.vue +1 -1
  279. package/dist/assets/components/table-of-contents/table-of-contents.internal.types.ts +1 -0
  280. package/dist/assets/components/table-of-contents/table-of-contents.stories.ts +1 -1
  281. package/dist/assets/components/table-of-contents/table-of-contents.types.ts +1 -1
  282. package/dist/assets/components/table-of-contents/table-of-contents.vue +1 -1
  283. package/dist/assets/components/tabs/components/tab.internal.types.ts +1 -0
  284. package/dist/assets/components/tabs/components/tab.types.ts +1 -1
  285. package/dist/assets/components/tabs/components/tab.vue +1 -1
  286. package/dist/assets/components/tabs/tabs.stories.ts +1 -1
  287. package/dist/assets/components/tabs/tabs.vue +1 -1
  288. package/dist/assets/components/tag/tag.docs.mdx +1 -1
  289. package/dist/assets/components/tag/tag.stories.ts +1 -1
  290. package/dist/assets/components/tag/tag.types.ts +1 -1
  291. package/dist/assets/components/tag/tag.vue +1 -1
  292. package/dist/assets/components/textarea/textarea.docs.mdx +0 -7
  293. package/dist/assets/components/textarea/textarea.stories.ts +1 -1
  294. package/dist/assets/components/textarea/textarea.types.ts +1 -1
  295. package/dist/assets/components/textarea/textarea.vue +1 -1
  296. package/dist/assets/components/timeline/components/timeline-item/timeline-item.stories.ts +1 -1
  297. package/dist/assets/components/timeline/components/timeline-item/timeline-item.vue +1 -1
  298. package/dist/assets/components/timeline/timeline.docs.mdx +0 -10
  299. package/dist/assets/components/timeline/timeline.internal.types.ts +1 -0
  300. package/dist/assets/components/timeline/timeline.stories.ts +1 -1
  301. package/dist/assets/components/timeline/timeline.types.ts +1 -1
  302. package/dist/assets/components/timeline/timeline.vue +1 -1
  303. package/dist/assets/components/toast/components/toast-item/toast-item.vue +1 -1
  304. package/dist/assets/components/toggle/toggle.stories.ts +1 -1
  305. package/dist/assets/components/toggle/toggle.types.ts +1 -1
  306. package/dist/assets/components/toggle/toggle.vue +1 -1
  307. package/dist/assets/components/tutorial/tutorial.stories.ts +1 -1
  308. package/dist/assets/components/typography/typography.stories.ts +1 -1
  309. package/dist/assets/components/typography/typography.types.ts +1 -1
  310. package/dist/assets/components/typography/typography.vue +1 -1
  311. package/dist/assets/components.json +1 -0
  312. package/dist/assets/composables/use-bento-base-filter/index.ts +1 -0
  313. package/dist/assets/composables/use-bento-base-filter/use-bento-base-filter.ts +1 -0
  314. package/dist/assets/composables/use-bento-base-filter/utils/index.ts +1 -0
  315. package/dist/assets/composables/use-bento-base-filter/utils/utils.ts +1 -0
  316. package/dist/assets/composables/use-bento-currency/index.ts +1 -0
  317. package/dist/assets/composables/use-bento-currency/use-bento-currency.stories.ts +1 -1
  318. package/dist/assets/composables/use-bento-currency/use-bento-currency.ts +1 -0
  319. package/dist/assets/composables/use-bento-delayed-hover/index.ts +1 -0
  320. package/dist/assets/composables/use-bento-delayed-hover/use-bento-delayed-hover.stories.ts +1 -1
  321. package/dist/assets/composables/use-bento-delayed-hover/use-bento-delayed-hover.ts +1 -0
  322. package/dist/assets/composables/use-bento-theme/index.ts +1 -0
  323. package/dist/assets/composables/use-bento-theme/install.ts +1 -1
  324. package/dist/assets/composables/use-bento-theme/install.types.ts +1 -1
  325. package/dist/assets/composables/use-bento-theme/use-bento-theme.ts +1 -0
  326. package/dist/assets/composables/use-bento-toast-controller/index.ts +1 -0
  327. package/dist/assets/composables/use-bento-toast-controller/toast-stack.ts +1 -0
  328. package/dist/assets/composables/use-bento-toast-controller/use-bento-toast-controller.ts +1 -0
  329. package/dist/assets/composables/use-click-outside/index.ts +1 -0
  330. package/dist/assets/composables/use-click-outside/use-click-outside.stories.ts +1 -1
  331. package/dist/assets/composables/use-click-outside/use-click-outside.ts +1 -0
  332. package/dist/assets/composables/use-form-validate/index.ts +1 -0
  333. package/dist/assets/composables/use-form-validate/use-form.ts +1 -0
  334. package/dist/assets/composables/use-form-validate/use-form.types.ts +1 -1
  335. package/dist/assets/composables.json +9 -0
  336. package/dist/assets/deprecations.md +139 -243
  337. package/dist/assets/directives/highlight/highlight.stories.ts +1 -1
  338. package/dist/assets/directives/keyboard-navigation/keyboard-navigation.stories.ts +1 -1
  339. package/dist/assets/directives/tooltip/tooltip.internal.types.ts +1 -0
  340. package/dist/assets/directives/tooltip/tooltip.stories.ts +1 -1
  341. package/dist/assets/directives/tooltip/tooltip.types.ts +1 -1
  342. package/dist/assets/icons.json +1 -0
  343. package/dist/assets/index.ts +1 -1
  344. package/dist/assets/install.ts +1 -1
  345. package/dist/assets/tailwind/README.md +3 -3
  346. package/dist/assets/templates/dashboard-template/components/dashboard-section/dashboard-section.stories.ts +1 -1
  347. package/dist/assets/templates/dashboard-template/dashboard-template.stories.ts +1 -1
  348. package/dist/assets/templates/data-grid-template/data-grid-template.stories.ts +1 -1
  349. package/dist/assets/usage.json +81 -80
  350. package/dist/assets/variables.css +152 -140
  351. package/dist/main.js +228 -34
  352. package/package.json +2 -2
  353. package/dist/assets/components/internal/base-button/base-button.types.ts +0 -1
  354. package/dist/assets/components/internal/base-button/base-button.vue +0 -1
  355. package/dist/assets/components/internal/button-actions-with-menu/button-actions-with-menu.stories.ts +0 -1
  356. package/dist/assets/components/internal/button-actions-with-menu/button-actions-with-menu.types.ts +0 -1
  357. package/dist/assets/components/internal/button-actions-with-menu/button-actions-with-menu.vue +0 -1
  358. package/dist/assets/components/internal/calendar/calendar.stories.ts +0 -1
  359. package/dist/assets/components/internal/calendar/calendar.types.ts +0 -1
  360. package/dist/assets/components/internal/calendar/calendar.vue +0 -1
  361. package/dist/assets/components/internal/calendar/components/calendar-month/calendar-month.stories.ts +0 -1
  362. package/dist/assets/components/internal/calendar/components/calendar-month/calendar-month.types.ts +0 -1
  363. package/dist/assets/components/internal/calendar/components/calendar-month/calendar-month.vue +0 -1
  364. package/dist/assets/components/internal/calendar/components/calendar-month/components/calendar-month-day/__test__/calendar-month-day-stub.vue +0 -1
  365. package/dist/assets/components/internal/calendar/components/calendar-month/components/calendar-month-day/calendar-month-day.stories.ts +0 -1
  366. package/dist/assets/components/internal/calendar/components/calendar-month/components/calendar-month-day/calendar-month-day.types.ts +0 -1
  367. package/dist/assets/components/internal/calendar/components/calendar-month/components/calendar-month-day/calendar-month-day.vue +0 -1
  368. package/dist/assets/components/internal/calendar/components/calendar-month/composables/granular-min-max-date.types.ts +0 -1
  369. package/dist/assets/components/internal/calendar/components/calendar-year/calendar-year.types.ts +0 -1
  370. package/dist/assets/components/internal/calendar/components/calendar-year/calendar-year.vue +0 -1
  371. package/dist/assets/components/internal/calendar/components/calendar-year/components/calendar-year-month/__test__/calendar-year-month-stub.vue +0 -1
  372. package/dist/assets/components/internal/calendar/components/calendar-year/components/calendar-year-month/calendar-year-month.types.ts +0 -1
  373. package/dist/assets/components/internal/calendar/components/calendar-year/components/calendar-year-month/calendar-year-month.vue +0 -1
  374. package/dist/assets/components/internal/calendar/components/calendar-year-selector/calendar-year-selector.types.ts +0 -1
  375. package/dist/assets/components/internal/calendar/components/calendar-year-selector/calendar-year-selector.vue +0 -1
  376. package/dist/assets/components/internal/calendar/composables/use-granularity-adjustments.types.ts +0 -1
  377. package/dist/assets/components/internal/calendar/composables/use-range-pane.types.ts +0 -1
  378. package/dist/assets/components/internal/checkbox-input/checkbox-input.stories.ts +0 -1
  379. package/dist/assets/components/internal/checkbox-input/checkbox-input.types.ts +0 -1
  380. package/dist/assets/components/internal/checkbox-input/checkbox-input.vue +0 -1
  381. package/dist/assets/components/internal/controls-group/controls-group.vue +0 -1
  382. package/dist/assets/components/internal/copy/copy.docs.mdx +0 -43
  383. package/dist/assets/components/internal/copy/copy.stories.ts +0 -1
  384. package/dist/assets/components/internal/copy/copy.types.ts +0 -1
  385. package/dist/assets/components/internal/copy/copy.vue +0 -1
  386. package/dist/assets/components/internal/decorative-checkbox/decorative-checkbox.vue +0 -1
  387. package/dist/assets/components/internal/dialog-page/dialog-page.types.ts +0 -1
  388. package/dist/assets/components/internal/dialog-page/dialog-page.vue +0 -1
  389. package/dist/assets/components/internal/error-message/error-message.vue +0 -1
  390. package/dist/assets/components/internal/field-label/field-label.vue +0 -1
  391. package/dist/assets/components/internal/fixed-scroller/fixed-scroller.docs.mdx +0 -21
  392. package/dist/assets/components/internal/fixed-scroller/fixed-scroller.stories.ts +0 -1
  393. package/dist/assets/components/internal/fixed-scroller/fixed-scroller.vue +0 -1
  394. package/dist/assets/components/internal/footer-actions/footer-actions.vue +0 -1
  395. package/dist/assets/components/internal/grid-layout/grid-layout.types.ts +0 -1
  396. package/dist/assets/components/internal/grid-layout/grid-layout.vue +0 -1
  397. package/dist/assets/components/internal/header-meta/header-meta.types.ts +0 -1
  398. package/dist/assets/components/internal/header-meta/header-meta.vue +0 -1
  399. package/dist/assets/components/internal/info-icon-with-popover/info-icon-with-popover.vue +0 -1
  400. package/dist/assets/components/internal/listbox/components/listbox-lazy-load/listbox-lazy-load.types.ts +0 -1
  401. package/dist/assets/components/internal/listbox/components/listbox-lazy-load/listbox-lazy-load.vue +0 -1
  402. package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/components/listbox-multi-select-category/listbox-multi-select-category.types.ts +0 -1
  403. package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/components/listbox-multi-select-category/listbox-multi-select-category.vue +0 -1
  404. package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/components/listbox-multi-select-nested-lazy-load/listbox-multi-select-nested-lazy-load.types.ts +0 -1
  405. package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/components/listbox-multi-select-nested-lazy-load/listbox-multi-select-nested-lazy-load.vue +0 -1
  406. package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/listbox-multi-select-options.types.ts +0 -1
  407. package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/listbox-multi-select-options.vue +0 -1
  408. package/dist/assets/components/internal/listbox/components/listbox-multi-select/listbox-multi-select.types.ts +0 -1
  409. package/dist/assets/components/internal/listbox/components/listbox-multi-select/listbox-multi-select.vue +0 -1
  410. package/dist/assets/components/internal/listbox/components/listbox-option/listbox-option.vue +0 -1
  411. package/dist/assets/components/internal/listbox/components/listbox-option-tag/listbox-option-tag.vue +0 -1
  412. package/dist/assets/components/internal/listbox/components/listbox-single-select/components/listbox-single-select-category/listbox-single-select-category.vue +0 -1
  413. package/dist/assets/components/internal/listbox/components/listbox-single-select/listbox-single-select.vue +0 -1
  414. package/dist/assets/components/internal/listbox/components/listbox-single-select-option/listbox-single-select-option.vue +0 -1
  415. package/dist/assets/components/internal/listbox/listbox.stories.ts +0 -1
  416. package/dist/assets/components/internal/listbox/listbox.types.ts +0 -1
  417. package/dist/assets/components/internal/listbox/listbox.vue +0 -1
  418. package/dist/assets/components/internal/radio-input/radio-input.stories.ts +0 -1
  419. package/dist/assets/components/internal/radio-input/radio-input.types.ts +0 -1
  420. package/dist/assets/components/internal/radio-input/radio-input.vue +0 -1
  421. package/dist/assets/components/internal/teleport/teleport.types.ts +0 -1
  422. package/dist/assets/components/internal/teleport/teleport.vue +0 -1
  423. package/dist/assets/components/internal/tooltip/tooltip.test.vue +0 -1
  424. package/dist/assets/components/internal/tooltip/tooltip.types.ts +0 -1
  425. package/dist/assets/components/internal/tooltip/tooltip.vue +0 -1
  426. package/dist/assets/composables/use-form-validate-zod-4/use-form.types.ts +0 -1
  427. package/dist/assets/composables/use-numeric-input/use-numeric-input.types.ts +0 -1
  428. package/dist/assets/composables/use-section-navigation-keyboard/use-section-navigation-keyboard.types.ts +0 -1
  429. package/dist/assets/composables/use-virtual-list/use-virtual-list.types.ts +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.12.0 (2026-09-09)
4
+
5
+ ### Features
6
+
7
+ - excluded internal components and added composable docs and MCP tools ([d6891800a](https://github.com/Adyen/bento/commit/d6891800a))
8
+ - improved design token discoverability in MCP ([f8be70c37](https://github.com/Adyen/bento/commit/f8be70c37))
9
+
10
+ Update packages/mcp/SKILL.md
11
+ Co-authored-by: Gerald Campbell <86044115+GeraldAdyen@users.noreply.github.com>
12
+ - added script to copy code snippet vue files into storybook data for each story ([c7938960f](https://github.com/Adyen/bento/commit/c7938960f))
13
+
14
+ ### Bug Fixes
15
+
16
+ - built design tokens before copying MCP assets ([d5b1fd9f5](https://github.com/Adyen/bento/commit/d5b1fd9f5))
17
+
18
+ ### Build System
19
+
20
+ - updated the AGENTS.md files structure and content, expanded with skills ([8c303283d](https://github.com/Adyen/bento/commit/8c303283d))
21
+
22
+ ### Miscellaneous Chores
23
+
24
+ - updated `pnpm` from `10` to `11` ([eddaae383](https://github.com/Adyen/bento/commit/eddaae383))
25
+ - updated `typescript` to `6.0.3` ([54f914b8c](https://github.com/Adyen/bento/commit/54f914b8c))
26
+
27
+ ### ❤️ Thank You
28
+
29
+ - daver
30
+ - gerald
31
+ - Gerald Campbell @GeraldAdyen
32
+
33
+
34
+ ## 0.11.0 (2026-07-29)
35
+
36
+ This was a version bump only for mcp to align it with other projects, there were no code changes.
37
+
38
+
3
39
  ## 0.10.0 (2026-07-21)
4
40
 
5
41
  ### Documentation
package/README.md CHANGED
@@ -114,6 +114,20 @@ this to understand which components are available in the library and their names
114
114
 
115
115
  - **Returns:** The list of components available in Bento.
116
116
 
117
+ ### `get_composable`
118
+
119
+ Retrieves all available documentation, stories, TypeScript implementations, and type definitions for a list of publicly
120
+ exported composables.
121
+
122
+ - **Arguments:** `composableNames` (`Array<string>`): A list of composable names, such as `["use-bento-currency"]`.
123
+ - **Returns:** A Markdown formatted string containing the composable's available documentation and TypeScript files.
124
+
125
+ ### `get_all_composables`
126
+
127
+ Retrieves the registry of composables publicly exported by Bento.
128
+
129
+ - **Returns:** The list of composables publicly exported by Bento.
130
+
117
131
  ### `get_deprecations`
118
132
 
119
133
  Retrieves the Bento Deprecations Registry. Use this to find out which components, properties, or features are deprecated
@@ -133,9 +147,17 @@ Retrieves specific documentation files for Bento.
133
147
  Retrieves Bento Design Tokens (CSS variables), grouped by semantic categories (color, spacing, border, shadow,
134
148
  animation, typography, layout).
135
149
 
150
+ - **When to use:** Call this before choosing colors, spacing, typography, borders, shadows, or other themeable values.
151
+ - **Token package:** Use `@adyen/bento-design-tokens`, whose generated CSS entry point is
152
+ `@adyen/bento-design-tokens/dist/css/bento/variables.css`.
136
153
  - **Arguments:** `searchQuery` (`string`, optional): A search term to filter tokens (e.g., `"critical"`, `"spacer"`,
137
- `"background"`).
138
- - **Returns:** A Markdown formatted string containing a categorized list of CSS variable names and their values.
154
+ `"background"`, `"label"`, `"decorative"`).
155
+ - **Returns:** A Markdown formatted string containing grouped CSS variable names, values, and the documented
156
+ descriptions for color alias groups. Prefer alias tokens over definition tokens. If no suitable token exists, submit a
157
+ design-token request instead of creating an arbitrary local value.
158
+ - **Token layers:** Color aliases are the semantic styling API. Use only variables returned by this tool. Public
159
+ foundation variables, such as spacers and border widths, are intentionally included and may come from source files
160
+ under `definitions`.
139
161
 
140
162
  ### `get_utility_classes`
141
163
 
package/SKILL.md CHANGED
@@ -21,19 +21,49 @@ If you need to install or configure Bento in a project:
21
21
  - Execute `get_docs({ docType: 'getting-started' })` for the core Bento installation guide.
22
22
  - Execute `get_docs({ docType: 'tailwind' })` if Tailwind integration is required.
23
23
 
24
- ### Step 1: Discovery (Check Existence)
24
+ ### Step 1: Token Discovery (Before Styling)
25
+
26
+ Before choosing colors, spacing, typography, borders, shadows, or other themeable values:
27
+
28
+ - **DO** execute `get_design_tokens()` to inspect the available Bento tokens and their documented groups.
29
+ - Tokens are provided by `@adyen/bento-design-tokens`. Its generated CSS entry point is
30
+ `@adyen/bento-design-tokens/dist/css/bento/variables.css`.
31
+ - Use `get_design_tokens({ searchQuery: 'background' })`, `get_design_tokens({ searchQuery: 'label' })`, or
32
+ `get_design_tokens({ searchQuery: 'decorative' })` to narrow the results.
33
+ - **USE** alias tokens such as `var(--b-color-label-primary)` and `var(--b-color-decorative-blue)`.
34
+ - Use only token names returned by `get_design_tokens`; do not construct or infer token names from the source token
35
+ structure.
36
+ - If no suitable Bento token exists, submit a design-token request. Do not invent an arbitrary local token or color.
37
+
38
+ The token output groups color aliases as `Background`, `Label`, `Link`, `Outline`, `Separator`, `Decorative`, and
39
+ `Support`, and includes the documented description for each group.
40
+
41
+ #### Alias and definition tokens
42
+
43
+ - **Alias tokens** are semantic, consumer-facing tokens. They describe intent, for example `--b-color-label-primary` or
44
+ `--b-color-background-critical-weak`, and should be preferred for component styling.
45
+ - Private definition files are implementation details and are not emitted to `variables.css` or returned by
46
+ `get_design_tokens`.
47
+ - The generated stylesheet also contains a small set of public foundation tokens, such as spacing, border
48
+ widths, shadows, and breakpoints. These are intentionally available CSS variables, even though their source files live
49
+ under `definitions`; use them when the MCP returns them.
50
+ - The MCP reads the generated `@adyen/bento-design-tokens/dist/css/bento/variables.css`, not the private YAML source
51
+ files. Therefore every token returned by `get_design_tokens` is available in the published stylesheet. Never infer or
52
+ construct private definition names.
53
+
54
+ ### Step 2: Discovery (Check Existence)
25
55
 
26
56
  If you are unsure if a Bento component exists or what it is called:
27
57
 
28
58
  - **DO NOT** use `ls`, `grep`, or `read_file` on `node_modules`.
29
59
  - **DO** execute `get_all_components()` to retrieve the official registry of components.
30
60
 
31
- ### Step 2: Inspection (Fetch Truth)
61
+ ### Step 3: Inspection (Fetch Truth)
32
62
 
33
63
  Once the component name is known:
34
64
 
35
65
  - Execute `get_component(['component-name'])`.
36
- - **If tools are missing:** Provide the user with the setup instructions in Section 2.
66
+ - **If tools are missing:** Provide the user with the setup instructions in Section 4.
37
67
 
38
68
  #### ⚠️ CRITICAL: Truncation & Completeness Rules
39
69
 
@@ -50,13 +80,13 @@ Once the component name is known:
50
80
  4. **Pre-Write Checklist:** Before any `write_file` or code edit, mentally verify: _"Have I called `get_component` for
51
81
  every Bento component in this file?"_ If the answer is no, **STOP** and fetch the missing components.
52
82
 
53
- ### Step 3: Constraints First (Read `.docs.mdx`)
83
+ ### Step 4: Constraints First (Read `.docs.mdx`)
54
84
 
55
85
  - **DO NOT SKIM.** Look specifically for **"Do not use"** and **"Guidelines"** sections.
56
86
  - **Rule:** If the docs say "text only," you MUST NOT use custom HTML in that slot.
57
87
  - **Rule:** If the docs say "max 2 buttons," you MUST NOT include 3.
58
88
 
59
- ### Step 4: Syntax & Logic Validation
89
+ ### Step 5: Syntax & Logic Validation
60
90
 
61
91
  - Check `.stories.ts` for correct icon imports from `@adyen/ui-assets-icons-16`.
62
92
  - Check `.vue` implementation for event names (e.g., `update:model-value`) and prop types.
@@ -132,9 +162,9 @@ If the Bento MCP tools are not available in your environment, add the following
132
162
 
133
163
  ---
134
164
 
135
- ## 📚 5. Immutable Documentation (Tailwind & Tokens)
165
+ ## 📚 5. Implementation Guidance (Tailwind & Token Usage)
136
166
 
137
- The following rules are NOT available via the MCP and must be followed strictly:
167
+ The following rules complement the information available through the MCP and must be followed strictly:
138
168
 
139
169
  ### Tailwind 4 "Golden Standard" Setup
140
170
 
@@ -1 +1 @@
1
- import { ref } from 'vue'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import { isVue2 } from 'vue-demi'; import BentoAccordion from './accordion.vue'; import BentoAccordionItem from './components/accordion-item.vue'; import { BentoButton } from '@/components/button'; import { BentoTypography } from '@/components/typography'; import type { Meta, StoryObj } from '@storybook/vue'; import { BentoAccordionTitleSizeOptions } from './accordion.types'; export default { title: 'Accordion', component: BentoAccordion, argTypes: { titleSize: { options: BentoAccordionTitleSizeOptions, control: { type: 'select', }, }, default: { control: false, table: { type: { summary: 'BentoAccordionItem[]' }, }, }, }, } as Meta; type Story = StoryObj<typeof BentoAccordion>; const DEFAULT_PROPS = { titleSize: 'default', }; const defaultCode = ` <template> <bento-accordion> <bento-accordion-item title="Alderaan" :is-expanded.sync="toggle"> <bento-typography> Alderaan had a reputation as one of the most peaceful and cultured worlds in the Galaxy, an idyllic locale for vacation or education in high demand among the denizens of Star Wars' most cultured and aspirational. </bento-typography> </bento-accordion-item> <bento-accordion-item title="Coruscant" is-expanded> <bento-typography> Coruscant is among the most diverse locales in the Galaxy, though it tends to be humans who hold wealth and power. Although it appears a flawless futuristic paradise on its surface, the lower you descend into the city's levels, the more crime and poverty you'll find. </bento-typography> </bento-accordion-item> <bento-accordion-item title="Dagobah"> <bento-typography> A swamp planet teeming with so much life that any manner of Force detection is rendered irrelevant, Dagobah is where Jedi Grandmaster in exile Yoda made his home for the last years of his life following the fall of the Jedi Order, awaiting the arrival of his final pupil and the Galaxy's last hope. </bento-typography> </bento-accordion-item> <bento-accordion-item title="Hoth"> <bento-typography> This snowy ice planet was home to the Rebellion's Echo Base, which Leia, Han, and Luke called home when the Empire titularly struck back in The Empire Strikes Back. Luke fights a wampa, Han guts a tauntaun for warmth, and the rebels hogtie some elephantine AT-AT imperial walkers with their snowspeeders here before beating a hasty retreat from the Empire. </bento-typography> </bento-accordion-item> </bento-accordion> <bento-button type="button" style="margin-top: 1rem" @click="toggle = !toggle">Toggle "Alderaan"</bento-button> </template> <script setup lang="ts"> import { BentoAccordion, BentoAccordionItem, BentoTypography, BentoButton } from '@adyen/bento-vue2' const toggle = ref(false); </script> `; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoAccordion, BentoAccordionItem, BentoButton, BentoTypography }, props: Object.keys(argTypes), template: ` <div> <bento-accordion v-bind="args"> <bento-accordion-item title="Alderaan" :is-expanded.sync="toggle"> <bento-typography> Alderaan had a reputation as one of the most peaceful and cultured worlds in the Galaxy, an idyllic locale for vacation or education in high demand among the denizens of Star Wars' most cultured and aspirational. </bento-typography> </bento-accordion-item> <bento-accordion-item title="Coruscant" is-expanded> <bento-typography> Coruscant is among the most diverse locales in the Galaxy, though it tends to be humans who hold wealth and power. Although it appears a flawless futuristic paradise on its surface, the lower you descend into the city's levels, the more crime and poverty you'll find. </bento-typography> </bento-accordion-item> <bento-accordion-item title="Dagobah"> <bento-typography> A swamp planet teeming with so much life that any manner of Force detection is rendered irrelevant, Dagobah is where Jedi Grandmaster in exile Yoda made his home for the last years of his life following the fall of the Jedi Order, awaiting the arrival of his final pupil and the Galaxy's last hope. </bento-typography> </bento-accordion-item> <bento-accordion-item title="Hoth"> <bento-typography> This snowy ice planet was home to the Rebellion's Echo Base, which Leia, Han, and Luke called home when the Empire titularly struck back in The Empire Strikes Back. Luke fights a wampa, Han guts a tauntaun for warmth, and the rebels hogtie some elephantine AT-AT imperial walkers with their snowspeeders here before beating a hasty retreat from the Empire. </bento-typography> </bento-accordion-item> </bento-accordion> <bento-button type="button" style="margin-top: 1rem" @click="toggle = !toggle">Toggle "Alderaan"</bento-button> </div> `, setup(props) { const toggle = ref(false); return { args: isVue2 ? props : _args, toggle }; }, }), args: DEFAULT_PROPS, parameters: storybookDocsParameter(defaultCode), };
1
+ import { ref } from 'vue'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import { isVue2 } from 'vue-demi'; import BentoAccordion from './accordion.vue'; import BentoAccordionItem from './components/accordion-item.vue'; import { BentoButton } from '@/components/button'; import { BentoTypography } from '@/components/typography'; import type { Meta, StoryObj } from '@storybook/vue'; import { BentoAccordionTitleSizeOptions } from './accordion.types'; const AccordionDefault = "<template>\n <div>\n <bento-accordion>\n <bento-accordion-item :is-expanded=\"toggle\" title=\"Alderaan\" @update:is-expanded=\"toggle = $event\">\n <bento-typography>\n Alderaan had a reputation as one of the most peaceful and cultured worlds in the Galaxy, an idyllic\n locale for vacation or education in high demand among the denizens of Star Wars' most cultured and\n aspirational.\n </bento-typography>\n </bento-accordion-item>\n <bento-accordion-item is-expanded title=\"Coruscant\">\n <bento-typography>\n Coruscant is among the most diverse locales in the Galaxy, though it tends to be humans who hold\n wealth and power. Although it appears a flawless futuristic paradise on its surface, the lower you\n descend into the city's levels, the more crime and poverty you'll find.\n </bento-typography>\n </bento-accordion-item>\n <bento-accordion-item title=\"Dagobah\">\n <bento-typography>\n A swamp planet teeming with so much life that any manner of Force detection is rendered irrelevant,\n Dagobah is where Jedi Grandmaster in exile Yoda made his home for the last years of his life\n following the fall of the Jedi Order, awaiting the arrival of his final pupil and the Galaxy's last\n hope.\n </bento-typography>\n </bento-accordion-item>\n <bento-accordion-item title=\"Hoth\">\n <bento-typography>\n This snowy ice planet was home to the Rebellion's Echo Base, which Leia, Han, and Luke called home\n when the Empire titularly struck back in The Empire Strikes Back. Luke fights a wampa, Han guts a\n tauntaun for warmth, and the rebels hogtie some elephantine AT-AT imperial walkers with their\n snowspeeders here before beating a hasty retreat from the Empire.\n </bento-typography>\n </bento-accordion-item>\n </bento-accordion>\n\n <bento-button style=\"margin-top: 1rem\" type=\"button\" @click=\"toggle = !toggle\">\n Toggle \"Alderaan\"\n </bento-button>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref } from 'vue';\n import { BentoAccordion, BentoAccordionItem, BentoButton, BentoTypography } from '@adyen/bento-vue2';\n\n const toggle = ref(false);\n</script>\n"; export default { title: 'Accordion', component: BentoAccordion, argTypes: { titleSize: { options: BentoAccordionTitleSizeOptions, control: { type: 'select', }, }, default: { control: false, table: { type: { summary: 'BentoAccordionItem[]' }, }, }, }, } as Meta; type Story = StoryObj<typeof BentoAccordion>; const DEFAULT_PROPS = { titleSize: 'default', }; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoAccordion, BentoAccordionItem, BentoButton, BentoTypography }, props: Object.keys(argTypes), template: ` <div> <bento-accordion v-bind="args"> <bento-accordion-item title="Alderaan" :is-expanded.sync="toggle"> <bento-typography> Alderaan had a reputation as one of the most peaceful and cultured worlds in the Galaxy, an idyllic locale for vacation or education in high demand among the denizens of Star Wars' most cultured and aspirational. </bento-typography> </bento-accordion-item> <bento-accordion-item title="Coruscant" is-expanded> <bento-typography> Coruscant is among the most diverse locales in the Galaxy, though it tends to be humans who hold wealth and power. Although it appears a flawless futuristic paradise on its surface, the lower you descend into the city's levels, the more crime and poverty you'll find. </bento-typography> </bento-accordion-item> <bento-accordion-item title="Dagobah"> <bento-typography> A swamp planet teeming with so much life that any manner of Force detection is rendered irrelevant, Dagobah is where Jedi Grandmaster in exile Yoda made his home for the last years of his life following the fall of the Jedi Order, awaiting the arrival of his final pupil and the Galaxy's last hope. </bento-typography> </bento-accordion-item> <bento-accordion-item title="Hoth"> <bento-typography> This snowy ice planet was home to the Rebellion's Echo Base, which Leia, Han, and Luke called home when the Empire titularly struck back in The Empire Strikes Back. Luke fights a wampa, Han guts a tauntaun for warmth, and the rebels hogtie some elephantine AT-AT imperial walkers with their snowspeeders here before beating a hasty retreat from the Empire. </bento-typography> </bento-accordion-item> </bento-accordion> <bento-button type="button" style="margin-top: 1rem" @click="toggle = !toggle">Toggle "Alderaan"</bento-button> </div> `, setup(props) { const toggle = ref(false); return { args: isVue2 ? props : _args, toggle }; }, }), args: DEFAULT_PROPS, parameters: storybookDocsParameter(AccordionDefault), };
@@ -1 +1 @@
1
- import { isVue2 } from 'vue-demi'; import BentoAccordionItem from './accordion-item.vue'; import { BentoTypography } from '@/components/typography'; import type { Meta, StoryObj } from '@storybook/vue'; export default { title: 'Accordion/Accordion Item', component: BentoAccordionItem, argTypes: { default: { name: 'default', type: { name: 'string', required: false }, description: 'Content of the BentoAccordionItem', control: 'text', table: { type: { summary: 'VNode[]' }, }, }, 'update:is-expanded': { control: false, table: { type: { summary: '($event) => void' }, }, }, }, } as Meta; type Story = StoryObj<typeof BentoAccordionItem>; const DEFAULT_PROPS = { title: 'Default title', default: 'Are you threatening me, Master Jedi? Once more the Sith will rule the galaxy.', isExpanded: true, }; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoAccordionItem, BentoTypography }, props: Object.keys(argTypes), template: ` <bento-accordion-item v-bind="args"> <bento-typography> {{ args.default }} </bento-typography> </bento-accordion-item> `, setup(props) { return { args: isVue2 ? props : _args }; }, }), args: DEFAULT_PROPS, };
1
+ import { isVue2 } from 'vue-demi'; import BentoAccordionItem from './accordion-item.vue'; import { BentoTypography } from '@/components/typography'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import type { Meta, StoryObj } from '@storybook/vue'; const AccordionItemDefault = "<template>\n <bento-accordion-item is-expanded title=\"Default title\">\n <bento-typography>\n Are you threatening me, Master Jedi? Once more the Sith will rule the galaxy.\n </bento-typography>\n </bento-accordion-item>\n</template>\n\n<script setup lang=\"ts\">\n import { BentoAccordionItem, BentoTypography } from '@adyen/bento-vue2';\n</script>\n"; export default { title: 'Accordion/Accordion Item', component: BentoAccordionItem, argTypes: { default: { name: 'default', type: { name: 'string', required: false }, description: 'Content of the BentoAccordionItem', control: 'text', table: { type: { summary: 'VNode[]' }, }, }, 'update:is-expanded': { control: false, table: { type: { summary: '($event) => void' }, }, }, }, } as Meta; type Story = StoryObj<typeof BentoAccordionItem>; const DEFAULT_PROPS = { title: 'Default title', default: 'Are you threatening me, Master Jedi? Once more the Sith will rule the galaxy.', isExpanded: true, }; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoAccordionItem, BentoTypography }, props: Object.keys(argTypes), template: ` <bento-accordion-item v-bind="args"> <bento-typography> {{ args.default }} </bento-typography> </bento-accordion-item> `, setup(props) { return { args: isVue2 ? props : _args }; }, }), args: DEFAULT_PROPS, parameters: storybookDocsParameter(AccordionItemDefault), };
@@ -1 +1 @@
1
- <template> <div class="b-accordion-item"> <bento-typography el="h3" :variant="titleSize === 'small' ? 'body' : 'title'" :strongest="titleSize === 'small'" > <button :id="buttonId" :aria-controls="contentId" :aria-expanded="`${isOpen}`" type="button" class="b-accordion-item__button" @click="isOpen = !isOpen" > <chevron-up-icon v-if="isOpen" class="b-accordion-item__icon" :svg-title="t('collapse')" aria-hidden="true" /> <chevron-down-icon v-else class="b-accordion-item__icon" :svg-title="t('expand')" aria-hidden="true" /> {{ title }} </button> </bento-typography> <Transition :name="CONTENT_TRANSITION_NAME"> <div v-if="isOpen" :id="contentId" :aria-labelledby="buttonId" role="region" :style="contentMaxHeight"> <div ref="contentDiv" class="b-accordion-item__content"> <slot /> </div> </div> </Transition> </div> </template> <script setup lang="ts"> import { computed, inject, ref, watch } from 'vue'; import { BentoTypography } from '@/components/typography'; import ChevronDownIcon from '@adyen/ui-assets-icons-16/vue/chevron-down'; import ChevronUpIcon from '@adyen/ui-assets-icons-16/vue/chevron-up'; import { generateUid } from '@/core/utils/ts'; import { useI18n } from '@/utils/ts/i18n'; import { ACCORDION_TITLE_SIZE_INJECTION_KEY } from '../accordion.keys'; import type { BentoAccordionTitleSize } from '../accordion.types'; import { useExpandableContentHeight } from '@/composables/use-expandable-content-height/use-expandable-content-height'; import messages from './messages.json'; type MessageSchema = (typeof messages)['en-US']; const CONTENT_TRANSITION_NAME = 'b-accordion-item__animation--content'; const props = defineProps({ /** * Sets the title of the accordion item. */ title: { type: String, required: true, }, /** * Controls if the content is visible or hidden. */ isExpanded: { type: Boolean, default: false, }, }); const emit = defineEmits<{ /** * Emits update event when content is toggled */ (e: 'update:is-expanded', value: boolean): void; }>(); const { t } = useI18n<{ message: MessageSchema }>({ messages }); // Refs const contentDiv = ref<HTMLDivElement>(null); const isOpen = ref(props.isExpanded); // Generating IDs const buttonId = generateUid('accordionItemButton'); const contentId = generateUid('accordionItemContent'); // Injecting prop from parent const titleSize = inject<`${BentoAccordionTitleSize}`>(ACCORDION_TITLE_SIZE_INJECTION_KEY, 'default'); // Getting and setting the item height to be able to handle height animation const { contentHeight } = useExpandableContentHeight(contentDiv, isOpen); const contentMaxHeight = computed(() => (contentHeight.value ? { 'max-height': contentHeight.value } : {})); watch( () => props.isExpanded, value => { isOpen.value = value; } ); watch( isOpen, value => { // Enable two-way data binding for `isExpanded` emit('update:is-expanded', value); }, { immediate: true } ); </script> <script lang="ts"> /** * An accordion item is an interactive header used to reveal or hide a * section of content associated with this header. * * This component must always be wrapped by a `BentoAccordion` component. * * @example * import { BentoAccordion, BentoAccordionItem } from '@adyen/bento-vue2'; * * export default { * components: { BentoAccordion, BentoAccordionItem }, * template: ` * <bento-accordion> * <bento-accordion-item title="Item 1"> * Content for item 1 * </bento-accordion-item> * <bento-accordion-item title="Item 2"> * Content for item 2 * </bento-accordion-item> * </bento-accordion> * ` * } */ export default { i18n: { messages }, }; </script> <style lang="scss" scoped src="./accordion-item.scss" />
1
+ <template> <div class="b-accordion-item"> <bento-typography el="h3" :variant="titleSize === 'small' ? 'body' : 'title'" :strongest="titleSize === 'small'" > <button :id="buttonId" :aria-controls="contentId" :aria-expanded="`${isOpen}`" type="button" class="b-accordion-item__button" @click="isOpen = !isOpen" > <chevron-up-icon v-if="isOpen" class="b-accordion-item__icon" :svg-title="t('collapse')" aria-hidden="true" /> <chevron-down-icon v-else class="b-accordion-item__icon" :svg-title="t('expand')" aria-hidden="true" /> {{ title }} </button> </bento-typography> <Transition :name="CONTENT_TRANSITION_NAME"> <div v-if="isOpen" :id="contentId" :aria-labelledby="buttonId" role="region" :style="contentMaxHeight"> <div ref="contentDiv" class="b-accordion-item__content"> <slot /> </div> </div> </Transition> </div> </template> <script setup lang="ts"> import { computed, inject, ref, watch } from 'vue'; import { BentoTypography } from '@/components/typography'; import ChevronDownIcon from '@adyen/ui-assets-icons-16/vue/chevron-down'; import ChevronUpIcon from '@adyen/ui-assets-icons-16/vue/chevron-up'; import { generateUid } from '@/utils/ts/generate-uid'; import { useI18n } from '@/utils/ts/i18n'; import { ACCORDION_TITLE_SIZE_INJECTION_KEY } from '../accordion.keys'; import type { BentoAccordionTitleSize } from '../accordion.types'; import { useExpandableContentHeight } from '@/composables/use-expandable-content-height/use-expandable-content-height'; import messages from './messages.json'; type MessageSchema = (typeof messages)['en-US']; const CONTENT_TRANSITION_NAME = 'b-accordion-item__animation--content'; const props = defineProps({ /** * Sets the title of the accordion item. */ title: { type: String, required: true, }, /** * Controls if the content is visible or hidden. */ isExpanded: { type: Boolean, default: false, }, }); const emit = defineEmits<{ /** * Emits update event when content is toggled */ (e: 'update:is-expanded', value: boolean): void; }>(); const { t } = useI18n<{ message: MessageSchema }>({ messages }); // Refs const contentDiv = ref<HTMLDivElement>(null); const isOpen = ref(props.isExpanded); // Generating IDs const buttonId = generateUid('accordionItemButton'); const contentId = generateUid('accordionItemContent'); // Injecting prop from parent const titleSize = inject<`${BentoAccordionTitleSize}`>(ACCORDION_TITLE_SIZE_INJECTION_KEY, 'default'); // Getting and setting the item height to be able to handle height animation const { contentHeight } = useExpandableContentHeight(contentDiv, isOpen); const contentMaxHeight = computed(() => (contentHeight.value ? { 'max-height': contentHeight.value } : {})); watch( () => props.isExpanded, value => { isOpen.value = value; } ); watch( isOpen, value => { // Enable two-way data binding for `isExpanded` emit('update:is-expanded', value); }, { immediate: true } ); </script> <script lang="ts"> /** * An accordion item is an interactive header used to reveal or hide a * section of content associated with this header. * * This component must always be wrapped by a `BentoAccordion` component. * * @example * import { BentoAccordion, BentoAccordionItem } from '@adyen/bento-vue2'; * * export default { * components: { BentoAccordion, BentoAccordionItem }, * template: ` * <bento-accordion> * <bento-accordion-item title="Item 1"> * Content for item 1 * </bento-accordion-item> * <bento-accordion-item title="Item 2"> * Content for item 2 * </bento-accordion-item> * </bento-accordion> * ` * } */ export default { i18n: { messages }, name: 'bento-accordion-item', }; </script> <style lang="scss" scoped src="./accordion-item.scss" />
@@ -67,12 +67,19 @@ The Action bar component comes in two variants - `default` and `confirmation`.
67
67
 
68
68
  ### Default
69
69
 
70
- The default variant should be used for any generic case, accepts all props.
70
+ The default variant should be used for any generic case. Use `dismissible` to control the close button and
71
+ `selectionLabel` to customize the label following the item counter. When `selectionLabel` is omitted, it defaults to the
72
+ localized “selected” label. Pass `null` to hide the complete selection summary. For arbitrary content, the optional
73
+ `selectionLabel` slot overrides the complete summary and exposes `itemCounter` and `label` as slot properties. Set
74
+ `dismissible` to `false` when the Action Bar must not render a close button.
75
+
76
+ <Canvas of={ActionBarStories.WithoutLabel} />
71
77
 
72
78
  ### Confirmation
73
79
 
74
- To be used to confirm changes in a page. Only takes the `itemCounter` prop, the `selectionLabel` will always be 'unsaved
75
- changes' and the `actions` are always 'Save' and 'Cancel'. It also has no close button.
80
+ Use the confirmation variant to confirm changes on a page. Provide `itemCounter` to render the localized
81
+ `{count} unsaved change(s)` summary. The `selectionLabel` prop and slot, `dismissible`, and `actions` do not apply: its
82
+ label is fixed, its actions are always “Save” and “Cancel”, and it has no close button.
76
83
 
77
84
  ## State
78
85
 
@@ -0,0 +1 @@
1
+ export const BentoActionBarVariantOptions = ['default', 'confirmation'] as const; export const BentoActionBarStateOptions = ['start', 'loading', 'success', 'fail'] as const;
@@ -1 +1 @@
1
- import { action } from '@storybook/addon-actions'; import { computed, ref, watch } from 'vue'; import { isVue2 } from 'vue-demi'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import BentoActionBar from './action-bar.vue'; import { BentoButton } from '@/components/button'; import type { Meta, StoryObj } from '@storybook/vue'; import BinIcon from '@adyen/ui-assets-icons-16/vue/bin'; import EditIcon from '@adyen/ui-assets-icons-16/vue/edit-1'; import { BentoActionBarStateOptions, BentoActionBarVariantOptions } from './action-bar.types.ts'; import ActionBarDefault from './__tests__/action-bar-default.vue?raw'; const meta: Meta = { title: 'Action bar', component: BentoActionBar, argTypes: { variant: { options: BentoActionBarVariantOptions, control: { type: 'select', }, }, state: { options: BentoActionBarStateOptions, control: { type: 'select', }, }, // Slots stateLabel: { description: 'Custom text for the action bar state label.', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text' }, }, }, parameters: { layout: 'fullscreen', }, }; export default meta; type Story = StoryObj<typeof BentoActionBar>; const DEFAULT_ACTIONS = [ { title: 'Assign to...', disabled: true, event: () => true, }, { title: 'Snooze', event: () => true, }, { title: 'Edit', icon: EditIcon, event: () => true, }, { title: 'Delete', critical: true, icon: BinIcon, event: () => true, }, { title: 'Extra option', event: () => true, }, ]; const DEFAULT_PROPS = { actions: DEFAULT_ACTIONS, selectionLabel: 'selected', itemCounter: 3, variant: 'default', state: 'start', extraBottomSpacing: false, visibleActions: 4, }; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoActionBar, BentoButton }, props: Object.keys(argTypes), template: ` <div style="height:140px"> <bento-button @click='toggleActionBar = !toggleActionBar'>Toggle action bar</bento-button> <bento-action-bar v-if='toggleActionBar' v-bind="args" :actions="actions" @close="closeAction" @cancel="cancelAction" @save="saveAction" @retry-action="retryAction" @undo-action="undoAction" @cancel-action="cancelStateAction" :state="state" :show-undo-action="showUndoAction" > <template #stateLabel>{{ slotStateLabel }}</template> </bento-action-bar> </div> `, setup(props) { const args = isVue2 ? props : _args; const state = ref<string>(args.state); const operation = ref<'delete' | 'restore'>('delete'); const timeoutRef = ref<ReturnType<typeof setTimeout> | null>(null); const cancelAction = () => action('cancel')(); const saveAction = () => action('save')(); const toggleActionBar = ref(true); const closeAction = () => { action('close')(); toggleActionBar.value = false; }; const clearTimer = () => { if (timeoutRef.value) { clearTimeout(timeoutRef.value); timeoutRef.value = null; } }; const showSuccessAndReset = () => { state.value = 'success'; timeoutRef.value = setTimeout(() => { state.value = 'start'; operation.value = 'delete'; timeoutRef.value = null; }, 3000); }; const setLoading = (nextOperation: 'delete' | 'restore', callback: () => void) => { clearTimer(); state.value = 'loading'; operation.value = nextOperation; timeoutRef.value = setTimeout(() => { timeoutRef.value = null; callback(); }, 1000); }; const deleteAction = () => { setLoading('delete', () => { state.value = 'fail'; }); }; const retryAction = () => { setLoading('delete', showSuccessAndReset); action('retry-action')(); }; const undoAction = () => { setLoading('restore', showSuccessAndReset); action('undo-action')(); }; const cancelStateAction = () => { state.value = 'start'; operation.value = 'delete'; action('cancel-action')(); }; const actions = DEFAULT_ACTIONS.map(a => (a.title === 'Delete' ? { ...a, event: deleteAction } : a)); const showUndoAction = computed(() => args.showUndoAction && operation.value === 'delete'); const stateLabel = computed(() => { switch (state.value) { case 'loading': return operation.value === 'restore' ? 'Restoring...' : 'Deleting...'; case 'fail': return operation.value === 'restore' ? 'Could not restore the item. Please try again.' : 'Could not delete the item. Please try again.'; case 'success': return operation.value === 'restore' ? 'Item was restored' : 'Item was deleted.'; default: return ''; } }); const slotStateLabel = computed(() => args.stateLabel || stateLabel.value); watch( () => args.state, value => { state.value = value; if (value === 'start') { operation.value = 'delete'; } } ); return { // Values args, state, toggleActionBar, slotStateLabel, actions, showUndoAction, // Events closeAction, cancelAction, saveAction, deleteAction, retryAction, undoAction, cancelStateAction, }; }, }), args: { ...DEFAULT_PROPS, showUndoAction: true, showRetryAction: true, }, parameters: storybookDocsParameter(ActionBarDefault), };
1
+ import { action } from '@storybook/addon-actions'; import { computed, ref, watch } from 'vue'; import { isVue2 } from 'vue-demi'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import BentoActionBar from './action-bar.vue'; import { BentoButton } from '@/components/button'; import type { Meta, StoryObj } from '@storybook/vue'; import BinIcon from '@adyen/ui-assets-icons-16/vue/bin'; import EditIcon from '@adyen/ui-assets-icons-16/vue/edit-1'; import RefreshIcon from '@adyen/ui-assets-icons-16/vue/refresh'; import ZoomInIcon from '@adyen/ui-assets-icons-16/vue/zoom-in'; import ZoomOutIcon from '@adyen/ui-assets-icons-16/vue/zoom-out'; import { BentoActionBarStateOptions, BentoActionBarVariantOptions } from './action-bar.internal.types'; const ActionBarWithCustomLabel = "<template>\n <bento-action-bar :actions=\"actions\" :item-counter=\"3\" selection-label=\"ready\">\n <template #selectionLabel=\"{ itemCounter, label }\">\n <strong>{{ itemCounter }}</strong> payments {{ label }}\n </template>\n </bento-action-bar>\n</template>\n\n<script setup lang=\"ts\">\n import { BentoActionBar, type BentoButtonActionsList } from '@adyen/bento-vue2';\n\n const actions: BentoButtonActionsList = [\n {\n title: 'Review',\n event: () => undefined,\n },\n ];\n</script>\n"; const ActionBarWithoutLabel = "<template>\n <bento-action-bar :actions=\"actions\" :dismissible=\"false\" :selection-label=\"null\" />\n</template>\n\n<script setup lang=\"ts\">\n import { BentoActionBar, type BentoButtonActionsList } from '@adyen/bento-vue2';\n import RefreshIcon from '@adyen/ui-assets-icons-16/vue/refresh';\n import ZoomInIcon from '@adyen/ui-assets-icons-16/vue/zoom-in';\n import ZoomOutIcon from '@adyen/ui-assets-icons-16/vue/zoom-out';\n\n const actions: BentoButtonActionsList = [\n {\n title: 'Zoom in',\n icon: ZoomInIcon,\n iconOnly: true,\n event: () => undefined,\n },\n {\n title: 'Zoom out',\n icon: ZoomOutIcon,\n iconOnly: true,\n event: () => undefined,\n },\n {\n title: 'Reset',\n icon: RefreshIcon,\n event: () => undefined,\n },\n ];\n</script>\n"; const ActionBarDefault = "<template>\n <div>\n <bento-button @click=\"toggleActionBar = !toggleActionBar\">Toggle action bar</bento-button>\n <bento-action-bar\n v-if=\"toggleActionBar\"\n :actions=\"actions\"\n :state=\"state\"\n :show-undo-action=\"showUndoAction\"\n :item-counter=\"3\"\n show-retry-action\n @close=\"closeAction\"\n @retry-action=\"retryAction\"\n @undo-action=\"undoAction\"\n @cancel-action=\"cancelAction\"\n >\n <template #stateLabel>{{ stateLabel }}</template>\n </bento-action-bar>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n /* eslint-disable no-console */\n import { computed, ref } from 'vue';\n import { BentoActionBar, type BentoActionBarState, BentoButton } from '@adyen/bento-vue2';\n import BinIcon from '@adyen/ui-assets-icons-16/vue/bin';\n import EditIcon from '@adyen/ui-assets-icons-16/vue/edit-1';\n\n const state = ref<BentoActionBarState>('start');\n const operation = ref<'delete' | 'restore'>('delete');\n const timeoutRef = ref<ReturnType<typeof setTimeout> | null>(null);\n const toggleActionBar = ref(true);\n\n const clearTimer = () => {\n if (timeoutRef.value) {\n clearTimeout(timeoutRef.value);\n timeoutRef.value = null;\n }\n };\n\n const showSuccessAndReset = () => {\n state.value = 'success';\n timeoutRef.value = setTimeout(() => {\n state.value = 'start';\n operation.value = 'delete';\n timeoutRef.value = null;\n }, 3000);\n };\n\n const setLoading = (nextOperation: 'delete' | 'restore', callback: () => void) => {\n clearTimer();\n state.value = 'loading';\n operation.value = nextOperation;\n timeoutRef.value = setTimeout(() => {\n timeoutRef.value = null;\n callback();\n }, 1000);\n };\n\n const closeAction = () => {\n toggleActionBar.value = false;\n };\n\n const deleteAction = () => {\n setLoading('delete', () => {\n state.value = 'fail';\n });\n };\n\n const retryAction = () => {\n setLoading('delete', showSuccessAndReset);\n };\n\n const undoAction = () => {\n setLoading('restore', showSuccessAndReset);\n };\n\n const cancelAction = () => {\n state.value = 'start';\n operation.value = 'delete';\n };\n\n const actions = [\n {\n title: 'Assign to...',\n disabled: true,\n event: () => true,\n },\n {\n title: 'Snooze',\n event: () => console.log('snooze'),\n },\n {\n title: 'Edit',\n icon: EditIcon,\n event: () => console.log('edit'),\n },\n {\n title: 'Delete',\n critical: true,\n icon: BinIcon,\n event: deleteAction,\n },\n {\n title: 'Extra option',\n event: () => console.log('extra option'),\n },\n ];\n\n const showUndoAction = computed(() => operation.value === 'delete');\n\n const stateLabel = computed(() => {\n switch (state.value) {\n case 'loading':\n return operation.value === 'restore' ? 'Restoring...' : 'Deleting...';\n case 'fail':\n return operation.value === 'restore'\n ? 'Could not restore the item. Please try again.'\n : 'Could not delete the item. Please try again.';\n case 'success':\n return operation.value === 'restore' ? 'Item was restored' : 'Item was deleted.';\n default:\n return '';\n }\n });\n</script>\n"; const meta: Meta = { title: 'Action bar', component: BentoActionBar, argTypes: { variant: { options: BentoActionBarVariantOptions, control: { type: 'select', }, }, state: { options: BentoActionBarStateOptions, control: { type: 'select', }, }, // Slots selectionLabel: { description: 'Custom content for the complete selection summary in the `default` variant.', table: { type: { summary: 'VNode[]' }, }, control: { disable: true }, }, stateLabel: { description: 'Custom text for the action bar state label.', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text' }, }, }, parameters: { layout: 'fullscreen', }, }; export default meta; type Story = StoryObj<typeof BentoActionBar>; const DEFAULT_ACTIONS = [ { title: 'Assign to...', disabled: true, event: () => true, }, { title: 'Snooze', event: () => true, }, { title: 'Edit', icon: EditIcon, event: () => true, }, { title: 'Delete', critical: true, icon: BinIcon, event: () => true, }, { title: 'Extra option', event: () => true, }, ]; const DEFAULT_PROPS = { actions: DEFAULT_ACTIONS, selectionLabel: 'selected', itemCounter: 3, variant: 'default', state: 'start', extraBottomSpacing: false, visibleActions: 4, }; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoActionBar, BentoButton }, props: Object.keys(argTypes), template: ` <div style="height:140px"> <bento-button @click='toggleActionBar = !toggleActionBar'>Toggle action bar</bento-button> <bento-action-bar v-if='toggleActionBar' v-bind="args" :actions="actions" @close="closeAction" @cancel="cancelAction" @save="saveAction" @retry-action="retryAction" @undo-action="undoAction" @cancel-action="cancelStateAction" :state="state" :show-undo-action="showUndoAction" > <template #stateLabel>{{ slotStateLabel }}</template> </bento-action-bar> </div> `, setup(props) { const args = isVue2 ? props : _args; const state = ref<string>(args.state); const operation = ref<'delete' | 'restore'>('delete'); const timeoutRef = ref<ReturnType<typeof setTimeout> | null>(null); const cancelAction = () => action('cancel')(); const saveAction = () => action('save')(); const toggleActionBar = ref(true); const closeAction = () => { action('close')(); toggleActionBar.value = false; }; const clearTimer = () => { if (timeoutRef.value) { clearTimeout(timeoutRef.value); timeoutRef.value = null; } }; const showSuccessAndReset = () => { state.value = 'success'; timeoutRef.value = setTimeout(() => { state.value = 'start'; operation.value = 'delete'; timeoutRef.value = null; }, 3000); }; const setLoading = (nextOperation: 'delete' | 'restore', callback: () => void) => { clearTimer(); state.value = 'loading'; operation.value = nextOperation; timeoutRef.value = setTimeout(() => { timeoutRef.value = null; callback(); }, 1000); }; const deleteAction = () => { setLoading('delete', () => { state.value = 'fail'; }); }; const retryAction = () => { setLoading('delete', showSuccessAndReset); action('retry-action')(); }; const undoAction = () => { setLoading('restore', showSuccessAndReset); action('undo-action')(); }; const cancelStateAction = () => { state.value = 'start'; operation.value = 'delete'; action('cancel-action')(); }; const actions = DEFAULT_ACTIONS.map(a => (a.title === 'Delete' ? { ...a, event: deleteAction } : a)); const showUndoAction = computed(() => args.showUndoAction && operation.value === 'delete'); const stateLabel = computed(() => { switch (state.value) { case 'loading': return operation.value === 'restore' ? 'Restoring...' : 'Deleting...'; case 'fail': return operation.value === 'restore' ? 'Could not restore the item. Please try again.' : 'Could not delete the item. Please try again.'; case 'success': return operation.value === 'restore' ? 'Item was restored' : 'Item was deleted.'; default: return ''; } }); const slotStateLabel = computed(() => args.stateLabel || stateLabel.value); watch( () => args.state, value => { state.value = value; if (value === 'start') { operation.value = 'delete'; } } ); return { // Values args, state, toggleActionBar, slotStateLabel, actions, showUndoAction, // Events closeAction, cancelAction, saveAction, deleteAction, retryAction, undoAction, cancelStateAction, }; }, }), args: { ...DEFAULT_PROPS, showUndoAction: true, showRetryAction: true, }, parameters: storybookDocsParameter(ActionBarDefault), }; export const WithoutLabel: Story = { render: (_args, { argTypes }) => ({ components: { BentoActionBar }, props: Object.keys(argTypes), template: ` <div style="height:140px"> <bento-action-bar v-bind="args" :actions="actions" :dismissible="args.dismissible" :selection-label="args.selectionLabel" /> </div> `, setup(props) { const actions = [ { title: 'Zoom in', icon: ZoomInIcon, iconOnly: true, event: () => undefined, }, { title: 'Zoom out', icon: ZoomOutIcon, iconOnly: true, event: () => undefined, }, { title: 'Reset', icon: RefreshIcon, event: () => undefined, }, ]; return { actions, args: isVue2 ? props : _args, }; }, }), args: { ...DEFAULT_PROPS, dismissible: false, selectionLabel: null, }, parameters: storybookDocsParameter(ActionBarWithoutLabel), }; export const WithCustomLabel: Story = { render: (_args, { argTypes }) => ({ components: { BentoActionBar }, props: Object.keys(argTypes), template: ` <div style="height:140px"> <bento-action-bar v-bind="args" :actions="actions" :item-counter="args.itemCounter" :selection-label="args.selectionLabel" > <template #selectionLabel="{ itemCounter, label }"> <strong>{{ itemCounter }}</strong> payments {{ label }} </template> </bento-action-bar> </div> `, setup(props) { const actions = [ { title: 'Review', event: () => undefined, }, ]; return { actions, args: isVue2 ? props : _args, }; }, }), args: { ...DEFAULT_PROPS, selectionLabel: 'ready', }, parameters: storybookDocsParameter(ActionBarWithCustomLabel), };
@@ -1 +1 @@
1
- export const BentoActionBarVariantOptions = ['default', 'confirmation'] as const; export const BentoActionBarStateOptions = ['start', 'loading', 'success', 'fail'] as const; export type BentoActionBarVariant = (typeof BentoActionBarVariantOptions)[number]; export type BentoActionBarState = (typeof BentoActionBarStateOptions)[number];
1
+ import { type BentoActionBarStateOptions, type BentoActionBarVariantOptions } from './action-bar.internal.types'; export type BentoActionBarVariant = (typeof BentoActionBarVariantOptions)[number]; export type BentoActionBarState = (typeof BentoActionBarStateOptions)[number];
@@ -1 +1 @@
1
- <template> <Transition name="b-action-bar__animation" appear> <section class="b-action-bar" :class="conditionalClasses" :aria-label="t('actionBar')" @animationend="onAnimationEnd" > <Transition :name="`b-action-bar__state-animation--${state}`" :mode="stateTransitionMode" @before-leave="onBeforeLeave" @enter="onEnter" @after-enter="onAfterEnter" > <div ref="actionBar" :key="state" class="b-action-bar__container" :class="containerClasses" :style="{ width: containerWidth, maxWidth: containerMaxWidth }" > <div v-if="state === 'start'" class="b-action-bar__container-inner"> <div v-if="!isConfirmationVariant" class="b-action-bar__close-button"> <bento-button variant="tertiary" inverse :aria-label="t('close')" @click="emit('close')"> <template #iconLeft><cross-icon :aria-hidden="true" /></template> </bento-button> </div> <bento-typography el="span" stronger class="b-action-bar__selection"> <template v-if="isConfirmationVariant && noItemCounter"> {{ tc('unsavedChanges', 0) }} </template> <template v-else> {{ n(itemCounter) }} {{ isConfirmationVariant ? tc('unsavedChanges', itemCounter) : label }} </template> </bento-typography> <bento-button-actions v-if="isConfirmationVariant" :actions="confirmationActions" class="b-action-bar__actions" inverse /> <button-actions-with-menu v-else :actions="actionsInternal" class="b-action-bar__actions" :displayed-actions="internalDisplayedActions" menu-position="top-end" disable-responsive-behavior inverse /> </div> <div v-else class="b-action-bar__container-inner"> <div class="b-action-bar__state-icon"> <bento-loading-indicator v-if="state === 'loading'" small inverse /> <checkmark-circle-fill v-if="state === 'success'" :aria-hidden="true" /> <cross-circle-fill v-if="state === 'fail'" :aria-hidden="true" /> </div> <bento-typography stronger> <slot name="stateLabel">{{ defaultStateLabel }}</slot> </bento-typography> <div v-if="!hideStateActions" class="b-action-bar__state-actions"> <bento-button v-if="state === 'success' && showUndoAction" variant="tertiary" inverse @click="emit('undo-action')" >{{ t('undo') }}</bento-button > <bento-button v-if="state === 'fail' && showRetryAction" variant="tertiary" inverse @click="emit('retry-action')" >{{ t('retry') }}</bento-button > <bento-button v-if="state === 'fail'" variant="tertiary" inverse @click="emit('cancel-action')" >{{ t('cancel') }}</bento-button > </div> </div> </div> </Transition> </section> </Transition> </template> <script setup lang="ts"> import { computed, nextTick, type PropType, provide, ref, toRefs, type TransitionProps, watch } from 'vue'; import { BentoButton, BentoButtonActions, type BentoButtonActionsList } from '@/components/button'; import { BentoTypography } from '@/components/typography'; import { BentoLoadingIndicator } from '@/components/loading-indicator'; import { type BentoActionBarState, type BentoActionBarVariant } from '@/components/action-bar/action-bar.types'; import ButtonActionsWithMenu from '@/components/internal/button-actions-with-menu/button-actions-with-menu.vue'; import CrossIcon from '@adyen/ui-assets-icons-16/vue/cross'; import CheckmarkCircleFill from '@adyen/ui-assets-icons-16/vue/checkmark-circle-fill'; import CrossCircleFill from '@adyen/ui-assets-icons-16/vue/cross-circle-fill'; import { useI18n } from '@/utils/ts/i18n'; import { useWindowSize } from '@vueuse/core'; import messages from './messages.json'; import { POPOVER_OFFSET_INJECTION_KEY } from '@/components/popover/popover.keys'; type MessageSchema = (typeof messages)['en-US']; // Constants const AVERAGE_BUTTON_SIZE = 100; const MENU_OFFSET = 7; const RESPONSIVE_BREAKPOINT = 500; const SPACING = 32; const props = defineProps({ /** * List of actions that will be used to render the buttons. * Required and used for the `default` variant. * * Each object in the list should have a `title`, an `event` and, * optionally, an `icon`. * * The component will display 4 actions and the hide the rest inside a menu. * * @see BentoButton for a list of all the other props supported by each button action. */ actions: { type: Array as PropType<BentoButtonActionsList>, default: () => [], }, /** * How many actions should be visible outside the menu, cannot be more than 4 */ visibleActions: { type: Number, default: 4, validator: (value: number) => value > 0 && value <= 4, }, /** * Use when there are sticky elements at the bottom, like sticky pagination */ extraBottomSpacing: { type: Boolean, default: false, }, /** * Show how many items are selected. * When omitted in the `confirmation` variant, a generic "Unsaved changes" label is displayed. */ itemCounter: { type: Number, default: null, }, /** * Label for the selection, e.g. 'selected'/'changed' */ selectionLabel: { type: String, default: null, }, /** * State of the action bar. * @values start, loading, success, fail */ state: { type: String as PropType<BentoActionBarState>, default: 'start', }, /** * Displays the undo action button in `success` state. */ showUndoAction: { type: Boolean, default: false, }, /** * Displays the retry action button in `fail` state. */ showRetryAction: { type: Boolean, default: false, }, /** * Variant for the action bar * @values default, confirmation */ variant: { type: String as PropType<BentoActionBarVariant>, default: 'default', }, }); const emit = defineEmits<{ /** * Event emitted when the user click the close button */ (e: 'close'): void; /** * Event emitted when the user clicks the cancel button in `confirmation` variant. */ (e: 'cancel'): void; /** * Event emitted when the user clicks the save button in `confirmation` variant. */ (e: 'save'): void; /** * Event emitted when the user clicks the undo button in `success` state. */ (e: 'undo-action'): void; /** * Event emitted when the user clicks the retry button in `fail` state. */ (e: 'retry-action'): void; /** * Event emitted when the user clicks the cancel button in `fail` state. */ (e: 'cancel-action'): void; }>(); const { t, tc, n } = useI18n<{ message: MessageSchema }>({ messages }); const label = computed(() => (props.selectionLabel ? props.selectionLabel : t('selected'))); const defaultStateLabel = computed(() => { switch (props.state) { case 'loading': return t('applying'); case 'success': return t('success'); case 'fail': return t('somethingWentWrong'); default: return ''; } }); // Refs const actionBar = ref<HTMLDivElement>(null); const containerMaxWidth = ref<string | null>(null); const containerWidth = ref<string | null>(null); const isShaking = ref(false); const stateTransitionMode = computed( () => (props.state === 'loading' ? 'out-in' : undefined) as TransitionProps['mode'] ); const hideStateActions = computed( () => props.state === 'loading' || (props.state === 'success' && !props.showUndoAction) ); const onBeforeLeave = (el: HTMLElement) => { if (props.state !== 'loading') { return; } containerMaxWidth.value = `${el.offsetWidth}px`; containerWidth.value = '100%'; }; const onEnter = (el: HTMLElement) => { if (props.state !== 'loading') { return; } // Reset styles to get natural width Object.assign(el.style, { width: 'auto', maxWidth: 'none' }); const newWidth = el.offsetWidth; // Reset it back to the original values Object.assign(el.style, { width: '100%', maxWidth: containerMaxWidth.value }); requestAnimationFrame(() => { containerMaxWidth.value = `${newWidth}px`; }); }; const onAfterEnter = () => { containerMaxWidth.value = null; containerWidth.value = null; if (props.state === 'fail') { isShaking.value = true; } }; const onAnimationEnd = (event: AnimationEvent) => { if (event.animationName.startsWith('shake-')) { isShaking.value = false; } }; const { extraBottomSpacing, visibleActions } = toRefs(props); const { width } = useWindowSize(); const internalDisplayedActions = ref(null); const internalVisibleActions = ref(null); const isConfirmationVariant = computed(() => props.variant === 'confirmation'); watch( () => visibleActions.value, value => { internalVisibleActions.value = value <= 4 ? value : 4; internalDisplayedActions.value = internalVisibleActions.value; }, { immediate: true } ); // Styling const conditionalClasses = computed(() => ({ 'b-action-bar--extra-spacing': extraBottomSpacing.value, 'b-action-bar--confirmation': isConfirmationVariant.value, 'b-action-bar__state-animation--shake': isShaking.value, })); const containerClasses = computed(() => ({ [`b-action-bar__container--${props.state}`]: props.state !== 'start', })); // Provide POPOVER_OFFSET_INJECTION_KEY to change the value of the popover offset provide(POPOVER_OFFSET_INJECTION_KEY, MENU_OFFSET); // Manipulate actions array to display as intended const actionsInternal = computed(() => { // All buttons should be of type secondary in the action bar const actions = props.actions.map(action => ({ ...action, variant: 'secondary', })) as BentoButtonActionsList; // Shown actions should display from left to right in action bar, instead of right to left which is the button actions default const shownActions = actions.slice(0, internalDisplayedActions.value).reverse(); const hiddenActions = actions.slice(internalDisplayedActions.value); return [...shownActions, ...hiddenActions]; }); const confirmationActions = computed<BentoButtonActionsList>(() => [ { title: t('save'), event: () => emit('save'), }, { title: t('cancel'), variant: 'secondary', event: () => emit('cancel'), }, ]); const noItemCounter = computed(() => { return props.itemCounter == null || props.itemCounter < 1; }); // Recursive functions to determine how many actions should be visible/hidden based on the screens width const showActions = async () => { await nextTick(); if ( width.value > actionBar.value.clientWidth + SPACING + AVERAGE_BUTTON_SIZE && internalDisplayedActions.value < internalVisibleActions.value ) { internalDisplayedActions.value += 1; showActions(); } }; const hideActions = async () => { await nextTick(); if (width.value < actionBar.value.clientWidth + SPACING && internalDisplayedActions.value > 0) { internalDisplayedActions.value -= 1; hideActions(); } }; // Screen width watcher to toggle hidden/visible actions watch( () => width.value, async (newValue, oldValue) => { await nextTick(); if (!actionBar.value) { return; } const isIncreasing = newValue > oldValue; if (width.value < RESPONSIVE_BREAKPOINT) { internalDisplayedActions.value = 0; } else if (isIncreasing) { showActions(); } else { hideActions(); } }, { immediate: true } ); </script> <script lang="ts"> /** * Action bar is a floating bar that provides users with quick access to key actions that can be applied to one or multiple items. * * @example * import { BentoActionBar } from '@adyen/bento-vue2'; * * export default { * components: { BentoActionBar }, * template: ` * <bento-action-bar * :actions='[ * { * title: 'Delete', * critical: true, * icon: BinIcon, * event: () => true, * }, * { * title: 'Edit', * icon: EditIcon, * event: () => true, * } * ]' * @close="closeAction" * :item-counter="5" * /> * ` * } */ export default { i18n: { messages }, }; </script> <style lang="scss" scoped src="./action-bar.scss" />
1
+ <template> <Transition name="b-action-bar__animation" appear> <section class="b-action-bar" :class="conditionalClasses" :aria-label="t('actionBar')" @animationend="onAnimationEnd" > <Transition :name="`b-action-bar__state-animation--${state}`" :mode="stateTransitionMode" @before-leave="onBeforeLeave" @enter="onEnter" @after-enter="onAfterEnter" > <div ref="actionBar" :key="state" class="b-action-bar__container" :class="containerClasses" :style="{ width: containerWidth, maxWidth: containerMaxWidth }" > <div v-if="state === 'start'" class="b-action-bar__container-inner"> <div v-if="showCloseButton" class="b-action-bar__close-button"> <bento-button variant="tertiary" inverse :aria-label="t('close')" @click="emit('close')"> <template #iconLeft><cross-icon :aria-hidden="true" /></template> </bento-button> </div> <bento-typography v-if="showSelectionLabel()" el="span" stronger class="b-action-bar__selection" > <template v-if="isConfirmationVariant && noItemCounter"> {{ tc('unsavedChanges', 0) }} </template> <template v-else> <slot v-if="!isConfirmationVariant && hasSelectionLabelSlot()" name="selectionLabel" :item-counter="itemCounter" :label="label" /> <template v-else> {{ n(itemCounter) }} {{ computedSelectionLabel }} </template> </template> </bento-typography> <bento-button-actions v-if="isConfirmationVariant" :actions="confirmationActions" class="b-action-bar__actions" inverse /> <button-actions-with-menu v-else :actions="actionsInternal" class="b-action-bar__actions" :displayed-actions="internalDisplayedActions" menu-position="top-end" disable-responsive-behavior inverse /> </div> <div v-else class="b-action-bar__container-inner"> <div class="b-action-bar__state-icon"> <bento-loading-indicator v-if="state === 'loading'" small inverse /> <checkmark-circle-fill v-if="state === 'success'" :aria-hidden="true" /> <cross-circle-fill v-if="state === 'fail'" :aria-hidden="true" /> </div> <bento-typography stronger> <slot name="stateLabel">{{ defaultStateLabel }}</slot> </bento-typography> <div v-if="!hideStateActions" class="b-action-bar__state-actions"> <bento-button v-if="state === 'success' && showUndoAction" variant="tertiary" inverse @click="emit('undo-action')" >{{ t('undo') }}</bento-button > <bento-button v-if="state === 'fail' && showRetryAction" variant="tertiary" inverse @click="emit('retry-action')" >{{ t('retry') }}</bento-button > <bento-button v-if="state === 'fail'" variant="tertiary" inverse @click="emit('cancel-action')" >{{ t('cancel') }}</bento-button > </div> </div> </div> </Transition> </section> </Transition> </template> <script setup lang="ts"> import { computed, nextTick, type PropType, provide, ref, toRefs, type TransitionProps, useSlots, watch, } from 'vue'; import { BentoButton, BentoButtonActions, type BentoButtonActionsList } from '@/components/button'; import { BentoTypography } from '@/components/typography'; import { BentoLoadingIndicator } from '@/components/loading-indicator'; import { type BentoActionBarState, type BentoActionBarVariant } from '@/components/action-bar/action-bar.types'; import ButtonActionsWithMenu from '@/components/internal/button-actions-with-menu/button-actions-with-menu.vue'; import CrossIcon from '@adyen/ui-assets-icons-16/vue/cross'; import CheckmarkCircleFill from '@adyen/ui-assets-icons-16/vue/checkmark-circle-fill'; import CrossCircleFill from '@adyen/ui-assets-icons-16/vue/cross-circle-fill'; import { useI18n } from '@/utils/ts/i18n'; import { useWindowSize } from '@vueuse/core'; import messages from './messages.json'; import { POPOVER_OFFSET_INJECTION_KEY } from '@/components/popover/popover.keys'; type MessageSchema = (typeof messages)['en-US']; // Constants const AVERAGE_BUTTON_SIZE = 100; const MENU_OFFSET = 7; const RESPONSIVE_BREAKPOINT = 500; const SPACING = 32; const props = defineProps({ /** * List of actions that will be used to render the buttons. * Required and used for the `default` variant. * * Each object in the list should have a `title`, an `event` and, * optionally, an `icon`. * * The component will display 4 actions and the hide the rest inside a menu. * * @see BentoButton for a list of all the other props supported by each button action. */ actions: { type: Array as PropType<BentoButtonActionsList>, default: () => [], }, /** * Determines whether the close button is displayed in the `default` variant. */ dismissible: { type: Boolean, default: true, }, /** * How many actions should be visible outside the menu, cannot be more than 4 */ visibleActions: { type: Number, default: 4, validator: (value: number) => value > 0 && value <= 4, }, /** * Use when there are sticky elements at the bottom, like sticky pagination */ extraBottomSpacing: { type: Boolean, default: false, }, /** * Show how many items are selected. * When omitted in the `confirmation` variant, a generic "Unsaved changes" label is displayed. */ itemCounter: { type: Number, default: null, }, /** * Label for the selection in the `default` variant, e.g. 'selected'/'changed'. * Pass `null` to hide it. In the `confirmation` variant, this prop is ignored. */ selectionLabel: { type: String, default: undefined, }, /** * State of the action bar. * @values start, loading, success, fail */ state: { type: String as PropType<BentoActionBarState>, default: 'start', }, /** * Displays the undo action button in `success` state. */ showUndoAction: { type: Boolean, default: false, }, /** * Displays the retry action button in `fail` state. */ showRetryAction: { type: Boolean, default: false, }, /** * Variant for the action bar * @values default, confirmation */ variant: { type: String as PropType<BentoActionBarVariant>, default: 'default', }, }); const emit = defineEmits<{ /** * Event emitted when the user click the close button */ (e: 'close'): void; /** * Event emitted when the user clicks the cancel button in `confirmation` variant. */ (e: 'cancel'): void; /** * Event emitted when the user clicks the save button in `confirmation` variant. */ (e: 'save'): void; /** * Event emitted when the user clicks the undo button in `success` state. */ (e: 'undo-action'): void; /** * Event emitted when the user clicks the retry button in `fail` state. */ (e: 'retry-action'): void; /** * Event emitted when the user clicks the cancel button in `fail` state. */ (e: 'cancel-action'): void; }>(); const { t, tc, n } = useI18n<{ message: MessageSchema }>({ messages }); const slots = useSlots(); const hasSelectionLabelSlot = () => Boolean(slots.selectionLabel); const label = computed(() => (props.selectionLabel === undefined ? t('selected') : props.selectionLabel)); const defaultStateLabel = computed(() => { switch (props.state) { case 'loading': return t('applying'); case 'success': return t('success'); case 'fail': return t('somethingWentWrong'); default: return ''; } }); // Refs const actionBar = ref<HTMLDivElement>(null); const containerMaxWidth = ref<string | null>(null); const containerWidth = ref<string | null>(null); const isShaking = ref(false); const stateTransitionMode = computed( () => (props.state === 'loading' ? 'out-in' : undefined) as TransitionProps['mode'] ); const hideStateActions = computed( () => props.state === 'loading' || (props.state === 'success' && !props.showUndoAction) ); const onBeforeLeave = (el: HTMLElement) => { if (props.state !== 'loading') { return; } containerMaxWidth.value = `${el.offsetWidth}px`; containerWidth.value = '100%'; }; const onEnter = (el: HTMLElement) => { if (props.state !== 'loading') { return; } // Reset styles to get natural width Object.assign(el.style, { width: 'auto', maxWidth: 'none' }); const newWidth = el.offsetWidth; // Reset it back to the original values Object.assign(el.style, { width: '100%', maxWidth: containerMaxWidth.value }); requestAnimationFrame(() => { containerMaxWidth.value = `${newWidth}px`; }); }; const onAfterEnter = () => { containerMaxWidth.value = null; containerWidth.value = null; if (props.state === 'fail') { isShaking.value = true; } }; const onAnimationEnd = (event: AnimationEvent) => { if (event.animationName.startsWith('shake-')) { isShaking.value = false; } }; const { extraBottomSpacing, visibleActions } = toRefs(props); const { width } = useWindowSize(); const internalDisplayedActions = ref(null); const internalVisibleActions = ref(null); const isConfirmationVariant = computed(() => props.variant === 'confirmation'); const computedSelectionLabel = computed(() => isConfirmationVariant.value ? tc('unsavedChanges', props.itemCounter) : label.value ); const showCloseButton = computed(() => !isConfirmationVariant.value && props.dismissible !== false); const showSelectionLabel = () => isConfirmationVariant.value || hasSelectionLabelSlot() || props.selectionLabel !== null; watch( () => visibleActions.value, value => { internalVisibleActions.value = value <= 4 ? value : 4; internalDisplayedActions.value = internalVisibleActions.value; }, { immediate: true } ); // Styling const conditionalClasses = computed(() => ({ 'b-action-bar--extra-spacing': extraBottomSpacing.value, 'b-action-bar--confirmation': isConfirmationVariant.value, 'b-action-bar__state-animation--shake': isShaking.value, })); const containerClasses = computed(() => ({ [`b-action-bar__container--${props.state}`]: props.state !== 'start', })); // Provide POPOVER_OFFSET_INJECTION_KEY to change the value of the popover offset provide(POPOVER_OFFSET_INJECTION_KEY, MENU_OFFSET); // Manipulate actions array to display as intended const actionsInternal = computed(() => { // All buttons should be of type secondary in the action bar const actions = props.actions.map(action => ({ ...action, variant: 'secondary', })) as BentoButtonActionsList; // Shown actions should display from left to right in action bar, instead of right to left which is the button actions default const shownActions = actions.slice(0, internalDisplayedActions.value).reverse(); const hiddenActions = actions.slice(internalDisplayedActions.value); return [...shownActions, ...hiddenActions]; }); const confirmationActions = computed<BentoButtonActionsList>(() => [ { title: t('save'), event: () => emit('save'), }, { title: t('cancel'), variant: 'secondary', event: () => emit('cancel'), }, ]); const noItemCounter = computed(() => { return props.itemCounter == null || props.itemCounter < 1; }); // Recursive functions to determine how many actions should be visible/hidden based on the screens width const showActions = async () => { await nextTick(); if ( width.value > actionBar.value.clientWidth + SPACING + AVERAGE_BUTTON_SIZE && internalDisplayedActions.value < internalVisibleActions.value ) { internalDisplayedActions.value += 1; showActions(); } }; const hideActions = async () => { await nextTick(); if (width.value < actionBar.value.clientWidth + SPACING && internalDisplayedActions.value > 0) { internalDisplayedActions.value -= 1; hideActions(); } }; // Screen width watcher to toggle hidden/visible actions watch( () => width.value, async (newValue, oldValue) => { await nextTick(); if (!actionBar.value) { return; } const isIncreasing = newValue > oldValue; if (width.value < RESPONSIVE_BREAKPOINT) { internalDisplayedActions.value = 0; } else if (isIncreasing) { showActions(); } else { hideActions(); } }, { immediate: true } ); </script> <script lang="ts"> /** * Action bar is a floating bar that provides users with quick access to key actions that can be applied to one or multiple items. * * @example * import { BentoActionBar } from '@adyen/bento-vue2'; * * export default { * components: { BentoActionBar }, * template: ` * <bento-action-bar * :actions='[ * { * title: 'Delete', * critical: true, * icon: BinIcon, * event: () => true, * }, * { * title: 'Edit', * icon: EditIcon, * event: () => true, * } * ]' * @close="closeAction" * :item-counter="5" * /> * ` * } */ export default { i18n: { messages }, name: 'bento-action-bar', }; </script> <style lang="scss" scoped src="./action-bar.scss" />
@@ -1 +1 @@
1
- import BentoAiTag from './ai-tag.vue'; import AiTagDefault from './__tests__/ai-tag-default.vue?raw'; import { action } from '@storybook/addon-actions'; import { isVue2 } from 'vue-demi'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import type { Meta, StoryObj } from '@storybook/vue'; const meta: Meta = { title: 'AI tag', component: BentoAiTag, }; export default meta; type Story = StoryObj<typeof BentoAiTag>; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoAiTag }, props: Object.keys(argTypes), template: ` <bento-ai-tag v-bind="args" @update:toggled="onToggleAction"/> `, setup(props) { const onToggleAction = (value: boolean) => action('update:toggled')(value); return { // Values args: isVue2 ? props : _args, // Events onToggleAction, }; }, }), args: { title: 'Input fields auto-filled by AI', description: 'Based on your documents uploaded, AI has auto-filled some information for you. You can change that information any time.', influencedValue: '30%', action: { title: 'Learn more', event: () => action('action-click')('Learn more clicked'), }, }, parameters: storybookDocsParameter(AiTagDefault), };
1
+ import BentoAiTag from './ai-tag.vue'; const AiTagDefault = "<template>\n <bento-ai-tag\n title=\"Input fields auto-filled by AI\"\n description=\"Based on your documents uploaded, AI has auto-filled some information for you. You can change that information any time.\"\n influenced-value=\"30%\"\n :action=\"learnMore\"\n @update:toggled=\"onToggle\"\n />\n</template>\n\n<script setup lang=\"ts\">\n /* eslint-disable no-console */\n import { BentoAiTag, type BentoButtonActionObject } from '@adyen/bento-vue2';\n\n const learnMore: BentoButtonActionObject = {\n title: 'Learn more',\n event: () => {\n console.log('Learn more clicked');\n },\n };\n\n const onToggle = (isOpen: boolean) => {\n console.log('Popover toggled. Open:', isOpen);\n };\n</script>\n"; import { action } from '@storybook/addon-actions'; import { isVue2 } from 'vue-demi'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import type { Meta, StoryObj } from '@storybook/vue'; const meta: Meta = { title: 'AI tag', component: BentoAiTag, }; export default meta; type Story = StoryObj<typeof BentoAiTag>; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoAiTag }, props: Object.keys(argTypes), template: ` <bento-ai-tag v-bind="args" @update:toggled="onToggleAction"/> `, setup(props) { const onToggleAction = (value: boolean) => action('update:toggled')(value); return { // Values args: isVue2 ? props : _args, // Events onToggleAction, }; }, }), args: { title: 'Input fields auto-filled by AI', description: 'Based on your documents uploaded, AI has auto-filled some information for you. You can change that information any time.', influencedValue: '30%', action: { title: 'Learn more', event: () => action('action-click')('Learn more clicked'), }, }, parameters: storybookDocsParameter(AiTagDefault), };
@@ -1 +1 @@
1
- <template> <div ref="aiTagRef" class="b-ai-tag" @keydown.esc="closePopover"> <bento-toggle-button ref="targetElement" :toggled="toggled" :aria-controls="popoverId" variant="secondary" condensed class="b-ai-tag__trigger" @update:toggled="onToggle" > <template #iconLeft> <artificial-intelligence-ai-icon class="b-ai-tag__trigger-icon" :aria-hidden="true" /> </template> {{ t('ai') }} </bento-toggle-button> <bento-popover v-if="targetElement" :id="popoverId" :open="toggled" :target-element="targetElement" :actions="popoverActions" actions-layout="fill-container" :title="t('aiExplained')" trap-all :trap-all-options="{ onDeactivate: closePopover, allowOutsideClick: true }" fixed-positioning overflow-visible @dismiss="closePopover" > <template #headerIcon> <artificial-intelligence-ai-icon class="b-ai-tag__popover-header-icon" :aria-hidden="true" /> </template> <div class="b-ai-tag__popover-content"> <bento-typography v-if="influencedValue" variant="title" medium class="b-ai-tag__influenced-value"> {{ influencedValue }} </bento-typography> <bento-typography variant="title"> {{ title }} </bento-typography> <bento-typography> {{ description }} </bento-typography> </div> </bento-popover> </div> </template> <script setup lang="ts"> import { computed, ref, watch } from 'vue'; import { BentoPopover } from '@/components/popover'; import { BentoToggleButton } from '@/components/button'; import { BentoTypography } from '@/components/typography'; import { useClickOutside } from '@/composables'; import { useI18n } from '@/utils/ts/i18n'; import { generateUid } from '@/core/utils/ts'; import type { BentoButtonActionsList } from '@/components/button/components/button-actions/button-actions.types'; import ArtificialIntelligenceAiIcon from '@adyen/ui-assets-icons-16/vue/artificial-intelligence-ai-filled'; import type { BentoAiTagProps } from './ai-tag.types'; import messages from './messages.json'; type MessageSchema = (typeof messages)['en-US']; const props = withDefaults(defineProps<BentoAiTagProps>(), { influencedValue: undefined, toggled: false, action: undefined, }); const { t } = useI18n<{ message: MessageSchema }>({ messages }); const toggled = ref(props.toggled); const aiTagRef = ref<HTMLElement | null>(null); const targetElement = ref<InstanceType<typeof BentoToggleButton> | null>(null); const popoverId = generateUid('b-ai-tag-popover'); watch( () => props.toggled, value => { toggled.value = value; } ); useClickOutside(aiTagRef, () => { closePopover(); }); const popoverActions = computed<BentoButtonActionsList>(() => props.action ? [ { ...props.action, variant: 'secondary', }, ] : undefined ); const emit = defineEmits<{ /** * Triggered when the popover is toggled */ (e: 'update:toggled', toggled: boolean): void; }>(); const onToggle = (value: boolean) => { toggled.value = value; emit('update:toggled', value); }; const closePopover = () => { if (toggled.value) { onToggle(false); } }; </script> <script lang="ts"> /** * The AI tag is a component used to transparently identify content, data, or experiences that have been generated or * enhanced by artificial intelligence. * * @example * import { BentoAiTag } from '@adyen/bento-vue2'; * * export default { * components: { BentoAiTag }, * template: ` * <bento-ai-tag * title="Input fields auto-filled by AI" * description="Based on your documents uploaded, AI has auto-filled some information for you." * /> * ` * } */ export default { i18n: { messages }, }; </script> <style lang="scss" scoped src="./ai-tag.scss" />
1
+ <template> <div ref="aiTagRef" class="b-ai-tag" @keydown.esc="closePopover"> <bento-toggle-button ref="targetElement" :toggled="toggled" :aria-controls="popoverId" variant="secondary" condensed class="b-ai-tag__trigger" @update:toggled="onToggle" > <template #iconLeft> <artificial-intelligence-ai-icon class="b-ai-tag__trigger-icon" :aria-hidden="true" /> </template> {{ t('ai') }} </bento-toggle-button> <bento-popover v-if="targetElement" :id="popoverId" :open="toggled" :target-element="targetElement" :actions="popoverActions" actions-layout="fill-container" :title="t('aiExplained')" trap-all :trap-all-options="{ onDeactivate: closePopover, allowOutsideClick: true }" fixed-positioning overflow-visible @dismiss="closePopover" > <template #headerIcon> <artificial-intelligence-ai-icon class="b-ai-tag__popover-header-icon" :aria-hidden="true" /> </template> <div class="b-ai-tag__popover-content"> <bento-typography v-if="influencedValue" variant="title" medium class="b-ai-tag__influenced-value"> {{ influencedValue }} </bento-typography> <bento-typography variant="title"> {{ title }} </bento-typography> <bento-typography> {{ description }} </bento-typography> </div> </bento-popover> </div> </template> <script setup lang="ts"> import { computed, ref, watch } from 'vue'; import { BentoPopover } from '@/components/popover'; import { BentoToggleButton } from '@/components/button'; import { BentoTypography } from '@/components/typography'; import { useClickOutside } from '@/composables'; import { useI18n } from '@/utils/ts/i18n'; import { generateUid } from '@/utils/ts/generate-uid'; import type { BentoButtonActionsList } from '@/components/button/components/button-actions/button-actions.types'; import ArtificialIntelligenceAiIcon from '@adyen/ui-assets-icons-16/vue/artificial-intelligence-ai-filled'; import type { BentoAiTagProps } from './ai-tag.types'; import messages from './messages.json'; type MessageSchema = (typeof messages)['en-US']; const props = withDefaults(defineProps<BentoAiTagProps>(), { influencedValue: undefined, toggled: false, action: undefined, }); const { t } = useI18n<{ message: MessageSchema }>({ messages }); const toggled = ref(props.toggled); const aiTagRef = ref<HTMLElement | null>(null); const targetElement = ref<InstanceType<typeof BentoToggleButton> | null>(null); const popoverId = generateUid('b-ai-tag-popover'); watch( () => props.toggled, value => { toggled.value = value; } ); useClickOutside(aiTagRef, () => { closePopover(); }); const popoverActions = computed<BentoButtonActionsList>(() => props.action ? [ { ...props.action, variant: 'secondary', }, ] : undefined ); const emit = defineEmits<{ /** * Triggered when the popover is toggled */ (e: 'update:toggled', toggled: boolean): void; }>(); const onToggle = (value: boolean) => { toggled.value = value; emit('update:toggled', value); }; const closePopover = () => { if (toggled.value) { onToggle(false); } }; </script> <script lang="ts"> /** * The AI tag is a component used to transparently identify content, data, or experiences that have been generated or * enhanced by artificial intelligence. * * @example * import { BentoAiTag } from '@adyen/bento-vue2'; * * export default { * components: { BentoAiTag }, * template: ` * <bento-ai-tag * title="Input fields auto-filled by AI" * description="Based on your documents uploaded, AI has auto-filled some information for you." * /> * ` * } */ export default { i18n: { messages }, }; </script> <style lang="scss" scoped src="./ai-tag.scss" />
@@ -1 +1 @@
1
- import { action } from '@storybook/addon-actions'; import { BentoAlertTypeOption, BentoAlertVariant } from './alert.types'; import { BentoButton } from '@/components/button'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import { type Meta, type StoryObj } from '@storybook/vue'; import { isVue2 } from 'vue-demi'; import BentoAlert from './alert.vue'; export default { title: 'Alert', component: BentoAlert, parameters: { layout: 'centered', }, argTypes: { default: { name: 'default', defaultValue: '', description: 'Heading title', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, variant: { options: Object.values(BentoAlertVariant), defaultValue: BentoAlertVariant.TIP, mapping: BentoAlertVariant, control: { type: 'select', }, }, type: { options: Object.values(BentoAlertTypeOption), defaultValue: BentoAlertTypeOption.HIGHLIGHT, mapping: BentoAlertTypeOption, control: { type: 'select', }, }, description: { name: 'description', defaultValue: '', description: 'Description in alert body', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, actions: { name: 'actions', defaultValue: '', description: 'Actions in the footer', table: { type: { summary: 'VNode[]' }, }, control: { disable: true, }, }, }, } as Meta; type Story = StoryObj<typeof BentoAlert>; const DEFAULT_ALERT_PROPS = { default: 'Alert title', type: 'highlight', description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent ultrices leo massa, at accumsan lorem sagittis vehicula. Ut elit orci, finibus id neque quis, cursus posuere metus. Proin sed convallis odio, ut porttitor turpis.', closeButton: true, variant: 'default', }; const defaultCode = ` <bento-alert @close-alert='clickedCloseAction'> <template #default> ${DEFAULT_ALERT_PROPS.default} </template> <template #description> ${DEFAULT_ALERT_PROPS.description} </template> </bento-alert> `; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoAlert }, props: Object.keys(argTypes), template: ` <bento-alert v-bind='args' @close-alert='clickedCloseAction' style="width: 100vw;max-width: 700px;"> <template #default v-if='args.default'> {{ args.default }} </template> <template #description v-if='args.description'> {{ args.description }} </template> </bento-alert> `, setup(props) { return { clickedCloseAction: action('onClickCloseButton'), args: isVue2 ? props : _args, }; }, }), args: { ...DEFAULT_ALERT_PROPS }, parameters: storybookDocsParameter(defaultCode), }; export const WithActions: Story = { render: (_args, { argTypes }) => ({ components: { BentoAlert, BentoButton }, props: Object.keys(argTypes), template: ` <bento-alert v-bind='args' @close-alert='clickedCloseAction' style="width: 100vw;max-width: 700px;"> <template #default v-if='args.default'> {{ args.default }} </template> <template #description v-if='args.description'> {{ args.description }} </template> <template #actions> <bento-button @click='clickedAction' variant="tertiary">Cancel</bento-button> <bento-button @click='clickedAction' variant="tertiary">Confirm</bento-button> </template> </bento-alert> `, setup(props) { return { clickedCloseAction: action('onClickCloseButton'), clickedAction: action('onClickAction'), args: isVue2 ? props : _args, }; }, }), args: { ...DEFAULT_ALERT_PROPS }, parameters: storybookDocsParameter(defaultCode), };
1
+ import { action } from '@storybook/addon-actions'; import { BentoAlertTypeOption, BentoAlertVariant } from './alert.types'; import { BentoButton } from '@/components/button'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import { type Meta, type StoryObj } from '@storybook/vue'; import { isVue2 } from 'vue-demi'; import BentoAlert from './alert.vue'; const AlertDefault = "<template>\n <bento-alert\n close-button\n style=\"width: 100vw; max-width: 700px\"\n type=\"highlight\"\n variant=\"default\"\n @close-alert=\"clickedCloseAction\"\n >\n <template #default>Alert title</template>\n <template #description>\n Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent ultrices leo massa, at accumsan lorem\n sagittis vehicula. Ut elit orci, finibus id neque quis, cursus posuere metus. Proin sed convallis odio, ut\n porttitor turpis.\n </template>\n </bento-alert>\n</template>\n\n<script setup lang=\"ts\">\n import { BentoAlert } from '@adyen/bento-vue2';\n\n const clickedCloseAction = () => true;\n</script>\n"; const AlertWithActions = "<template>\n <bento-alert\n close-button\n style=\"width: 100vw; max-width: 700px\"\n type=\"highlight\"\n variant=\"default\"\n @close-alert=\"clickedCloseAction\"\n >\n <template #default>Alert title</template>\n <template #description>\n Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent ultrices leo massa, at accumsan lorem\n sagittis vehicula. Ut elit orci, finibus id neque quis, cursus posuere metus. Proin sed convallis odio, ut\n porttitor turpis.\n </template>\n <template #actions>\n <bento-button variant=\"tertiary\" @click=\"clickedAction\">Cancel</bento-button>\n <bento-button variant=\"tertiary\" @click=\"clickedAction\">Confirm</bento-button>\n </template>\n </bento-alert>\n</template>\n\n<script setup lang=\"ts\">\n import { BentoAlert, BentoButton } from '@adyen/bento-vue2';\n\n const clickedCloseAction = () => true;\n const clickedAction = () => true;\n</script>\n"; export default { title: 'Alert', component: BentoAlert, parameters: { layout: 'centered', }, argTypes: { default: { name: 'default', defaultValue: '', description: 'Heading title', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, variant: { options: Object.values(BentoAlertVariant), defaultValue: BentoAlertVariant.TIP, mapping: BentoAlertVariant, control: { type: 'select', }, }, type: { options: Object.values(BentoAlertTypeOption), defaultValue: BentoAlertTypeOption.HIGHLIGHT, mapping: BentoAlertTypeOption, control: { type: 'select', }, }, description: { name: 'description', defaultValue: '', description: 'Description in alert body', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, actions: { name: 'actions', defaultValue: '', description: 'Actions in the footer', table: { type: { summary: 'VNode[]' }, }, control: { disable: true, }, }, }, } as Meta; type Story = StoryObj<typeof BentoAlert>; const DEFAULT_ALERT_PROPS = { default: 'Alert title', type: 'highlight', description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent ultrices leo massa, at accumsan lorem sagittis vehicula. Ut elit orci, finibus id neque quis, cursus posuere metus. Proin sed convallis odio, ut porttitor turpis.', closeButton: true, variant: 'default', }; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoAlert }, props: Object.keys(argTypes), template: ` <bento-alert v-bind='args' @close-alert='clickedCloseAction' style="width: 100vw;max-width: 700px;"> <template #default v-if='args.default'> {{ args.default }} </template> <template #description v-if='args.description'> {{ args.description }} </template> </bento-alert> `, setup(props) { return { clickedCloseAction: action('onClickCloseButton'), args: isVue2 ? props : _args, }; }, }), args: { ...DEFAULT_ALERT_PROPS }, parameters: storybookDocsParameter(AlertDefault), }; export const WithActions: Story = { render: (_args, { argTypes }) => ({ components: { BentoAlert, BentoButton }, props: Object.keys(argTypes), template: ` <bento-alert v-bind='args' @close-alert='clickedCloseAction' style="width: 100vw;max-width: 700px;"> <template #default v-if='args.default'> {{ args.default }} </template> <template #description v-if='args.description'> {{ args.description }} </template> <template #actions> <bento-button @click='clickedAction' variant="tertiary">Cancel</bento-button> <bento-button @click='clickedAction' variant="tertiary">Confirm</bento-button> </template> </bento-alert> `, setup(props) { return { clickedCloseAction: action('onClickCloseButton'), clickedAction: action('onClickAction'), args: isVue2 ? props : _args, }; }, }), args: { ...DEFAULT_ALERT_PROPS }, parameters: storybookDocsParameter(AlertWithActions), };
@@ -1 +1 @@
1
- /** * @deprecated Since v2.0.0. Use string literal instead. */ export enum BentoAlertVariant { DEFAULT = 'default', TIP = 'tip', } /** * @deprecated Since v2.0.0. Use string literal instead. */ export enum BentoAlertTypeOption { WARNING = 'warning', CRITICAL = 'critical', HIGHLIGHT = 'highlight', SUCCESS = 'success', } /** * @deprecated Since v2.0.0. Use `@close-alert` instead. */ export enum BentoAlertEvent { CLOSE_ALERT = 'close-alert', }
1
+ /** * @deprecated Since v3.0.0. Use string literal instead. */ export enum BentoAlertVariant { DEFAULT = 'default', TIP = 'tip', } /** * @deprecated Since v3.0.0. Use string literal instead. */ export enum BentoAlertTypeOption { WARNING = 'warning', CRITICAL = 'critical', HIGHLIGHT = 'highlight', SUCCESS = 'success', } /** * @deprecated Since v3.0.0. Use `@close-alert` instead. */ export enum BentoAlertEvent { CLOSE_ALERT = 'close-alert', }
@@ -1 +1 @@
1
- import { storybookDocsParameter } from '@/utils/ts/storybook'; import type { Meta, StoryObj } from '@storybook/vue'; import { computed, ref } from 'vue'; import BentoAnchorScroller from './anchor-scroller.vue'; import AnchorScrollerDefaultExample from './__tests__/anchor-scroller-default-example.vue?raw'; import BentoTypography from '../typography/typography.vue'; import { action } from '@storybook/addon-actions'; const meta: Meta = { title: 'Anchor Scroller', component: BentoAnchorScroller, argTypes: { // Slots default: { description: 'Content to be displayed. This enables the anchor scroller to be sticky when scrolling.', control: 'text', table: { type: { summary: 'VNode[]' }, }, }, // Props activeIndex: { table: { type: { summary: 'number' }, }, }, items: { table: { type: { summary: "BentoAnchorScrollerProps['items']" }, }, }, // Events 'update:active-index': { table: { type: { summary: '(index: number) => void' }, }, }, }, }; export default meta; type Story = StoryObj<typeof BentoAnchorScroller>; const ITEMS = [ { title: 'Overview', elementRef: null }, { title: 'Disabled', elementRef: null, disabled: true }, { title: 'Configuration', elementRef: null }, { title: 'Usage', elementRef: null }, ]; export const Default: Story = { render: args => ({ components: { BentoAnchorScroller, BentoTypography }, template: ` <bento-anchor-scroller v-bind="args" :items="computedItems" @update:active-index="updateActiveIndex" > <section ref="section1" style="height: 500px; border: 1px dashed #ccc; margin-bottom: 32px; padding: 24px; border-radius: 8px" > <bento-typography el="h2" variant="title">Overview</bento-typography> <bento-typography>This is the content for the first section.</bento-typography> </section> <section ref="section2" style="height: 400px; border: 1px dashed #ccc; margin-bottom: 32px; padding: 24px; border-radius: 8px" > <bento-typography el="h2" variant="title">Configuration</bento-typography> <bento-typography>This section is shorter.</bento-typography> </section> <section ref="section3" style="height: 600px; border: 1px dashed #ccc; margin-bottom: 32px; padding: 24px; border-radius: 8px" > <bento-typography el="h2" variant="title">Usage</bento-typography> <bento-typography>This is a tall section to demonstrate scrolling.</bento-typography> </section> </bento-anchor-scroller> `, setup() { const section1 = ref<HTMLElement | null>(null); const section2 = ref<HTMLElement | null>(null); const section3 = ref<HTMLElement | null>(null); const sectionDisabled = ref<HTMLElement | null>(null); const sectionRefs = [section1, sectionDisabled, section2, section3]; const computedItems = computed(() => { return (args.items || []).map((item, index) => ({ ...item, // Keep whatever title/disabled state is currently in the Storybook UI elementRef: sectionRefs[index]?.value || null, // Inject the real DOM node! })); }); const updateActiveIndex = value => action('update:active-index')(value); return { args, computedItems, section1, section2, section3, updateActiveIndex }; }, }), args: { items: ITEMS, activeIndex: 0, }, parameters: storybookDocsParameter(AnchorScrollerDefaultExample), };
1
+ import { storybookDocsParameter } from '@/utils/ts/storybook'; import type { Meta, StoryObj } from '@storybook/vue'; import { computed, ref } from 'vue'; import BentoAnchorScroller from './anchor-scroller.vue'; const AnchorScrollerDefaultExample = "<template>\n <bento-anchor-scroller :items=\"items\" :active-index=\"activeIndex\" @update:active-index=\"updateActiveIndex\">\n <section\n ref=\"section1\"\n style=\"height: 500px; border: 1px dashed #ccc; margin-bottom: 32px; padding: 24px; border-radius: 8px\"\n >\n <bento-typography el=\"h2\" variant=\"title\">Overview</bento-typography>\n <bento-typography>This is the content for the first section.</bento-typography>\n </section>\n\n <section\n ref=\"section2\"\n style=\"height: 400px; border: 1px dashed #ccc; margin-bottom: 32px; padding: 24px; border-radius: 8px\"\n >\n <bento-typography el=\"h2\" variant=\"title\">Configuration</bento-typography>\n <bento-typography>This section is shorter.</bento-typography>\n </section>\n\n <section\n ref=\"section3\"\n style=\"height: 600px; border: 1px dashed #ccc; margin-bottom: 32px; padding: 24px; border-radius: 8px\"\n >\n <bento-typography el=\"h2\" variant=\"title\">Usage</bento-typography>\n <bento-typography>This is a tall section to demonstrate scrolling.</bento-typography>\n </section>\n </bento-anchor-scroller>\n</template>\n\n<script setup lang=\"ts\">\n import { ref } from 'vue';\n import { BentoAnchorScroller, BentoTypography } from '@adyen/bento-vue2';\n\n const section1 = ref<HTMLElement | null>(null);\n const section2 = ref<HTMLElement | null>(null);\n const section3 = ref<HTMLElement | null>(null);\n const sectionDisabled = ref<HTMLElement | null>(null);\n\n const activeIndex = ref(0);\n\n const items = [\n { title: 'Overview', elementRef: section1 },\n { title: 'Disabled', elementRef: sectionDisabled, disabled: true },\n { title: 'Configuration', elementRef: section2 },\n { title: 'Usage', elementRef: section3 },\n ];\n\n const updateActiveIndex = (index: number) => (activeIndex.value = index);\n</script>\n"; import BentoTypography from '../typography/typography.vue'; import { action } from '@storybook/addon-actions'; const meta: Meta = { title: 'Anchor Scroller', component: BentoAnchorScroller, argTypes: { // Slots default: { description: 'Content to be displayed. This enables the anchor scroller to be sticky when scrolling.', control: 'text', table: { type: { summary: 'VNode[]' }, }, }, // Props activeIndex: { table: { type: { summary: 'number' }, }, }, items: { table: { type: { summary: "BentoAnchorScrollerProps['items']" }, }, }, // Events 'update:active-index': { table: { type: { summary: '(index: number) => void' }, }, }, }, }; export default meta; type Story = StoryObj<typeof BentoAnchorScroller>; const ITEMS = [ { title: 'Overview', elementRef: null }, { title: 'Disabled', elementRef: null, disabled: true }, { title: 'Configuration', elementRef: null }, { title: 'Usage', elementRef: null }, ]; export const Default: Story = { render: args => ({ components: { BentoAnchorScroller, BentoTypography }, template: ` <bento-anchor-scroller v-bind="args" :items="computedItems" @update:active-index="updateActiveIndex" > <section ref="section1" style="height: 500px; border: 1px dashed #ccc; margin-bottom: 32px; padding: 24px; border-radius: 8px" > <bento-typography el="h2" variant="title">Overview</bento-typography> <bento-typography>This is the content for the first section.</bento-typography> </section> <section ref="section2" style="height: 400px; border: 1px dashed #ccc; margin-bottom: 32px; padding: 24px; border-radius: 8px" > <bento-typography el="h2" variant="title">Configuration</bento-typography> <bento-typography>This section is shorter.</bento-typography> </section> <section ref="section3" style="height: 600px; border: 1px dashed #ccc; margin-bottom: 32px; padding: 24px; border-radius: 8px" > <bento-typography el="h2" variant="title">Usage</bento-typography> <bento-typography>This is a tall section to demonstrate scrolling.</bento-typography> </section> </bento-anchor-scroller> `, setup() { const section1 = ref<HTMLElement | null>(null); const section2 = ref<HTMLElement | null>(null); const section3 = ref<HTMLElement | null>(null); const sectionDisabled = ref<HTMLElement | null>(null); const sectionRefs = [section1, sectionDisabled, section2, section3]; const computedItems = computed(() => { return (args.items || []).map((item, index) => ({ ...item, // Keep whatever title/disabled state is currently in the Storybook UI elementRef: sectionRefs[index]?.value || null, // Inject the real DOM node! })); }); const updateActiveIndex = value => action('update:active-index')(value); return { args, computedItems, section1, section2, section3, updateActiveIndex }; }, }), args: { items: ITEMS, activeIndex: 0, }, parameters: storybookDocsParameter(AnchorScrollerDefaultExample), };
@@ -1 +1 @@
1
- <template> <div v-if="computedItems.length" class="b-anchor-scroller"> <nav ref="navigationRef" class="b-anchor-scroller__navigation" :class="navigationConditionalClasses" :aria-labelledby="navLabelId" > <fixed-scroller condensed centered> <div class="b-anchor-scroller__navigation-panel"> <bento-typography :id="navLabelId" el="span" class="b-anchor-scroller__navigation-panel-label" stronger > {{ t('jumpTo') }} </bento-typography> <anchor-scroller-list :items="computedItems" :active-index="currentActiveIndex" :scroll-offset="bottom" /> </div> </fixed-scroller> </nav> <slot /> </div> </template> <script setup lang="ts"> import { computed, ref, toRef, watch } from 'vue'; import { useElementBounding } from '@vueuse/core'; import BentoTypography from '@/components/typography/typography.vue'; import { FixedScroller } from '@/internal'; import { type BentoAnchorScrollerItem, type BentoAnchorScrollerProps } from './anchor-scroller.types'; import { AnchorScrollerList } from './components/anchor-scroller-list'; import { useI18n } from '@/utils/ts/i18n'; import { generateUid } from '@/core/utils/ts'; import { unrefElement } from '@/directives/click-outside/utils'; import messages from './messages.json'; import { useScrollSpy } from '@/composables/use-scroll-spy'; import { printDevelopmentWarning } from '@/utils/ts/print-development-warning'; type MessageSchema = (typeof messages)['en-US']; const { t } = useI18n<{ message: MessageSchema }>({ messages }); const props = withDefaults(defineProps<BentoAnchorScrollerProps>(), { activeIndex: undefined, }); const emit = defineEmits<{ /** * Emits update event when the active index is changed */ (e: 'update:active-index', value: number): void; }>(); const navigationRef = ref(null); const computedItems = computed<Array<BentoAnchorScrollerItem>>(() => props.items.map(item => ({ ...item }))); // Skip and cache only items that are enabled const enabledItems = computed(() => props.items .map((item, originalIndex) => ({ element: unrefElement(item.elementRef), originalIndex, disabled: item.disabled, })) .filter( (item): item is { element: Element; originalIndex: number; disabled: boolean } => !item.disabled && !!item.element ) ); const { top, bottom } = useElementBounding(navigationRef); // Extract strictly the elements for the ScrollSpy to watch const scrollToTargets = computed(() => enabledItems.value.map(c => c.element)); const navigationConditionalClasses = computed(() => ({ 'b-anchor-scroller__navigation--pinned': top.value <= 1, })); const { activeIndex: scrollSpyActiveIndex } = useScrollSpy(scrollToTargets, { default: toRef(props, 'activeIndex'), debounce: 200, }); const currentActiveIndex = computed(() => { const candidate = enabledItems.value[scrollSpyActiveIndex.value]; return candidate ? candidate.originalIndex : 0; }); watch(currentActiveIndex, val => { if (Number.isFinite(val)) { emit('update:active-index', val); } }); watch( () => props.activeIndex, val => { if (Number.isFinite(val) && computedItems.value[val].disabled) { printDevelopmentWarning(`[bento-anchor-scroller] activeIndex should not be a disabled item`); } } ); const navLabelId = generateUid('bento-anchor-scroller-label'); </script> <script lang="ts"> /** * A navigation component that tracks page scroll and allows jumping to sections. * * @example * import { BentoAnchorScroller } from '@adyen/bento-vue2'; * import { ref } from 'vue'; * * export default { * components: { BentoAnchorScroller }, * template: ` * <bento-anchor-scroller :items="items"> * <section ref="section1">Section 1</section> * <section ref="section2">Section 2</section> * </bento-anchor-scroller> * `, * setup() { * const section1 = ref(null); * const section2 = ref(null); * const items = ref([ * { title: 'Section 1', elementRef: section1 }, * { title: 'Section 2', elementRef: section2 }, * ]); * return { * items, * section1, * section2, * } * } * } */ export default { i18n: { messages }, name: 'bento-anchor-scroller', }; </script> <style lang="scss" scoped src="./anchor-scroller.scss" />
1
+ <template> <div v-if="computedItems.length" class="b-anchor-scroller"> <nav ref="navigationRef" class="b-anchor-scroller__navigation" :class="navigationConditionalClasses" :aria-labelledby="navLabelId" > <fixed-scroller condensed centered> <div class="b-anchor-scroller__navigation-panel"> <bento-typography :id="navLabelId" el="span" class="b-anchor-scroller__navigation-panel-label" stronger > {{ t('jumpTo') }} </bento-typography> <anchor-scroller-list :items="computedItems" :active-index="currentActiveIndex" :scroll-offset="bottom" /> </div> </fixed-scroller> </nav> <slot /> </div> </template> <script setup lang="ts"> import { computed, ref, toRef, watch } from 'vue'; import { useElementBounding } from '@vueuse/core'; import BentoTypography from '@/components/typography/typography.vue'; import { FixedScroller } from '@/internal'; import { type BentoAnchorScrollerItem, type BentoAnchorScrollerProps } from './anchor-scroller.types'; import { AnchorScrollerList } from './components/anchor-scroller-list'; import { useI18n } from '@/utils/ts/i18n'; import { generateUid } from '@/utils/ts/generate-uid'; import { unrefElement } from '@/directives/click-outside/utils'; import messages from './messages.json'; import { useScrollSpy } from '@/composables/use-scroll-spy'; import { printDevelopmentWarning } from '@/utils/ts/print-development-warning'; type MessageSchema = (typeof messages)['en-US']; const { t } = useI18n<{ message: MessageSchema }>({ messages }); const props = withDefaults(defineProps<BentoAnchorScrollerProps>(), { activeIndex: undefined, }); const emit = defineEmits<{ /** * Emits update event when the active index is changed */ (e: 'update:active-index', value: number): void; }>(); const navigationRef = ref(null); const computedItems = computed<Array<BentoAnchorScrollerItem>>(() => props.items.map(item => ({ ...item }))); // Skip and cache only items that are enabled const enabledItems = computed(() => props.items .map((item, originalIndex) => ({ element: unrefElement(item.elementRef), originalIndex, disabled: item.disabled, })) .filter( (item): item is { element: Element; originalIndex: number; disabled: boolean } => !item.disabled && !!item.element ) ); const { top, bottom } = useElementBounding(navigationRef); // Extract strictly the elements for the ScrollSpy to watch const scrollToTargets = computed(() => enabledItems.value.map(c => c.element)); const navigationConditionalClasses = computed(() => ({ 'b-anchor-scroller__navigation--pinned': top.value <= 1, })); const { activeIndex: scrollSpyActiveIndex } = useScrollSpy(scrollToTargets, { default: toRef(props, 'activeIndex'), debounce: 200, }); const currentActiveIndex = computed(() => { const candidate = enabledItems.value[scrollSpyActiveIndex.value]; return candidate ? candidate.originalIndex : 0; }); watch(currentActiveIndex, val => { if (Number.isFinite(val)) { emit('update:active-index', val); } }); watch( () => props.activeIndex, val => { if (Number.isFinite(val) && computedItems.value[val].disabled) { printDevelopmentWarning(`[bento-anchor-scroller] activeIndex should not be a disabled item`); } } ); const navLabelId = generateUid('bento-anchor-scroller-label'); </script> <script lang="ts"> /** * A navigation component that tracks page scroll and allows jumping to sections. * * @example * import { BentoAnchorScroller } from '@adyen/bento-vue2'; * import { ref } from 'vue'; * * export default { * components: { BentoAnchorScroller }, * template: ` * <bento-anchor-scroller :items="items"> * <section ref="section1">Section 1</section> * <section ref="section2">Section 2</section> * </bento-anchor-scroller> * `, * setup() { * const section1 = ref(null); * const section2 = ref(null); * const items = ref([ * { title: 'Section 1', elementRef: section1 }, * { title: 'Section 2', elementRef: section2 }, * ]); * return { * items, * section1, * section2, * } * } * } */ export default { i18n: { messages }, name: 'bento-anchor-scroller', }; </script> <style lang="scss" scoped src="./anchor-scroller.scss" />
@@ -0,0 +1 @@
1
+ export const BentoAvatarSizeOptions = ['small', 'medium', 'large', 'xlarge'] as const;
@@ -1 +1 @@
1
- import { type StoryObj } from '@storybook/vue'; import BentoAvatar from './avatar.vue'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import { isVue2 } from 'vue-demi'; import { BentoAvatarSizeOptions } from './avatar.types'; const meta = { title: 'Avatar', component: BentoAvatar, argTypes: { username: { name: 'username', description: 'Name of user', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, src: { name: 'src', description: 'Image src of user profile picture', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, size: { options: BentoAvatarSizeOptions, control: { type: 'select', }, }, }, }; export default meta; type Story = StoryObj<typeof BentoAvatar>; const defaultCode = ` <bento-avatar username="John" /> `; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoAvatar }, props: Object.keys(argTypes), setup: props => ({ args: isVue2 ? props : _args }), template: ` <bento-avatar v-bind="args"/> `, }), args: { username: 'John', iconOnly: false, size: 'small', }, parameters: storybookDocsParameter(defaultCode), };
1
+ import { type StoryObj } from '@storybook/vue'; import BentoAvatar from './avatar.vue'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import { isVue2 } from 'vue-demi'; import { BentoAvatarSizeOptions } from './avatar.internal.types'; const AvatarDefault = "<template>\n <bento-avatar username=\"John\" />\n</template>\n\n<script setup lang=\"ts\">\n import { BentoAvatar } from '@adyen/bento-vue2';\n</script>\n"; const meta = { title: 'Avatar', component: BentoAvatar, argTypes: { username: { name: 'username', description: 'Name of user', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, src: { name: 'src', description: 'Image src of user profile picture', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, size: { options: BentoAvatarSizeOptions, control: { type: 'select', }, }, }, }; export default meta; type Story = StoryObj<typeof BentoAvatar>; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoAvatar }, props: Object.keys(argTypes), setup: props => ({ args: isVue2 ? props : _args }), template: ` <bento-avatar v-bind="args"/> `, }), args: { username: 'John', iconOnly: false, size: 'small', }, parameters: storybookDocsParameter(AvatarDefault), };
@@ -1 +1 @@
1
- /** * Public */ export type BentoAvatarSize = (typeof BentoAvatarSizeOptions)[number]; /** * Private */ export const BentoAvatarSizeOptions = ['small', 'medium', 'large', 'xlarge'] as const;
1
+ import type { BentoAvatarSizeOptions } from './avatar.internal.types'; export type BentoAvatarSize = (typeof BentoAvatarSizeOptions)[number];
@@ -24,8 +24,8 @@ Here are some examples:
24
24
  Here are some "don't dos":
25
25
 
26
26
  - Add custom HTML inside the button's `default` slot e.g. `<bento-button><strong>click me</hello></bento-button>`.
27
- - Putting any elements other than icon components (from the `@adyen/ui-assets` package) in the `iconLeft` or `iconRight`
28
- slots .
27
+ - Putting any elements other than icon components (from the `@adyen/ui-assets-icons-16` package) in the `iconLeft` or
28
+ `iconRight` slots.
29
29
 
30
30
  ## Variations
31
31
 
@@ -72,7 +72,8 @@ Critical buttons have same variations as the regular default buttons except that
72
72
  <Story of={ButtonStories.WithIcon} />
73
73
  </Canvas>
74
74
 
75
- Please use the @adyen/ui-assets-icons-16 NPM package for all icons.
75
+ > **Icon requirement:** Only components from `@adyen/ui-assets-icons-16` are allowed in icon props and icon slots. Icon
76
+ > fonts, custom SVGs, and external icon libraries are not supported.
76
77
 
77
78
  All the buttons variation can be used combined with an icon. The combination of text and icon together should be use if
78
79
  the icon adds value to the user interaction.
@@ -1 +1 @@
1
- import { action } from '@storybook/addon-actions'; import { BentoButtonVariant } from '@/components/button/button.types'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import type { Meta, StoryObj } from '@storybook/vue'; import { isVue2 } from 'vue-demi'; import CheckMark from '@adyen/ui-assets-icons-16/vue/checkmark-circle-fill'; import BentoButton from './button.vue'; const meta: Meta = { title: 'Button', component: BentoButton, argTypes: { variant: { options: Object.values(BentoButtonVariant), mapping: BentoButtonVariant, control: { type: 'select', }, }, default: { name: 'default', defaultValue: '', description: 'Button text', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, iconLeft: { name: 'iconLeft', defaultValue: '', description: 'Icon component', table: { type: { summary: 'VNode[]' }, }, control: { disable: true, }, }, iconRight: { name: 'iconRight', defaultValue: '', description: 'Icon component', table: { type: { summary: 'VNode[]' }, }, control: { disable: true, }, }, type: { options: ['button', 'submit', 'reset'], control: { type: 'select', }, }, // Events blur: { table: { type: { summary: '() => void' }, }, control: { disable: true }, }, click: { table: { type: { summary: '(event: MouseEvent) => void' }, }, control: { disable: true }, }, focus: { table: { type: { summary: '() => void' }, }, control: { disable: true }, }, 'keydown.esc': { table: { type: { summary: '() => void' }, }, control: { disable: true }, }, }, }; export default meta; type Story = StoryObj<typeof BentoButton>; const BUTTON_TEXT_DEFAULT = { default: 'Button', }; const DEFAULT_BUTTON_PROPS = { disabled: false, variant: 'primary', ...BUTTON_TEXT_DEFAULT, }; const defaultCode = ` <bento-button @click="clickedButtonAction"> ${BUTTON_TEXT_DEFAULT.default} </bento-button> `; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoButton }, props: Object.keys(argTypes), template: ` <bento-button v-bind="args" @click="clickedButtonAction" > {{args.default}} </bento-button> `, setup(props) { return { clickedButtonAction: action('onClick'), args: isVue2 ? props : _args, }; }, }), args: DEFAULT_BUTTON_PROPS, parameters: storybookDocsParameter(defaultCode), }; const ButtonWithIconTemplate = { render: (_args, { argTypes }) => ({ components: { BentoButton, CheckMark }, props: Object.keys(argTypes), template: ` <bento-button v-bind="args" @click="clickedButtonAction" > <template #iconLeft> <check-mark svg-title="checked" /> </template> {{args.default}} <template #iconRight> <check-mark svg-title="checked" /> </template> </bento-button> `, setup(props) { return { clickedButtonAction: action('onClick'), args: isVue2 ? props : _args, }; }, }), }; const WithIconCode = ` <bento-button @click="clickedButtonAction" > <template #iconLeft> <check-mark svg-title="checked" /> </template> ${BUTTON_TEXT_DEFAULT.default} <template #iconRight> <check-mark svg-title="checked" /> </template> </bento-button> `; export const WithIcon = { ...ButtonWithIconTemplate, args: DEFAULT_BUTTON_PROPS, parameters: storybookDocsParameter(WithIconCode), }; const OnlyIconTemplate = { render: (_args, { argTypes }) => ({ components: { BentoButton, CheckMark }, props: Object.keys(argTypes), template: ` <bento-button v-bind="args" @click="clickedButtonAction" > <template #iconLeft> <check-mark svg-title="check item" /> </template> </bento-button> `, setup(props) { return { clickedButtonAction: action('onClick'), args: isVue2 ? props : _args, }; }, }), }; export const OnlyIcon = { ...OnlyIconTemplate, argTypes: { default: { table: { disable: true } }, }, }; const LinkCode = ` <bento-button :link="{ to: 'https://adyen.com', external: true }"> {{${BUTTON_TEXT_DEFAULT.default}}} </bento-button> `; export const Link: Story = { render: (_args, { argTypes }) => ({ components: { BentoButton }, props: Object.keys(argTypes), template: ` <bento-button v-bind="args" @click="clickedButtonAction" > {{args.default}} </bento-button> `, setup(props) { return { clickedButtonAction: action('onClick'), args: isVue2 ? props : _args, }; }, }), args: { ...DEFAULT_BUTTON_PROPS, link: { to: '/' } }, parameters: storybookDocsParameter(LinkCode), };
1
+ import { action } from '@storybook/addon-actions'; import { BentoButtonVariant } from '@/components/button/button.types'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import type { Meta, StoryObj } from '@storybook/vue'; import { isVue2 } from 'vue-demi'; import CheckMark from '@adyen/ui-assets-icons-16/vue/checkmark-circle-fill'; import BentoButton from './button.vue'; const ButtonDefault = "<template>\n <bento-button @click=\"clickedButtonAction\">Button</bento-button>\n</template>\n\n<script setup lang=\"ts\">\n import { BentoButton } from '@adyen/bento-vue2';\n\n const clickedButtonAction = () => true;\n</script>\n"; const ButtonLink = "<template>\n <bento-button :link=\"{ to: '/' }\">Button</bento-button>\n</template>\n\n<script setup lang=\"ts\">\n import { BentoButton } from '@adyen/bento-vue2';\n</script>\n"; const ButtonOnlyIcon = "<template>\n <bento-button @click=\"clickedButtonAction\">\n <template #iconLeft>\n <check-mark svg-title=\"check item\" />\n </template>\n </bento-button>\n</template>\n\n<script setup lang=\"ts\">\n import { BentoButton } from '@adyen/bento-vue2';\n import CheckMark from '@adyen/ui-assets-icons-16/vue/checkmark-circle-fill';\n\n const clickedButtonAction = () => true;\n</script>\n"; const ButtonWithIcon = "<template>\n <bento-button @click=\"clickedButtonAction\">\n <template #iconLeft>\n <check-mark svg-title=\"checked\" />\n </template>\n Button\n <template #iconRight>\n <check-mark svg-title=\"checked\" />\n </template>\n </bento-button>\n</template>\n\n<script setup lang=\"ts\">\n import { BentoButton } from '@adyen/bento-vue2';\n import CheckMark from '@adyen/ui-assets-icons-16/vue/checkmark-circle-fill';\n\n const clickedButtonAction = () => true;\n</script>\n"; const meta: Meta = { title: 'Button', component: BentoButton, argTypes: { variant: { options: Object.values(BentoButtonVariant), mapping: BentoButtonVariant, control: { type: 'select', }, }, default: { name: 'default', defaultValue: '', description: 'Button text', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, iconLeft: { name: 'iconLeft', defaultValue: '', description: 'Icon component', table: { type: { summary: 'VNode[]' }, }, control: { disable: true, }, }, iconRight: { name: 'iconRight', defaultValue: '', description: 'Icon component', table: { type: { summary: 'VNode[]' }, }, control: { disable: true, }, }, type: { options: ['button', 'submit', 'reset'], control: { type: 'select', }, }, // Events blur: { table: { type: { summary: '() => void' }, }, control: { disable: true }, }, click: { table: { type: { summary: '(event: MouseEvent) => void' }, }, control: { disable: true }, }, focus: { table: { type: { summary: '() => void' }, }, control: { disable: true }, }, 'keydown.esc': { table: { type: { summary: '() => void' }, }, control: { disable: true }, }, }, }; export default meta; type Story = StoryObj<typeof BentoButton>; const BUTTON_TEXT_DEFAULT = { default: 'Button', }; const DEFAULT_BUTTON_PROPS = { disabled: false, variant: 'primary', ...BUTTON_TEXT_DEFAULT, }; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoButton }, props: Object.keys(argTypes), template: ` <bento-button v-bind="args" @click="clickedButtonAction" > {{args.default}} </bento-button> `, setup(props) { return { clickedButtonAction: action('onClick'), args: isVue2 ? props : _args, }; }, }), args: DEFAULT_BUTTON_PROPS, parameters: storybookDocsParameter(ButtonDefault), }; const ButtonWithIconTemplate = { render: (_args, { argTypes }) => ({ components: { BentoButton, CheckMark }, props: Object.keys(argTypes), template: ` <bento-button v-bind="args" @click="clickedButtonAction" > <template #iconLeft> <check-mark svg-title="checked" /> </template> {{args.default}} <template #iconRight> <check-mark svg-title="checked" /> </template> </bento-button> `, setup(props) { return { clickedButtonAction: action('onClick'), args: isVue2 ? props : _args, }; }, }), }; export const WithIcon = { ...ButtonWithIconTemplate, args: DEFAULT_BUTTON_PROPS, parameters: storybookDocsParameter(ButtonWithIcon), }; const OnlyIconTemplate = { render: (_args, { argTypes }) => ({ components: { BentoButton, CheckMark }, props: Object.keys(argTypes), template: ` <bento-button v-bind="args" @click="clickedButtonAction" > <template #iconLeft> <check-mark svg-title="check item" /> </template> </bento-button> `, setup(props) { return { clickedButtonAction: action('onClick'), args: isVue2 ? props : _args, }; }, }), }; export const OnlyIcon = { ...OnlyIconTemplate, argTypes: { default: { table: { disable: true } }, }, parameters: storybookDocsParameter(ButtonOnlyIcon), }; export const Link: Story = { render: (_args, { argTypes }) => ({ components: { BentoButton }, props: Object.keys(argTypes), template: ` <bento-button v-bind="args" @click="clickedButtonAction" > {{args.default}} </bento-button> `, setup(props) { return { clickedButtonAction: action('onClick'), args: isVue2 ? props : _args, }; }, }), args: { ...DEFAULT_BUTTON_PROPS, link: { to: '/' } }, parameters: storybookDocsParameter(ButtonLink), };
@@ -1 +1 @@
1
- /** * @deprecated Since v2.0.0. Use string literal instead. */ export enum BentoButtonVariant { PRIMARY = 'primary', SECONDARY = 'secondary', TERTIARY = 'tertiary', TERTIARY_WITH_BACKGROUND = 'tertiary-with-background', } export enum BentoButtonPropClass { CONDENSED = 'condensed', DESTRUCTIVE = 'critical', DISABLED = 'disabled', ICON_ONLY = 'icon-only', INVERSE = 'inverse', } export interface BentoButtonProps { condensed?: boolean; critical?: boolean; disabled?: boolean; inverse?: boolean; variant?: BentoButtonVariant | `${BentoButtonVariant}`; type?: string; link?: object; }
1
+ /** * @deprecated Since v3.0.0. Use string literal instead. */ export enum BentoButtonVariant { PRIMARY = 'primary', SECONDARY = 'secondary', TERTIARY = 'tertiary', TERTIARY_WITH_BACKGROUND = 'tertiary-with-background', } export enum BentoButtonPropClass { CONDENSED = 'condensed', DESTRUCTIVE = 'critical', DISABLED = 'disabled', ICON_ONLY = 'icon-only', INVERSE = 'inverse', } export interface BentoButtonProps { condensed?: boolean; critical?: boolean; disabled?: boolean; inverse?: boolean; variant?: BentoButtonVariant | `${BentoButtonVariant}`; type?: string; link?: object; }
@@ -1 +1 @@
1
- import BentoAiButton from './ai-button.vue'; import BentoAiButtonDefault from './__tests__/ai-button-default.vue?raw'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import { action } from '@storybook/addon-actions'; import { isVue2 } from 'vue-demi'; import { type Meta, type StoryObj } from '@storybook/vue'; export default { title: 'Button/AI Button', component: BentoAiButton, argTypes: { condensed: { control: { type: 'boolean', }, table: { type: { summary: 'boolean' }, }, }, default: { name: 'default', defaultValue: '', description: 'Button text', table: { type: { summary: 'VNode[]' }, }, control: { disable: true }, }, disabled: { control: { type: 'boolean', }, table: { type: { summary: 'boolean' }, }, }, inverse: { control: { type: 'boolean', }, table: { type: { summary: 'boolean' }, }, }, }, } as Meta; type Story = StoryObj<typeof BentoAiButton>; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoAiButton }, props: Object.keys(argTypes), template: ` <bento-ai-button @click="onClick" v-bind="args"> Generate with AI </bento-ai-button> `, setup(props) { return { args: isVue2 ? props : _args, onClick: action('click'), }; }, }), parameters: storybookDocsParameter(BentoAiButtonDefault), };
1
+ import BentoAiButton from './ai-button.vue'; const BentoAiButtonDefault = "<template>\n <bento-ai-button @click=\"onClick\">Generate with AI</bento-ai-button>\n</template>\n\n<script setup lang=\"ts\">\n import { BentoAiButton } from '@adyen/bento-vue2';\n\n const onClick = () => true;\n</script>\n"; import { storybookDocsParameter } from '@/utils/ts/storybook'; import { action } from '@storybook/addon-actions'; import { isVue2 } from 'vue-demi'; import { type Meta, type StoryObj } from '@storybook/vue'; export default { title: 'Button/AI Button', component: BentoAiButton, argTypes: { condensed: { control: { type: 'boolean', }, table: { type: { summary: 'boolean' }, }, }, default: { name: 'default', defaultValue: '', description: 'Button text', table: { type: { summary: 'VNode[]' }, }, control: { disable: true }, }, disabled: { control: { type: 'boolean', }, table: { type: { summary: 'boolean' }, }, }, inverse: { control: { type: 'boolean', }, table: { type: { summary: 'boolean' }, }, }, }, } as Meta; type Story = StoryObj<typeof BentoAiButton>; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoAiButton }, props: Object.keys(argTypes), template: ` <bento-ai-button @click="onClick" v-bind="args"> Generate with AI </bento-ai-button> `, setup(props) { return { args: isVue2 ? props : _args, onClick: action('click'), }; }, }), parameters: storybookDocsParameter(BentoAiButtonDefault), };