@adyen/bento-mcp 0.0.0 → 0.1.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 (410) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +21 -0
  3. package/README.md +113 -0
  4. package/dist/assets/components/accordion/accordion.docs.mdx +77 -0
  5. package/dist/assets/components/accordion/accordion.stories.ts +1 -0
  6. package/dist/assets/components/accordion/accordion.vue +1 -0
  7. package/dist/assets/components/accordion/components/accordion-item.stories.ts +1 -0
  8. package/dist/assets/components/accordion/components/accordion-item.vue +1 -0
  9. package/dist/assets/components/action-bar/action-bar.docs.mdx +103 -0
  10. package/dist/assets/components/action-bar/action-bar.stories.ts +1 -0
  11. package/dist/assets/components/action-bar/action-bar.vue +1 -0
  12. package/dist/assets/components/alert/alert.docs.mdx +106 -0
  13. package/dist/assets/components/alert/alert.stories.ts +1 -0
  14. package/dist/assets/components/alert/alert.vue +1 -0
  15. package/dist/assets/components/avatar/avatar.docs.mdx +44 -0
  16. package/dist/assets/components/avatar/avatar.stories.ts +1 -0
  17. package/dist/assets/components/avatar/avatar.vue +1 -0
  18. package/dist/assets/components/avatar/components/avatar-image/avatar-image.vue +1 -0
  19. package/dist/assets/components/button/button.docs.mdx +137 -0
  20. package/dist/assets/components/button/button.stories.ts +1 -0
  21. package/dist/assets/components/button/button.vue +1 -0
  22. package/dist/assets/components/button/components/ai-button/ai-button.docs.mdx +40 -0
  23. package/dist/assets/components/button/components/ai-button/ai-button.stories.ts +1 -0
  24. package/dist/assets/components/button/components/ai-button/ai-button.vue +1 -0
  25. package/dist/assets/components/button/components/button-actions/button-actions.docs.mdx +169 -0
  26. package/dist/assets/components/button/components/button-actions/button-actions.stories.ts +1 -0
  27. package/dist/assets/components/button/components/button-actions/button-actions.vue +1 -0
  28. package/dist/assets/components/button/components/loading-button/loading-button.docs.mdx +106 -0
  29. package/dist/assets/components/button/components/loading-button/loading-button.stories.ts +1 -0
  30. package/dist/assets/components/button/components/loading-button/loading-button.vue +1 -0
  31. package/dist/assets/components/button/components/toggle-button/toggle-button.docs.mdx +81 -0
  32. package/dist/assets/components/button/components/toggle-button/toggle-button.stories.ts +1 -0
  33. package/dist/assets/components/button/components/toggle-button/toggle-button.vue +1 -0
  34. package/dist/assets/components/card/card.docs.mdx +166 -0
  35. package/dist/assets/components/card/card.stories.ts +1 -0
  36. package/dist/assets/components/card/card.vue +1 -0
  37. package/dist/assets/components/checkbox/checkbox.docs.mdx +116 -0
  38. package/dist/assets/components/checkbox/checkbox.stories.ts +1 -0
  39. package/dist/assets/components/checkbox/checkbox.vue +1 -0
  40. package/dist/assets/components/checkbox/components/checkbox-group/checkbox-group.docs.mdx +134 -0
  41. package/dist/assets/components/checkbox/components/checkbox-group/checkbox-group.stories.ts +1 -0
  42. package/dist/assets/components/checkbox/components/checkbox-group/checkbox-group.vue +1 -0
  43. package/dist/assets/components/chip/chip.docs.mdx +51 -0
  44. package/dist/assets/components/chip/chip.stories.ts +1 -0
  45. package/dist/assets/components/chip/chip.vue +1 -0
  46. package/dist/assets/components/click-outside/click-outside.docs.mdx +30 -0
  47. package/dist/assets/components/click-outside/click-outside.stories.ts +1 -0
  48. package/dist/assets/components/code-snippet/code-snippet.docs.mdx +73 -0
  49. package/dist/assets/components/code-snippet/code-snippet.stories.ts +1 -0
  50. package/dist/assets/components/code-snippet/code-snippet.vue +1 -0
  51. package/dist/assets/components/country/country.docs.mdx +61 -0
  52. package/dist/assets/components/country/country.stories.ts +1 -0
  53. package/dist/assets/components/country/country.vue +1 -0
  54. package/dist/assets/components/currency/currency.docs.mdx +38 -0
  55. package/dist/assets/components/currency/currency.stories.ts +1 -0
  56. package/dist/assets/components/currency/currency.vue +1 -0
  57. package/dist/assets/components/dashed-underline/dashed-underline.docs.mdx +57 -0
  58. package/dist/assets/components/dashed-underline/dashed-underline.stories.ts +1 -0
  59. package/dist/assets/components/dashed-underline/dashed-underline.vue +1 -0
  60. package/dist/assets/components/data-grid/components/data-grid-cell/data-grid-cell.vue +1 -0
  61. package/dist/assets/components/data-grid/components/data-grid-cell-actions/data-grid-cell-actions.vue +1 -0
  62. package/dist/assets/components/data-grid/components/data-grid-columns/data-grid-columns.vue +1 -0
  63. package/dist/assets/components/data-grid/components/data-grid-config-settings/components/data-grid-config-settings-column-row/data-grid-config-settings-column-row.vue +1 -0
  64. package/dist/assets/components/data-grid/components/data-grid-config-settings/data-grid-config-settings.vue +1 -0
  65. package/dist/assets/components/data-grid/components/data-grid-lazy-load/data-grid-lazy-load.vue +1 -0
  66. package/dist/assets/components/data-grid/components/data-grid-row/data-grid-row.vue +1 -0
  67. package/dist/assets/components/data-grid/components/data-grid-static-icon/data-grid-static-icon.docs.mdx +61 -0
  68. package/dist/assets/components/data-grid/components/data-grid-static-icon/data-grid-static-icon.stories.ts +1 -0
  69. package/dist/assets/components/data-grid/components/data-grid-static-icon/data-grid-static-icon.vue +1 -0
  70. package/dist/assets/components/data-grid/components/data-grid-summary-cell/data-grid-summary-cell.docs.mdx +56 -0
  71. package/dist/assets/components/data-grid/components/data-grid-summary-cell/data-grid-summary-cell.stories.ts +1 -0
  72. package/dist/assets/components/data-grid/components/data-grid-summary-cell/data-grid-summary-cell.vue +1 -0
  73. package/dist/assets/components/data-grid/components/data-grid-trend-cell/data-grid-trend-cell.docs.mdx +48 -0
  74. package/dist/assets/components/data-grid/components/data-grid-trend-cell/data-grid-trend-cell.stories.ts +1 -0
  75. package/dist/assets/components/data-grid/components/data-grid-trend-cell/data-grid-trend-cell.vue +1 -0
  76. package/dist/assets/components/data-grid/data-grid.docs.mdx +951 -0
  77. package/dist/assets/components/data-grid/data-grid.stories.ts +1 -0
  78. package/dist/assets/components/data-grid/data-grid.vue +1 -0
  79. package/dist/assets/components/date/date.docs.mdx +49 -0
  80. package/dist/assets/components/date/date.stories.ts +1 -0
  81. package/dist/assets/components/date/date.vue +1 -0
  82. package/dist/assets/components/date-picker/date-picker.docs.mdx +69 -0
  83. package/dist/assets/components/date-picker/date-picker.stories.ts +1 -0
  84. package/dist/assets/components/date-picker/date-picker.vue +1 -0
  85. package/dist/assets/components/date-range-picker/components/date-range-picker-calendar/date-range-picker-calendar.vue +1 -0
  86. package/dist/assets/components/date-range-picker/date-range-picker.docs.mdx +168 -0
  87. package/dist/assets/components/date-range-picker/date-range-picker.stories.ts +1 -0
  88. package/dist/assets/components/date-range-picker/date-range-picker.vue +1 -0
  89. package/dist/assets/components/divider/divider.docs.mdx +27 -0
  90. package/dist/assets/components/divider/divider.stories.ts +1 -0
  91. package/dist/assets/components/divider/divider.vue +1 -0
  92. package/dist/assets/components/dropdown/components/dropdown-base-textbox/dropdown-base-textbox.vue +1 -0
  93. package/dist/assets/components/dropdown/components/dropdown-default-textbox/dropdown-default-textbox.vue +1 -0
  94. package/dist/assets/components/dropdown/components/dropdown-options-container/dropdown-options-container.vue +1 -0
  95. package/dist/assets/components/dropdown/components/dropdown-small-textbox/dropdown-small-textbox.vue +1 -0
  96. package/dist/assets/components/dropdown/components/variants/dropdown-avatar/dropdown-avatar.stories.ts +1 -0
  97. package/dist/assets/components/dropdown/components/variants/dropdown-avatar/dropdown-avatar.vue +1 -0
  98. package/dist/assets/components/dropdown/components/variants/dropdown-country/dropdown-country.stories.ts +1 -0
  99. package/dist/assets/components/dropdown/components/variants/dropdown-country/dropdown-country.vue +1 -0
  100. package/dist/assets/components/dropdown/components/variants/dropdown-currency/dropdown-currency.stories.ts +1 -0
  101. package/dist/assets/components/dropdown/components/variants/dropdown-currency/dropdown-currency.vue +1 -0
  102. package/dist/assets/components/dropdown/components/variants/dropdown-payment-method/dropdown-payment-method.stories.ts +1 -0
  103. package/dist/assets/components/dropdown/components/variants/dropdown-payment-method/dropdown-payment-method.vue +1 -0
  104. package/dist/assets/components/dropdown/components/variants/dropdown-tag/dropdown-tag.stories.ts +1 -0
  105. package/dist/assets/components/dropdown/components/variants/dropdown-tag/dropdown-tag.vue +1 -0
  106. package/dist/assets/components/dropdown/dropdown.docs.mdx +420 -0
  107. package/dist/assets/components/dropdown/dropdown.stories.ts +1 -0
  108. package/dist/assets/components/dropdown/dropdown.vue +1 -0
  109. package/dist/assets/components/empty-state/empty-state.docs.mdx +115 -0
  110. package/dist/assets/components/empty-state/empty-state.stories.ts +1 -0
  111. package/dist/assets/components/empty-state/empty-state.vue +1 -0
  112. package/dist/assets/components/file-uploader/components/file-uploader-file-card/components/file-uploader-file-card-animation/file-uploader-file-card-animation.vue +1 -0
  113. package/dist/assets/components/file-uploader/components/file-uploader-file-card/file-uploader-file-card.stories.ts +1 -0
  114. package/dist/assets/components/file-uploader/components/file-uploader-file-card/file-uploader-file-card.vue +1 -0
  115. package/dist/assets/components/file-uploader/components/file-uploader-restrictions/file-uploader-restrictions.stories.ts +1 -0
  116. package/dist/assets/components/file-uploader/components/file-uploader-restrictions/file-uploader-restrictions.vue +1 -0
  117. package/dist/assets/components/file-uploader/file-uploader.docs.mdx +117 -0
  118. package/dist/assets/components/file-uploader/file-uploader.stories.ts +1 -0
  119. package/dist/assets/components/file-uploader/file-uploader.vue +1 -0
  120. package/dist/assets/components/filter-bar/components/all-filters-modal/all-filters-modal.stories.ts +1 -0
  121. package/dist/assets/components/filter-bar/components/all-filters-modal/all-filters-modal.vue +1 -0
  122. package/dist/assets/components/filter-bar/components/all-filters-modal/components/all-filters-modal-button/all-filters-modal-button.vue +1 -0
  123. package/dist/assets/components/filter-bar/components/base-filter/base-filter.docs.mdx +90 -0
  124. package/dist/assets/components/filter-bar/components/base-filter/base-filter.stories.ts +1 -0
  125. package/dist/assets/components/filter-bar/components/base-filter/base-filter.vue +1 -0
  126. package/dist/assets/components/filter-bar/components/base-filter-button/base-filter-button.vue +1 -0
  127. package/dist/assets/components/filter-bar/components/boolean-filter/boolean-filter.vue +1 -0
  128. package/dist/assets/components/filter-bar/components/checkbox-group-filter/checkbox-group-filter.stories.ts +1 -0
  129. package/dist/assets/components/filter-bar/components/checkbox-group-filter/checkbox-group-filter.vue +1 -0
  130. package/dist/assets/components/filter-bar/components/date-filter/date-filter.stories.ts +1 -0
  131. package/dist/assets/components/filter-bar/components/date-filter/date-filter.vue +1 -0
  132. package/dist/assets/components/filter-bar/components/date-range-filter/date-range-filter.stories.ts +1 -0
  133. package/dist/assets/components/filter-bar/components/date-range-filter/date-range-filter.vue +1 -0
  134. package/dist/assets/components/filter-bar/components/filter-bar-button/filter-bar-button.vue +1 -0
  135. package/dist/assets/components/filter-bar/components/filter-bar-button-group/filter-bar-button-group.vue +1 -0
  136. package/dist/assets/components/filter-bar/components/input-filter/input-filter.docs.mdx +18 -0
  137. package/dist/assets/components/filter-bar/components/input-filter/input-filter.stories.ts +1 -0
  138. package/dist/assets/components/filter-bar/components/input-filter/input-filter.vue +1 -0
  139. package/dist/assets/components/filter-bar/components/input-with-dropdown-filter/input-with-dropdown-filter.docs.mdx +18 -0
  140. package/dist/assets/components/filter-bar/components/input-with-dropdown-filter/input-with-dropdown-filter.stories.ts +1 -0
  141. package/dist/assets/components/filter-bar/components/input-with-dropdown-filter/input-with-dropdown-filter.vue +1 -0
  142. package/dist/assets/components/filter-bar/components/radio-group-filter/radio-group-filter.stories.ts +1 -0
  143. package/dist/assets/components/filter-bar/components/radio-group-filter/radio-group-filter.vue +1 -0
  144. package/dist/assets/components/filter-bar/components/range-filter/range-filter.vue +1 -0
  145. package/dist/assets/components/filter-bar/components/select-filter/components/select-filter-button/select-filter-button.vue +1 -0
  146. package/dist/assets/components/filter-bar/components/select-filter/components/select-filter-dropdown/select-filter-dropdown.vue +1 -0
  147. package/dist/assets/components/filter-bar/components/select-filter/select-filter.stories.ts +1 -0
  148. package/dist/assets/components/filter-bar/components/select-filter/select-filter.vue +1 -0
  149. package/dist/assets/components/filter-bar/components/select-filter/variants/select-avatar-filter/select-avatar-filter.stories.ts +1 -0
  150. package/dist/assets/components/filter-bar/components/select-filter/variants/select-avatar-filter/select-avatar-filter.vue +1 -0
  151. package/dist/assets/components/filter-bar/components/select-filter/variants/select-country-filter/select-country-filter.stories.ts +1 -0
  152. package/dist/assets/components/filter-bar/components/select-filter/variants/select-country-filter/select-country-filter.vue +1 -0
  153. package/dist/assets/components/filter-bar/components/select-filter/variants/select-currency-filter/select-currency-filter.stories.ts +1 -0
  154. package/dist/assets/components/filter-bar/components/select-filter/variants/select-currency-filter/select-currency-filter.vue +1 -0
  155. package/dist/assets/components/filter-bar/components/select-filter/variants/select-payment-method-filter/select-payment-method-filter.stories.ts +1 -0
  156. package/dist/assets/components/filter-bar/components/select-filter/variants/select-payment-method-filter/select-payment-method-filter.vue +1 -0
  157. package/dist/assets/components/filter-bar/components/select-filter/variants/select-tag-filter/select-tag-filter.stories.ts +1 -0
  158. package/dist/assets/components/filter-bar/components/select-filter/variants/select-tag-filter/select-tag-filter.vue +1 -0
  159. package/dist/assets/components/filter-bar/components/toggle-filter/toggle-filter.stories.ts +1 -0
  160. package/dist/assets/components/filter-bar/components/toggle-filter/toggle-filter.vue +1 -0
  161. package/dist/assets/components/filter-bar/filter-bar.docs.mdx +1005 -0
  162. package/dist/assets/components/filter-bar/filter-bar.stories.ts +1 -0
  163. package/dist/assets/components/filter-bar/filter-bar.vue +1 -0
  164. package/dist/assets/components/focus-trap/focus-trap.docs.mdx +10 -0
  165. package/dist/assets/components/focus-trap/focus-trap.stories.ts +1 -0
  166. package/dist/assets/components/focus-trap/focus-trap.vue +1 -0
  167. package/dist/assets/components/form-layout/components/form-layout-field-tip/form-layout-field-tip.vue +1 -0
  168. package/dist/assets/components/form-layout/components/form-layout-group/form-layout-group.vue +1 -0
  169. package/dist/assets/components/form-layout/components/form-layout-title/form-layout-title.vue +1 -0
  170. package/dist/assets/components/form-layout/form-layout.docs.mdx +452 -0
  171. package/dist/assets/components/form-layout/form-layout.stories.ts +1 -0
  172. package/dist/assets/components/form-layout/form-layout.vue +1 -0
  173. package/dist/assets/components/header/header.docs.mdx +85 -0
  174. package/dist/assets/components/header/header.stories.ts +1 -0
  175. package/dist/assets/components/header/header.vue +1 -0
  176. package/dist/assets/components/header-with-views/components/header-with-views-all-views/header-with-views-all-views.vue +1 -0
  177. package/dist/assets/components/header-with-views/components/header-with-views-item-edit-form/header-with-views-edit-form.vue +1 -0
  178. package/dist/assets/components/header-with-views/header-with-views.docs.mdx +103 -0
  179. package/dist/assets/components/header-with-views/header-with-views.stories.ts +1 -0
  180. package/dist/assets/components/header-with-views/header-with-views.vue +1 -0
  181. package/dist/assets/components/image/image.docs.mdx +34 -0
  182. package/dist/assets/components/image/image.stories.ts +1 -0
  183. package/dist/assets/components/image/image.vue +1 -0
  184. package/dist/assets/components/info-icon/info-icon.docs.mdx +57 -0
  185. package/dist/assets/components/info-icon/info-icon.stories.ts +1 -0
  186. package/dist/assets/components/info-icon/info-icon.vue +1 -0
  187. package/dist/assets/components/input-field/input-field.docs.mdx +141 -0
  188. package/dist/assets/components/input-field/input-field.stories.ts +1 -0
  189. package/dist/assets/components/input-field/input-field.vue +1 -0
  190. package/dist/assets/components/input-field-password/input-field-password.docs.mdx +292 -0
  191. package/dist/assets/components/input-field-password/input-field-password.stories.ts +1 -0
  192. package/dist/assets/components/input-field-password/input-field-password.vue +1 -0
  193. package/dist/assets/components/input-field-phone-number/input-field-phone-number.docs.mdx +72 -0
  194. package/dist/assets/components/input-field-phone-number/input-field-phone-number.stories.ts +1 -0
  195. package/dist/assets/components/input-field-phone-number/input-field-phone-number.vue +1 -0
  196. package/dist/assets/components/inspector/inspector.docs.mdx +118 -0
  197. package/dist/assets/components/inspector/inspector.stories.ts +1 -0
  198. package/dist/assets/components/inspector/inspector.vue +1 -0
  199. package/dist/assets/components/internal/base-button/base-button.vue +1 -0
  200. package/dist/assets/components/internal/button-actions-with-menu/button-actions-with-menu.stories.ts +1 -0
  201. package/dist/assets/components/internal/button-actions-with-menu/button-actions-with-menu.vue +1 -0
  202. package/dist/assets/components/internal/calendar/calendar.stories.ts +1 -0
  203. package/dist/assets/components/internal/calendar/calendar.vue +1 -0
  204. package/dist/assets/components/internal/calendar/components/calendar-month/calendar-month.stories.ts +1 -0
  205. package/dist/assets/components/internal/calendar/components/calendar-month/calendar-month.vue +1 -0
  206. package/dist/assets/components/internal/calendar/components/calendar-month/components/calendar-month-day/__test__/calendar-month-day-stub.vue +1 -0
  207. package/dist/assets/components/internal/calendar/components/calendar-month/components/calendar-month-day/calendar-month-day.stories.ts +1 -0
  208. package/dist/assets/components/internal/calendar/components/calendar-month/components/calendar-month-day/calendar-month-day.vue +1 -0
  209. package/dist/assets/components/internal/calendar/components/calendar-year/calendar-year.vue +1 -0
  210. package/dist/assets/components/internal/calendar/components/calendar-year/components/calendar-year-month/__test__/calendar-year-month-stub.vue +1 -0
  211. package/dist/assets/components/internal/calendar/components/calendar-year/components/calendar-year-month/calendar-year-month.vue +1 -0
  212. package/dist/assets/components/internal/checkbox-input/checkbox-input.stories.ts +1 -0
  213. package/dist/assets/components/internal/checkbox-input/checkbox-input.vue +1 -0
  214. package/dist/assets/components/internal/controls-group/controls-group.vue +1 -0
  215. package/dist/assets/components/internal/copy/copy.docs.mdx +43 -0
  216. package/dist/assets/components/internal/copy/copy.stories.ts +1 -0
  217. package/dist/assets/components/internal/copy/copy.vue +1 -0
  218. package/dist/assets/components/internal/decorative-checkbox/decorative-checkbox.vue +1 -0
  219. package/dist/assets/components/internal/dialog-page/dialog-page.vue +1 -0
  220. package/dist/assets/components/internal/error-message/error-message.vue +1 -0
  221. package/dist/assets/components/internal/field-label/field-label.vue +1 -0
  222. package/dist/assets/components/internal/fixed-scroller/fixed-scroller.docs.mdx +21 -0
  223. package/dist/assets/components/internal/fixed-scroller/fixed-scroller.stories.ts +1 -0
  224. package/dist/assets/components/internal/fixed-scroller/fixed-scroller.vue +1 -0
  225. package/dist/assets/components/internal/footer-actions/footer-actions.vue +1 -0
  226. package/dist/assets/components/internal/grid-layout/grid-layout.vue +1 -0
  227. package/dist/assets/components/internal/header-meta/header-meta.vue +1 -0
  228. package/dist/assets/components/internal/info-icon-with-popover/info-icon-with-popover.vue +1 -0
  229. 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 +1 -0
  230. package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/listbox-multi-select-options.vue +1 -0
  231. package/dist/assets/components/internal/listbox/components/listbox-multi-select/listbox-multi-select.vue +1 -0
  232. package/dist/assets/components/internal/listbox/components/listbox-option/listbox-option.vue +1 -0
  233. package/dist/assets/components/internal/listbox/components/listbox-option-tag/listbox-option-tag.vue +1 -0
  234. package/dist/assets/components/internal/listbox/components/listbox-single-select/components/listbox-single-select-category/listbox-single-select-category.vue +1 -0
  235. package/dist/assets/components/internal/listbox/components/listbox-single-select/listbox-single-select.vue +1 -0
  236. package/dist/assets/components/internal/listbox/components/listbox-single-select-option/listbox-single-select-option.vue +1 -0
  237. package/dist/assets/components/internal/listbox/listbox.stories.ts +1 -0
  238. package/dist/assets/components/internal/listbox/listbox.vue +1 -0
  239. package/dist/assets/components/internal/radio-input/radio-input.stories.ts +1 -0
  240. package/dist/assets/components/internal/radio-input/radio-input.vue +1 -0
  241. package/dist/assets/components/internal/teleport/teleport.vue +1 -0
  242. package/dist/assets/components/internal/tooltip/tooltip.test.vue +1 -0
  243. package/dist/assets/components/internal/tooltip/tooltip.vue +1 -0
  244. package/dist/assets/components/layout/components/layout-row/layout-row.stories.ts +1 -0
  245. package/dist/assets/components/layout/components/layout-row/layout-row.vue +1 -0
  246. package/dist/assets/components/layout/layout.docs.mdx +108 -0
  247. package/dist/assets/components/layout/layout.stories.ts +1 -0
  248. package/dist/assets/components/layout/layout.vue +1 -0
  249. package/dist/assets/components/link/link.docs.mdx +119 -0
  250. package/dist/assets/components/link/link.stories.ts +1 -0
  251. package/dist/assets/components/link/link.vue +1 -0
  252. package/dist/assets/components/loading-indicator/loading-indicator.docs.mdx +65 -0
  253. package/dist/assets/components/loading-indicator/loading-indicator.stories.ts +1 -0
  254. package/dist/assets/components/loading-indicator/loading-indicator.vue +1 -0
  255. package/dist/assets/components/menu/components/menu-item/menu-item.vue +1 -0
  256. package/dist/assets/components/menu/components/menu-item-list/menu-item-list.vue +1 -0
  257. package/dist/assets/components/menu/components/menu-list-container/menu-list-container.vue +1 -0
  258. package/dist/assets/components/menu/components/sub-menu-item-list/sub-menu-item-list.vue +1 -0
  259. package/dist/assets/components/menu/menu.docs.mdx +121 -0
  260. package/dist/assets/components/menu/menu.stories.ts +1 -0
  261. package/dist/assets/components/menu/menu.vue +1 -0
  262. package/dist/assets/components/modal/components/base-modal/base-modal.vue +1 -0
  263. package/dist/assets/components/modal/components/modal-default/modal-default.vue +1 -0
  264. package/dist/assets/components/modal/components/modal-dialog/modal-dialog.vue +1 -0
  265. package/dist/assets/components/modal/components/modal-page/modal-page.vue +1 -0
  266. package/dist/assets/components/modal/modal.docs.mdx +215 -0
  267. package/dist/assets/components/modal/modal.stories.ts +1 -0
  268. package/dist/assets/components/modal/modal.vue +1 -0
  269. package/dist/assets/components/modal-fullscreen/components/modal-fullscreen-page.vue +1 -0
  270. package/dist/assets/components/modal-fullscreen/modal-fullscreen.docs.mdx +217 -0
  271. package/dist/assets/components/modal-fullscreen/modal-fullscreen.stories.ts +1 -0
  272. package/dist/assets/components/modal-fullscreen/modal-fullscreen.vue +1 -0
  273. package/dist/assets/components/pagination/components/pagination-context/pagination-context.vue +1 -0
  274. package/dist/assets/components/pagination/components/pagination-controls/pagination-controls.vue +1 -0
  275. package/dist/assets/components/pagination/components/pagination-results-per-page/pagination-results-per-page.vue +1 -0
  276. package/dist/assets/components/pagination/pagination.docs.mdx +116 -0
  277. package/dist/assets/components/pagination/pagination.stories.ts +1 -0
  278. package/dist/assets/components/pagination/pagination.vue +1 -0
  279. package/dist/assets/components/payment-method/payment-method.docs.mdx +34 -0
  280. package/dist/assets/components/payment-method/payment-method.stories.ts +1 -0
  281. package/dist/assets/components/payment-method/payment-method.vue +1 -0
  282. package/dist/assets/components/popover/components/popover-dismiss-button/popover-dismiss-button.vue +1 -0
  283. package/dist/assets/components/popover/components/popover-image/popover-image.vue +1 -0
  284. package/dist/assets/components/popover/components/popover-title/popover-title.vue +1 -0
  285. package/dist/assets/components/popover/popover.docs.mdx +89 -0
  286. package/dist/assets/components/popover/popover.stories.ts +1 -0
  287. package/dist/assets/components/popover/popover.vue +1 -0
  288. package/dist/assets/components/popper-container/popper-container.docs.mdx +11 -0
  289. package/dist/assets/components/popper-container/popper-container.stories.ts +1 -0
  290. package/dist/assets/components/popper-container/popper-container.vue +1 -0
  291. package/dist/assets/components/promo-banner/promo-banner.docs.mdx +94 -0
  292. package/dist/assets/components/promo-banner/promo-banner.stories.ts +1 -0
  293. package/dist/assets/components/promo-banner/promo-banner.vue +1 -0
  294. package/dist/assets/components/radio-group/components/radio-button/radio-button.docs.mdx +76 -0
  295. package/dist/assets/components/radio-group/components/radio-button/radio-button.stories.ts +1 -0
  296. package/dist/assets/components/radio-group/components/radio-button/radio-button.vue +1 -0
  297. package/dist/assets/components/radio-group/radio-group.docs.mdx +154 -0
  298. package/dist/assets/components/radio-group/radio-group.stories.ts +1 -0
  299. package/dist/assets/components/radio-group/radio-group.vue +1 -0
  300. package/dist/assets/components/rich-text-editor/components/rich-text-editor-content-area/rich-text-editor-content-area.vue +1 -0
  301. package/dist/assets/components/rich-text-editor/components/rich-text-editor-renderer/components/rich-text-editor-code-block/rich-text-editor-code-block.vue +1 -0
  302. package/dist/assets/components/rich-text-editor/components/rich-text-editor-renderer/components/rich-text-editor-inline-code/rich-text-editor-inline-code.vue +1 -0
  303. package/dist/assets/components/rich-text-editor/components/rich-text-editor-renderer/components/rich-text-editor-link/rich-text-editor-link.vue +1 -0
  304. package/dist/assets/components/rich-text-editor/components/rich-text-editor-renderer/components/rich-text-editor-list-item/rich-text-editor-list-item.vue +1 -0
  305. package/dist/assets/components/rich-text-editor/components/rich-text-editor-renderer/components/rich-text-editor-table/rich-text-editor-table.vue +1 -0
  306. package/dist/assets/components/rich-text-editor/rich-text-editor.docs.mdx +52 -0
  307. package/dist/assets/components/rich-text-editor/rich-text-editor.stories.ts +1 -0
  308. package/dist/assets/components/rich-text-editor/rich-text-editor.vue +1 -0
  309. package/dist/assets/components/search-bar/search-bar.docs.mdx +117 -0
  310. package/dist/assets/components/search-bar/search-bar.stories.ts +1 -0
  311. package/dist/assets/components/search-bar/search-bar.vue +1 -0
  312. package/dist/assets/components/secondary-nav/components/secondary-nav-category/secondary-nav-category.vue +1 -0
  313. package/dist/assets/components/secondary-nav/components/secondary-nav-item/secondary-nav-item.vue +1 -0
  314. package/dist/assets/components/secondary-nav/secondary-nav.docs.mdx +40 -0
  315. package/dist/assets/components/secondary-nav/secondary-nav.stories.ts +1 -0
  316. package/dist/assets/components/secondary-nav/secondary-nav.vue +1 -0
  317. package/dist/assets/components/segmented-control/components/segmented-control-button/segmented-control-button.vue +1 -0
  318. package/dist/assets/components/segmented-control/segmented-control.docs.mdx +90 -0
  319. package/dist/assets/components/segmented-control/segmented-control.stories.ts +1 -0
  320. package/dist/assets/components/segmented-control/segmented-control.vue +1 -0
  321. package/dist/assets/components/selection-card/components/selection-card-group/selection-card-group.docs.mdx +119 -0
  322. package/dist/assets/components/selection-card/components/selection-card-group/selection-card-group.stories.ts +1 -0
  323. package/dist/assets/components/selection-card/components/selection-card-group/selection-card-group.vue +1 -0
  324. package/dist/assets/components/selection-card/selection-card.docs.mdx +108 -0
  325. package/dist/assets/components/selection-card/selection-card.stories.ts +1 -0
  326. package/dist/assets/components/selection-card/selection-card.vue +1 -0
  327. package/dist/assets/components/sidepanel/components/sidepanel-page.stories.ts +1 -0
  328. package/dist/assets/components/sidepanel/components/sidepanel-page.vue +1 -0
  329. package/dist/assets/components/sidepanel/sidepanel.docs.mdx +129 -0
  330. package/dist/assets/components/sidepanel/sidepanel.stories.ts +1 -0
  331. package/dist/assets/components/sidepanel/sidepanel.vue +1 -0
  332. package/dist/assets/components/status/status.docs.mdx +62 -0
  333. package/dist/assets/components/status/status.stories.ts +1 -0
  334. package/dist/assets/components/status/status.vue +1 -0
  335. package/dist/assets/components/stepper/components/step/step.stories.ts +1 -0
  336. package/dist/assets/components/stepper/components/step/step.vue +1 -0
  337. package/dist/assets/components/stepper/stepper.docs.mdx +127 -0
  338. package/dist/assets/components/stepper/stepper.stories.ts +1 -0
  339. package/dist/assets/components/stepper/stepper.vue +1 -0
  340. package/dist/assets/components/structured-list/components/structered-list-item/structured-list-item.stories.ts +1 -0
  341. package/dist/assets/components/structured-list/components/structered-list-item/structured-list-item.vue +1 -0
  342. package/dist/assets/components/structured-list/structured-list.docs.mdx +68 -0
  343. package/dist/assets/components/structured-list/structured-list.stories.ts +1 -0
  344. package/dist/assets/components/structured-list/structured-list.vue +1 -0
  345. package/dist/assets/components/summary-grid/components/summary-grid-item/summary-grid-item.vue +1 -0
  346. package/dist/assets/components/summary-grid/components/summary-grid-item-amount/summary-grid-item-amount.stories.ts +1 -0
  347. package/dist/assets/components/summary-grid/components/summary-grid-item-amount/summary-grid-item-amount.vue +1 -0
  348. package/dist/assets/components/summary-grid/components/summary-grid-item-custom/summary-grid-item-custom.stories.ts +1 -0
  349. package/dist/assets/components/summary-grid/components/summary-grid-item-custom/summary-grid-item-custom.vue +1 -0
  350. package/dist/assets/components/summary-grid/components/summary-grid-item-numeric/summary-grid-item-numeric.stories.ts +1 -0
  351. package/dist/assets/components/summary-grid/components/summary-grid-item-numeric/summary-grid-item-numeric.vue +1 -0
  352. package/dist/assets/components/summary-grid/components/summary-grid-item-percentage/summary-grid-item-percentage.stories.ts +1 -0
  353. package/dist/assets/components/summary-grid/components/summary-grid-item-percentage/summary-grid-item-percentage.vue +1 -0
  354. package/dist/assets/components/summary-grid/components/summary-grid-item-text/summary-grid-item-text.stories.ts +1 -0
  355. package/dist/assets/components/summary-grid/components/summary-grid-item-text/summary-grid-item-text.vue +1 -0
  356. package/dist/assets/components/summary-grid/summary-grid.docs.mdx +152 -0
  357. package/dist/assets/components/summary-grid/summary-grid.stories.ts +1 -0
  358. package/dist/assets/components/summary-grid/summary-grid.vue +1 -0
  359. package/dist/assets/components/tabs/components/tab.vue +1 -0
  360. package/dist/assets/components/tabs/tabs.docs.mdx +98 -0
  361. package/dist/assets/components/tabs/tabs.stories.ts +1 -0
  362. package/dist/assets/components/tabs/tabs.vue +1 -0
  363. package/dist/assets/components/tag/tag.docs.mdx +137 -0
  364. package/dist/assets/components/tag/tag.stories.ts +1 -0
  365. package/dist/assets/components/tag/tag.vue +1 -0
  366. package/dist/assets/components/textarea/textarea.docs.mdx +53 -0
  367. package/dist/assets/components/textarea/textarea.stories.ts +1 -0
  368. package/dist/assets/components/textarea/textarea.vue +1 -0
  369. package/dist/assets/components/timeline/components/timeline-item/timeline-item.stories.ts +1 -0
  370. package/dist/assets/components/timeline/components/timeline-item/timeline-item.vue +1 -0
  371. package/dist/assets/components/timeline/timeline.docs.mdx +131 -0
  372. package/dist/assets/components/timeline/timeline.stories.ts +1 -0
  373. package/dist/assets/components/timeline/timeline.vue +1 -0
  374. package/dist/assets/components/toast/components/toast-item/toast-item.vue +1 -0
  375. package/dist/assets/components/toast/components/toast-shadow-stack/toast-shadow-stack.vue +1 -0
  376. package/dist/assets/components/toast/toast.docs.mdx +151 -0
  377. package/dist/assets/components/toast/toast.stories.ts +1 -0
  378. package/dist/assets/components/toast/toast.vue +1 -0
  379. package/dist/assets/components/toggle/toggle.docs.mdx +81 -0
  380. package/dist/assets/components/toggle/toggle.stories.ts +1 -0
  381. package/dist/assets/components/toggle/toggle.vue +1 -0
  382. package/dist/assets/components/tutorial/components/tutorial-popover/components/tutorial-indicator/tutorial-indicator.vue +1 -0
  383. package/dist/assets/components/tutorial/components/tutorial-popover/tutorial-popover.vue +1 -0
  384. package/dist/assets/components/tutorial/tutorial.docs.mdx +85 -0
  385. package/dist/assets/components/tutorial/tutorial.stories.ts +1 -0
  386. package/dist/assets/components/tutorial/tutorial.vue +1 -0
  387. package/dist/assets/components/typography/typography.docs.mdx +124 -0
  388. package/dist/assets/components/typography/typography.stories.ts +1 -0
  389. package/dist/assets/components/typography/typography.vue +1 -0
  390. package/dist/assets/composables/use-bento-currency/use-bento-currency.docs.mdx +28 -0
  391. package/dist/assets/composables/use-bento-currency/use-bento-currency.stories.ts +1 -0
  392. package/dist/assets/composables/use-click-outside/use-click-outside.docs.mdx +10 -0
  393. package/dist/assets/composables/use-click-outside/use-click-outside.stories.ts +1 -0
  394. package/dist/assets/directives/highlight/highlight.docs.mdx +64 -0
  395. package/dist/assets/directives/highlight/highlight.stories.ts +1 -0
  396. package/dist/assets/directives/keyboard-navigation/keyboard-navigation.docs.mdx +41 -0
  397. package/dist/assets/directives/keyboard-navigation/keyboard-navigation.stories.ts +1 -0
  398. package/dist/assets/directives/tooltip/tooltip.docs.mdx +86 -0
  399. package/dist/assets/directives/tooltip/tooltip.stories.ts +1 -0
  400. package/dist/assets/index.ts +1 -0
  401. package/dist/assets/templates/dashboard-template/components/dashboard-section/dashboard-section.stories.ts +1 -0
  402. package/dist/assets/templates/dashboard-template/components/dashboard-section/dashboard-section.vue +1 -0
  403. package/dist/assets/templates/dashboard-template/dashboard-template.docs.mdx +148 -0
  404. package/dist/assets/templates/dashboard-template/dashboard-template.stories.ts +1 -0
  405. package/dist/assets/templates/dashboard-template/dashboard-template.vue +1 -0
  406. package/dist/assets/templates/data-grid-template/data-grid-template.docs.mdx +117 -0
  407. package/dist/assets/templates/data-grid-template/data-grid-template.stories.ts +1 -0
  408. package/dist/assets/templates/data-grid-template/data-grid-template.vue +1 -0
  409. package/dist/main.js +30031 -0
  410. package/package.json +45 -3
@@ -0,0 +1 @@
1
+ import { storybookDocsParameter } from '@/utils/ts/storybook'; import { BentoCountry, BentoCountryCode } from '@/components/country'; import BentoSummaryGridItemCustom from './summary-grid-item-custom.vue'; import { type Meta, type StoryObj } from '@storybook/vue'; import { isVue2 } from 'vue-demi'; import { action } from '@storybook/addon-actions'; const meta: Meta = { title: 'Summary Grid/Summary Grid Item Custom', component: BentoSummaryGridItemCustom, }; export default meta; type Story = StoryObj<typeof BentoSummaryGridItemCustom>; const SUMMARY_BAR_ITEM_TITLE = 'Item title'; const SUMMARY_BAR_INFO_ICON_TOOLTIP = 'Text for icon tooltip'; const SUMMARY_BAR_ITEM_DEFAULT_PROPS = { title: SUMMARY_BAR_ITEM_TITLE, }; const defaultCode = ` <bento-summary-grid-item-custom :title="titleVariable"> Item content bento-summary-grid-item-custom> `; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoSummaryGridItemCustom, BentoCountry }, props: Object.keys(argTypes), template: ` <bento-summary-grid-item-custom v-bind="args" class="b-summary-grid-item-story" @copy-click="copyClicked" @info-icon-mouseenter="infoIconMouseEnter" > <bento-country code="${BentoCountryCode.NL}" /> </bento-summary-grid-item-custom> `, setup(props) { const copyClicked = (event: PointerEvent) => action('copy-click')(event); const infoIconMouseEnter = (event: PointerEvent) => action('info-icon-mouseenter')(event); return { args: isVue2 ? props : _args, copyClicked, infoIconMouseEnter, }; }, }), args: { ...SUMMARY_BAR_ITEM_DEFAULT_PROPS, }, parameters: storybookDocsParameter(defaultCode), }; const withIconsCode = ` <bento-summary-grid-item-custom :title="titleVariable" :copy="textToCopy" info-icon-tooltip-text="tooltip text" @copy-click="copyClicked" @info-icon-mouseenter="infoIconMouseEnter" > <bento-country code="${BentoCountryCode.NL}" /> </bento-summary-grid-item-custom> `; export const WithIcons: Story = { render: Default.render, args: { ...SUMMARY_BAR_ITEM_DEFAULT_PROPS, infoIconTooltipText: SUMMARY_BAR_INFO_ICON_TOOLTIP, copy: 'copy this', }, parameters: storybookDocsParameter(withIconsCode), }; const FitContentCode = ` <bento-summary-grid-item-custom :title="titleVariable" :fit-content="true"> Item content bento-summary-grid-item-custom> `; export const FitContent: Story = { render: Default.render, args: { ...SUMMARY_BAR_ITEM_DEFAULT_PROPS, infoIconTooltipText: SUMMARY_BAR_INFO_ICON_TOOLTIP, copyIcon: true, fitContent: true, }, parameters: storybookDocsParameter(FitContentCode), }; const withUnderlineCode = ` <bento-summary-grid-item-custom :title="titleVariable"> <template #dashed-underline> <strong>Underline</strong> <em>popover</em> content </template> Item content <bento-summary-grid-item-custom> `; export const WithDashedUnderline: Story = { render: (_args, { argTypes }) => ({ components: { BentoSummaryGridItemCustom }, props: Object.keys(argTypes), template: ` <bento-summary-grid-item-custom v-bind="args" class="b-summary-grid-item-story" > <template #dashed-underline> <strong>Underline</strong> <em>popover</em> content </template> Item content </bento-summary-grid-item-custom> `, setup(props) { return { args: isVue2 ? props : _args, }; }, }), args: { ...SUMMARY_BAR_ITEM_DEFAULT_PROPS, }, parameters: storybookDocsParameter(withUnderlineCode), };
@@ -0,0 +1 @@
1
+ <template> <summary-grid-item :title="title" :info-icon-tooltip-text="infoIconTooltipText" :copy="copy" :fit-content="fitContent" :underline-popover-size="underlinePopoverSize" :underline-tooltip-text="underlineTooltipText" @copy-click="$emit('copy-click', $event)" @info-icon-mouseenter="$emit('info-icon-mouseenter', $event)" > <template v-if="hasSlot('dashed-underline')" #dashed-underline> <slot name="dashed-underline" /> </template> <slot /> </summary-grid-item> </template> <script setup lang="ts"> import { useSlots } from 'vue'; import { SummaryGridItem } from '../summary-grid-item'; import { useHasSlot } from '@/composables'; import type { BentoSummaryGridItemCustomProps } from './summary-grid-item-custom.types'; defineEmits<{ /** * Emitted when the copy button is clicked. */ (e: 'copy-click', event: MouseEvent): void; /** * Emitted when the mouse pointer enters the info icon component. */ (e: 'info-icon-mouseenter', event: MouseEvent): void; }>(); withDefaults(defineProps<BentoSummaryGridItemCustomProps>(), { copy: undefined, infoIconTooltipText: null, fitContent: false, underlinePopoverSize: 'fit-content', underlineTooltipText: null, }); const slots = useSlots(); const hasSlot = useHasSlot(slots); </script> <script lang="ts"> /** * A summary bar item is a piece of information to be displayed in `bento-summary-bar` component * * @example * import { SummaryBarItem } from '@adyen/bento-vue2'; * * export default { * components: { SummaryBarItem }, * template: ` * <summary-grid-item :title="textVariable"> * Content of the item * </summary-grid-item> * ` * } */ export default {}; </script>
@@ -0,0 +1 @@
1
+ import { type Meta, type StoryObj } from '@storybook/vue'; import { BentoSummaryGridItemSize, BentoSummaryGridItemTrendDirection } from '../../summary-grid.types'; import BentoSummaryGridItemNumeric from './summary-grid-item-numeric.vue'; import { isVue2 } from 'vue-demi'; import { action } from '@storybook/addon-actions'; const meta: Meta = { title: 'Summary Grid/Summary Grid Item/Summary Grid Item Numeric', component: BentoSummaryGridItemNumeric, argTypes: { size: { options: Object.values(BentoSummaryGridItemSize), mapping: BentoSummaryGridItemSize, control: { type: 'select', }, }, trendDirection: { options: Object.values(BentoSummaryGridItemTrendDirection), mapping: BentoSummaryGridItemTrendDirection, control: { type: 'select', }, }, secondaryTrendDirection: { options: Object.values(BentoSummaryGridItemTrendDirection), mapping: BentoSummaryGridItemTrendDirection, control: { type: 'select', }, }, }, }; export default meta; type Story = StoryObj<typeof BentoSummaryGridItemNumeric>; const SUMMARY_BAR_ITEM_TITLE = 'Summary grid item numeric'; const SUMMARY_BAR_ITEM_LABEL = '123'; const SUMMARY_BAR_ITEM_SECONDARY_METRIC = '345'; const SUMMARY_BAR_INFO_ICON_TOOLTIP = 'Text for icon tooltip'; const SUMMARY_BAR_ITEM_TREND = '+12%'; const SUMMARY_BAR_ITEM_SECONDARY_TREND = '-12%'; const SUMMARY_BAR_ITEM_DEFAULT_PROPS = { title: SUMMARY_BAR_ITEM_TITLE, label: SUMMARY_BAR_ITEM_LABEL, size: 'small', infoIconTooltipText: SUMMARY_BAR_INFO_ICON_TOOLTIP, copy: 'copy this', trend: SUMMARY_BAR_ITEM_TREND, }; const SUMMARY_BAR_ITEM_WITH_SECONDARY_METRIC_PROPS = { ...SUMMARY_BAR_ITEM_DEFAULT_PROPS, secondaryMetric: SUMMARY_BAR_ITEM_SECONDARY_METRIC, secondaryTrend: SUMMARY_BAR_ITEM_SECONDARY_TREND, secondaryTrendDirection: 'negative', }; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoSummaryGridItemNumeric }, props: Object.keys(argTypes), template: ` <bento-summary-grid-item-numeric v-bind="args" @copy-click="copyClicked" @info-icon-mouseenter="infoIconMouseEnter" /> `, setup(props) { const copyClicked = (event: PointerEvent) => action('copy-click')(event); const infoIconMouseEnter = (event: PointerEvent) => action('info-icon-mouseenter')(event); return { args: isVue2 ? props : _args, copyClicked, infoIconMouseEnter, }; }, }), args: { ...SUMMARY_BAR_ITEM_DEFAULT_PROPS, }, }; export const WithSecondaryMetric: Story = { render: (_args, { argTypes }) => ({ components: { BentoSummaryGridItemNumeric }, props: Object.keys(argTypes), template: `<bento-summary-grid-item-numeric v-bind="args"/>`, setup(props) { return { args: isVue2 ? props : _args, }; }, }), args: { ...SUMMARY_BAR_ITEM_WITH_SECONDARY_METRIC_PROPS, }, };
@@ -0,0 +1 @@
1
+ <template> <summary-grid-item item-type="numeric" :info-icon-tooltip-text="infoIconTooltipText" :title="title" :copy="copy" :fit-content="fitContent" :size="size" :trend="trend" :trend-direction="trendDirection" :secondary-trend="secondaryTrend" :secondary-trend-direction="secondaryTrendDirection" :underline-popover-size="underlinePopoverSize" :underline-tooltip-text="underlineTooltipText" class="b-summary-grid-item-numeric" @copy-click="$emit('copy-click', $event)" @info-icon-mouseenter="$emit('info-icon-mouseenter', $event)" > <template v-if="hasSlot('dashed-underline')" #dashed-underline> <slot name="dashed-underline" /> </template> {{ label }} <template v-if="secondaryMetric" #secondary> {{ secondaryMetric }} </template> </summary-grid-item> </template> <script setup lang="ts"> import { useSlots } from 'vue'; import { SummaryGridItem } from '../summary-grid-item'; import { useHasSlot } from '@/composables'; import type { BentoSummaryGridItemNumericProps } from './summary-grid-item-numeric.types'; defineEmits<{ /** * Emitted when the copy button is clicked. */ (e: 'copy-click', event: MouseEvent): void; /** * Emitted when the mouse pointer enters the info icon component. */ (e: 'info-icon-mouseenter', event: MouseEvent): void; }>(); withDefaults(defineProps<BentoSummaryGridItemNumericProps>(), { copy: undefined, fitContent: false, infoIconTooltipText: null, secondaryMetric: null, secondaryTrend: null, secondaryTrendDirection: 'positive', size: 'small', trend: null, trendDirection: 'positive', underlinePopoverSize: 'fit-content', underlineTooltipText: null, }); const slots = useSlots(); const hasSlot = useHasSlot(slots); </script> <script lang="ts"> /** * Summary grid item component used to display any numeric information * * @example * import { BentoSummaryGridItemNumeric } from '@adyen/bento-vue2'; * * export default { * components: { BentoSummaryGridItemNumeric }, * template: ` * <bento-summary-grid-item-numeric * title="Your title" * label="123" * info-icon-tooltip-text="Your tooltip text here will be toggled by the info icon" * trend="+12%" * trend-direction="neutral" * size="medium" * /> * ` * } */ export default {}; </script>
@@ -0,0 +1 @@
1
+ import { type Meta, type StoryObj } from '@storybook/vue'; import BentoSummaryGridItemPercentage from './summary-grid-item-percentage.vue'; import { BentoSummaryGridItemSize, BentoSummaryGridItemTrendDirection } from '../../summary-grid.types'; import { isVue2 } from 'vue-demi'; import { action } from '@storybook/addon-actions'; const meta: Meta = { title: 'Summary Grid/Summary Grid Item/Summary Grid Item Percentage', component: BentoSummaryGridItemPercentage, argTypes: { size: { options: Object.values(BentoSummaryGridItemSize), mapping: BentoSummaryGridItemSize, control: { type: 'select', }, }, trendDirection: { options: Object.values(BentoSummaryGridItemTrendDirection), mapping: BentoSummaryGridItemTrendDirection, control: { type: 'select', }, }, secondaryTrendDirection: { options: Object.values(BentoSummaryGridItemTrendDirection), mapping: BentoSummaryGridItemTrendDirection, control: { type: 'select', }, }, }, }; export default meta; type Story = StoryObj<typeof BentoSummaryGridItemPercentage>; const SUMMARY_BAR_ITEM_TITLE = 'Summary grid item percentage'; const SUMMARY_BAR_ITEM_LABEL = 20.12; const SUMMARY_BAR_INFO_ICON_TOOLTIP = 'Text for icon tooltip'; const SUMMARY_BAR_ITEM_TREND = '+12%'; const SUMMARY_BAR_ITEM_SECONDARY_METRIC = 40; const SUMMARY_BAR_ITEM_SECONDARY_TREND = '-24%'; const SUMMARY_BAR_ITEM_DEFAULT_PROPS = { title: SUMMARY_BAR_ITEM_TITLE, label: SUMMARY_BAR_ITEM_LABEL, size: 'small', infoIconTooltipText: SUMMARY_BAR_INFO_ICON_TOOLTIP, copy: 'copy this', trend: SUMMARY_BAR_ITEM_TREND, }; const SUMMARY_BAR_ITEM_WITH_SECONDARY_METRIC_PROPS = { ...SUMMARY_BAR_ITEM_DEFAULT_PROPS, secondaryMetric: SUMMARY_BAR_ITEM_SECONDARY_METRIC, secondaryTrend: SUMMARY_BAR_ITEM_SECONDARY_TREND, secondaryTrendDirection: 'negative', }; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoSummaryGridItemPercentage }, props: Object.keys(argTypes), template: ` <bento-summary-grid-item-percentage v-bind="args" @copy-click="copyClicked" @info-icon-mouseenter="infoIconMouseEnter" /> `, setup(props) { const copyClicked = (event: PointerEvent) => action('copy-click')(event); const infoIconMouseEnter = (event: PointerEvent) => action('info-icon-mouseenter')(event); return { args: isVue2 ? props : _args, copyClicked, infoIconMouseEnter, }; }, }), args: { ...SUMMARY_BAR_ITEM_DEFAULT_PROPS, }, }; export const WithSecondaryMetric: Story = { render: (_args, { argTypes }) => ({ components: { BentoSummaryGridItemPercentage }, props: Object.keys(argTypes), template: `<bento-summary-grid-item-percentage v-bind="args"/>`, setup(props) { return { args: isVue2 ? props : _args, }; }, }), args: { ...SUMMARY_BAR_ITEM_WITH_SECONDARY_METRIC_PROPS, }, };
@@ -0,0 +1 @@
1
+ <template> <summary-grid-item item-type="percentage" :info-icon-tooltip-text="infoIconTooltipText" :title="title" :copy="copy" :fit-content="fitContent" :size="size" :trend="trend" :trend-direction="trendDirection" :secondary-trend="secondaryTrend" :secondary-trend-direction="secondaryTrendDirection" :underline-popover-size="underlinePopoverSize" :underline-tooltip-text="underlineTooltipText" class="b-summary-grid-item-percentage" @copy-click="$emit('copy-click', $event)" @info-icon-mouseenter="$emit('info-icon-mouseenter', $event)" > <template v-if="hasSlot('dashed-underline')" #dashed-underline> <slot name="dashed-underline" /> </template> {{ computedLabelPercentage }} <template v-if="secondaryMetric" #secondary> {{ computedSecondaryMetricPercentage }} </template> </summary-grid-item> </template> <script setup lang="ts"> import { computed, useSlots } from 'vue'; import { SummaryGridItem } from '../summary-grid-item'; import { useHasSlot } from '@/composables'; import { useI18n } from '@/utils/ts/i18n'; import type { BentoSummaryGridItemPercentageProps } from './summary-grid-item-percentage.types'; import type { NumberFormatOptions } from 'vue-i18n'; const { locale } = useI18n(); defineEmits<{ /** * Emitted when the copy button is clicked. */ (e: 'copy-click', event: MouseEvent): void; /** * Emitted when the mouse pointer enters the info icon component. */ (e: 'info-icon-mouseenter', event: MouseEvent): void; }>(); const props = withDefaults(defineProps<BentoSummaryGridItemPercentageProps>(), { copy: undefined, fitContent: false, infoIconTooltipText: null, secondaryMetric: null, secondaryTrend: null, secondaryTrendDirection: 'positive', size: 'small', trend: null, trendDirection: 'positive', underlinePopoverSize: 'fit-content', underlineTooltipText: null, }); const slots = useSlots(); const hasSlot = useHasSlot(slots); const percentageArgs: NumberFormatOptions = { style: 'percent', maximumFractionDigits: 2, }; const isNumeric = (value: string | number) => value != null && value !== '' && !isNaN(Number(value)); const convertToPercentIfNumber = (value: string | number) => { if (value && isNumeric(value)) { return new Intl.NumberFormat(locale.value, percentageArgs).format(Number(value) / 100); } return value; }; const computedLabelPercentage = computed(() => convertToPercentIfNumber(props.label)); const computedSecondaryMetricPercentage = computed(() => convertToPercentIfNumber(props.secondaryMetric)); </script> <script lang="ts"> /** * Summary grid item component used to display any percentage information * * @example * import { BentoSummaryGridItemPercentage } from '@adyen/bento-vue2'; * * export default { * components: { BentoSummaryGridItemPercentage }, * template: ` * <bento-summary-grid-item-percentage * title="Your title" * label="123" * info-icon-tooltip-text="Your tooltip text here will be toggled by the info icon" * trend="+12%" * trend-direction="neutral" * size="medium" * /> * ` * } */ export default { i18n: {}, }; </script>
@@ -0,0 +1 @@
1
+ import { type Meta, type StoryObj } from '@storybook/vue'; import { action } from '@storybook/addon-actions'; import { isVue2 } from 'vue-demi'; import BentoSummaryGridItemText from './summary-grid-item-text.vue'; const meta: Meta = { title: 'Summary Grid/Summary Grid Item/Summary Grid Item Text', component: BentoSummaryGridItemText, }; export default meta; type Story = StoryObj<typeof BentoSummaryGridItemText>; const SUMMARY_BAR_ITEM_TITLE = 'Summary grid item text'; const SUMMARY_BAR_ITEM_LABEL = 'hjsagdf1255fasdgh621ghjkjaksasdsad'; const SUMMARY_BAR_INFO_ICON_TOOLTIP = 'Text for icon tooltip'; const SUMMARY_BAR_ITEM_DEFAULT_PROPS = { title: SUMMARY_BAR_ITEM_TITLE, label: SUMMARY_BAR_ITEM_LABEL, infoIconTooltipText: SUMMARY_BAR_INFO_ICON_TOOLTIP, copy: 'copy this', }; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoSummaryGridItemText }, props: Object.keys(argTypes), template: ` <bento-summary-grid-item-text v-bind="args" @copy-click="copyClicked" @info-icon-mouseenter="infoIconMouseEnter" /> `, setup(props) { const copyClicked = (event: PointerEvent) => action('copy-click')(event); const infoIconMouseEnter = (event: PointerEvent) => action('info-icon-mouseenter')(event); return { args: isVue2 ? props : _args, copyClicked, infoIconMouseEnter, }; }, }), args: { ...SUMMARY_BAR_ITEM_DEFAULT_PROPS, }, };
@@ -0,0 +1 @@
1
+ <template> <summary-grid-item item-type="text" :info-icon-tooltip-text="infoIconTooltipText" :title="title" :copy="copy" :fit-content="fitContent" :underline-popover-size="underlinePopoverSize" :underline-tooltip-text="underlineTooltipText" class="b-summary-grid-item-text" @copy-click="$emit('copy-click', $event)" @info-icon-mouseenter="$emit('info-icon-mouseenter', $event)" > <template v-if="hasSlot('dashed-underline')" #dashed-underline> <slot name="dashed-underline" /> </template> {{ label }} </summary-grid-item> </template> <script setup lang="ts"> import { useSlots } from 'vue'; import { SummaryGridItem } from '../summary-grid-item'; import { useHasSlot } from '@/composables'; import type { BentoSummaryGridItemTextProps } from './summary-grid-item-text.types'; defineEmits<{ /** * Emitted when the copy button is clicked. */ (e: 'copy-click', event: MouseEvent): void; /** * Emitted when the mouse pointer enters the info icon component. */ (e: 'info-icon-mouseenter', event: MouseEvent): void; }>(); withDefaults(defineProps<BentoSummaryGridItemTextProps>(), { copy: undefined, fitContent: false, infoIconTooltipText: null, underlinePopoverSize: 'fit-content', underlineTooltipText: null, }); const slots = useSlots(); const hasSlot = useHasSlot(slots); </script> <script lang="ts"> /** * Summary grid item component used to display text only. Can be used for references, IDs or any other text data. * * @example * import { BentoSummaryGridItemText } from '@adyen/bento-vue2'; * * export default { * components: { BentoSummaryGridItemText }, * template: ` * <bento-summary-grid-item-text * title="Your title" * label="Your text here" * info-icon-tooltip-text="Your tooltip text here will be toggled by the info icon" * /> * ` * } */ export default {}; </script>
@@ -0,0 +1,152 @@
1
+ import { Canvas, Story, Meta } from '@storybook/blocks';
2
+ import * as SummaryGridStories from './summary-grid.stories';
3
+ import * as SummaryGridItemAmountStories from './components/summary-grid-item-amount/summary-grid-item-amount.stories';
4
+ import * as SummaryGridItemNumericStories from './components/summary-grid-item-numeric/summary-grid-item-numeric.stories';
5
+ import * as SummaryGridItemPercentageStories from './components/summary-grid-item-percentage/summary-grid-item-percentage.stories';
6
+ import * as SummaryGridItemTextStories from './components/summary-grid-item-text/summary-grid-item-text.stories';
7
+ import * as SummaryGridItemCustomStories from './components/summary-grid-item-custom/summary-grid-item-custom.stories';
8
+
9
+ <Meta title="Summary Grid" of={SummaryGridStories} />
10
+
11
+ # Summary Grid
12
+
13
+ Summary grid is a set of summary card items that are placed on a 12 column grid and can be used to highlight key
14
+ information on your page.
15
+
16
+ You can choose to use summary grid (based on 12 columns) or summary cards individually (hug content behaviour, no grid).
17
+
18
+ <Canvas sourceState="closed">
19
+ <Story of={SummaryGridStories.Default} />
20
+ </Canvas>
21
+
22
+ ## Use Cases
23
+
24
+ Use a SummaryGrid if:
25
+
26
+ - You need to display key information on page to a user
27
+
28
+ ### Do not use
29
+
30
+ - Do not put use for displaying complicated large chunks of information.
31
+
32
+ ## Slots
33
+
34
+ The BentoSummaryGrid has a maximum of 3 rows. Each row contains 6 columns.
35
+
36
+ To place content into a particular row and columns one must simply use the named slot:
37
+
38
+ ```html
39
+ <bento-summary-grid>
40
+ <template #cell-{ROW_NUMBER}-{COLUMN_NUMBER}> ...item component placed here </template>
41
+ </bento-summary-grid>
42
+ ```
43
+
44
+ For example if we wanted we could make a 4 column layout that would be spread evenly across the row by using the
45
+ following code:
46
+
47
+ ```html
48
+ <bento-summary-grid>
49
+ <template #cell-1-1> ...item component placed here </template>
50
+ <template #cell-1-2> ...item component placed here </template>
51
+ <template #cell-1-3> ...item component placed here </template>
52
+ <template #cell-1-4> ...item component placed here </template>
53
+ </bento-summary-grid>
54
+ ```
55
+
56
+ ## Column Width
57
+
58
+ You are able to sets the responsive columns widths for any of the 3 rows in the BentoSummaryGrid.
59
+
60
+ Each row can be set by setting the `row{ROW_NUMBER_TO_SET_COLUMN_WIDTHS_ON}` in the `columnWidth` prop.
61
+
62
+ e.g.
63
+
64
+ ```typescript
65
+ columnWidth: {
66
+ row2: [
67
+ { small: 12, medium: 6, large: 8 },
68
+ { small: 6, medium: 3, large: 2 },
69
+ { small: 6, medium: 3, large: 2 }
70
+ ],
71
+ },
72
+ ```
73
+
74
+ The code above will set the responsive column widths for all 3 columns on the second row.
75
+
76
+ Each of your items can have one of the following widths: 2 (minimal), 3, 4, or 6.
77
+
78
+ You can construct any layout you wish from available width keeping in mind that in total you should fill 12 columns (not
79
+ less, not more).
80
+
81
+ We provide 2 breakpoints Small size (0-549px) Medium size (550px-1089px) Large size (1090px+)
82
+
83
+ Users have to pass config setting for each breakpoint to define what happens with the grid.
84
+
85
+ Please note that these are container queries, not media queries, so the breakpoints are defined by the size of the
86
+ container the grid sits in. Therefore, if you place it in a sidebar, a small size will apply.
87
+
88
+ If you do not supply any columns widths for a row, the columns will automatically fill up the row being of equal width.
89
+
90
+ ## Modifiers
91
+
92
+ ### Slashed zero
93
+
94
+ If the `slashedZero` prop is set to `true`, the summary grid will render zeroes in a slashed font numeric style.
95
+
96
+ ## Items
97
+
98
+ ### Variants
99
+
100
+ #### Amount
101
+
102
+ <Canvas sourceState="closed">
103
+ <Story of={SummaryGridItemAmountStories.Default} />
104
+ </Canvas>
105
+
106
+ Used to display financial data, such as currency values and monetary amounts.
107
+
108
+ #### Numeric
109
+
110
+ <Canvas sourceState="closed">
111
+ <Story of={SummaryGridItemNumericStories.Default} />
112
+ </Canvas>
113
+
114
+ Used to display any numeric information.
115
+
116
+ #### Percentage
117
+
118
+ <Canvas sourceState="closed">
119
+ <Story of={SummaryGridItemPercentageStories.Default} />
120
+ </Canvas>
121
+
122
+ Used to display any percentage information.
123
+
124
+ The `label` and `secondaryMetric` props accept a number (e.g., `12.14`) or a numeric string (e.g., `"12.14"`), which
125
+ will be automatically formatted as a (translated) percentage. If you provide a pre-formatted string like `"12.14%"`, it
126
+ will be displayed as is. The `trend` and `secondaryTrend` props expect a pre-formatted (and translated) string (e.g.,
127
+ `"+12%"`), as they are displayed as is.
128
+
129
+ #### Text
130
+
131
+ <Canvas sourceState="closed">
132
+ <Story of={SummaryGridItemTextStories.Default} />
133
+ </Canvas>
134
+
135
+ Used to display text only. Can be used for references, IDs or any other text data.
136
+
137
+ #### Custom
138
+
139
+ <Canvas sourceState="closed">
140
+ <Story of={SummaryGridItemCustomStories.Default} />
141
+ </Canvas>
142
+
143
+ Only use the `summary-grid-item-custom` component with the following components in the `default` slot:
144
+
145
+ - A BentoStatus
146
+ - A BentoPaymentMethod
147
+ - A BentoCountry
148
+ - A BentoDate
149
+
150
+ ## Resources
151
+
152
+ - [Figma link](https://www.figma.com/file/uLabwF3243jdMDsNSP7U9I/Bento---Components?type=design&node-id=8195-14548&mode=design&t=61tB76dAUA0HpXF8-0)
@@ -0,0 +1 @@
1
+ import { BentoStatus } from '@/components/status'; import { BentoPaymentMethod } from '@/components/payment-method'; import { BentoCountry, BentoCountryCode } from '@/components/country'; import { BentoDate, BentoDateFormat } from '@/components/date'; import type { Meta, StoryObj } from '@storybook/vue'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import { BentoSummaryGridItemAmount, BentoSummaryGridItemCustom, BentoSummaryGridItemNumeric, BentoSummaryGridItemPercentage, BentoSummaryGridItemText, } from './index'; import BentoSummaryGrid from './summary-grid.vue'; import './summary-grid.stories.scss?module'; import { isVue2 } from 'vue-demi'; const meta: Meta = { title: 'Summary Grid', component: BentoSummaryGrid, }; export default meta; type Story = StoryObj<typeof BentoSummaryGrid>; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoStatus, BentoDate, BentoPaymentMethod, BentoCountry, BentoSummaryGrid, BentoSummaryGridItemCustom, BentoSummaryGridItemAmount, BentoSummaryGridItemNumeric, BentoSummaryGridItemPercentage, BentoSummaryGridItemText, }, template: ` <div class="b-summary-grid-story"> <bento-summary-grid v-bind="args" > <template #cell-1-1> <bento-summary-grid-item-custom title="Status Item" info-icon-tooltip-text="text for icon" copy="copy this to clipboard" > <bento-status variant="red"> Status </bento-status> </bento-summary-grid-item-custom> </template> <template #cell-1-2> <bento-summary-grid-item-custom title="Payment Method Item" info-icon-tooltip-text="text for icon" copy="copy this to clipboard" > <template #dashed-underline> Extra popover information </template> <bento-payment-method type="ideal" label='923601322401537F'/> </bento-summary-grid-item-custom> </template> <template #cell-1-3> <bento-summary-grid-item-custom title="Country/Region Item" info-icon-tooltip-text="text for icon" copy="copy this to clipboard" > <bento-country :code="BentoCountryCode.NL" /> </bento-summary-grid-item-custom> </template> <template #cell-1-4> <bento-summary-grid-item-custom title="Date/Time Item" info-icon-tooltip-text="text for icon" copy="copy this to clipboard" > <bento-date :date="dateNow" :format="BentoDateFormat.FULL_DATE_TIME_WITH_TIMEZONE_AND_PERIOD"/> </bento-summary-grid-item-custom> </template> <template #cell-2-1> <bento-summary-grid-item-percentage title="Percentage Item" label="123" info-icon-tooltip-text="text for icon" trend="12" copy="copy this to clipboard" /> </template> <template #cell-2-2> <bento-summary-grid-item-amount title="Text Item" label="14" info-icon-tooltip-text="text for icon" copy="copy this to clipboard" underline-tooltip-text="text for underline tooltip" /> </template> <template #cell-2-3> <bento-summary-grid-item-numeric title="Numeric Item" label="123" info-icon-tooltip-text="text for icon" trend="12%" trend-direction="positive" copy="copy this to clipboard" size="large" /> </template> <template #cell-2-4> <bento-summary-grid-item-text title="Text Item" label="text label" info-icon-tooltip-text="text for icon" copy="copy this to clipboard" /> </template> </bento-summary-grid> </div> `, props: Object.keys(argTypes), setup(props) { const DATE_OBJECT = new Date(); return { // Values args: isVue2 ? props : _args, dateNow: DATE_OBJECT, BentoCountryCode, BentoDateFormat, }; }, }), args: { columnWidth: { row2: [ { small: 12, medium: 6, large: 6 }, { small: 6, medium: 6, large: 2 }, { small: 6, medium: 6, large: 2 }, { small: 12, medium: 6, large: 2 }, ], }, }, parameters: storybookDocsParameter(`<bento-summary-grid> <template #cell-1-1> <bento-summary-grid-item-custom title="Status Item" info-icon-tooltip-text="text for icon" copy="copy this to clipboard" > <bento-status variant="red"> Status </bento-status> </bento-summary-grid-item-custom> </template> <template #cell-1-2> <bento-summary-grid-item-custom title="Payment Method Item" info-icon-tooltip-text="text for icon" copy="copy this to clipboard" > <bento-payment-method type="ideal" label='923601322401537F'/> </bento-summary-grid-item-custom> </template> <template #cell-1-3> <bento-summary-grid-item-custom title="Country/Region Item" info-icon-tooltip-text="text for icon" copy="copy this to clipboard" > <bento-country :code="BentoCountryCode.NL" /> </bento-summary-grid-item-custom> </template> <template #cell-1-4> <bento-summary-grid-item-custom title="Date/Time Item" info-icon-tooltip-text="text for icon" copy="copy this to clipboard" > <bento-date :date="dateNow" :format="BentoDateFormat.FULL_DATE_TIME_WITH_TIMEZONE_AND_PERIOD"/> </bento-summary-grid-item-custom> </template> <template #cell-2-1> <bento-summary-grid-item-percentage title="Percentage Item" label="123" info-icon-tooltip-text="text for icon" trend="12" copy="copy this to clipboard" /> </template> <template #cell-2-2> <bento-summary-grid-item-amount title="Text Item" label="14" info-icon-tooltip-text="text for icon" copy="copy this to clipboard" /> </template> <template #cell-2-3> <bento-summary-grid-item-numeric title="Numeric Item" label="123" info-icon-tooltip-text="text for icon" trend="12%" trend-direction="positive" copy="copy this to clipboard" size="large" /> </template> <template #cell-2-4> <bento-summary-grid-item-text title="Text Item" label="text label" info-icon-tooltip-text="text for icon" copy="copy this to clipboard" /> </template> </bento-summary-grid>`), };
@@ -0,0 +1 @@
1
+ <template> <div class="b-summary-grid"> <grid-layout v-for="index in numberOfRows" :key="`summary-grid-row-${index}`" :data-testid="`summary-grid-row-${index}`" :column-width="columnWidth?.[`row${index}`]" > <template v-if="hasSlot(`cell-${index}-1`)" #col-1> <slot :name="`cell-${index}-1`" /> </template> <template v-if="hasSlot(`cell-${index}-2`)" #col-2> <slot :name="`cell-${index}-2`" /> </template> <template v-if="hasSlot(`cell-${index}-3`)" #col-3> <slot :name="`cell-${index}-3`" /> </template> <template v-if="hasSlot(`cell-${index}-4`)" #col-4> <slot :name="`cell-${index}-4`" /> </template> <template v-if="hasSlot(`cell-${index}-5`)" #col-5> <slot :name="`cell-${index}-5`" /> </template> <template v-if="hasSlot(`cell-${index}-6`)" #col-6> <slot :name="`cell-${index}-6`" /> </template> </grid-layout> </div> </template> <script setup lang="ts"> import { onMounted, provide, toRef, useSlots } from 'vue'; import type { BentoSummaryGridLayout, BentoSummaryGridProps } from './summary-grid.types'; import { GridLayout } from '@/components/internal'; import { useHasSlot } from '@/composables'; import { SUMMARY_GRID_LAYOUT_INJECTION_KEY, SUMMARY_GRID_SLASHED_ZERO, } from '@/components/summary-grid/summary-grid.keys'; const props = withDefaults(defineProps<BentoSummaryGridProps>(), { columnWidth: null, slashedZero: false, }); const slots = useSlots(); const hasSlot = useHasSlot(slots); let numberOfRows = 1; if (slots) { const slotRows = Object.keys(slots) ?.filter(slotName => slotName.includes('cell-')) ?.map(slotName => parseInt(slotName.split('-')?.[1], 10)); numberOfRows = Math.max(...slotRows); } onMounted(() => { if (numberOfRows > 3) { throw new Error( 'BentoSummaryGrid must only have a maximum of 3 rows. Read the documentation for more information.' ); } }); const registerComponentsInSummaryGrid: BentoSummaryGridLayout = () => { const isSummaryGridLayout = true; return { isSummaryGridLayout }; }; provide(SUMMARY_GRID_LAYOUT_INJECTION_KEY, registerComponentsInSummaryGrid); provide(SUMMARY_GRID_SLASHED_ZERO, toRef(props, 'slashedZero')); </script> <script lang="ts"> /** * A summary grid component that displays a collection items. * * @example * import { BentoSummaryGrid, BentoSummaryGridItemAmount } from '@adyen/bento-vue2'; * * export default { * components: { BentoSummaryGrid, BentoSummaryGridItemAmount }, * template: ` * <bento-summary-grid> * <template #cell-2-2> * <bento-summary-grid-item-amount * title="Text Item" * label="14" * info-icon-tooltip-text="text for icon" * copy="copy this to clipboard" * /> * </template> * </bento-summary-grid> * ` * } */ export default {}; </script> <style lang="scss" scoped src="./summary-grid.scss" />
@@ -0,0 +1 @@
1
+ <template> <div v-show="activeTabId === id" :id="`${id}-tabpanel`" class="b-tab" role="tabpanel" :aria-labelledby="id"> <template v-if="activeTabId === id"> <slot /> </template> </div> </template> <script setup lang="ts"> import { computed, inject, onUnmounted, provide, ref, toRefs } from 'vue'; import { EXTERNAL_TITLE_REGISTER_ENTRY_INJECTION_KEY, TABS_ACTIVE_TAB_ID_KEY, TABS_REGISTER_TAB_INJECTION_KEY, } from '../tabs.keys'; import { type BentoTabsRegisterTab } from '../tabs.types'; import { type BentoTabProps, type BentoTabProvidedTitle } from './tab.types'; const props = withDefaults(defineProps<BentoTabProps>(), { counter: null, disabled: false, hidden: false, withNotificationIndicator: false, setElementRef: undefined, }); // External title injection const { counter, disabled, hidden, withNotificationIndicator } = toRefs(props); const componentTitle = ref<BentoTabProps['title']>(); const setTitle: BentoTabProvidedTitle = (value: string) => { componentTitle.value = value; }; provide(EXTERNAL_TITLE_REGISTER_ENTRY_INJECTION_KEY, setTitle); const computedTitle = computed<BentoTabProps['title']>(() => componentTitle.value ?? props.title); const registerTab: BentoTabsRegisterTab = inject(TABS_REGISTER_TAB_INJECTION_KEY); const activeTabId = inject(TABS_ACTIVE_TAB_ID_KEY); const { id, unregisterTab } = registerTab({ counter, disabled, hidden, title: computedTitle, withNotificationIndicator, setElementRef: props.setElementRef, }); onUnmounted(() => unregisterTab()); </script> <script lang="ts"> /** * Tab content which attaches a tab to the `bento-tabs` component * and renders is content when it becomes active. * * @example * import { BentoTab, BentoTabs } from '@adyen/bento-vue2'; * * <template> * <bento-tabs> * <bento-tab * :counter="1" * :disabled="false" * :hidden="false" * title="Tab's title" * with-notification-indicator * > * Tab content * </bento-tab> * </bento-tabs> * </template> */ export default { name: 'bento-tab', }; </script> <style lang="scss" scoped src="./tab.scss" />
@@ -0,0 +1,98 @@
1
+ import { Canvas, Story, Source } from '@storybook/blocks';
2
+ import * as TabsStories from './tabs.stories';
3
+
4
+ # Tabs
5
+
6
+ Tabs are used to navigate between different, but related content views within a page. They always contain at least two
7
+ tabs, with one of them active. By default, the first tab is always active and content from that tab is displayed on the
8
+ page. Selecting another tab replaces content with the new tab’s content.
9
+
10
+ <Canvas of={TabsStories.Default} />
11
+
12
+ <br />
13
+
14
+ ## Do's
15
+
16
+ - Use tabs on content-heavy pages to organise related content into different views. This can help reduce cognitive load.
17
+ - Use concise tab headers that are easily understandable, ideally one or two words.
18
+
19
+ ### Do not's
20
+
21
+ - Don’t use tabs if users needs to read through all the content to fully understand a process or flow, or if they need
22
+ to compare information between them.
23
+
24
+ ## Variations
25
+
26
+ ### Notification indicators
27
+
28
+ If there’s something requiring user attention, the tab gets a blue notification dot. To set/unset this notification dot,
29
+ set the `withNotificationIndicator` prop to `true` or `false` for the designated `bento-tab`.
30
+
31
+ <Canvas of={TabsStories.WithNotificationIndicator} />
32
+
33
+ ## Modifiers
34
+
35
+ ### Hiding tabs
36
+
37
+ Hiding individual `bento-tab` elements might deem necessary, for instance, when a tab's content is not relevant to the
38
+ user based on their permissions or the current state of the application.
39
+
40
+ To hide a tab, set the `hidden` prop to `true` for the designated `bento-tab` instead of using `v-show` in the template.
41
+
42
+ <Source
43
+ dark
44
+ language="html"
45
+ code={`<bento-tab hidden title="Hidden tab" :counter="0">
46
+ This shouldn't be seen!
47
+ </bento-tab>`}
48
+ />
49
+
50
+ ## Capturing tab elements
51
+
52
+ If you need to target a specific tab to anchor a tooltip or a popover, use the `set-element-ref` prop on `bento-tab`.
53
+ This prop accepts a callback function that safely returns the HTML element back to your component's state.
54
+
55
+ ## Responsiveness
56
+
57
+ When the tabs cannot fit within the viewport, two chevron buttons are added and the bar becomes horizontally scrollable.
58
+
59
+ Each press of the button scrolls 80% of the visible bar’s width, so that there is always a little bit of previously
60
+ visible content still in view on each scroll. This helps user with orientating themselves again. The 80% is calculated
61
+ from either left or right, depending which direction the user is scrolling (see below).
62
+
63
+ The first and last scroll should always end 24px away from the button.
64
+
65
+ Scrolling the bar does not automatically change tab selection. To select another tab user still needs to click/tap on
66
+ it.
67
+
68
+ ## Accessibility
69
+
70
+ ### Keyboard interaction
71
+
72
+ | Keyboard interaction | Action |
73
+ | -------------------- | ------------------------------------------------------------------------------------------------------------ |
74
+ | `Tab` | Sets focus on the active tab (further repeats would move focus into the tab panel) |
75
+ | `ArrowLeft` | When the active tab is in focus, moves the focus to the previous non-disabled and visible tab, if available. |
76
+ | `ArrowRight` | When the active tab is in focus, moves the focus to the next non-disabled and visible tab, if available. |
77
+ | `Space` | Activates the tab. |
78
+ | `Enter` | Activates the tab. |
79
+
80
+ ### Roles, states and properties
81
+
82
+ | Role | Attribute | Element | Usage |
83
+ | ---------- | -------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
84
+ | `tablist` | | `div` | Indicates that the element serves as a container for a set of tabs. |
85
+ | `tab` | | `button` | <ul><li>Indicates the element serves as a tab control.</li><li>Provides a title for its associated <code>tabpanel</code>.</li></ul> |
86
+ | | `aria-selected="true"` | `button` | <ul> <li>Indicates the tab control is activated and its associated panel is displayed.</li> <li>Set when a user activates a tab.</li> <li> Does not change when focus moves in the <code>tablist</code>. </li> </ul> |
87
+ | | `aria-selected="false"` | `button` | <ul> <li> Indicates the tab control is not active and its associated panel is <strong>NOT</strong> displayed. </li> <li> Set for all tab elements in the tab set except the active tab; the one associated with the currently displayed panel. </li> </ul> |
88
+ | | `aria-hidden="false"` | `button` | Indicates the tab control is visible and it is listed in the _accessibility tree_ |
89
+ | | `aria-hidden="true"` | `button` | Indicates the tab control is **not** visible and it is **not** listed in the _accessibility tree_ |
90
+ | | `tabindex="-1"` | `button` | <ul> <li> Removes the element from the page <kbd>Tab</kbd> sequence. </li> <li> Set when a tab is not selected so that only the selected (active) tab is in the page <kbd>Tab</kbd> sequence. </li> <li> Since an HTML <code>button</code> element is used for the tab, it is not necessary to set <code>tabindex="0"</code> on the selected (active) tab element. </li> <li> This approach to managing focus is described in the section on "Managing Focus Within Components Using a Roving tabindex". </li> </ul> |
91
+ | | `aria-controls="ID_REFERENCE"` | `button` | Refers to the `tabpanel` element associated with the tab. |
92
+ | `tabpanel` | | `div` | <ul> <li>Indicates the element serves as a container for tab panel content.</li> <li> Is hidden unless its associated <code>tab</code> control is activated. </li> </ul> |
93
+ | | `aria-labelledby="ID_REFERENCE"` | `div` | <ul> <li> Refers to the <code>tab</code> element that controls the panel. </li> <li>Provides an accessible name for the tab panel.</li> </ul> |
94
+
95
+ ## Resources
96
+
97
+ - [Figma link](https://www.figma.com/file/uLabwF3243jdMDsNSP7U9I/Bento---Components?node-id=3298%3A73472&mode=dev)
98
+ - [W3 Example of Tabs with Manual Activation](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/examples/tabs-manual/)
@@ -0,0 +1 @@
1
+ import { isVue2 } from 'vue-demi'; import BentoTabs from './tabs.vue'; import BentoTab from './components/tab.vue'; import type { Meta, StoryObj } from '@storybook/vue'; import { storybookDocsParameter } from '@/utils/ts/storybook'; const meta: Meta = { title: 'Tabs', component: BentoTabs, argTypes: { // Slots default: { name: 'default', type: { name: 'string', required: false }, description: 'Default slot content', control: 'text', table: { type: { summary: 'VNode[]' }, }, }, }, }; export default meta; type Story = StoryObj<typeof BentoTabs>; const defaultCode = ` <template> <bento-tabs :activeTabIndex="activeTabIndex" @update:active-tab-index="onTabSelected"> <bento-tab title="Maria Ahlefeldt"> (16 January 1755 - 20 December 1810) was a Danish, (originally German), composer. She is known as the first female composer in Denmark. </bento-tab> <bento-tab title="Carl Andersen"> (29 April 1847 - 7 May 1909) was a Danish flutist, conductor and composer born in Copenhagen, son of the flutist Christian Joachim Andersen. </bento-tab> <bento-tab title="Karl Truffel"> (1 March 1981 - 7 November 1992) was a Danish dog and commander born in Berlin, son of the machinist Tom Jahoor Truffel. </bento-tab> <bento-tab title="Maria Ahlefeldt" :disabled="true"> (16 January 1755 - 20 December 1810) was a Danish, (originally German), composer. She is known as the first female composer in Denmark. </bento-tab> </bento-tabs> </template> <script setup lang="ts"> import { BentoTab, BentoTabs } from '@adyen/bento-vue2'; import { ref } from 'vue' const activeTabIndex = ref(1) const onTabSelected = (newActiveTabIndex: number) => { activeTabIndex.value = newActiveTabIndex; } </script> `; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoTabs, BentoTab }, props: Object.keys(argTypes), template: ` <bento-tabs v-bind="args"> <bento-tab title="Maria Ahlefeldt"> (16 January 1755 - 20 December 1810) was a Danish, (originally German), composer. She is known as the first female composer in Denmark. </bento-tab> <bento-tab title="Carl Andersen"> (29 April 1847 - 7 May 1909) was a Danish flutist, conductor and composer born in Copenhagen, son of the flutist Christian Joachim Andersen. </bento-tab> <bento-tab title="Karl Truffel"> (1 March 1981 - 7 November 1992) was a Danish dog and commander born in Berlin, son of the machinist Tom Jahoor Truffel. </bento-tab> <bento-tab title="Maria Ahlefeldt" :disabled="true"> (16 January 1755 - 20 December 1810) was a Danish, (originally German), composer. She is known as the first female composer in Denmark. </bento-tab> </bento-tabs> `, setup(props) { return { args: isVue2 ? props : _args, }; }, }), parameters: storybookDocsParameter(defaultCode), }; export const Sticky: Story = { render: (_args, { argTypes }) => ({ components: { BentoTabs, BentoTab }, props: Object.keys(argTypes), template: ` <bento-tabs v-bind="args"> <bento-tab title="Maria Ahlefeldt"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas gravida dictum tellus vel semper. Maecenas id purus id massa sollicitudin lobortis sed at massa. Ut venenatis laoreet purus, ac sodales arcu facilisis vitae. Curabitur interdum quis nunc ac faucibus. Sed id dictum nibh, in dignissim augue. Mauris id convallis orci, ac ultrices nibh. Cras sollicitudin vitae tortor id aliquet. Sed vel interdum lectus. Sed nec augue non odio aliquet aliquam quis ut urna. Donec at tincidunt dolor, quis eleifend tellus. Nam ornare cursus ipsum, eu euismod dui hendrerit sed. Donec pulvinar ante a mattis gravida. Cras posuere magna nec lectus varius tincidunt. Suspendisse potenti. In congue, nibh vitae dapibus mollis, nibh erat dapibus magna, vel pretium risus nibh vitae nunc. Nunc ultricies iaculis erat, id accumsan tortor. Proin nec lacus quis arcu tempor cursus vitae et augue. Donec eget egestas est. Praesent pharetra aliquam justo id cursus. Suspendisse ut viverra dolor. Aliquam at rutrum enim, eget volutpat mi. Nunc ut pulvinar turpis. Aliquam porttitor mollis lacus et aliquam. Etiam ullamcorper ut nunc ac ultricies. Vestibulum congue ultrices dictum. Etiam volutpat, felis at fringilla luctus, turpis arcu varius dui, eget eleifend mi mauris nec nisl. Ut et elementum eros, a dapibus leo. Sed molestie lectus in dui consequat vehicula. Phasellus sodales odio et vestibulum consectetur. Maecenas sodales malesuada felis eget semper. Morbi et vestibulum arcu. Fusce ex massa, elementum at massa non, ultricies vestibulum elit. Pellentesque nec felis id quam vulputate dapibus id id dolor. Aenean facilisis nibh sed enim lacinia sodales. Cras viverra ac ipsum vitae commodo. Nulla quis congue ipsum. Nunc ultricies tristique fermentum. Fusce nec maximus nisl, id facilisis mauris. Duis nec maximus tellus. Fusce quis mauris posuere ex mollis faucibus viverra at leo. Donec ac neque fermentum, fringilla magna vel, scelerisque nisi. Nulla id vehicula lectus, ac gravida justo. Sed in lorem odio. Vivamus lacinia ipsum id nisi tincidunt mollis. Sed quis dui ut dolor tempus mattis id eu erat. Sed tempus arcu lectus, sit amet placerat dolor consequat sed. Maecenas fermentum, ligula eu luctus imperdiet, dolor nisi condimentum dolor, nec molestie justo dolor eu dolor. Nullam nisl dui, gravida et massa vel, malesuada faucibus diam. Aenean non convallis nulla, sit amet egestas eros. Ut efficitur tellus vel placerat euismod. In luctus scelerisque elit rutrum ornare. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Fusce iaculis scelerisque tincidunt. Ut vel consequat eros. Vivamus sodales dictum quam quis mattis. Curabitur rutrum bibendum dictum. Suspendisse eros nisi, maximus sed lorem eu, elementum dictum nibh. Donec pellentesque lorem non egestas aliquet. Suspendisse sit amet sagittis ipsum, sit amet venenatis nulla. Sed finibus lacus eu cursus vestibulum. Quisque laoreet tellus nunc, sit amet viverra leo consequat vel. Nunc feugiat porttitor diam, id gravida arcu pretium mollis. Duis mollis odio quam, vel rhoncus metus rhoncus non. Proin ac rutrum nisl. Pellentesque nec porta turpis, accumsan faucibus nisi. Nam at dui sed dui vestibulum porttitor. Nam sed tristique nisi, vitae placerat urna. Aliquam sit amet pretium dui, ac cursus dolor. Nullam vitae auctor neque, quis ornare massa. Duis hendrerit dolor sed ligula interdum pellentesque. Nullam enim turpis, venenatis quis diam vel, mattis porttitor metus. Vivamus vel porttitor nisi, eu commodo augue. Vestibulum libero erat, fringilla ac fermentum in, malesuada nec velit. Morbi quis venenatis dolor. Quisque a congue metus, in pellentesque nibh. Phasellus sodales felis id tempus dictum. Nam molestie nulla eu iaculis porttitor. Etiam in urna mi. Aenean sit amet egestas arcu, a pretium sem. Vestibulum dictum odio vel tempor porta. Mauris laoreet tristique feugiat. In dui est, sollicitudin sed aliquet non, posuere at augue. Praesent auctor vel tellus mollis imperdiet. Phasellus et tincidunt lacus, ut volutpat velit. Quisque vitae tortor accumsan ante semper tincidunt ac vel lorem. Duis in elit vel arcu malesuada semper ac ac mi. Duis massa sapien, lacinia ac sapien ut, volutpat sollicitudin eros. Maecenas cursus massa eu felis dignissim, gravida tincidunt lectus tristique. Maecenas et vehicula leo, consectetur vehicula orci. Sed viverra dictum lacus, ac tristique nisi laoreet vitae. Cras porta suscipit tempus. Praesent lacus massa, volutpat et convallis ac, feugiat sit amet purus. Sed semper faucibus dui, vitae ultricies urna scelerisque at. Curabitur tortor felis, porttitor non augue quis, cursus sollicitudin augue. Fusce sed viverra lorem. Integer sit amet ullamcorper odio. Vivamus et metus ac sem convallis accumsan ut vitae purus. Praesent ligula arcu, varius id vehicula non, sagittis at risus. Duis porta pellentesque commodo. Nullam fermentum nisi neque, in scelerisque eros rutrum ut. Duis id orci non justo sodales dictum et eget ex. Curabitur quis ante at lectus semper eleifend in id purus. Aenean sed suscipit nulla. Mauris ullamcorper sapien velit, sed volutpat ante luctus quis. Cras lobortis orci nec quam finibus dapibus. Aenean nec purus et nisl tristique commodo ac sed odio. Integer placerat ac mauris a elementum. Etiam vestibulum tellus diam, non eleifend justo ultrices a. Duis et elementum tellus. Pellentesque felis orci, rhoncus sed diam eu, finibus faucibus diam. Donec a magna odio. Vestibulum iaculis interdum arcu, ut vulputate nisl dictum sed. Praesent quis eros et nulla condimentum placerat. Nam vel auctor erat. Donec lobortis dapibus erat sit amet luctus. Sed vitae feugiat nulla, in suscipit massa. Nunc ut tellus consequat, pellentesque nibh id, finibus risus. Etiam vulputate a nisi vitae fermentum. Duis tempor, mauris scelerisque commodo molestie, risus massa gravida nisi, et iaculis libero risus non velit. Vestibulum in felis sed justo porttitor bibendum nec id ligula. Maecenas eros sapien, dapibus non scelerisque et, tristique et mi. Maecenas id felis odio. Donec sed lacus gravida justo egestas varius in id dolor. Nunc eu luctus urna, vitae consectetur lorem. Nunc et diam consequat, rhoncus odio non, bibendum ipsum. Aenean et sagittis elit. Aliquam posuere sit amet nisi vitae efficitur. Nulla id blandit dui, at iaculis tellus. In varius sem ac nulla volutpat egestas. Donec condimentum feugiat mauris, in tempor nibh cursus ac. Etiam interdum imperdiet vehicula. Aliquam fringilla, risus eu porttitor accumsan, mi ante consequat tellus, sed vehicula mi nulla quis nisl. Nunc sollicitudin turpis commodo urna egestas, eget pharetra ligula consequat. Donec in odio a arcu tempus tempus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Vestibulum iaculis turpis quis euismod pellentesque. Curabitur mattis ex et libero auctor, vel placerat est mollis. Sed nec felis eu sapien faucibus fermentum. Morbi ut risus a lectus fringilla commodo nec in massa. Sed ac suscipit magna. Nunc vel augue mollis, fermentum risus eu, varius dolor. Quisque molestie fringilla ligula. Integer sed posuere magna. Mauris porta ornare interdum. Vivamus ullamcorper maximus lorem, eu consectetur est finibus a. Vivamus sagittis egestas eros nec porta. Sed congue lacus nisl, nec euismod ex volutpat ut. Aliquam erat volutpat. Nam posuere nisl in scelerisque venenatis. Curabitur sed mauris lorem. Mauris ornare est in velit dapibus, nec aliquet dui rhoncus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nunc euismod orci a odio iaculis, venenatis congue lorem vestibulum. Aenean sollicitudin egestas porta. Nulla ut sem eu nulla vehicula fringilla. Morbi eu sodales sem. Integer tristique tincidunt est vestibulum vehicula. Donec eget nulla congue, posuere lacus at, ornare sapien. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aenean interdum volutpat lobortis. Sed nulla augue, suscipit quis laoreet sit amet, vestibulum ac ex. Phasellus in volutpat diam. Phasellus tristique ultrices purus, a aliquam erat. Proin diam quam, luctus non bibendum non, vulputate eget nulla. Morbi ornare mauris eget nulla imperdiet, eu pulvinar est blandit. Mauris ut tempor arcu. Cras facilisis dictum lacus, et faucibus sem consectetur et. Cras arcu ligula, posuere ac tempor eu, ornare a felis. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aenean posuere congue elementum. Sed id ligula a ante tristique aliquet. Quisque nec mollis felis. Pellentesque varius eu massa venenatis dapibus. Praesent lacinia lorem nec facilisis luctus. Donec malesuada pretium dui, vitae luctus metus. Morbi ut aliquam ligula. Sed gravida urna in augue accumsan facilisis. Maecenas ultricies augue eu fermentum vestibulum. Vivamus at orci a libero sagittis pretium. Suspendisse quis est justo. Duis rutrum varius est eget lacinia. Duis augue ante, finibus quis auctor sit amet, ultrices id odio. Duis ultricies laoreet fringilla. Nulla vitae placerat lectus. Aenean nisl dui, pellentesque et bibendum quis, fringilla vitae tortor. Aenean cursus velit sed ex facilisis eleifend et eu ante. Maecenas leo est, auctor id tempus aliquet, pharetra eget leo. Nullam fermentum metus mi, ac varius velit lobortis non. Nam ultricies, orci ut lacinia elementum, justo elit efficitur orci, nec ornare augue justo vel odio. Quisque efficitur mauris ac sagittis varius. Fusce id nunc feugiat, efficitur libero eget, imperdiet mi. Nullam at sollicitudin augue, vitae bibendum turpis. Quisque vitae semper nisl. Aenean justo nulla, tincidunt at est vitae, consectetur porta turpis. Ut accumsan dolor mi, feugiat accumsan orci aliquet at. Pellentesque velit tortor, gravida quis magna quis, eleifend posuere est. Aliquam libero quam, porta non tincidunt eu, consequat eu eros. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris justo lectus, maximus in faucibus vitae, vestibulum ut tortor. Nulla facilisi. Nunc et lectus tellus. Aliquam pretium fringilla mauris, eu congue dui ultricies a. Suspendisse potenti. Maecenas dapibus auctor nisl a tincidunt. Vivamus elementum ex elit, vel molestie sem tristique nec. Etiam tristique volutpat risus, at sodales ex cursus sit amet. Donec aliquam, turpis sit amet vestibulum vulputate, mi leo mollis lorem, eleifend venenatis neque sapien ac erat. Morbi ullamcorper, mi et placerat dictum, tellus libero bibendum sem, id auctor justo lectus sed leo. Phasellus lacinia scelerisque tristique. Curabitur ut congue elit, vitae ullamcorper ligula. Cras purus lacus, dignissim eget justo ac, commodo convallis arcu. In ac pellentesque metus. Proin lobortis diam ac pellentesque sodales. In porta dolor id augue ultricies laoreet. Phasellus aliquam ultricies lorem, a mattis quam maximus vel. Vestibulum eu maximus nunc, eu pellentesque lorem. Vivamus sagittis arcu odio. Praesent nec malesuada sem. Morbi lobortis ullamcorper mollis. Morbi porttitor lectus sed erat luctus cursus. Donec a lacus a ligula vehicula iaculis. Vestibulum sagittis quam eu bibendum dapibus. Donec eleifend mollis suscipit. Morbi vitae magna libero. Nunc imperdiet ligula augue, ullamcorper molestie lacus mollis eget. Vestibulum vel tellus tortor. Suspendisse tincidunt in nisl vitae volutpat. Sed pharetra consequat dui sit amet venenatis. Suspendisse lobortis quis lectus ac maximus. Phasellus feugiat quam accumsan ipsum gravida faucibus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vivamus pellentesque diam non urna tristique, vel elementum mi aliquam. Aliquam turpis urna, fringilla a lorem sit amet, vestibulum laoreet mauris. Etiam ut justo finibus, tempor turpis eu, aliquet nisi. Aliquam eget lorem quam. Ut venenatis eros velit, eget lacinia augue aliquet at. Sed massa urna, imperdiet ut augue at, varius hendrerit arcu. Curabitur quis imperdiet diam. Aliquam porta eu metus et posuere. Suspendisse finibus lacus ex, quis aliquam urna rhoncus vitae. Morbi vel massa a sem vehicula elementum. Etiam orci diam, euismod quis aliquam eget, pulvinar et magna. Suspendisse volutpat leo risus, sed pretium tellus pharetra non. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Phasellus sed nunc vel enim vulputate convallis. Maecenas sit amet pretium mauris, in suscipit ligula. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras ultrices facilisis nunc vel suscipit. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur nunc justo, placerat tristique leo eu, facilisis tempor sapien. Nulla tempor metus ligula, sed consectetur eros hendrerit eget. Maecenas vel ex eget mi malesuada ultricies ut eget lorem. Morbi rutrum et nunc non volutpat. Sed id tellus est. Vivamus ac leo vulputate nulla pellentesque aliquam ut vel sem. Quisque sed semper enim. Quisque mattis ultrices tortor, at dapibus lectus facilisis non. Ut leo massa, semper a facilisis at, ultrices id risus. Duis id leo bibendum lacus lobortis laoreet. In hac habitasse platea dictumst. Suspendisse tempus diam ac tempus tempor. Suspendisse tincidunt quis tellus quis bibendum. Vivamus eu urna quis ex mollis mattis auctor nec sapien. Aliquam a libero egestas, accumsan ligula at, porttitor enim. Etiam finibus felis non nisl euismod, eu aliquam metus maximus. Nulla a tortor eu magna ultricies tempus sed vel risus. Nam id lacus quis massa auctor mattis. Vestibulum nec tempus enim, ut rhoncus enim. Vestibulum semper imperdiet lacus sit amet aliquet. Cras eros justo, vestibulum in mattis a, efficitur ac diam. Sed a malesuada leo. Quisque porta ex iaculis, pulvinar velit et, egestas nibh. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer et euismod sem. Aliquam ligula tortor, fermentum eu erat eu, pellentesque pharetra nibh. Fusce rutrum scelerisque purus, id auctor lorem vestibulum sed. Fusce id convallis sapien. Mauris feugiat eleifend orci. Donec nunc lorem, malesuada sit amet odio a, facilisis cursus odio. Maecenas eu faucibus lorem. Duis ut diam eu diam volutpat mollis. Aenean id dui nec ipsum porttitor scelerisque a quis purus. In scelerisque arcu fringilla, suscipit metus vitae, gravida lacus. Suspendisse non nibh consectetur, elementum nisi faucibus, tristique diam. Nunc auctor ipsum ac neque suscipit, nec dignissim est viverra. Cras luctus tempus suscipit. Maecenas ullamcorper diam ac quam fermentum venenatis. </bento-tab> <bento-tab title="Carl Andersen"> (29 April 1847 - 7 May 1909) was a Danish flutist, conductor and composer born in Copenhagen, son of the flutist Christian Joachim Andersen. </bento-tab> <bento-tab title="Karl Truffel"> (1 March 1981 - 7 November 1992) was a Danish dog and commander born in Berlin, son of the machinist Tom Jahoor Truffel. </bento-tab> <bento-tab title="Maria Ahlefeldt" :disabled="true"> (16 January 1755 - 20 December 1810) was a Danish, (originally German), composer. She is known as the first female composer in Denmark. </bento-tab> </bento-tabs> `, setup(props) { return { args: isVue2 ? props : _args, }; }, }), parameters: storybookDocsParameter(defaultCode), args: { sticky: true, }, }; const withNotificationIndicatorCode = ` <template> <bento-tabs :activeTabIndex="activeTabIndex" @update:active-tab-index="onTabSelected"> <bento-tab title="Maria Ahlefeldt"> (16 January 1755 - 20 December 1810) was a Danish, (originally German), composer. She is known as the first female composer in Denmark. </bento-tab> <bento-tab title="Carl Andersen" :with-notification-indicator="true"> (29 April 1847 - 7 May 1909) was a Danish flutist, conductor and composer born in Copenhagen, son of the flutist Christian Joachim Andersen. </bento-tab> <bento-tab title="Karl Truffel"> (1 March 1981 - 7 November 1992) was a Danish dog and commander born in Berlin, son of the machinist Tom Jahoor Truffel. </bento-tab> <bento-tab title="Maria Ahlefeldt" :disabled="true"> (16 January 1755 - 20 December 1810) was a Danish, (originally German), composer. She is known as the first female composer in Denmark. </bento-tab> </bento-tabs> </template> <script setup lang="ts"> import { BentoTab, BentoTabs } from '@adyen/bento-vue2'; import { ref } from 'vue' const activeTabIndex = ref(1) const onTabSelected = (newActiveTabIndex: number) => { activeTabIndex.value = newActiveTabIndex; } </script> `; export const WithNotificationIndicator: Story = { render: (_args, { argTypes }) => ({ components: { BentoTabs, BentoTab }, props: Object.keys(argTypes), template: ` <bento-tabs v-bind="args"> <bento-tab title="Maria Ahlefeldt"> (16 January 1755 - 20 December 1810) was a Danish, (originally German), composer. She is known as the first female composer in Denmark. </bento-tab> <bento-tab title="Carl Andersen" :with-notification-indicator="true"> (29 April 1847 - 7 May 1909) was a Danish flutist, conductor and composer born in Copenhagen, son of the flutist Christian Joachim Andersen. </bento-tab> <bento-tab title="Karl Truffel"> (1 March 1981 - 7 November 1992) was a Danish dog and commander born in Berlin, son of the machinist Tom Jahoor Truffel. </bento-tab> <bento-tab title="Maria Ahlefeldt" :disabled="true"> (16 January 1755 - 20 December 1810) was a Danish, (originally German), composer. She is known as the first female composer in Denmark. </bento-tab> </bento-tabs> `, setup(props) { return { args: isVue2 ? props : _args, }; }, }), parameters: storybookDocsParameter(withNotificationIndicatorCode), }; const withCountersCode = ` <template> <bento-tabs :activeTabIndex="activeTabIndex" @update:active-tab-index="onTabSelected"> <bento-tab title="Maria Ahlefeldt"> (16 January 1755 - 20 December 1810) was a Danish, (originally German), composer. She is known as the first female composer in Denmark. </bento-tab> <bento-tab title="Carl Andersen" :counter="10"> (29 April 1847 - 7 May 1909) was a Danish flutist, conductor and composer born in Copenhagen, son of the flutist Christian Joachim Andersen. </bento-tab> <bento-tab title="Karl Truffel" :counter="7" with-notification-indicator> (1 March 1981 - 7 November 1992) was a Danish dog and commander born in Berlin, son of the machinist Tom Jahoor Truffel. </bento-tab> <bento-tab title="Maria Ahlefeldt" :disabled="true" :counter="2"> (16 January 1755 - 20 December 1810) was a Danish, (originally German), composer. She is known as the first female composer in Denmark. </bento-tab> </bento-tabs> </template> <script setup lang="ts"> import { BentoTab, BentoTabs } from '@adyen/bento-vue2'; import { ref } from 'vue' const activeTabIndex = ref(1) const onTabSelected = (newActiveTabIndex: number) => { activeTabIndex.value = newActiveTabIndex; } </script> `; export const WithCounters: Story = { render: (_args, { argTypes }) => ({ components: { BentoTabs, BentoTab }, props: Object.keys(argTypes), template: ` <bento-tabs v-bind="args"> <bento-tab title="Maria Ahlefeldt"> (16 January 1755 - 20 December 1810) was a Danish, (originally German), composer. She is known as the first female composer in Denmark. </bento-tab> <bento-tab title="Carl Andersen" :counter="10"> (29 April 1847 - 7 May 1909) was a Danish flutist, conductor and composer born in Copenhagen, son of the flutist Christian Joachim Andersen. </bento-tab> <bento-tab title="Karl Truffel" :counter="7" with-notification-indicator> (1 March 1981 - 7 November 1992) was a Danish dog and commander born in Berlin, son of the machinist Tom Jahoor Truffel. </bento-tab> <bento-tab title="Maria Ahlefeldt" :disabled="true" :counter="2"> (16 January 1755 - 20 December 1810) was a Danish, (originally German), composer. She is known as the first female composer in Denmark. </bento-tab> </bento-tabs> `, setup(props) { return { args: isVue2 ? props : _args, }; }, }), parameters: storybookDocsParameter(withCountersCode), };
@@ -0,0 +1 @@
1
+ <template> <div class="b-tabs"> <div ref="tablistwrapper" class="b-tabs__tab-list-wrapper" :class="tablistWrapperConditionalClasses" :style="tablistWrapperStyles" > <fixed-scroller condensed :extra-padding-top="2"> <div ref="tablist" class="b-tabs__tab-list" role="tablist" @keydown="onKeydownTabsNavigation"> <button v-for="{ counter, disabled, hidden, id, title, withNotificationIndicator, setElementRef, } in tabs" v-show="!hidden" :id="id" :ref="setElementRef" :key="id" role="tab" type="button" class="b-tabs__tab" :class="{ 'b-tabs__tab--active': activeTabId === id, 'b-tabs__tab--disabled': disabled, }" :aria-controls="`${id}-tabpanel`" :aria-hidden="hidden ? 'true' : 'false'" :aria-selected="activeTabId === id ? 'true' : 'false'" :tabindex="activeTabId === id && !disabled.value ? null : -1" :disabled="isDisabled(disabled)" @click="handleTabChange(id)" @keydown.enter.space="handleTabChange(id)" > <span class="b-tabs__tab-text"> <bento-typography class="b-tabs__tab-title" el="span" variant="body" stronger> {{ title }} </bento-typography> <bento-typography v-if="counter != null" class="b-tabs__tab-counter" el="span" variant="body" stronger :class="{ 'b-tabs__tab-counter--active': activeTabId === id, }" > {{ counter }} </bento-typography> <span v-if="withNotificationIndicator" class="b-tabs__tab-notification-dot" aria-hidden="true" ></span> </span> <span v-show="activeTabId === id" class="b-tabs__tab-underline" aria-hidden="true"></span> </button> </div> </fixed-scroller> </div> <slot /> </div> </template> <script lang="ts"> import { computed, defineComponent, nextTick, onUnmounted, type PropType, provide, ref, type Ref, unref, watch, } from 'vue'; // components import { BentoTypography } from '@/components/typography'; import { FixedScroller } from '@/internal'; // utils import { generateUid } from '@/core/utils/ts'; import { getNextTabIndex, getPreviousTabIndex } from './utils'; // types import { type Booleanish } from '@/types/prop-types'; import { type BentoTab } from './components/tab.types'; import { type BentoStickyTabsOptions, BentoTabsEvent, type BentoTabsRegisterTab } from './tabs.types'; // keys import { TABS_ACTIVE_TAB_ID_KEY, TABS_REGISTER_TAB_INJECTION_KEY } from './tabs.keys'; /** * Tabs are used to navigate between different, but related content views within a page. * This component conforms to the official WAI-ARIA guidelines for tabs: https://www.w3.org/WAI/ARIA/apg/patterns/tabs/ * * @example * import { BentoTabs, BentoTab } from '@adyen/bento-vue2'; * * export default { * components: { BentoTabs, BentoTab }, * template: ` * <bento-tabs v-bind="$props"> * <bento-tab title="Maria Ahlefeldt"> * (16 January 1755 - 20 December 1810) was a Danish, (originally German), composer. She is known as the first female composer in Denmark. * </bento-tab> * <bento-tab title="Carl Andersen"> * (29 April 1847 - 7 May 1909) was a Danish flutist, conductor and composer born in Copenhagen, son of the flutist Christian Joachim Andersen. * </bento-tab> * <bento-tab title="Karl Truffel"> * (1 March 1981 - 7 November 1992) was a Danish dog and commander born in Berlin, son of the machinist Tom Jahoor Truffel. * </bento-tab> * <bento-tab title="Maria Ahlefeldt" :disabled="true"> * (16 January 1755 - 20 December 1810) was a Danish, (originally German), composer. She is known as the first female composer in Denmark. * </bento-tab> * </bento-tabs> * ` * }; */ // component export default defineComponent({ components: { BentoTypography, FixedScroller, }, props: { /** * Sets the active tab by its index (0 being the first tab item). */ activeTabIndex: { type: Number, default: 0 }, /* * Renders the tab with a sticky positioning. */ sticky: { type: Boolean, default: false }, /** * Additional configurable options for tabs rendered with a sticky positioning. * It must be an object of type {@see BentoStickyTabsOption} * @property {Ref<number>} stickyOptions.top - Top position the tabs should take up when rendered as sticky. */ stickyOptions: { type: Object as PropType<BentoStickyTabsOptions>, default: null }, }, emits: [BentoTabsEvent.ACTIVE_TAB_INDEX], setup(props, { emit }) { const tabs: Ref<Array<BentoTab>> = ref([]); const tablist = ref(null); const tablistwrapper = ref(); const activeTabId = ref(''); const isPinnedByObserver = ref(false); let observer; provide(TABS_ACTIVE_TAB_ID_KEY, activeTabId); // unregister tab if removed / destroyed const unregisterTab = (tabIdToRemove: string) => () => { tabs.value = tabs.value?.filter(({ id }) => id !== tabIdToRemove); }; // register tab const registerTab: BentoTabsRegisterTab = ({ title, disabled, withNotificationIndicator, counter, hidden, setElementRef, }) => { const id = generateUid('b-tab'); // add tab to tabs tabs.value.push({ counter, disabled, hidden, id, title, withNotificationIndicator, setElementRef, }); // return values to the Tab component return { id, unregisterTab: unregisterTab(id) }; }; // provide activeTab and registerTab to tab items provide(TABS_REGISTER_TAB_INJECTION_KEY, registerTab); // keyboard navigation const onKeydownTabsNavigation = (e: KeyboardEvent) => { if (e.code === 'ArrowLeft' || e.code === 'ArrowRight') { // find tab that is focussed const activeTab = tabs.value.find(tab => document.activeElement.id === tab.id); let activeTabIndex = tabs.value.indexOf(activeTab); // conditionally increase or decrease the if (e.code === 'ArrowLeft') { activeTabIndex = getPreviousTabIndex(activeTabIndex, tabs.value); } else if (e.code === 'ArrowRight') { activeTabIndex = getNextTabIndex(activeTabIndex, tabs.value); } // focus new active tab tablist.value.children[activeTabIndex].focus(); } }; watch( [() => props.activeTabIndex, tabs], ([index, currentTabs]) => { nextTick(() => { const tab = currentTabs[index]; activeTabId.value = tab && !tab.disabled ? tab.id : tabs.value.find(({ disabled }) => !disabled)?.id; }); }, { immediate: true } ); const handleTabChange = (tabId: string) => { activeTabId.value = tabId; const activeIndex = tabs.value.findIndex(({ id }) => id === activeTabId.value); emit(BentoTabsEvent.ACTIVE_TAB_INDEX, activeIndex); }; const isDisabled = (isDisabledTab: Ref<boolean>): Booleanish => (isDisabledTab ? 'disabled' : false) as Booleanish; /* == Sticky tabs logic == */ const topOffset = computed(() => (props.stickyOptions?.top ? unref(props.stickyOptions.top) : 0)); const isPinned = computed(() => { if (props.sticky && topOffset.value > 0) { return true; } return isPinnedByObserver.value; }); const disconnectObserver = () => { if (observer) { observer.disconnect(); observer = null; } isPinnedByObserver.value = false; }; const setupObserver = (element: HTMLDivElement) => { // The observer is only needed when the tabs are sticky at the top of the screen (no top offset). if (props.sticky && topOffset.value === 0) { observer = new IntersectionObserver( ([e]) => { isPinnedByObserver.value = e.intersectionRatio < 1; }, { threshold: [1] } ); observer.observe(element); } }; // This watcher manages the entire lifecycle of the observer. watch( [() => props.sticky, tablistwrapper, topOffset], ([isSticky, element]) => { disconnectObserver(); if (isSticky && element) { nextTick(() => setupObserver(element)); } }, { immediate: true } ); onUnmounted(() => { disconnectObserver(); }); const tablistWrapperConditionalClasses = computed(() => ({ 'b-tabs__tab-list-wrapper--sticky': props.sticky, 'b-tabs__tab-list-wrapper--pinned': isPinned.value, })); const tablistWrapperStyles = computed(() => // This helps us detect when the tabs are pinned without calculations on the tabs positions because it makes the tabs intersect by 1 pixel with the element on top of it, which is getting aught by the intersection observer. // Followed this example: https://css-tricks.com/how-to-detect-when-a-sticky-element-gets-pinned/ props.sticky ? { top: `${(props.stickyOptions?.top ?? 0) - 1}px`, } : {} ); return { tabs, tablist, tablistwrapper, activeTabId, tablistWrapperConditionalClasses, tablistWrapperStyles, onKeydownTabsNavigation, handleTabChange, isDisabled, }; }, }); </script> <style lang="scss" scoped src="./tabs.scss" />
@@ -0,0 +1,137 @@
1
+ import { Canvas, Meta, Story } from '@storybook/blocks';
2
+ import * as TagStories from './tag.stories';
3
+
4
+ # Tag
5
+
6
+ <Canvas withSource="closed">
7
+ <Story of={TagStories.Default} />
8
+ </Canvas>
9
+
10
+ A Tag represents a property or keyword related to an object. Use tags to label, categorize, and organize items, like
11
+ blog categories or quick filter categories.
12
+
13
+ ## ⚠️ Default slot deprecated ⚠️
14
+
15
+ The `default` slot for tag has been deprecated, please use the `label` property instead to add the text content.
16
+
17
+ ## Use Cases
18
+
19
+ Use tags to:
20
+
21
+ - Label items
22
+ - Categorize items
23
+ - Organize items
24
+
25
+ Examples of said usage are blog categories and quick filter categories.
26
+
27
+ ### Do not use
28
+
29
+ When using a tag, do not:
30
+
31
+ - Add custom HTML inside the tag's `default` slot e.g. `<bento-tag><strong>Tag Text</strong></bento-tag>`.
32
+ - Put any elements in the `default` slot, even icon components from the `@adyen/ui-assets` package
33
+ - Use such component to convey a status (e.g. payment status or terminal’s activity). In this case, prefer the `status`
34
+ component instead
35
+
36
+ ## Variations
37
+
38
+ ### Variant
39
+
40
+ The `variant` property affects the text color and background color of the component.
41
+
42
+ It accepts one of the following values:
43
+
44
+ - `'grey'`
45
+ - `'blue'`
46
+ - `'green'`
47
+ - `'orange'`
48
+ - `'red'`
49
+ - `'white'`
50
+
51
+ <Canvas withSource="closed">
52
+ <Story of={TagStories.AllVariantsTemplate} />
53
+ </Canvas>
54
+
55
+ ### Icon
56
+
57
+ Shows/hide an optional icon, which needs to be passed via the `icon` named slot. The icon only displays if the tag label
58
+ is also present.
59
+
60
+ ## Modifiers
61
+
62
+ ### Truncate
63
+
64
+ It is possible that the text of some tags will be quite long.
65
+
66
+ This property accepts a number and determines the maximum length of the text displayed in the component. If the length
67
+ of the text exceeds the specified value, it will be truncated and "..." will be added to the end. If the truncate
68
+ property is not specified, the original text will be displayed in full.
69
+
70
+ <Canvas withSource="closed">
71
+ <Story of={TagStories.Truncated} />
72
+ </Canvas>
73
+
74
+ ## Accessibility
75
+
76
+ ### Keyboard Interaction
77
+
78
+ The tag component is not reachable through keyboard navigation since it's a non-interactive element that displays a
79
+ property or keyword related to an object.
80
+
81
+ ### Colors
82
+
83
+ Different variants options can be used to differentiate between tags or to add additional meaning. Make sure you don’t
84
+ rely on color only, though, as users with color blindness may struggle with discerning them.
85
+
86
+ ### Role
87
+
88
+ There are a number of roles that could be valid for this component, depending on the circumstances and how the component
89
+ is used. The recommended approach is to apply the role to the structure around the tag instead of applying a specific
90
+ role to it.
91
+
92
+ For example, rather than giving the tag component itself the “status” role, the tag can be used inside a list with the
93
+ “status” role. This would also allow for greater control of how the “status” live region is announced, like adding
94
+ `aria-atomic="true"` to cause the live region to announce all of its contents when a change is made, or adding
95
+ `aria-atomic="false"` to instruct the screen reader to announce only the updated content.
96
+
97
+ ```HTML
98
+ <p role="status" aria-atomic="true">
99
+ <img src="shopping-cart.png" alt="Shopping Cart">
100
+ <bento-tag>0</bento-tag> items
101
+ </p>
102
+ ```
103
+
104
+ Another example would be to use it inside a breadcrumb, using the tag within a link, in an ordered list inside a nav
105
+ element with `aria-label="Breadcrumb"`.
106
+
107
+ ```HTML
108
+ <nav aria-label="Breadcrumb">
109
+ <ol>
110
+ <li><a href="#"><bento-tag>Home</bento-tag></a></li>
111
+ <li><bento-tag>Stories</bento-tag></a></li>
112
+ <li aria-current="page"><bento-tag>Tag</bento-tag></li>
113
+ </ol>
114
+ </nav>
115
+ ```
116
+
117
+ ### Use of color
118
+
119
+ Do not use tag colors as the sole means of communicating any information, as this would be a violation of the
120
+ `Use of Color` criterion. Color should either be decorative or there should be another mean of communicating any
121
+ information provided by the color. For example, using the green tag along with a text label that reads “Success” is
122
+ correct, but using the green tag to indicate success without the text label communicating it too is wrong; a user who is
123
+ color blind must be able to discern any information discernable by a user who is not color blind.
124
+
125
+ ### Aria attributes
126
+
127
+ Adhering to the Adhering to the [WAI-ARIA 1.2 standard](https://www.w3.org/TR/wai-aria-1.2/) we follow the
128
+ [button pattern](https://www.w3.org/WAI/ARIA/apg/patterns/button/#wai-ariaroles,states,andproperties) documentation
129
+ provided. we apply the following:
130
+
131
+ | ARIA attribute | is automatic? | fallback used | manual override |
132
+ | -------------- | ---------------------- | ----------------------------------------------------- | --------------- |
133
+ | `aria-label` | Yes, default slot text | If no slot text present, then default `tag` value set | - |
134
+
135
+ ## Resources
136
+
137
+ - [Figma link](https://www.figma.com/file/uLabwF3243jdMDsNSP7U9I/ADL-2.0---Components?node-id=615-2645&t=piB5Gc11SCKIogWg-0)
@@ -0,0 +1 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import CheckmarkCircleFillIcon from '@adyen/ui-assets-icons-16/vue/checkmark-circle-fill'; import BentoTagWithIcon from './__tests__/tag-with-icon.vue?raw'; import BentoTag from './tag.vue'; import { isVue2 } from 'vue-demi'; import { BentoTagVariant } from './tag.types'; export default { title: 'Tag', component: BentoTag, parameters: { layout: 'centered', }, argTypes: { default: { name: 'default (deprecated)', defaultValue: '', description: 'Tag content slot (will be deprecated, use label property instead)', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, variant: { options: Object.values(BentoTagVariant), mapping: BentoTagVariant, control: { type: 'select', }, }, }, } as Meta; type Story = StoryObj<typeof BentoTag>; const DEFAULT_TAG_PROPS = { label: 'Default Tag Text', }; const defaultCode = ` <bento-tag label="${DEFAULT_TAG_PROPS.label}" /> `; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoTag }, props: Object.keys(argTypes), template: ` <div style="display:flex; gap: 10px"> <bento-tag v-bind="args" /> </div> `, setup(props) { return { args: isVue2 ? props : _args, }; }, }), args: DEFAULT_TAG_PROPS, parameters: storybookDocsParameter(defaultCode), }; const truncatedCode = ` <bento-tag truncate="10" label="${DEFAULT_TAG_PROPS.label}" /> `; export const Truncated: Story = { render: (_args, { argTypes }) => ({ components: { BentoTag }, props: Object.keys(argTypes), template: ` <div style="display:flex; gap: 10px"> <bento-tag v-bind="args" /> </div> `, setup(props) { return { args: isVue2 ? props : _args, }; }, }), args: { ...DEFAULT_TAG_PROPS, variant: 'green', truncate: 10 }, parameters: storybookDocsParameter(truncatedCode), }; export const WithIcon: Story = { render: (_args, { argTypes }) => ({ components: { BentoTag, CheckmarkCircleFillIcon }, props: Object.keys(argTypes), template: ` <div style="display:flex; gap: 10px"> <bento-tag v-bind="args"> <template #icon><checkmark-circle-fill-icon /></template> </bento-tag> </div> `, setup(props) { return { args: isVue2 ? props : _args, }; }, }), args: DEFAULT_TAG_PROPS, parameters: storybookDocsParameter(BentoTagWithIcon), }; const allVariantsCode = ` <div style="display:flex; gap: 10px"> <bento-tag variant="grey" label="Grey" /> <bento-tag variant="green" label="Green" /> <bento-tag variant="red" label="Red" /> <bento-tag variant="blue" label="Blue" /> <bento-tag variant="orange" label="Orange" /> <bento-tag variant="white" label="White" /> </div>`; export const AllVariantsTemplate: Story = { render: (_args, { argTypes }) => ({ components: { BentoTag }, props: Object.keys(argTypes), template: ` <div style="display:flex; gap: 10px"> <bento-tag variant="grey" v-bind="args" label="Grey" /> <bento-tag variant="green" v-bind="args" label="Green" /> <bento-tag variant="red" v-bind="args" label="Red" /> <bento-tag variant="blue" v-bind="args" label="Blue" /> <bento-tag variant="orange" v-bind="args" label="Orange" /> <bento-tag variant="white" v-bind="args" label="White" /> </div> `, setup(props) { return { args: isVue2 ? props : _args, }; }, }), parameters: storybookDocsParameter(allVariantsCode), };
@@ -0,0 +1 @@
1
+ <template> <span v-bento-tooltip-directive="shouldShowTooltip ? textFromSlot : null" data-testid="tag" class="b-tag" :class="tagConditionalClasses" :aria-label="computedAriaLabel" > <div v-if="hasTextContent && hasSlot('icon')" class="b-tag__icon" role="presentation"> <slot name="icon"></slot> </div> <bento-typography class="b-tag__label" el="span" variant="caption" stronger> {{ formattedText }} </bento-typography> </span> </template> <script setup lang="ts"> import { computed, useSlots } from 'vue'; // Use relative paths otherwise the interface won't be correctly detected // TODO: Use alias once the support is added to work with the betterDefine macro import { type BentoTagProps, BentoTagVariant } from './tag.types'; import { BentoTypography } from '@/components/typography'; import { BentoTooltipDirective as vBentoTooltipDirective } from '@/directives'; import { useAriaLabel } from '@/utils/ts/aria-label'; import { getSlotText } from '@/utils/ts/get-slot-text'; const props = withDefaults(defineProps<BentoTagProps>(), { label: null, truncate: null, variant: BentoTagVariant.GREY, }); const slots = useSlots(); // Slots logic // Temporary, use-has-slots composable doesn't currently work for vue3 named scoped slots // We do the same in bento-checkbox-group const hasSlot = name => !!slots[name]; const hasTextContent = computed(() => !!(props.label || getSlotText(slots)('default'))); const computedAriaLabel = useAriaLabel({ label: props.label || getSlotText(slots)('default'), defaultFallback: 'tag', }); const tagConditionalClasses = computed(() => ({ [`b-tag--${props.variant}`]: props.variant, })); const textFromSlot = computed(() => props.label ?? getSlotText(slots)('default') ?? 'tag'); const shouldShowTooltip = computed(() => props.truncate && textFromSlot.value.length > props.truncate); const formattedText = computed(() => { if (!props.truncate) { return textFromSlot.value; } return shouldShowTooltip.value ? `${textFromSlot.value.slice(0, props.truncate)}...` : textFromSlot.value; }); </script> <script lang="ts"> export default { name: 'bento-tag', }; </script> <style lang="scss" scoped src="./tag.scss" />