@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
+ <template> <bento-base-filter v-bind="$props" :button-label="buttonLabel" :button-secondary-label="buttonSecondaryLabel" :disable-apply-button="isApplyButtonDisabled" :disable-secondary-button="isSecondaryButtonDisabled" :only-slot="onlySlot" :popover-overflow-visible="isDropdownVariant" :tooltip-position="options?.tooltipPosition" :tooltip-text="options?.tooltipText" @apply="updateFilter" @clear="clearFilter" @open="openFilter" @reset="resetFilter" > <div class="b-input-filter" :class="conditionalClasses" @keydown.enter="updateFilter" @input="onInput"> <bento-input-field ref="inputTextRef" :dropdown="dropdownProp" :dropdown-position="options?.dropdownPosition" :placeholder="options?.placeholder" :variant="inputVariant" :model-value="internalFilterValue" :disabled="disabled" @update:model-value="setInternalFilterValue" @dropdown-input="onDropdownInput" /> </div> </bento-base-filter> </template> <script setup lang="ts"> import { computed, onBeforeUpdate, provide, ref, toRef, watch } from 'vue'; import { BentoBaseFilter, useBaseFilter } from '../base-filter'; import { type BentoInputFilterInputAndDropdownValues, type BentoInputFilterValue, } from '@/components/filter-bar/filter-bar.types'; import { BentoInputField } from '@/components/input-field'; import { truncate } from '@/utils/ts/truncate'; import { type BentoListboxSelectedValue } from '@/types/listbox'; import { INPUT_FILTER_POPOVER_INJECTION_KEY } from '@/components/filter-bar/components/input-filter/input-filter.keys'; import { deprecate } from '@/utils/ts/deprecate'; import { type BentoInputFilterProps } from './input-filter.types'; const props = withDefaults(defineProps<BentoInputFilterProps>(), { defaultValue: null, disabled: false, onlySlot: false, options: undefined, value: null, }); const emit = defineEmits<{ /** * Fires upon the user interacting with the filter */ (e: 'input', props: BentoInputFilterProps): void; /** * Fires on the (new) filter values being applied */ (e: 'update', props: BentoInputFilterProps): void; }>(); const inputTextRef = ref(null); // Dropdown const dropdownValue = ref<BentoListboxSelectedValue>(props?.options?.dropdown?.value); const isDropdownVariant = computed( () => props?.options?.variant === 'dropdown' && props?.options?.dropdown !== undefined ); const dropdownProp = computed(() => isDropdownVariant.value ? { ...props?.options?.dropdown, value: dropdownValue.value } : undefined ); // For now we only allow the dropdown or the default variant for the input field. const inputVariant = computed(() => (props?.options?.variant === 'dropdown' ? 'dropdown' : 'default')); // Computed value as the input value location will be different if it is a dropdown variant const valueProp = computed(() => isDropdownVariant.value ? (props.value as BentoInputFilterInputAndDropdownValues)?.inputValue : (props?.value as string) ); const { internalFilterValue, isSecondaryButtonDisabled, isApplyButtonDisabled } = useBaseFilter<string>( valueProp, toRef(props, 'defaultValue') ); const buttonLabel = computed(() => props.label); const buttonSecondaryLabel = computed(() => truncate(valueProp.value, 12)); const conditionalClasses = computed(() => ({ [`b-input-filter--only-slot`]: props.onlySlot, })); onBeforeUpdate(() => { // Set value to null when the string is empty if (internalFilterValue.value === '') { internalFilterValue.value = null; } }); watch(inputTextRef, () => { // Focus on the input when it's opened inputTextRef.value?.focusInput(); }); const openFilter = () => { internalFilterValue.value = valueProp.value; }; const updateFilter = () => { if (!internalFilterValue.value && props.defaultValue !== null) { // If value set to empty, reset back to default value internalFilterValue.value = props.defaultValue; } emit('update', { ...props, value: isDropdownVariant.value ? ({ inputValue: internalFilterValue.value, dropdownValue: dropdownValue.value, } as BentoInputFilterValue) : internalFilterValue.value, }); }; const resetFilter = () => emit('update', { ...props, value: props.defaultValue }); const clearFilter = () => { internalFilterValue.value = null; updateFilter(); }; const onInput = () => { emit('input', { ...props, value: internalFilterValue.value }); }; const setInternalFilterValue = (event: string) => { internalFilterValue.value = event; }; const onDropdownInput = (selectedValue: BentoListboxSelectedValue) => { dropdownValue.value = selectedValue; }; // We need to change the base filter's popover to have overflow visible so the dropdown options is // not hidden inside the filter when opened. provide(INPUT_FILTER_POPOVER_INJECTION_KEY, isDropdownVariant.value); // Verify that no unsopported attributes are passed to the component watch( () => props.options, () => { if (props.options?.dropdown || props.options?.dropdownPosition || props.options?.variant) { deprecate( 'BentoInputFilter "options" property', `BentoInputFilter "options" no longer supports "dropdown", "dropdownPosition" or "variant" attributes. Use the "BentoFilterItemType.INPUT_DROPDOWN" instead of "BentoFilterItemType.INPUT" <bento-filter-bar :config="[{ field: 'name', label: 'Name', type: BentoFilterItemType.INPUT_DROPDOWN, options: [...], }]" />`, '2.0.0' ); } }, { immediate: true } ); </script> <script lang="ts"> export default { name: 'bento-input-filter', }; </script> <style lang="scss" scoped src="./input-filter.scss" />
@@ -0,0 +1,18 @@
1
+ import { Canvas, Story, Meta } from '@storybook/blocks';
2
+ import { ArgTypes } from '@storybook/blocks';
3
+ import * as BentoInputWithDropdwnFilterStories from './input-with-dropdown-filter.stories';
4
+
5
+ <Meta of={BentoInputWithDropdwnFilterStories} />
6
+
7
+ # Input with dropdown filter
8
+
9
+ A **TextFilter** component provides a filter text input and allows you to filter and render a list of data based on the
10
+ entered filter text.
11
+
12
+ <Canvas>
13
+ <Story of={BentoInputWithDropdwnFilterStories.Default} />
14
+ </Canvas>
15
+
16
+ ## Props
17
+
18
+ <ArgTypes of={BentoInputWithDropdwnFilterStories} />
@@ -0,0 +1 @@
1
+ import { action } from '@storybook/addon-actions'; import { type Meta, type StoryObj } from '@storybook/vue'; import { ref } from 'vue'; import { isVue2 } from 'vue-demi'; import BentoInputWithDropdownFilter from './input-with-dropdown-filter.vue'; import { type BentoInputWithDropdownFilterOptions } from '../../filter-bar.types'; export default { title: 'Filter bar/Input with dropdown filter', component: BentoInputWithDropdownFilter, argTypes: { dismiss: { name: 'dismiss', defaultValue: '', description: '`dismiss` event handler. Called whenever the "X" (dismiss) button is clicked or the value is set to empty (null)', table: { type: { summary: '({ field, label, value }) => void' } }, control: { disable: true }, }, update: { name: 'update', defaultValue: '', description: '`update` event handler. Called whenever the "Apply" button is clicked.', table: { type: { summary: '({ field, label, value }) => void' } }, control: { disable: true }, }, }, } satisfies Meta; type Story = StoryObj<typeof BentoInputWithDropdownFilter>; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoInputWithDropdownFilter }, props: Object.keys(argTypes), template: ` <div style="padding-top: 24px"> <bento-input-with-dropdown-filter v-bind="args" :value="value" @update="updateFilter" @dismiss="dismissFilter" /> </div> `, setup(props) { const value = ref(null); const updateFilter = newFilterValue => { action('update')(newFilterValue); value.value = newFilterValue.value; }; const dismissFilter = newFilterValue => { action('dismiss')(newFilterValue); value.value = null; }; return { args: isVue2 ? props : _args, value, updateFilter, dismissFilter, }; }, }), args: { label: 'Input with dropdown', field: 'input', options: { dropdown: { items: [ { label: 'EUR', value: 'EUR' }, { label: 'USD', value: 'USD' }, ], value: 'EUR', }, } satisfies BentoInputWithDropdownFilterOptions, }, };
@@ -0,0 +1 @@
1
+ <template> <bento-base-filter v-bind="$props" :button-label="buttonLabel" :button-secondary-label="buttonSecondaryLabel" :disable-apply-button="shouldDisableApply" :disable-secondary-button="isSecondaryButtonDisabled" :only-slot="onlySlot" :tooltip-position="options?.tooltipPosition" :tooltip-text="options?.tooltipText" @apply="updateFilter" @clear="clearFilter" @open="openFilter" @reset="resetFilter" > <div class="b-input-with-dropdown-filter" :class="conditionalClasses" @keydown.enter="updateFilter" @input="onInput" > <bento-input-field ref="inputTextRef" :dropdown="dropdownOptions" :dropdown-position="options?.dropdownPosition" variant="dropdown" :model-value="internalFilterValue?.inputValue" :disabled="disabled" @update:model-value="setInternalFilterValue" @dropdown-input="onDropdownInput" /> </div> </bento-base-filter> </template> <script setup lang="ts"> import { computed, onBeforeUpdate, provide, ref, toRef, watch } from 'vue'; import { BentoBaseFilter, useBaseFilter } from '../base-filter'; import { BentoFilterEvent, type BentoInputWithDropdownFilterOptions, type BentoInpuWithDropdowntFilterValue, } from '../../filter-bar.types'; import { type BentoInputDropdownProps, BentoInputField } from '@/components/input-field'; import { truncate } from '@/utils/ts/truncate'; import { type BentoListboxSelectedValue } from '@/types/listbox'; import { INPUT_FILTER_WITH_DROPDOWN_POPOVER_INJECTION_KEY } from '@/components/filter-bar/components/input-with-dropdown-filter/input-with-dropdown-filter.keys'; const props = withDefaults( defineProps<{ /** * Disables the filter from being interacted with. */ disabled?: boolean; /** * Default value of the filter to reset to. */ defaultValue?: BentoInpuWithDropdowntFilterValue; /** * Filter name/key referencing the actual property name in the data set. * Should be unique per filter bar. */ field: string; /** * Label text to be displayed */ label: string; /** * Renders the base filter's slot content only - leaving out the button and the popover. * Used for the allFiltersModal component. */ onlySlot?: boolean; /** * List of options that are needed to setup the filter * Available options: * - dropdown: all the dropdown properties that can be set in the inner dropdown of the input field. @see BentoDropdown for more info. * - dropdownPosition: allow the user to set the dropdown on the left or right side. Accepts the `start` or `end` values. * - tooltipPosition: The position of the tooltip attached to the filter button * - tooltipText: The content of the tooltip attached to the filter button */ options?: BentoInputWithDropdownFilterOptions; /** * Current value of the filter. * If the options.variant is equal to 'dropdown', the value should be of type should be `{ inputValue: string | null; dropdownValue?: string }`. */ value?: BentoInpuWithDropdowntFilterValue; }>(), { defaultValue: undefined, onlySlot: false, options: undefined, value: undefined, } ); const emit = defineEmits([BentoFilterEvent.INPUT, BentoFilterEvent.UPDATE]); const inputTextRef = ref(null); const { internalFilterValue, isSecondaryButtonDisabled, isApplyButtonDisabled } = useBaseFilter<BentoInpuWithDropdowntFilterValue>(toRef(props, 'value'), toRef(props, 'defaultValue')); const buttonLabel = computed(() => props.label); const buttonSecondaryLabel = computed(() => truncate(props.value?.inputValue, 12)); const dropdownSelection = computed( () => internalFilterValue.value?.dropdownValue ?? props.options?.dropdown?.modelValue ?? props.options?.dropdown?.value ); const dropdownOptions = computed<BentoInputDropdownProps>(() => ({ ...((props.options?.dropdown || {}) as BentoInputDropdownProps), modelValue: dropdownSelection.value, })); const conditionalClasses = computed(() => ({ [`b-input-with-dropdown-filter--only-slot`]: props.onlySlot, })); const shouldDisableApply = computed(() => { const allFieldsAreSet = !!internalFilterValue.value?.inputValue && !!dropdownSelection.value; return !allFieldsAreSet || isApplyButtonDisabled.value; }); onBeforeUpdate(() => { // Set value to null when the string is empty if (internalFilterValue.value?.inputValue === '') { internalFilterValue.value = { ...internalFilterValue.value, inputValue: undefined }; } }); watch(inputTextRef, () => { // Focus on the input when it's opened inputTextRef.value?.focusInput(); }); const openFilter = () => { internalFilterValue.value = props.value; }; const updateFilter = () => { if (!internalFilterValue.value?.inputValue && props.defaultValue !== null) { // If value set to empty, reset back to default value internalFilterValue.value = { ...props.defaultValue }; } emit(BentoFilterEvent.UPDATE, { ...props, value: internalFilterValue.value, }); }; const resetFilter = () => emit(BentoFilterEvent.UPDATE, { ...props, value: props.defaultValue }); const clearFilter = () => { internalFilterValue.value = null; updateFilter(); }; const onInput = () => { emit(BentoFilterEvent.INPUT, { ...props, value: internalFilterValue.value }); }; const setInternalFilterValue = (event: string) => { internalFilterValue.value = { dropdownValue: dropdownSelection.value, inputValue: event }; }; const onDropdownInput = (selectedValue: BentoListboxSelectedValue) => { internalFilterValue.value = { ...internalFilterValue.value, dropdownValue: selectedValue }; }; // We need to change the base filter's popover to have overflow visible so the dropdown options is // not hidden inside the filter when opened. provide(INPUT_FILTER_WITH_DROPDOWN_POPOVER_INJECTION_KEY, true); </script> <script lang="ts"> /** * */ export default { name: 'bento-input-with-dropdown-filter', }; </script> <style lang="scss" scoped src="./input-with-dropdown-filter.scss" />
@@ -0,0 +1 @@
1
+ import { action } from '@storybook/addon-actions'; import { ref } from 'vue'; import { isVue2 } from 'vue-demi'; import { type BentoRadioGroupFilterProps, type BentoRadioGroupFilterValue } from './radio-group-filter.types'; import type { Meta, StoryObj } from '@storybook/vue'; import BentoRadioGroupFilter from './radio-group-filter.vue'; const meta: Meta = { title: 'Filter bar/Radio group filter', component: BentoRadioGroupFilter, }; export default meta; type Story = StoryObj<typeof BentoRadioGroupFilter>; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoRadioGroupFilter }, props: Object.keys(argTypes), template: ` <bento-radio-group-filter v-bind="args" :value="value" @input="selectOption" @update="applyOption" /> `, setup(props) { const value = ref<BentoRadioGroupFilterValue>(); const selectOption = (newOptionValue: BentoRadioGroupFilterProps) => { action('input')(newOptionValue); }; const applyOption = (newOptionValue: BentoRadioGroupFilterProps) => { value.value = newOptionValue.value; action('update')(newOptionValue); }; return { // Values args: isVue2 ? props : _args, value, // Events applyOption, selectOption, }; }, }), args: { label: 'Radio group filter', field: 'radio-group-filter', options: { items: [ { value: 1, label: 'First option' }, { value: 2, label: 'Second option with very long label that cascades' }, { value: 3, label: 'Last option' }, ], }, } satisfies BentoRadioGroupFilterProps, }; export const Persistent: Story = { render: (_args, { argTypes }) => ({ components: { BentoRadioGroupFilter }, props: Object.keys(argTypes), template: ` <bento-radio-group-filter v-bind="args" :value="value" :defaultValue="defaultValue" @input="selectOption" @update="applyOption" /> `, setup(props) { const args = isVue2 ? props : _args; const defaultValue: BentoRadioGroupFilterValue = args.options.items[0].value; const value = ref<BentoRadioGroupFilterValue>(defaultValue); const selectOption = (newOptionValue: BentoRadioGroupFilterProps) => { action('input')(newOptionValue); }; const applyOption = (newOptionValue: BentoRadioGroupFilterProps) => { value.value = newOptionValue.value; action('update')(newOptionValue); }; return { // Values args, value, defaultValue, // Events applyOption, selectOption, }; }, }), args: { label: 'Radio group filter', field: 'radio-group-filter', options: { items: [ { value: 1, label: 'First option' }, { value: 2, label: 'Second option' }, { value: 3, label: 'Last option' }, ], }, } satisfies BentoRadioGroupFilterProps, };
@@ -0,0 +1 @@
1
+ <template> <bento-base-filter v-bind="$props" :button-label="label" :button-secondary-label="buttonSecondaryLabel" :disable-apply-button="isApplyButtonDisabled" :disable-secondary-button="isSecondaryButtonDisabled" :only-slot="onlySlot" @apply="updateFilter" @clear="clearFilter(updateFilter)" @open="openFilter" @reset="resetFilter(updateFilter)" > <div class="b-radio-group-filter" :class="conditionalClasses"> <bento-radio-group v-model="internalFilterValue" :items="options?.items" :label="label" :disabled="disabled" hide-label variant="vertical" @update:model-value="onInput" /> </div> </bento-base-filter> </template> <script setup lang="ts"> import { BentoRadioGroup } from '@/components/radio-group'; import { BentoBaseFilter } from '../base-filter'; import { computed, toRef } from 'vue'; import { useBentoBaseFilter } from '@/composables/use-bento-base-filter'; import { truncate } from '@/utils/ts/truncate'; import { type BentoRadioGroupFilterProps, type BentoRadioGroupFilterValue } from './radio-group-filter.types'; const props = withDefaults(defineProps<BentoRadioGroupFilterProps>(), { defaultValue: undefined, value: undefined, options: () => ({ items: [], }), }); const emit = defineEmits<{ /** * Used in the All filters modal */ (e: 'input', newFilterValue: BentoRadioGroupFilterProps): void; /** * Used in the Filter Bar */ (e: 'update', newFilterValue: BentoRadioGroupFilterProps): void; }>(); const { // Fields internalFilterValue, isSecondaryButtonDisabled, isApplyButtonDisabled, // Methods clearFilter, openFilter, resetFilter, } = useBentoBaseFilter<BentoRadioGroupFilterValue>(toRef(props, 'value'), toRef(props, 'defaultValue')); // Used to truncate the label of the selected option const buttonSecondaryLabel = computed(() => { const selectedValueLabel = props.options.items.find(item => item.value === props.value)?.label || ''; return truncate(selectedValueLabel, 12); }); const conditionalClasses = computed(() => ({ [`b-radio-group-filter--only-slot`]: props.onlySlot, })); function onInput(newValue: BentoRadioGroupFilterValue) { internalFilterValue.value = newValue; // Emitted for the filter bar all filters modal emit('input', { ...props, value: internalFilterValue.value }); } function updateFilter() { // Emitted for the filter bar emit('update', { ...props, value: internalFilterValue.value }); } </script> <script lang="ts"> /** * Radio group filter component * * @example * import { BentoRadioGroupFilter } from '@adyen/bento-vue2'; * * export default { * components: { BentoRadioGroupFilter }, * template: ` * <bento-radio-group-filter * :label="label" * :options="{ * items: [ * { value: 'value1', label: 'Label 1' }, * { value: 'value2', label: 'Label 2' }, * ], * }" * value="value1" * defaultValue="value2" * /> * ` * } */ export default { name: 'bento-radio-group-filter', }; </script> <style lang="scss" scoped src="./radio-group-filter.scss" />
@@ -0,0 +1 @@
1
+ <template> <bento-base-filter v-bind="$props" :disable-apply-button="isApplyButtonDisabled" :disable-secondary-button="isSecondaryButtonDisabled" :button-label="buttonLabel" :button-secondary-label="buttonSecondaryLabel" :only-slot="onlySlot" :tooltip-position="options?.tooltipPosition" :tooltip-text="options?.tooltipText" @apply="updateFilter" @clear="clearFilter" @open="openFilter" @reset="resetFilter" > <div class="b-range-filter" :class="conditionalClasses" @keydown.enter="updateFilter"> <bento-input-field ref="inputTextRef" :model-value="internalFilterValue ? internalFilterValue[0] : ''" type="number" :aria-label="t('from').toString()" :disabled="disabled" @update:model-value="updateFrom" > {{ t('from') }} </bento-input-field> <bento-input-field class="b-range-filter__input-field" :model-value="internalFilterValue ? internalFilterValue[1] : ''" type="number" :aria-label="t('to')" :disabled="disabled" @update:model-value="updateTo" > {{ t('to') }} </bento-input-field> </div> </bento-base-filter> </template> <script lang="ts"> import { computed, defineComponent, nextTick, type PropType, ref, toRef } from 'vue'; import { BentoFilterEvent, type BentoRangeFilterOptions } from '../../filter-bar.types'; import { BentoBaseFilter, useBaseFilter } from '@/components/filter-bar/components/base-filter'; import { BentoInputField } from '@/components/input-field'; import { truncate } from '@/utils/ts/truncate'; import { useI18n } from '@/utils/ts/i18n'; import messages from './messages.json'; type MessageSchema = (typeof messages)['en-US']; /** * Range filter used in the filter-bar component. * * @example * import { BentoRangeFilter } from '@adyen/bento-vue2'; * * export default { * components: { BentoRangeFilter }, * template: ` * <bento-range-filter field="filter-field" label="Filter label" value="['0', '1']"/> * ` * } */ export default defineComponent({ name: 'bento-range-filter', i18n: { messages }, components: { BentoBaseFilter, BentoInputField }, props: { /** * Disables the filter from being interacted with. */ disabled: { type: Boolean, default: false }, /** * Default value of the filter to reset to. */ defaultValue: { type: Array as PropType<Array<string>>, default: null }, /** * Filter name/key referencing the actual property name in the data set. * Should be unique per filter bar. */ field: { type: String, required: true }, /** * Label text to be displayed */ label: { type: String, required: true }, /** * Current value of the filter */ value: { type: Array as PropType<Array<string>>, default: () => ['', ''] }, /** * Renders the base filter's slot content only - leaving out the button and the popover. * Used for the allFiltersModal component. */ onlySlot: { type: Boolean, default: false }, /** * List of options that are needed to setup the filter * Available options: * - tooltipPosition: The position of the tooltip attached to the filter button * - tooltipText: The content of the tooltip attached to the filter button */ options: { type: Object as PropType<BentoRangeFilterOptions>, default: undefined }, }, emits: [BentoFilterEvent.INPUT, BentoFilterEvent.UPDATE], setup(props, { emit }) { const { t } = useI18n<{ message: MessageSchema }>({ messages }); const inputTextRef = ref(null); const { internalFilterValue, isSecondaryButtonDisabled, isApplyButtonDisabled } = useBaseFilter( toRef(props, 'value'), toRef(props, 'defaultValue') ); const truncatedRangeValues = computed(() => { if (!props.value?.[0] && !props.value?.[1]) { return null; } // Set prefix is one range value is not set let prefix = ''; if (!props.value?.[0]) { prefix = '≤'; } else if (!props.value?.[1]) { prefix = '≥'; } const rangeFromLabel = props.value?.[0] ? `${truncate(props.value[0], 5)}` : ''; const seperator = props.value?.[0] && props.value?.[1] ? ' - ' : ''; const rangeToLabel = props.value?.[1] ? `${truncate(props.value[1], 5)}` : ''; return `${prefix}${rangeFromLabel}${seperator}${rangeToLabel}`; }); const buttonLabel = computed(() => props.label); const buttonSecondaryLabel = computed(() => truncatedRangeValues.value); const conditionalClasses = computed(() => ({ [`b-range-filter--only-slot`]: props.onlySlot, })); const openFilter = () => { internalFilterValue.value = props.value; nextTick(() => inputTextRef.value.focusInput()); }; const onInput = () => { emit(BentoFilterEvent.INPUT, { ...props, value: internalFilterValue.value }); }; const updateFrom = newValue => { internalFilterValue.value = [newValue, internalFilterValue.value[1]]; onInput(); }; const updateTo = newValue => { internalFilterValue.value = [internalFilterValue.value[0], newValue]; onInput(); }; const updateFilter = () => { if (!internalFilterValue.value.some(x => x)) { // If both range values are empty, // If persistent filter, reset back to default value, else reset back to undefined internalFilterValue.value = props.defaultValue !== null ? props.defaultValue : undefined; } emit(BentoFilterEvent.UPDATE, { ...props, value: internalFilterValue.value, }); }; const resetFilter = () => emit(BentoFilterEvent.UPDATE, { ...props, value: props.defaultValue }); const clearFilter = () => { internalFilterValue.value = ['', '']; updateFilter(); }; return { // Values inputTextRef, conditionalClasses, internalFilterValue, isApplyButtonDisabled, isSecondaryButtonDisabled, buttonLabel, buttonSecondaryLabel, // Events updateFrom, updateTo, updateFilter, clearFilter, openFilter, resetFilter, // Translations t, }; }, }); </script> <style lang="scss" scoped src="./range-filter.scss" />
@@ -0,0 +1 @@
1
+ <template> <bento-base-filter :applied-filters-count="appliedFiltersCount" :button-label="buttonLabel" :button-secondary-label="buttonSecondaryLabel" :disabled="disabled" :disable-apply-button="isApplyButtonDisabled" :disable-secondary-button="isSecondaryButtonDisabled" :default-value="defaultValue" :label="label" :field="field" :only-slot="false" :tooltip-position="options?.tooltipPosition" :tooltip-text="options?.tooltipText" :value="value" @apply="updateFilter" @clear="clearFilter" @reset="resetFilter" @open="openFilter" @close="closeFilter" > <div class="b-select-filter-button__search-bar-wrapper"> <div v-if="options?.dynamicFiltering ?? true" class="b-select-filter-button__search-bar"> <bento-search-bar :debounce-time="options?.search?.debounceTime" :value="searchTerm" :input-field-aria-label="t('searchFilter', { filter: label.toLocaleLowerCase() })" @input="searchTerm = $event" /> </div> <div class="b-select-filter-button__divider"> <bento-divider /> </div> </div> <bento-listbox :id="listboxFilterId" :aria-label="label" class="b-select-filter-button__wrapper" :component-loading="options?.loading" :empty-state="options?.emptyState" :has-more-items="options?.lazy?.hasMoreItems" :items="filteredItems" :is-option-disabled="options?.isOptionDisabled" :lazy-load-type="options?.lazy?.lazyLoadType" :loading="options?.lazy?.loading" :multiple="options?.multiple" :static-categories="options?.staticCategories" :no-results-message="noResultsMessage" :searching="!!searchTerm" :selected-value="internalFilterValue" :virtual-scroll="options?.virtualScroll" @select="onOptionSelected" @space-pressed="onOptionSelected" @enter-pressed="onOptionSelected" @show-more="options?.lazy?.showMoreEvent()" > <template v-for="(_, innerSlot) of slots" #[innerSlot]="scope"> <slot :name="innerSlot" v-bind="scope" /> </template> </bento-listbox> </bento-base-filter> </template> <script setup lang="ts"> import { computed, type PropType, ref, toRef, useSlots, watch } from 'vue'; // Components import BentoSearchBar from '@/components/search-bar/search-bar.vue'; import { BentoDivider } from '@/components/divider'; import { BentoListbox, useCachedSelectedValues } from '@/internal'; import { type BentoListboxMultiSelectValue, type BentoListboxOptionItem, type BentoListboxOptions, type BentoListboxSelectedValue, type BentoListboxSelectedValueLabelPair, type BentoListboxValue, } from '@/types/listbox'; import { BentoBaseFilter, useBaseFilter } from '../../../base-filter'; // Types import { BentoFilterEvent, type BentoSelectFilterOptions } from '../../../../filter-bar.types'; // Utilities import { useSearchBarFilter } from '@/components/search-bar'; import { generateUid } from '@/core/utils/ts'; import { truncate } from '@/utils/ts/truncate'; import { useI18n } from '@/utils/ts/i18n'; import { printDevelopmentWarning } from '@/utils/ts/print-development-warning'; import messages from './messages.json'; type MessageSchema = (typeof messages)['en-US']; const slots = useSlots(); const emit = defineEmits<{ (e: 'input', value: any); (e: 'update', value: any); }>(); const props = defineProps({ /** * Disables the filter from being interacted with. */ disabled: { type: Boolean, default: false }, /** * Default value of the filter to reset to. * */ defaultValue: { type: [String, Number, Array] as PropType<BentoListboxSelectedValue>, default: null, }, /** * Filter name/key referencing the actual property name in the data set. * Should be unique per filter bar. */ field: { type: String, required: true }, /** * Label text to be displayed */ label: { type: String, required: true }, /** * Renders the base filter's slot content only - leaving out the button and the popover. * Used for the allFiltersModal component. */ onlySlot: { type: Boolean, default: false }, /** * List of options that are needed to setup the filter * Available options: * - multiple: If "true", the user will be able to select multiple items. * - listboxItems: The option elements to populate the filter with. * * @default undefined */ options: { type: Object as PropType<BentoSelectFilterOptions>, default: undefined, }, /** * Current value of the filter * * @default undefined */ value: { type: [String, Number, Array, Object] as PropType<BentoListboxSelectedValue>, default: undefined, }, }); const { t } = useI18n<{ message: MessageSchema }>({ messages }); const searchTerm = ref(''); const optionsRef = toRef(props, 'options'); const itemsRef = ref(props.options.listboxItems ?? []); const { cachedSelectedListboxOptions, setCachedValues, resetCache } = useCachedSelectedValues( itemsRef, toRef(props, 'value'), toRef(optionsRef.value, 'multiple') ); const { cachedSelectedListboxOptions: cachedDefaultSelectedListboxOptions } = useCachedSelectedValues( itemsRef, toRef(props, 'defaultValue'), toRef(optionsRef.value, 'multiple') ); const { internalFilterValue, isSecondaryButtonDisabled, isApplyButtonDisabled } = useBaseFilter<BentoListboxOptions>(cachedSelectedListboxOptions, cachedDefaultSelectedListboxOptions); // We need to make sure to update the items if the consumer updates them manually watch(optionsRef, () => { itemsRef.value = optionsRef.value.listboxItems ?? []; }); const filteredItems = useSearchBarFilter<BentoListboxOptionItem>( searchTerm, itemsRef, props.options?.search?.searchEvent ); const noResultsMessage = computed(() => t('noFiltersMatchThisSearch') as string); const buttonLabel = computed(() => props.label); const buttonSecondaryLabel = computed(() => { const isSingleSelectAndOneItemSelected = !props?.options?.multiple && props.value != null; const isMultiSelectedAndOneItemSelected = props?.options?.multiple && Array.isArray(props.value) && props.value.length === 1; // When only 1 item is selected: Display the Label of the selected value or use value as Label if (isSingleSelectAndOneItemSelected || isMultiSelectedAndOneItemSelected) { // If enableValueLabelPair is enabled then "value" has the label, no need to search for it. if (props.options?.enableValueLabelPair) { let displayValue = (props.value as Array<BentoListboxSelectedValueLabelPair>)?.length > 0 ? (props.value[0] as BentoListboxSelectedValueLabelPair).label : (props.value as BentoListboxSelectedValueLabelPair).label; if (!displayValue) { displayValue = props.value as string; printDevelopmentWarning( 'BentoFilterBar Select filter (single & multi): The "value" provided is incorrect. The "value" must be of type "BentoListboxSelectedValueLabelPair" or "Array<BentoListboxSelectedValueLabelPair>" when "enableValueLabelPair" is set to true' ); } return truncate(displayValue as string, 12); } const flatListboxItems = props.options.listboxItems.flatMap(x => (x.items ? x.items : x)); // If the value is not in the list of Items set the value as secondary label. // This happens on external filtering let displayValue = flatListboxItems.find(({ value }) => Array.isArray(props.value) ? (props?.value as BentoListboxMultiSelectValue)?.includes(value as BentoListboxValue) : value === props.value )?.label; if (!displayValue && props.value) { displayValue = (props.value as BentoListboxMultiSelectValue)[0] as string; } return truncate(displayValue, 12); } return null; }); const listboxFilterId = computed(() => generateUid(`filter-listbox-${props.field}`)); const onOptionSelected = (selectedValue: BentoListboxOptions) => { internalFilterValue.value = selectedValue; const { onlySlot, ...cleanedProps } = props; // Return null if there are no selected values if (props.options?.multiple) { let value: BentoListboxSelectedValue; if (props.options?.enableValueLabelPair) { value = selectedValue.length ? internalFilterValue.value : null; } else { value = selectedValue.length ? internalFilterValue.value.map(({ value }) => value) : null; } emit(BentoFilterEvent.INPUT, { ...cleanedProps, value }); return; } let value: BentoListboxSelectedValue; if (props.options?.enableValueLabelPair) { value = selectedValue.length ? selectedValue[0] : null; } else { value = selectedValue.length ? selectedValue[0].value : null; } emit(BentoFilterEvent.INPUT, { ...cleanedProps, value }); }; const updateFilter = () => { // Omit the onlySlot prop as it is not needed const { onlySlot, ...cleanedProps } = props; if (props.options.multiple) { // If multi select filter and all items unchecked, // If persistent filter, reset back to default value, else reset back to undefined if (internalFilterValue.value && (internalFilterValue.value as Array<unknown>)?.length === 0) { internalFilterValue.value = props.defaultValue !== null ? cachedDefaultSelectedListboxOptions.value : undefined; } let value: BentoListboxSelectedValue; if (props.options?.enableValueLabelPair) { value = internalFilterValue.value?.length ? internalFilterValue.value : null; } else { value = internalFilterValue.value?.length ? internalFilterValue.value?.map(({ value }) => value) : null; } emit(BentoFilterEvent.UPDATE, { ...cleanedProps, value, }); return; } let value: BentoListboxSelectedValue; if (props.options?.enableValueLabelPair) { value = internalFilterValue.value.length ? internalFilterValue.value[0] : undefined; } else { value = internalFilterValue.value.length ? internalFilterValue.value[0].value : undefined; } emit(BentoFilterEvent.UPDATE, { ...cleanedProps, value }); }; const openFilter = () => { internalFilterValue.value = cachedSelectedListboxOptions.value; props.options?.onOpen?.(); }; const closeFilter = () => { // If the search term is set, reset it to "empty" if (searchTerm.value) { searchTerm.value = ''; } }; const resetFilter = () => { setCachedValues(cachedDefaultSelectedListboxOptions.value); internalFilterValue.value = cachedDefaultSelectedListboxOptions.value; updateFilter(); }; const clearFilter = () => { resetCache(); internalFilterValue.value = []; updateFilter(); }; const appliedFiltersCount = computed(() => { // Don't show if no filter applied or peristent filter or not multiple select if (props.value == null || !props.options.multiple) { return null; } /* * Show amount of items selceted (props.value) or 'All' if all items selected */ // If nested we need to get the correct count const allSelectableItemsCount = props.options.listboxItems?.reduce((acc, item) => { // eslint-disable-next-line no-param-reassign acc += item?.items?.length ? item.items.length : 1; return acc; }, 0); const selectedAmount = (props.value as Array<string | number>)?.length; if (selectedAmount === 1) { return null; } return selectedAmount === allSelectableItemsCount ? t('all') : selectedAmount; }); </script> <script lang="ts"> /** * The Listbox filter displays a listbox of items * passed in the "options.listboxItems" property. * * @example * import { BentoSelectFilter } from '@adyen/bento-vue2'; * * export default { * components: { BentoSelectFilter }, * template: ` * <bento-select-filter * :field="filter.field" * :label="filter.label" * :options="filter.options" * :value="filter.value" * @update="updateFilterHandler" * > * ` * } */ export default { i18n: { messages }, }; </script> <style lang="scss" scoped src="./select-filter-button.scss" />
@@ -0,0 +1 @@
1
+ <template> <bento-dropdown :model-value="internalFilterValue" :items="options.listboxItems" :search="options?.search" :multiple="options?.multiple" :static-categories="options?.staticCategories" :no-results-message="noResultsMessage" :is-option-disabled="options.isOptionDisabled" :dynamic-filtering="options?.dynamicFiltering ?? true" :component-loading="options?.loading" :empty-state="options?.emptyState" :disabled="disabled" :enable-value-label-pair="options?.enableValueLabelPair" @update:model-value="onOptionSelected" @open="() => options?.onOpen?.()" > <template v-for="(_, innerSlot) of slots" #[innerSlot]="scope"> <slot :name="innerSlot" v-bind="scope" /> </template> </bento-dropdown> </template> <script setup lang="ts"> import { computed, type PropType, ref, toRef, useSlots, watch } from 'vue'; // Components import { BentoDropdown } from '@/components/dropdown'; // Composables import { useBaseFilter } from '../../../base-filter'; // Types import { type BentoListboxSelectedValue } from '@/types/listbox'; import { BentoFilterEvent, type BentoSelectFilterOptions } from '../../../../filter-bar.types'; // Utils import { useI18n } from '@/utils/ts/i18n'; import messages from './messages.json'; type MessageSchema = (typeof messages)['en-US']; const { t } = useI18n<{ message: MessageSchema }>({ messages }); const slots = useSlots(); const emit = defineEmits<{ (e: 'input', updatedProps: any): void; (e: 'update', updatedProps: any): void; }>(); const props = defineProps({ /** * Disables the filter from being interacted with. */ disabled: { type: Boolean, default: false }, /** * Default value of the filter to reset to. * */ defaultValue: { type: [String, Number, Array] as PropType<BentoListboxSelectedValue>, default: null, }, /** * Filter name/key referencing the actual property name in the data set. * Should be unique per filter bar. */ field: { type: String, required: true }, /** * Label text to be displayed */ label: { type: String, required: true }, /** * Renders the base filter's slot content only - leaving out the button and the popover. * Used for the allFiltersModal component. * */ onlySlot: { type: Boolean, default: false }, /** * List of options that are needed to setup the filter * Available options: * - multiple: If "true", the user will be able to select multiple items. * - listboxItems: The option elements to populate the filter with. * * @default undefined */ options: { type: Object as PropType<BentoSelectFilterOptions>, default: undefined, }, /** * Current value of the filter * * @default undefined */ value: { type: [String, Number, Array] as PropType<BentoListboxSelectedValue>, default: undefined, }, }); const { internalFilterValue } = useBaseFilter(toRef(props, 'value'), toRef(props, 'defaultValue')); const optionsRef = toRef(props, 'options'); const itemsRef = ref(props.options.listboxItems); // We need to make sure to update the items if the consumer updates them manually watch(optionsRef, () => { itemsRef.value = optionsRef.value.listboxItems; }); const noResultsMessage = computed(() => t('noFiltersMatchThisSearch') as string); const onOptionSelected = (selectedValue: BentoListboxSelectedValue) => { internalFilterValue.value = selectedValue; const { onlySlot, ...cleanedProps } = props; emit(BentoFilterEvent.INPUT, { ...cleanedProps, value: internalFilterValue.value }); }; </script> <script lang="ts"> /** * The Listbox filter displays a listbox of items * passed in the "options.listboxItems" property. * * @example * import { BentoSelectFilter } from '@adyen/bento-vue2'; * * export default { * components: { BentoSelectFilter }, * template: ` * <bento-select-filter * :field="filter.field" * :label="filter.label" * :options="filter.options" * :value="filter.value" * @update="updateFilterHandler" * > * ` * } */ export default { i18n: { messages }, name: 'select-filter-dropdown', }; </script>
@@ -0,0 +1 @@
1
+ import { computed, ref } from 'vue'; import { action } from '@storybook/addon-actions'; import { type BentoListboxOptions } from '@/types/listbox'; import { BentoTypography } from '@/components/typography'; import { isVue2 } from 'vue-demi'; import { type BentoSelectFilterOptions, type BentoSelectFilterValue } from '../../filter-bar.types'; import { type Meta, type StoryObj } from '@storybook/vue'; import BentoSelectFilter from './select-filter.vue'; // Generate array from 1 to # // { label: 'Option #', value: # }, const DEFAULT_OPTIONS: BentoListboxOptions = new Array(10) .fill(0) .map((_, index) => ({ label: `Option ${index + 1}`, value: index + 1 })); const meta: Meta = { title: 'Filter bar/Select filter', component: BentoSelectFilter, argTypes: { update: { name: 'update', defaultValue: '', description: '`update` event handler. Called whenever the "Apply" button is clicked.', table: { type: { summary: '({ field, label, value }) => void' } }, control: { disable: true }, }, }, }; export default meta; type Story = StoryObj<typeof BentoSelectFilter>; const Template: Story = { render: (_args, { argTypes }) => ({ components: { BentoSelectFilter }, props: Object.keys(argTypes), setup(props) { const selectedValues = ref(props.selectedValue); const onInput = newFilterValue => { action('input')(newFilterValue); }; const updateFilter = newFilterValue => { action('update')(newFilterValue); selectedValues.value = newFilterValue.value; }; return { args: isVue2 ? props : _args, selectedValues, updateFilter, onInput, }; }, template: ` <div style="padding-top: 24px"> <bento-select-filter v-bind="args" :value="selectedValues" @input="onInput" @update="updateFilter" /> </div> `, }), }; export const SingleSelect: Story = { ...Template, args: { label: 'Company', field: 'company', selectedValue: undefined, options: { isOptionDisabled: option => [3, 5].includes(option), listboxItems: DEFAULT_OPTIONS, lazy: { lazyLoadType: 'button', hasMoreItems: true, showMoreEvent: action('showMoreEvent'), loading: true, }, }, }, }; export const MultiSelect: Story = { ...Template, args: { label: 'Company', field: 'company', selectedValue: [3, 1, 10], options: { isOptionDisabled: option => [3, 5].includes(option.value), listboxItems: DEFAULT_OPTIONS, multiple: true, lazy: { lazyLoadType: 'none', hasMoreItems: false, }, }, }, }; export const StaticCategoriesSingleSelect: Story = { ...Template, args: { label: 'Company', field: 'company', selectedValue: undefined, options: { listboxItems: [ { label: 'Category 1', value: 1, items: [ { label: 'Option 1', value: 10 }, { label: 'Option 2', value: 20 }, ], }, { label: 'Category 2', value: 2, items: [ { label: 'Option 3', value: 30 }, { label: 'Option 4', value: 40 }, ], }, ], staticCategories: true, }, }, }; export const StaticCategoriesMultiSelect: Story = { ...Template, args: { label: 'Company', field: 'company', selectedValue: undefined, options: { listboxItems: [ { label: 'Category 1', value: 1, items: [ { label: 'Option 1', value: 10 }, { label: 'Option 2', value: 20 }, ], }, { label: 'Category 2', value: 2, items: [ { label: 'Option 3', value: 30 }, { label: 'Option 4', value: 40 }, ], }, ], staticCategories: true, multiple: true, }, }, }; export const NestedMultiSelect: Story = { ...Template, args: { label: 'Company', field: 'company', selectedValue: [10], options: { isOptionDisabled: option => [3, 5].includes(option.value), listboxItems: [ { label: 'Category 1', value: 1, items: [ { label: 'Option 1', value: 10 }, { label: 'Option 2', value: 20 }, ], }, { label: 'Category 2', value: 2, items: [ { label: 'Option 3', value: 30 }, { label: 'Option 4', value: 40 }, ], }, ], multiple: true, lazy: { lazyLoadType: 'none', hasMoreItems: false, }, }, }, }; export const SearchAPI: Story = { render: (_args, { argTypes }) => ({ components: { BentoSelectFilter }, props: Object.keys(argTypes), setup(props) { const apiItems = ref(DEFAULT_OPTIONS); const selectedValues = ref(props.selectedValue); const search = { debounceTime: 2000, searchEvent: (val: string) => { action('searchEvent')(val); if (val) { apiItems.value = []; } else { apiItems.value = DEFAULT_OPTIONS; } }, }; const options = computed(() => ({ isOptionDisabled: option => [3, 5].includes(option), listboxItems: apiItems.value, search, })); const updateFilter = newFilterValue => { action('update')(newFilterValue); selectedValues.value = newFilterValue.value; }; return { selectedValues, updateFilter, options, }; }, template: ` <div style="padding-top: 24px"> <bento-select-filter :value="selectedValues" :options="options" label="hello" field="company" @update="updateFilter" /> </div> `, }), }; export const SingleSelectWithDefault: Story = { ...Template, args: { label: 'Company', field: 'company', selectedValue: 1, defaultValue: 1, options: { isOptionDisabled: option => [3, 5].includes(option), listboxItems: DEFAULT_OPTIONS, lazy: { lazyLoadType: 'button', hasMoreItems: true, showMoreEvent: action('showMoreEvent'), loading: true, }, }, }, }; export const SelectOnlySlot: Story = { ...Template, args: { label: 'Company', field: 'company', selectedValue: 1, defaultValue: 1, onlySlot: true, options: { listboxItems: DEFAULT_OPTIONS, multiple: false, }, }, }; export const ExternalFiltering: Story = { render: (_args, { argTypes }) => ({ components: { BentoSelectFilter, BentoTypography }, props: Object.keys(argTypes), template: ` <bento-typography> <span>This story showcases how you can hook your own handler into the dropdown's search event. Check the 'actions' section as you're searching to see what event is being emitted!</span> <div style="margin-top: 20px; max-width: 300px"> <bento-select-filter v-bind="args" :options="selectOptions" :value="selectedValue" @input="onInput" @update="updateFilter" /> </div> </bento-typography> `, setup(props) { const args = isVue2 ? props : _args; const selectedValue = ref<BentoSelectFilterValue>(null); const internalList = ref<BentoListboxOptions>(args.options.listboxItems); const setList = (items: BentoListboxOptions) => { internalList.value = items; }; const searchForValue = (searchString: string) => { if (!searchString || !searchString.length) { setList(args.options.listboxItems); return; } const currentId = parseInt(searchString, 10); if (isNaN(currentId)) { setList([]); return; } const repeatValue = (value, times) => String(value).repeat(times); setList( new Array(10).fill(0).map((_, index) => ({ value: repeatValue(currentId, index + 1), label: `Option ${repeatValue(currentId, index + 1)}`, })) ); }; const selectOptions = computed<BentoSelectFilterOptions>(() => ({ listboxItems: internalList.value, search: { searchEvent: value => { searchForValue(value); }, }, })); const onInput = newFilterValue => { action('input')(newFilterValue); }; const updateFilter = newSelectedValue => { selectedValue.value = newSelectedValue.value; action('update')(newSelectedValue); }; return { // Values args, selectedValue, selectOptions, // Methods onInput, updateFilter, }; }, }), args: { label: 'Company', field: 'company', selectedValue: 1, defaultValue: 1, options: { listboxItems: DEFAULT_OPTIONS, }, }, }; export const ExternalValues: Story = { render: (_args, { argTypes }) => ({ components: { BentoSelectFilter, BentoTypography }, props: Object.keys(argTypes), template: ` <bento-select-filter v-bind="args" :options="args.options" :value="selectedValue" @update="updateValues" /> `, setup(props) { // Value not in list from external data const selectedValue = ref<BentoSelectFilterValue>(['four']); const updateValues = options => { selectedValue.value = options.value; }; return { args: isVue2 ? props : _args, selectedValue, selectedOptions: props.options, updateValues, }; }, }), args: { label: 'Company', field: 'company', options: { multiple: true, listboxItems: [ { value: 'one', label: 'One' }, { value: 'two', label: 'Two' }, { value: 'three', label: 'Three' }, ], }, }, };
@@ -0,0 +1 @@
1
+ <template> <select-filter-dropdown v-if="onlySlot" :disabled="disabled" :default-value="defaultValue" :field="field" :label="label" :options="options" :value="value" @input="onInput" @update="onUpdate" > <template v-for="(_, innerSlot) of slots" #[innerSlot]="scope"> <slot :name="innerSlot" v-bind="scope" /> </template> </select-filter-dropdown> <select-filter-button v-else :disabled="disabled" :default-value="defaultValue" :field="field" :label="label" :options="options" :value="value" @input="onInput" @update="onUpdate" > <template v-for="(_, innerSlot) of slots" #[innerSlot]="scope"> <slot :name="innerSlot" v-bind="scope" /> </template> </select-filter-button> </template> <script setup lang="ts"> import { SelectFilterButton, SelectFilterDropdown } from './components'; import { onMounted, useSlots } from 'vue'; import { deprecate } from '@/utils/ts/deprecate'; import SelectFilterProps from '@/components/filter-bar/components/select-filter/select-filter.props'; const slots = useSlots(); const emit = defineEmits<{ (e: 'input', updatedProps: any): void; (e: 'update', updatedProps: any): void; }>(); const props = defineProps(SelectFilterProps); const onInput = (updatedProps: any) => emit('input', updatedProps); const onUpdate = (updatedProps: any) => emit('update', updatedProps); onMounted(() => { if (props?.options?.messages) { deprecate( 'BentoFilterBar filter of type "BentoFilterItemType.SELECT" options message property', `Please remove the "options.messages" property from this filter, it is not required any more for persistent filters. This will be the default behavior in the v2 and "options.messages" will be removed.`, '2.0.0' ); } }); </script> <script lang="ts"> /** * The Listbox filter displays a listbox of items * passed in the "options.listboxItems" property. * * @example * import { BentoSelectFilter } from '@adyen/bento-vue2'; * * export default { * components: { BentoSelectFilter }, * template: ` * <bento-select-filter * :field="filter.field" * :label="filter.label" * :options="filter.options" * :value="filter.value" * @update="updateFilterHandler" * > * ` * } */ export default {}; </script>
@@ -0,0 +1 @@
1
+ import { ref } from 'vue'; import { action } from '@storybook/addon-actions'; import { type BentoSelectAvatarFilterOptions } from '../../../../filter-bar.types'; import { storybookDocsParameter } from '../../../../../../utils/ts/storybook'; import { BentoSelectAvatarFilter } from './index'; import { isVue2 } from 'vue-demi'; const OPTIONS: BentoSelectAvatarFilterOptions = { listboxItems: [ { label: 'Avatar 1', value: 'avatar-1', }, { label: 'Avatar 2', value: 'avatar-2', }, ], }; export default { title: 'Filter bar/Select avatar filter', component: BentoSelectAvatarFilter, argTypes: { // Slots field: { name: 'field', type: { name: 'string', required: false }, description: 'Filter name/key referencing the actual property name in the data set. Should be unique per filter bar.', control: 'text', table: { type: { summary: 'string' }, }, }, label: { name: 'label', type: { name: 'string', required: false }, description: 'Label text to be displayed', control: 'text', table: { type: { summary: 'string' }, }, }, value: { name: 'value', type: { name: 'string', required: true }, description: 'Current value of the filter', control: { disable: true }, table: { type: { summary: 'string, number, Array<string, number>' }, }, }, // Events eventName: { name: 'update', defaultValue: '', description: 'Description waht the event is for', table: { type: { summary: '() => void' } }, control: { disable: true }, }, }, }; export const Default = (_args, { argTypes }) => ({ components: { BentoSelectAvatarFilter }, props: Object.keys(argTypes), template: ` <bento-select-avatar-filter v-bind="args" :value="valueRef" @update="onSelected"/> `, setup(props) { const valueRef = ref(); const onSelected = selectedValue => { valueRef.value = selectedValue.value; action('update')(selectedValue); }; return { // Values args: isVue2 ? props : _args, valueRef, // Events onSelected, }; }, }); Default.args = { field: 'Avatar', label: 'Avatar', options: OPTIONS, }; Default.parameters = storybookDocsParameter(` <bento-select-avatar-filter v-model="selectedValue" :options="{ listboxOptions: [ { label: 'Avatar 1', value: 'avatar-id-1' }, { label: 'Avatar 2', value: 'avatar-id-2', src: 'image-source.jpeg' }, ]" }", label="Avatar" field="avatar" /> `);
@@ -0,0 +1 @@
1
+ <template> <bento-select-filter v-slot="{ label: slotLabel, data }" v-bind="$props" :field="field" :label="label" @update="onUpdate" @input="e => $emit(BentoFilterEvent.INPUT, e)" > <bento-avatar :username="slotLabel" :src="data" /> </bento-select-filter> </template> <script lang="ts"> import { defineComponent, type PropType } from 'vue'; import { type BentoListboxSelectedValue } from '@/types/listbox'; import { BentoSelectFilter } from '../../index'; import { BentoFilterEvent, type BentoSelectAvatarFilterOptions } from '@/components/filter-bar/filter-bar.types'; import { BentoAvatar } from '@/components/avatar'; import SelectFilterProps from '@/components/filter-bar/components/select-filter/select-filter.props'; /** * The Select Avatar filter displays a listbox of avatar items * passed in the "options.listboxItems" property. * * @example * import { BentoSelectAvatarFilter } from '@adyen/bento-vue2'; * * export default { * components: { BentoSelectAvatarFilter }, * template: ` * <bento-select-avatar-filter * :field="avatar" * :label="Avatar" * :options="{ * listboxItems: [{ * label: 'Avatar 1', * value: 'avatar-2' * }, { * label: 'Avatar 2', * value: 'avatar-2' * }], * :multiple="false" * }" * value="avatar-2" * @update="updateFilterHandler" * > * ` * } */ export default defineComponent({ name: 'bento-select-avatar-filter', components: { BentoSelectFilter, BentoAvatar, }, props: { ...SelectFilterProps, /** * List of options that are needed to setup the country filter * Available options: * - multiple: If "true", the user will be able to select multiple items. * - listboxItems: The option elements to populate the filter with {@see BentoSelectCountryFilterOptions} */ options: { type: Object as PropType<BentoSelectAvatarFilterOptions>, default: undefined, }, }, emits: [BentoFilterEvent.INPUT, BentoFilterEvent.UPDATE], setup(_, { emit }) { const onUpdate = (selectedValue: BentoListboxSelectedValue) => emit(BentoFilterEvent.UPDATE, selectedValue); return { // Enums BentoFilterEvent, // Methods onUpdate, }; }, }); </script>
@@ -0,0 +1 @@
1
+ import { ref } from 'vue'; import { action } from '@storybook/addon-actions'; import { BentoCountryCode } from '@/components/country/country.types'; import { type BentoSelectCountryFilterOptions } from '../../../../filter-bar.types'; import BentoSelectCountryFilter from './select-country-filter.vue'; import { isVue2 } from 'vue-demi'; const OPTIONS: BentoSelectCountryFilterOptions = { listboxItems: [ { label: 'Netherlands', value: BentoCountryCode.NL, }, { label: 'Belgium', value: BentoCountryCode.BE, }, ], variant: 'capital', }; export default { title: 'Filter bar/Select country filter', component: BentoSelectCountryFilter, argTypes: { // Slots field: { name: 'field', type: { name: 'string', required: false }, description: 'Filter name/key referencing the actual property name in the data set. Should be unique per filter bar.', control: 'text', table: { type: { summary: 'string' }, }, }, label: { name: 'label', type: { name: 'string', required: false }, description: 'Label text to be displayed', control: 'text', table: { type: { summary: 'string' }, }, }, value: { name: 'value', type: { name: 'string', required: true }, description: 'Current value of the filter', control: { disable: true }, table: { type: { summary: 'string, number, Array<string, number>' }, }, }, // Events eventName: { name: 'update', defaultValue: '', description: 'Description waht the event is for', table: { type: { summary: '() => void' } }, control: { disable: true }, }, }, }; const Template = (_args, { argTypes }) => ({ components: { BentoSelectCountryFilter }, props: Object.keys(argTypes), template: ` <bento-select-country-filter v-bind="args" :value="valueRef" @update="onSelected"/> `, setup(props) { const valueRef = ref(); const onSelected = selectedValue => { valueRef.value = selectedValue.value; action('update')(selectedValue); }; return { // Values args: isVue2 ? props : _args, valueRef, // Events onSelected, }; }, }); export const SingleSelect = Template.bind({}); SingleSelect.args = { field: 'country', label: 'Country/Region', options: OPTIONS, }; export const MultiSelect = Template.bind({}); MultiSelect.args = { field: 'country', label: 'Country/Region', multiple: true, options: { ...OPTIONS, multiple: true }, };
@@ -0,0 +1 @@
1
+ <template> <bento-select-filter v-slot="{ label: slotLabel }" v-bind="props" :field="field" :label="label" :options="countryOptions" @update="onUpdate" @input="e => $emit(BentoFilterEvent.INPUT, e)" > <bento-typography el="span">{{ slotLabel }}</bento-typography> </bento-select-filter> </template> <script setup lang="ts"> import { computed, type PropType, ref, watch } from 'vue'; import { useCountryItems } from '@/components/dropdown/components/variants/dropdown-country/composables/use-country-items'; import { type BentoListboxSelectedValue } from '@/types/listbox'; import { BentoFilterEvent, type BentoSelectCountryFilterOptions } from '@/components/filter-bar/filter-bar.types'; import { deprecate } from '@/utils/ts/deprecate'; import { BentoTypography } from '@/components/typography'; import BentoSelectFilter from '../../select-filter.vue'; import SelectFilterProps from '@/components/filter-bar/components/select-filter/select-filter.props'; const props = defineProps({ ...SelectFilterProps, /** * List of options that are needed to setup the country filter * Available options: * - multiple: If "true", the user will be able to select multiple items. * - listboxItems: The option elements to populate the filter with {@see BentoSelectCountryFilterOptions} * - variant: Which label variant to display for the option item. */ options: { type: Object as PropType<BentoSelectCountryFilterOptions>, default: undefined, }, }); const emit = defineEmits([BentoFilterEvent.INPUT, BentoFilterEvent.UPDATE]); const variant = ref(props.options.variant); const listboxItems = ref(props.options.listboxItems); watch([() => props.options.variant, () => props.options.listboxItems], () => { variant.value = props.options.variant; listboxItems.value = props.options.listboxItems; }); const onUpdate = (selectedValue: BentoListboxSelectedValue) => emit(BentoFilterEvent.UPDATE, selectedValue); const countryItems = useCountryItems(variant, listboxItems); const countryOptions = computed(() => { return { ...(props?.options ? props.options : {}), listboxItems: countryItems.value, }; }); if (!variant.value || variant.value === 'custom') { deprecate( 'BentoSelectCountryFilter type with `options.variant==="custom"`', 'Use any of the other BentoSelectCountryFilter variants instead OR use BentoSelectFilter type for custom labels', '2.0.0' ); } </script> <script lang="ts"> /** * The Select Country filter displays a listbox of country items * passed in the "options.listboxItems" property. * * @example * import { BentoSelectCountryFilter } from '@adyen/bento-vue2'; * * export default { * components: { BentoSelectCountryFilter }, * template: ` * <bento-select-country-filter * :field="country" * :label="Country" * :options="{ * listboxItems: [{ * value: "NL", * }, { * value: "BE", * }], * variant: 'capital' * }" * :value="BE" * @update="updateFilterHandler" * > * ` * } */ export default { name: 'bento-select-country-filter', }; </script>
@@ -0,0 +1 @@
1
+ import { action } from '@storybook/addon-actions'; import { type BentoSelectCurrencyFilterOptions } from '@/components/filter-bar/filter-bar.types'; import { ref } from 'vue'; import { BentoCurrencyISOCode } from '@/components/currency/currency.types'; import BentoSelectCurrencyFilter from './select-currency-filter.vue'; import { isVue2 } from 'vue-demi'; const OPTIONS: BentoSelectCurrencyFilterOptions = { listboxItems: [ { label: 'Euro', value: BentoCurrencyISOCode.EUR, }, { label: 'US Dollars', value: BentoCurrencyISOCode.USD, }, ], }; export default { title: 'Filter bar/Select currency filter', component: BentoSelectCurrencyFilter, // Slots field: { name: 'field', type: { name: 'string', required: false }, description: 'Filter name/key referencing the actual property name in the data set. Should be unique per filter bar.', control: 'text', table: { type: { summary: 'string' }, }, }, label: { name: 'label', type: { name: 'string', required: false }, description: 'Label text to be displayed', control: 'text', table: { type: { summary: 'string' }, }, }, value: { name: 'value', type: { name: 'string', required: true }, description: 'Current value of the filter', control: { disable: true }, table: { type: { summary: 'string, number, Array<string, number>' }, }, }, // Events eventName: { name: 'update', defaultValue: '', description: 'Triggered whenever the filter is updated by applying the selection.', table: { type: { summary: '() => void' } }, control: { disable: true }, }, }; export const Default = (_args, { argTypes }) => ({ components: { BentoSelectCurrencyFilter }, props: Object.keys(argTypes), template: ` <bento-select-currency-filter v-bind="args" :value="valueRef" @update="clickedAction"/> `, setup(props) { const valueRef = ref(); const clickedAction = selectedValue => { valueRef.value = selectedValue.value; action('input')(selectedValue); }; return { // Values args: isVue2 ? props : _args, valueRef, // Events clickedAction, }; }, }); Default.args = { field: 'currency', label: 'Currency', options: OPTIONS, };
@@ -0,0 +1 @@
1
+ <template> <bento-select-filter v-slot="slotProps" v-bind="$props" :field="field" :label="label" :options="internalOptions" @update="onUpdate" @input="e => $emit(BentoFilterEvent.INPUT, e)" > <listbox-option-tag :option="slotProps" /> </bento-select-filter> </template> <script lang="ts"> import { computed, defineComponent, type PropType, ref, watch } from 'vue'; import { type BentoListboxSelectedValue } from '@/types/listbox'; import { BentoSelectFilter } from '../../index'; import { ListboxOptionTag } from '@/internal'; import { BentoFilterEvent, type BentoSelectCurrencyFilterOptions } from '@/components/filter-bar/filter-bar.types'; import SelectFilterProps from '@/components/filter-bar/components/select-filter/select-filter.props'; import { useSearchBarFilter } from '@/components/search-bar'; import { type BentoCurrencyListboxOptions } from '@/components/dropdown'; /** * The Select Country filter displays a listbox of country items * passed in the "options.listboxItems" property. * * @example * import { BentoCurrencyISOCode, BentoSelectCurrencyFilter } from '@adyen/bento-vue2'; * * export default { * components: { BentoSelectCurrencyFilter }, * template: ` * <bento-select-currency-filter * :field="currency" * :label="Currency" * :options="{ * listboxItems: [{ * label: 'Euro', * value: BentoCurrencyISOCode.EUR, * }, { * label: 'US Dollars', * value: BentoCurrencyISOCode.USD, * }], * multiple="false", * isOptionsDisabled="option => option.value === BentoCurrencyISOCode.USD" * }" * :value="BentoCurrencyISOCode.EUR" * @update="updateFilterHandler" * > * ` * } */ export default defineComponent({ name: 'bento-select-currency-filter', components: { BentoSelectFilter, ListboxOptionTag, }, props: { ...SelectFilterProps, /** * List of options that are needed to setup the country filter * Available options: * - multiple: If "true", the user will be able to select multiple items. * - listboxItems: The option elements to populate the filter with {@see BentoSelectCurrencyFilterOptions} */ options: { type: Object as PropType<BentoSelectCurrencyFilterOptions>, default: undefined, }, }, emits: [BentoFilterEvent.INPUT, BentoFilterEvent.UPDATE], setup(props, { emit }) { const onUpdate = (selectedValue: BentoListboxSelectedValue) => { emit(BentoFilterEvent.UPDATE, selectedValue); }; // If the parent updates the list, the local reference needs to be updated so the UI isn't empty on load const filteredItems = ref<BentoCurrencyListboxOptions>([]); watch( () => props.options?.listboxItems, newList => { filteredItems.value = newList || []; }, { immediate: true } ); const search = props.options?.search ? props.options.search : { debounceTime: 500, searchEvent: async (searchTerm: string) => { // Combine value and label to be able to search by the currency code // If searchTerm is empty, reset to the full list if (!searchTerm) { filteredItems.value = props.options?.listboxItems || []; return; } const searchableItems = (props.options?.listboxItems || []).map(item => ({ ...item, label: `${item.value} ${item.label}`, })); const searchResults = useSearchBarFilter( ref(searchTerm), ref<BentoCurrencyListboxOptions>(searchableItems), props.options?.search?.searchEvent, ref(false) ).value; // Restore original labels by removing the prepended value const normalizedResults = searchResults?.map(result => ({ ...result, label: result.label.substring(result.value.length + 1), })); filteredItems.value = normalizedResults; }, }; const internalOptions = computed(() => ({ ...props.options, search: search, listboxItems: filteredItems.value, })); return { // Enums BentoFilterEvent, // Methods onUpdate, internalOptions, }; }, }); </script>
@@ -0,0 +1 @@
1
+ import { ref } from 'vue'; import { action } from '@storybook/addon-actions'; import { type BentoSelectPaymentMethodFilterOptions } from '@/components/filter-bar/filter-bar.types'; import BentoSelectPaymentMethodFilter from './select-payment-method-filter.vue'; import { isVue2 } from 'vue-demi'; const OPTIONS: BentoSelectPaymentMethodFilterOptions = { listboxItems: [ { label: 'iDEAL', value: 'ideal' }, { label: 'Visa', value: 'visa' }, ], }; export default { title: 'Filter bar/Select payment method filter', component: BentoSelectPaymentMethodFilter, argTypes: { // Slots field: { name: 'field', type: { name: 'string', required: false }, description: 'Filter name/key referencing the actual property name in the data set. Should be unique per filter bar.', control: 'text', table: { type: { summary: 'string' }, }, }, label: { name: 'label', type: { name: 'string', required: false }, description: 'Label text to be displayed', control: 'text', table: { type: { summary: 'string' }, }, }, value: { name: 'value', type: { name: 'string', required: true }, description: 'Current value of the filter', control: { disable: true }, table: { type: { summary: 'string, number, Array<string, number>' }, }, }, // Events eventName: { name: 'update', defaultValue: '', description: 'Description waht the event is for', table: { type: { summary: '() => void' } }, control: { disable: true }, }, }, }; const Template = (_args, { argTypes }) => ({ components: { BentoSelectPaymentMethodFilter }, props: Object.keys(argTypes), template: ` <bento-select-payment-method-filter v-bind="args" :value="valueRef" @update="onSelected"/> `, setup(props) { const valueRef = ref(); const onSelected = selectedValue => { valueRef.value = selectedValue.value; action('update')(selectedValue); }; return { // Values args: isVue2 ? props : _args, valueRef, // Events onSelected, }; }, }); export const SingleSelect = Template.bind({}); SingleSelect.args = { field: 'paymentMethod', label: 'Payment method', options: OPTIONS, }; export const MultiSelect = Template.bind({}); MultiSelect.args = { field: 'paymentMethod', label: 'Payment method', multiple: true, options: { ...OPTIONS, multiple: true }, };
@@ -0,0 +1 @@
1
+ <template> <bento-select-filter v-slot="{ value, label: slotLabel }" v-bind="$props" :field="field" :label="label" @update="onUpdate" @input="e => $emit(BentoFilterEvent.INPUT, e)" > <bento-payment-method :type="value" :label="slotLabel" /> </bento-select-filter> </template> <script lang="ts"> import { defineComponent, type PropType } from 'vue'; import { type BentoListboxSelectedValue } from '@/types/listbox'; import { BentoSelectFilter } from '../../index'; import { BentoFilterEvent, type BentoSelectPaymentMethodFilterOptions, } from '@/components/filter-bar/filter-bar.types'; import { BentoPaymentMethod } from '@/components/payment-method'; import SelectFilterProps from '@/components/filter-bar/components/select-filter/select-filter.props'; /** * The Select Payment Method filter displays a listbox of country items * passed in the "options.listboxItems" property to be used in the FilterBar component. * * @example * import { BentoSelectPaymentMethodFilter } from '@adyen/bento-vue2'; * * export default { * components: { BentoSelectPaymentMethodFilter }, * template: ` * <bento-select-paymnent-method-filter * :field="paymentMethod" * :label="Payment method" * :options="{ * listboxItems: [ * { label: 'Option 1', value: 'ideal' }, * { label: 'Option 2', value: 'visa' }, * ], * }" * value="ideal" * @update="updateFilterHandler" * > * ` * } */ export default defineComponent({ name: 'bento-select-payment-method-filter', components: { BentoSelectFilter, BentoPaymentMethod, }, props: { ...SelectFilterProps, /** * List of options that are needed to setup the payment method filter * Available options: * - multiple: If "true", the user will be able to select multiple items. * - listboxItems: The option elements to populate the filter with {@see BentoSelectPaymentMethodFilterOptions} */ options: { type: Object as PropType<BentoSelectPaymentMethodFilterOptions>, default: undefined, }, }, emits: [BentoFilterEvent.INPUT, BentoFilterEvent.UPDATE], setup(_props, { emit }) { const onUpdate = (selectedValue: BentoListboxSelectedValue) => emit(BentoFilterEvent.UPDATE, selectedValue); return { // Enums BentoFilterEvent, // Methods onUpdate, }; }, }); </script>
@@ -0,0 +1 @@
1
+ import { ref } from 'vue'; import { action } from '@storybook/addon-actions'; import { type BentoSelectTagFilterOptions } from '@/components/filter-bar/filter-bar.types'; import BentoSelectTagFilter from './select-tag-filter.vue'; import { isVue2 } from 'vue-demi'; const OPTIONS: BentoSelectTagFilterOptions = { listboxItems: [ { label: 'Offline', value: 'unique-id-1', variant: 'red' }, { label: 'Online', value: 'unique-id-2', variant: 'green' }, { label: 'Standby', value: 'unique-id-3', variant: 'orange' }, { label: 'Busy', value: 'unique-id-4', variant: 'blue' }, ], }; export default { title: 'Filter bar/Select tag filter', component: BentoSelectTagFilter, argTypes: { // Slots field: { name: 'field', type: { name: 'string', required: false }, description: 'Filter name/key referencing the actual property name in the data set. Should be unique per filter bar.', control: 'text', table: { type: { summary: 'string' }, }, }, label: { name: 'label', type: { name: 'string', required: false }, description: 'Label text to be displayed', control: 'text', table: { type: { summary: 'string' }, }, }, value: { name: 'value', type: { name: 'string', required: true }, description: 'Current value of the filter', control: { disable: true }, table: { type: { summary: 'string, number, Array<string, number>' }, }, }, // Events eventName: { name: 'update', defaultValue: '', description: 'Description waht the event is for', table: { type: { summary: '() => void' } }, control: { disable: true }, }, }, }; const Template = (_args, { argTypes }) => ({ components: { BentoSelectTagFilter }, props: Object.keys(argTypes), template: ` <bento-select-tag-filter v-bind="args" :value="valueRef" @update="onSelected"/> `, setup(props) { const valueRef = ref(); const onSelected = selectedValue => { valueRef.value = selectedValue.value; action('update')(selectedValue); }; return { // Values args: isVue2 ? props : _args, valueRef, // Events onSelected, }; }, }); export const SingleSelect = Template.bind({}); SingleSelect.args = { field: 'tag', label: 'Tag', options: OPTIONS, }; export const MultiSelect = Template.bind({}); MultiSelect.args = { field: 'tag', label: 'Tag', multiple: true, options: { ...OPTIONS, multiple: true }, };
@@ -0,0 +1 @@
1
+ <template> <bento-select-filter v-slot="{ label: slotLabel, data }" v-bind="$props" :field="field" :label="label" :options="countryOptions" @update="onUpdate" @input="e => $emit(BentoFilterEvent.INPUT, e)" > <listbox-option-tag :option="{ value: slotLabel, data, label: '' }" /> </bento-select-filter> </template> <script lang="ts"> import { computed, defineComponent, type PropType } from 'vue'; import { type BentoListboxSelectedValue } from '@/types/listbox'; import { BentoSelectFilter } from '../../index'; import { BentoFilterEvent, type BentoSelectTagFilterOptions } from '@/components/filter-bar/filter-bar.types'; import { ListboxOptionTag } from '@/internal'; import SelectFilterProps from '@/components/filter-bar/components/select-filter/select-filter.props'; /** * The Select Tag filter displays a listbox of tag items * passed in the "options.listboxItems" property. * * @example * import { BentoSelectTagFilter } from '@adyen/bento-vue2'; * * export default { * components: { BentoSelectTagFilter }, * template: ` * <bento-select-tag-filter * :field="tag" * :label="Tag" * :options="{ * listboxItems: [ * { label: 'Offline', value: 'unique-id-1', variant: 'red' }, * { label: 'Online', value: 'unique-id-2', variant: 'green' }, * { label: 'Standby', value: 'unique-id-3', variant: 'orange' }, * { label: 'Busy with things', value: 'unique-id-4', variant: 'blue' }, * ] * }" * :value="'unique-id-4'" * @update="updateFilterHandler" * > * ` * } */ export default defineComponent({ name: 'bento-select-country-filter', components: { BentoSelectFilter, ListboxOptionTag, }, props: { ...SelectFilterProps, /** * List of options that are needed to setup the tag filter * Available options: * - multiple: If "true", the user will be able to select multiple items. * - listboxItems: The option elements to populate the filter with {@see BentoSelectTagFilterOptions} */ options: { type: Object as PropType<BentoSelectTagFilterOptions>, default: undefined, }, }, emits: [BentoFilterEvent.INPUT, BentoFilterEvent.UPDATE], setup(props, { emit }) { const onUpdate = (selectedValue: BentoListboxSelectedValue) => emit(BentoFilterEvent.UPDATE, selectedValue); const tagItems = computed(() => props?.options?.listboxItems?.map(({ label, value, variant }) => ({ label, value, data: variant })) ); const countryOptions = computed(() => ({ ...props.options, listboxItems: tagItems.value, })); return { // Values countryOptions, // Methods onUpdate, // Enums BentoFilterEvent, }; }, }); </script>
@@ -0,0 +1 @@
1
+ import { action } from '@storybook/addon-actions'; import { isVue2 } from 'vue-demi'; import BentoToggleFilter from './toggle-filter.vue'; import type { Meta, StoryObj } from '@storybook/vue'; import { type BentoToggleFilterProps } from './toggle-filter.types'; const meta: Meta = { title: 'Filter bar/Toggle filter', component: BentoToggleFilter, }; export default meta; type Story = StoryObj<typeof BentoToggleFilter>; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoToggleFilter }, props: Object.keys(argTypes), template: ` <bento-toggle-filter v-bind="args" @input="onInput" @update="onUpdate"/> `, setup(props) { const onInput = action('input'); const onUpdate = action('update'); return { args: isVue2 ? props : _args, onInput, onUpdate, }; }, }), args: { label: 'Filter name', field: 'filter-name', disabled: false, onlySlot: false, description: 'Optional short filter description goes here. Some filters may not be self-explanatory just from the name itself.', options: { tooltipPosition: 'bottom', tooltipText: 'Tooltip text', }, } satisfies BentoToggleFilterProps, };
@@ -0,0 +1 @@
1
+ <template> <filter-bar-button-group v-if="!onlySlot" v-bento-tooltip-directive:[options?.tooltipPosition]="options?.tooltipText" :skip-grouping="!internalValue" > <filter-bar-button :aria-pressed="internalValue ? 'true' : 'false'" :active="internalValue" :disabled="disabled" @click="toggleFilter" > <div class="b-toggle-filter"> {{ label }} <checkmark-icon v-show="internalValue" aria-hidden="true" class="b-toggle-filter__checkmark" /> </div> </filter-bar-button> <filter-bar-button v-if="internalValue" :aria-label="t('resetFilter', { filterName: label })" :disabled="disabled" :active="internalValue" @click="resetFilter" > <template #iconLeft> <cross-small-icon aria-hidden="true" /> </template> </filter-bar-button> </filter-bar-button-group> <label v-else class="b-toggle-filter__only-slot" :class="onlySlotConditionalClasses"> <checkbox-input :aria-labelledby="checkboxLabelId" :aria-describedby="checkboxDescriptionId" :disabled="disabled" class="b-toggle-filter__checkbox" :model-value="internalValue" @update:model-value="onInput" ></checkbox-input> <div class="b-toggle-filter__content"> <bento-typography :id="checkboxLabelId" variant="title" medium>{{ label }}</bento-typography> <bento-typography v-if="description" :id="checkboxDescriptionId">{{ description }}</bento-typography> </div> </label> </template> <script setup lang="ts"> import { computed, ref, watch } from 'vue'; import { BentoTooltipDirective as vBentoTooltipDirective } from '@/directives/tooltip/tooltip'; import { FilterBarButtonGroup } from '../filter-bar-button-group'; import { FilterBarButton } from '../filter-bar-button'; import { type BentoToggleFilterProps, type BentoToggleFilterValue } from './toggle-filter.types'; import { CheckboxInput } from '@/internal/checkbox-input'; import { BentoTypography } from '@/components/typography'; import { generateUid } from '@/core/utils/ts'; import { useI18n } from '@/utils/ts/i18n'; import CheckmarkIcon from '@adyen/ui-assets-icons-16/vue/checkmark'; import CrossSmallIcon from '@adyen/ui-assets-icons-16/vue/cross-small'; import messages from './messages.json'; type MessageSchema = (typeof messages)['en-US']; const { t } = useI18n<{ message: MessageSchema }>({ messages }); /** * IDs used for the checkbox a11y */ const checkboxLabelId = generateUid('toggle-filter-checkbox-label'); const checkboxDescriptionId = generateUid('toggle-filter-checkbox-description'); const props = withDefaults(defineProps<BentoToggleFilterProps>(), { disabled: false, onlySlot: false, options: undefined, value: false, }); const emit = defineEmits<{ /** * Used in the All filters modal */ (e: 'input', updatedProps: BentoToggleFilterProps): void; /** * Used in the Filter Bar */ (e: 'update', updatedProps: BentoToggleFilterProps): void; }>(); /** * Toggle internal field in sync with props.value */ const internalValue = ref<BentoToggleFilterValue>(props.value); watch( () => props.value, value => { internalValue.value = value; } ); const onlySlotConditionalClasses = computed(() => ({ 'b-toggle-filter__only-slot--disabled': props.disabled, })); /** * Used only for the checkbox. * Input emitted for the `all filters` modal * @param value new checkbox value */ const onInput = (value: BentoToggleFilterValue) => { internalValue.value = value; emit('input', { ...props, value }); }; /** * Applies the filter. * Update emitted for the filter bar. Updates all props */ const updateProps = () => { emit('update', { ...props, value: internalValue.value }); }; /** * Toggles filter with the main part (left side button) */ const toggleFilter = () => { internalValue.value = !internalValue.value; updateProps(); }; /** * Resets filter with the main part (left side button). * Has no persistent filter functionality. */ const resetFilter = () => { internalValue.value = false; updateProps(); }; </script> <script lang="ts"> /** * Toggle filter. * * @example * import { BentoToggleFilter } from './toggle-filter'; * * export default { * components: { BentoToggleFilter }, * template: ` * <bento-toggle-filter * label="Toggle filter" * field="toggle-filter" * only-slot * disabled * :value="true" * :tooltip-text="Tooltip text" * tooltip-position="top" * /> * ` * } */ export default { i18n: { messages }, name: 'bento-toggle-filter', }; </script> <style lang="scss" scoped src="./toggle-filter.scss" />