@adyen/bento-mcp 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (429) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +24 -2
  3. package/SKILL.md +37 -7
  4. package/dist/assets/components/accordion/accordion.stories.ts +1 -1
  5. package/dist/assets/components/accordion/components/accordion-item.stories.ts +1 -1
  6. package/dist/assets/components/accordion/components/accordion-item.vue +1 -1
  7. package/dist/assets/components/action-bar/action-bar.docs.mdx +10 -3
  8. package/dist/assets/components/action-bar/action-bar.internal.types.ts +1 -0
  9. package/dist/assets/components/action-bar/action-bar.stories.ts +1 -1
  10. package/dist/assets/components/action-bar/action-bar.types.ts +1 -1
  11. package/dist/assets/components/action-bar/action-bar.vue +1 -1
  12. package/dist/assets/components/ai-tag/ai-tag.stories.ts +1 -1
  13. package/dist/assets/components/ai-tag/ai-tag.vue +1 -1
  14. package/dist/assets/components/alert/alert.stories.ts +1 -1
  15. package/dist/assets/components/alert/alert.types.ts +1 -1
  16. package/dist/assets/components/anchor-scroller/anchor-scroller.stories.ts +1 -1
  17. package/dist/assets/components/anchor-scroller/anchor-scroller.vue +1 -1
  18. package/dist/assets/components/avatar/avatar.internal.types.ts +1 -0
  19. package/dist/assets/components/avatar/avatar.stories.ts +1 -1
  20. package/dist/assets/components/avatar/avatar.types.ts +1 -1
  21. package/dist/assets/components/button/button.docs.mdx +4 -3
  22. package/dist/assets/components/button/button.stories.ts +1 -1
  23. package/dist/assets/components/button/button.types.ts +1 -1
  24. package/dist/assets/components/button/components/ai-button/ai-button.stories.ts +1 -1
  25. package/dist/assets/components/button/components/ai-button/ai-button.vue +1 -1
  26. package/dist/assets/components/button/components/button-actions/button-actions.docs.mdx +3 -0
  27. package/dist/assets/components/button/components/button-actions/button-actions.internal.types.ts +1 -0
  28. package/dist/assets/components/button/components/button-actions/button-actions.stories.ts +1 -1
  29. package/dist/assets/components/button/components/button-actions/button-actions.types.ts +1 -1
  30. package/dist/assets/components/button/components/button-actions/button-actions.vue +1 -1
  31. package/dist/assets/components/button/components/loading-button/loading-button.docs.mdx +26 -23
  32. package/dist/assets/components/button/components/loading-button/loading-button.stories.ts +1 -1
  33. package/dist/assets/components/button/components/loading-button/loading-button.vue +1 -1
  34. package/dist/assets/components/button/components/toggle-button/toggle-button.stories.ts +1 -1
  35. package/dist/assets/components/card/card.docs.mdx +18 -1
  36. package/dist/assets/components/card/card.stories.ts +1 -1
  37. package/dist/assets/components/card/card.types.ts +1 -1
  38. package/dist/assets/components/card/card.vue +1 -1
  39. package/dist/assets/components/checkbox/checkbox.stories.ts +1 -1
  40. package/dist/assets/components/checkbox/checkbox.types.ts +1 -1
  41. package/dist/assets/components/checkbox/checkbox.vue +1 -1
  42. package/dist/assets/components/checkbox/components/checkbox-group/checkbox-group.docs.mdx +9 -14
  43. package/dist/assets/components/checkbox/components/checkbox-group/checkbox-group.stories.ts +1 -1
  44. package/dist/assets/components/checkbox/components/checkbox-group/checkbox-group.types.ts +1 -1
  45. package/dist/assets/components/checkbox/components/checkbox-group/checkbox-group.vue +1 -1
  46. package/dist/assets/components/chip/chip.stories.ts +1 -1
  47. package/dist/assets/components/chip/chip.vue +1 -1
  48. package/dist/assets/components/click-outside/click-outside.stories.ts +1 -1
  49. package/dist/assets/components/code-snippet/code-snippet.types.ts +1 -1
  50. package/dist/assets/components/code-snippet/code-snippet.vue +1 -1
  51. package/dist/assets/components/country/country.stories.ts +1 -1
  52. package/dist/assets/components/country/country.types.ts +1 -1
  53. package/dist/assets/components/country/country.vue +1 -1
  54. package/dist/assets/components/currency/currency.stories.ts +1 -1
  55. package/dist/assets/components/currency/currency.vue +1 -1
  56. package/dist/assets/components/dashed-underline/dashed-underline.stories.ts +1 -1
  57. package/dist/assets/components/data-grid/components/data-grid-cell-actions/data-grid-cell-actions.types.ts +1 -1
  58. package/dist/assets/components/data-grid/components/data-grid-cell-actions/data-grid-cell-actions.vue +1 -1
  59. package/dist/assets/components/data-grid/components/data-grid-config-settings/data-grid-config-settings.vue +1 -1
  60. package/dist/assets/components/data-grid/components/data-grid-row/data-grid-row.vue +1 -1
  61. package/dist/assets/components/data-grid/components/data-grid-static-icon/data-grid-static-icon.stories.ts +1 -1
  62. package/dist/assets/components/data-grid/components/data-grid-summary-cell/data-grid-summary-cell.stories.ts +1 -1
  63. package/dist/assets/components/data-grid/components/data-grid-summary-cell/data-grid-summary-cell.vue +1 -1
  64. package/dist/assets/components/data-grid/components/data-grid-tag-with-text-cell/data-grid-tag-with-text-cell.stories.ts +1 -1
  65. package/dist/assets/components/data-grid/components/data-grid-trend-cell/data-grid-trend-cell.stories.ts +1 -1
  66. package/dist/assets/components/data-grid/components/data-grid-trend-cell/data-grid-trend-cell.vue +1 -1
  67. package/dist/assets/components/data-grid/data-grid.docs.mdx +3 -60
  68. package/dist/assets/components/data-grid/data-grid.stories.ts +1 -1
  69. package/dist/assets/components/data-grid/data-grid.vue +1 -1
  70. package/dist/assets/components/date/date.stories.ts +1 -1
  71. package/dist/assets/components/date-picker/date-picker.stories.ts +1 -1
  72. package/dist/assets/components/date-picker/date-picker.types.ts +1 -1
  73. package/dist/assets/components/date-picker/date-picker.vue +1 -1
  74. package/dist/assets/components/date-range-picker/components/date-range-picker-calendar/date-range-picker-calendar.vue +1 -1
  75. package/dist/assets/components/date-range-picker/components/date-time-input/date-time-input.types.ts +1 -1
  76. package/dist/assets/components/date-range-picker/components/date-time-input/date-time-input.vue +1 -1
  77. package/dist/assets/components/date-range-picker/date-range-picker.docs.mdx +31 -6
  78. package/dist/assets/components/date-range-picker/date-range-picker.stories.ts +1 -1
  79. package/dist/assets/components/date-range-picker/date-range-picker.types.ts +1 -1
  80. package/dist/assets/components/date-range-picker/date-range-picker.vue +1 -1
  81. package/dist/assets/components/date-time-picker/date-time-picker.stories.ts +1 -1
  82. package/dist/assets/components/date-time-picker/date-time-picker.types.ts +1 -1
  83. package/dist/assets/components/divider/divider.internal.types.ts +1 -0
  84. package/dist/assets/components/divider/divider.stories.ts +1 -1
  85. package/dist/assets/components/divider/divider.types.ts +1 -1
  86. package/dist/assets/components/divider/divider.vue +1 -1
  87. package/dist/assets/components/draggable/components/draggable-handle/draggable-handle.stories.ts +1 -1
  88. package/dist/assets/components/draggable/draggable.stories.ts +1 -1
  89. package/dist/assets/components/draggable/draggable.vue +1 -1
  90. package/dist/assets/components/drawer/drawer.stories.ts +1 -1
  91. package/dist/assets/components/dropdown/components/dropdown-base-textbox/dropdown-base-textbox.internal.types.ts +1 -0
  92. package/dist/assets/components/dropdown/components/dropdown-base-textbox/dropdown-base-textbox.types.ts +1 -1
  93. package/dist/assets/components/dropdown/components/dropdown-base-textbox/dropdown-base-textbox.vue +1 -1
  94. package/dist/assets/components/dropdown/components/dropdown-default-textbox/dropdown-default-textbox.vue +1 -1
  95. package/dist/assets/components/dropdown/components/dropdown-options-container/dropdown-options-container.vue +1 -1
  96. package/dist/assets/components/dropdown/components/dropdown-small-textbox/dropdown-small-textbox.vue +1 -1
  97. package/dist/assets/components/dropdown/components/variants/dropdown-avatar/dropdown-avatar.stories.ts +1 -1
  98. package/dist/assets/components/dropdown/components/variants/dropdown-avatar/dropdown-avatar.types.ts +1 -1
  99. package/dist/assets/components/dropdown/components/variants/dropdown-avatar/dropdown-avatar.vue +1 -1
  100. package/dist/assets/components/dropdown/components/variants/dropdown-country/dropdown-country.stories.ts +1 -1
  101. package/dist/assets/components/dropdown/components/variants/dropdown-country/dropdown-country.types.ts +1 -1
  102. package/dist/assets/components/dropdown/components/variants/dropdown-country/dropdown-country.vue +1 -1
  103. package/dist/assets/components/dropdown/components/variants/dropdown-currency/dropdown-currency.stories.ts +1 -1
  104. package/dist/assets/components/dropdown/components/variants/dropdown-currency/dropdown-currency.types.ts +1 -1
  105. package/dist/assets/components/dropdown/components/variants/dropdown-currency/dropdown-currency.vue +1 -1
  106. package/dist/assets/components/dropdown/components/variants/dropdown-payment-method/dropdown-payment-method.stories.ts +1 -1
  107. package/dist/assets/components/dropdown/components/variants/dropdown-payment-method/dropdown-payment-method.types.ts +1 -1
  108. package/dist/assets/components/dropdown/components/variants/dropdown-payment-method/dropdown-payment-method.vue +1 -1
  109. package/dist/assets/components/dropdown/components/variants/dropdown-tag/dropdown-tag.stories.ts +1 -1
  110. package/dist/assets/components/dropdown/components/variants/dropdown-tag/dropdown-tag.types.ts +1 -1
  111. package/dist/assets/components/dropdown/components/variants/dropdown-tag/dropdown-tag.vue +1 -1
  112. package/dist/assets/components/dropdown/dropdown.docs.mdx +4 -40
  113. package/dist/assets/components/dropdown/dropdown.internal.types.ts +1 -0
  114. package/dist/assets/components/dropdown/dropdown.stories.ts +1 -1
  115. package/dist/assets/components/dropdown/dropdown.types.ts +1 -1
  116. package/dist/assets/components/dropdown/dropdown.vue +1 -1
  117. package/dist/assets/components/empty-state/empty-state.stories.ts +1 -1
  118. package/dist/assets/components/empty-state/empty-state.types.ts +1 -1
  119. package/dist/assets/components/file-uploader/components/file-uploader-file-card/file-uploader-file-card.stories.ts +1 -1
  120. package/dist/assets/components/file-uploader/components/file-uploader-file-card/file-uploader-file-card.types.ts +1 -1
  121. package/dist/assets/components/file-uploader/components/file-uploader-file-card/file-uploader-file-card.vue +1 -1
  122. package/dist/assets/components/file-uploader/components/file-uploader-restrictions/file-uploader-restrictions.types.ts +1 -1
  123. package/dist/assets/components/file-uploader/components/file-uploader-restrictions/file-uploader-restrictions.vue +1 -1
  124. package/dist/assets/components/file-uploader/file-uploader.internal.types.ts +1 -0
  125. package/dist/assets/components/file-uploader/file-uploader.stories.ts +1 -1
  126. package/dist/assets/components/file-uploader/file-uploader.types.ts +1 -1
  127. package/dist/assets/components/file-uploader/file-uploader.vue +1 -1
  128. package/dist/assets/components/filter-bar/components/all-filters-modal/all-filters-modal.stories.ts +1 -1
  129. package/dist/assets/components/filter-bar/components/all-filters-modal/all-filters-modal.types.ts +1 -1
  130. package/dist/assets/components/filter-bar/components/all-filters-modal/all-filters-modal.vue +1 -1
  131. package/dist/assets/components/filter-bar/components/all-filters-modal/components/all-filters-modal-filter-selection/all-filters-modal-filter-selection.types.ts +1 -0
  132. package/dist/assets/components/filter-bar/components/all-filters-modal/components/all-filters-modal-filter-selection/all-filters-modal-filter-selection.vue +1 -0
  133. package/dist/assets/components/filter-bar/components/all-filters-modal/components/all-filters-modal-selected-filter/all-filters-modal-selected-filter.vue +1 -0
  134. package/dist/assets/components/filter-bar/components/base-filter/base-filter.internal.types.ts +1 -0
  135. package/dist/assets/components/filter-bar/components/base-filter/base-filter.types.ts +1 -1
  136. package/dist/assets/components/filter-bar/components/base-filter/base-filter.vue +1 -1
  137. package/dist/assets/components/filter-bar/components/boolean-filter/boolean-filter.vue +1 -1
  138. package/dist/assets/components/filter-bar/components/date-filter/date-filter.vue +1 -1
  139. package/dist/assets/components/filter-bar/components/date-range-filter/date-range-filter.vue +1 -1
  140. package/dist/assets/components/filter-bar/components/input-filter/input-filter.types.ts +1 -1
  141. package/dist/assets/components/filter-bar/components/input-filter/input-filter.vue +1 -1
  142. package/dist/assets/components/filter-bar/components/input-with-dropdown-filter/input-with-dropdown-filter.stories.ts +1 -1
  143. package/dist/assets/components/filter-bar/components/input-with-dropdown-filter/input-with-dropdown-filter.vue +1 -1
  144. package/dist/assets/components/filter-bar/components/select-filter/components/select-filter-button/select-filter-button.vue +1 -1
  145. package/dist/assets/components/filter-bar/components/select-filter/select-filter.vue +1 -1
  146. package/dist/assets/components/filter-bar/components/select-filter/variants/select-avatar-filter/select-avatar-filter.stories.ts +1 -1
  147. package/dist/assets/components/filter-bar/components/select-filter/variants/select-country-filter/select-country-filter.stories.ts +1 -1
  148. package/dist/assets/components/filter-bar/components/select-filter/variants/select-country-filter/select-country-filter.vue +1 -1
  149. package/dist/assets/components/filter-bar/components/toggle-filter/toggle-filter.vue +1 -1
  150. package/dist/assets/components/filter-bar/filter-bar.docs.mdx +4 -62
  151. package/dist/assets/components/filter-bar/filter-bar.stories.ts +1 -1
  152. package/dist/assets/components/filter-bar/filter-bar.types.ts +1 -1
  153. package/dist/assets/components/filter-bar/filter-bar.vue +1 -1
  154. package/dist/assets/components/form-layout/form-layout.docs.mdx +0 -23
  155. package/dist/assets/components/form-layout/form-layout.stories.ts +1 -1
  156. package/dist/assets/components/header/header.stories.ts +1 -1
  157. package/dist/assets/components/header/header.types.ts +1 -1
  158. package/dist/assets/components/header/header.vue +1 -1
  159. package/dist/assets/components/header-with-views/components/header-with-views-all-views/header-with-views-all-views.vue +1 -1
  160. package/dist/assets/components/header-with-views/components/header-with-views-item-edit-form/header-with-views-edit-form.types.ts +1 -1
  161. package/dist/assets/components/header-with-views/components/header-with-views-item-edit-form/header-with-views-edit-form.vue +1 -1
  162. package/dist/assets/components/header-with-views/header-with-views.internal.types.ts +1 -0
  163. package/dist/assets/components/header-with-views/header-with-views.stories.ts +1 -1
  164. package/dist/assets/components/header-with-views/header-with-views.types.ts +1 -1
  165. package/dist/assets/components/header-with-views/header-with-views.vue +1 -1
  166. package/dist/assets/components/image/image.stories.ts +1 -1
  167. package/dist/assets/components/info-icon/info-icon.stories.ts +1 -1
  168. package/dist/assets/components/input-field/input-field.docs.mdx +1 -13
  169. package/dist/assets/components/input-field/input-field.stories.ts +1 -1
  170. package/dist/assets/components/input-field/input-field.types.ts +1 -1
  171. package/dist/assets/components/input-field/input-field.vue +1 -1
  172. package/dist/assets/components/input-field-password/input-field-password.internal.types.ts +1 -0
  173. package/dist/assets/components/input-field-password/input-field-password.stories.ts +1 -1
  174. package/dist/assets/components/input-field-password/input-field-password.types.ts +1 -1
  175. package/dist/assets/components/input-field-password/input-field-password.vue +1 -1
  176. package/dist/assets/components/input-field-phone-number/input-field-phone-number.stories.ts +1 -1
  177. package/dist/assets/components/input-field-phone-number/input-field-phone-number.types.ts +1 -1
  178. package/dist/assets/components/input-field-phone-number/input-field-phone-number.vue +1 -1
  179. package/dist/assets/components/input-time/input-time.docs.mdx +17 -0
  180. package/dist/assets/components/input-time/input-time.stories.ts +1 -1
  181. package/dist/assets/components/input-time/input-time.types.ts +1 -1
  182. package/dist/assets/components/input-time/input-time.vue +1 -1
  183. package/dist/assets/components/inspector/inspector.stories.ts +1 -1
  184. package/dist/assets/components/inspector/inspector.vue +1 -1
  185. package/dist/assets/components/layout/components/layout-row/layout-row.stories.ts +1 -1
  186. package/dist/assets/components/layout/components/layout-row/layout-row.vue +1 -1
  187. package/dist/assets/components/layout/layout.docs.mdx +10 -0
  188. package/dist/assets/components/layout/layout.internal.types.ts +1 -0
  189. package/dist/assets/components/layout/layout.stories.ts +1 -1
  190. package/dist/assets/components/layout/layout.types.ts +1 -1
  191. package/dist/assets/components/link/link.stories.ts +1 -1
  192. package/dist/assets/components/link/link.types.ts +1 -1
  193. package/dist/assets/components/link/link.vue +1 -1
  194. package/dist/assets/components/list/list.stories.ts +1 -1
  195. package/dist/assets/components/loading-indicator/loading-indicator.stories.ts +1 -1
  196. package/dist/assets/components/menu/components/menu-item/menu-item.types.ts +1 -1
  197. package/dist/assets/components/menu/components/menu-item/menu-item.vue +1 -1
  198. package/dist/assets/components/menu/components/menu-item-list/menu-item-list.vue +1 -1
  199. package/dist/assets/components/menu/components/sub-menu-item-list/sub-menu-item-list.vue +1 -1
  200. package/dist/assets/components/menu/menu.docs.mdx +17 -7
  201. package/dist/assets/components/menu/menu.stories.ts +1 -1
  202. package/dist/assets/components/menu/menu.types.ts +1 -1
  203. package/dist/assets/components/menu/menu.vue +1 -1
  204. package/dist/assets/components/modal/components/base-modal/base-modal.vue +1 -1
  205. package/dist/assets/components/modal/components/modal-page/modal-page.vue +1 -1
  206. package/dist/assets/components/modal/modal.internal.types.ts +1 -0
  207. package/dist/assets/components/modal/modal.stories.ts +1 -1
  208. package/dist/assets/components/modal/modal.types.ts +1 -1
  209. package/dist/assets/components/modal/modal.vue +1 -1
  210. package/dist/assets/components/modal-fullscreen/components/modal-fullscreen-page.vue +1 -1
  211. package/dist/assets/components/modal-fullscreen/modal-fullscreen.stories.ts +1 -1
  212. package/dist/assets/components/modal-fullscreen/modal-fullscreen.vue +1 -1
  213. package/dist/assets/components/navigation-menu/components/navigation-menu-group/navigation-menu-group.internal.types.ts +1 -0
  214. package/dist/assets/components/navigation-menu/components/navigation-menu-group/navigation-menu-group.types.ts +1 -1
  215. package/dist/assets/components/navigation-menu/components/navigation-menu-group/navigation-menu-group.vue +1 -1
  216. package/dist/assets/components/navigation-menu/components/navigation-menu-item/navigation-menu-item.vue +1 -1
  217. package/dist/assets/components/navigation-menu/navigation-menu.internal.types.ts +1 -0
  218. package/dist/assets/components/navigation-menu/navigation-menu.stories.ts +1 -1
  219. package/dist/assets/components/navigation-menu/navigation-menu.types.ts +1 -1
  220. package/dist/assets/components/navigation-menu/navigation-menu.vue +1 -1
  221. package/dist/assets/components/pagination/components/pagination-context/pagination-context.vue +1 -1
  222. package/dist/assets/components/pagination/components/pagination-results-per-page/pagination-results-per-page.vue +1 -1
  223. package/dist/assets/components/pagination/pagination.stories.ts +1 -1
  224. package/dist/assets/components/pagination/pagination.types.ts +1 -1
  225. package/dist/assets/components/pagination/pagination.vue +1 -1
  226. package/dist/assets/components/payment-method/payment-method.stories.ts +1 -1
  227. package/dist/assets/components/payment-method/payment-method.types.ts +1 -1
  228. package/dist/assets/components/popover/popover.docs.mdx +32 -9
  229. package/dist/assets/components/popover/popover.stories.ts +1 -1
  230. package/dist/assets/components/popover/popover.types.ts +1 -1
  231. package/dist/assets/components/popover/popover.vue +1 -1
  232. package/dist/assets/components/popper-container/popper-container.types.ts +1 -1
  233. package/dist/assets/components/popper-container/popper-container.vue +1 -1
  234. package/dist/assets/components/progress-bar/progress-bar.docs.mdx +102 -0
  235. package/dist/assets/components/progress-bar/progress-bar.stories.ts +1 -0
  236. package/dist/assets/components/progress-bar/progress-bar.types.ts +1 -0
  237. package/dist/assets/components/progress-bar/progress-bar.vue +1 -0
  238. package/dist/assets/components/promo-banner/promo-banner.stories.ts +1 -1
  239. package/dist/assets/components/promo-banner/promo-banner.types.ts +1 -1
  240. package/dist/assets/components/promo-banner/promo-banner.vue +1 -1
  241. package/dist/assets/components/radio-group/components/radio-button/radio-button.vue +1 -1
  242. package/dist/assets/components/radio-group/radio-group.docs.mdx +1 -6
  243. package/dist/assets/components/radio-group/radio-group.stories.ts +1 -1
  244. package/dist/assets/components/radio-group/radio-group.types.ts +1 -1
  245. package/dist/assets/components/radio-group/radio-group.vue +1 -1
  246. package/dist/assets/components/rich-text-editor/rich-text-editor.internal.types.ts +1 -0
  247. package/dist/assets/components/rich-text-editor/rich-text-editor.stories.ts +1 -1
  248. package/dist/assets/components/rich-text-editor/rich-text-editor.types.ts +1 -1
  249. package/dist/assets/components/rich-text-editor/rich-text-editor.vue +1 -1
  250. package/dist/assets/components/search-bar/search-bar.stories.ts +1 -1
  251. package/dist/assets/components/search-bar/search-bar.vue +1 -1
  252. package/dist/assets/components/secondary-nav/components/secondary-nav-item/secondary-nav-item.vue +1 -1
  253. package/dist/assets/components/secondary-nav/secondary-nav.stories.ts +1 -1
  254. package/dist/assets/components/secondary-nav/secondary-nav.vue +1 -1
  255. package/dist/assets/components/segmented-control/components/segmented-control-button/segmented-control-button.vue +1 -1
  256. package/dist/assets/components/segmented-control/segmented-control.stories.ts +1 -1
  257. package/dist/assets/components/segmented-control/segmented-control.types.ts +1 -1
  258. package/dist/assets/components/segmented-control/segmented-control.vue +1 -1
  259. package/dist/assets/components/selection-card/components/selection-card-group/selection-card-group.docs.mdx +12 -13
  260. package/dist/assets/components/selection-card/components/selection-card-group/selection-card-group.stories.ts +1 -1
  261. package/dist/assets/components/selection-card/components/selection-card-group/selection-card-group.vue +1 -1
  262. package/dist/assets/components/selection-card/selection-card.stories.ts +1 -1
  263. package/dist/assets/components/selection-card/selection-card.types.ts +1 -1
  264. package/dist/assets/components/selection-card/selection-card.vue +1 -1
  265. package/dist/assets/components/sidepanel/sidepanel.docs.mdx +1 -1
  266. package/dist/assets/components/sidepanel/sidepanel.stories.ts +1 -1
  267. package/dist/assets/components/sidepanel/sidepanel.vue +1 -1
  268. package/dist/assets/components/status/status.stories.ts +1 -1
  269. package/dist/assets/components/status/status.types.ts +1 -1
  270. package/dist/assets/components/stepper/components/step/step.vue +1 -1
  271. package/dist/assets/components/stepper/stepper.stories.ts +1 -1
  272. package/dist/assets/components/stepper/stepper.vue +1 -1
  273. package/dist/assets/components/structured-list/structured-list.stories.ts +1 -1
  274. package/dist/assets/components/structured-list/structured-list.vue +1 -1
  275. package/dist/assets/components/summary-grid/components/summary-grid-item/summary-grid-item.types.ts +1 -1
  276. package/dist/assets/components/summary-grid/summary-grid.stories.ts +1 -1
  277. package/dist/assets/components/summary-grid/summary-grid.types.ts +1 -1
  278. package/dist/assets/components/table-of-contents/components/table-of-contents-list/table-of-contents-list.vue +1 -1
  279. package/dist/assets/components/table-of-contents/table-of-contents.internal.types.ts +1 -0
  280. package/dist/assets/components/table-of-contents/table-of-contents.stories.ts +1 -1
  281. package/dist/assets/components/table-of-contents/table-of-contents.types.ts +1 -1
  282. package/dist/assets/components/table-of-contents/table-of-contents.vue +1 -1
  283. package/dist/assets/components/tabs/components/tab.internal.types.ts +1 -0
  284. package/dist/assets/components/tabs/components/tab.types.ts +1 -1
  285. package/dist/assets/components/tabs/components/tab.vue +1 -1
  286. package/dist/assets/components/tabs/tabs.stories.ts +1 -1
  287. package/dist/assets/components/tabs/tabs.vue +1 -1
  288. package/dist/assets/components/tag/tag.docs.mdx +1 -1
  289. package/dist/assets/components/tag/tag.stories.ts +1 -1
  290. package/dist/assets/components/tag/tag.types.ts +1 -1
  291. package/dist/assets/components/tag/tag.vue +1 -1
  292. package/dist/assets/components/textarea/textarea.docs.mdx +0 -7
  293. package/dist/assets/components/textarea/textarea.stories.ts +1 -1
  294. package/dist/assets/components/textarea/textarea.types.ts +1 -1
  295. package/dist/assets/components/textarea/textarea.vue +1 -1
  296. package/dist/assets/components/timeline/components/timeline-item/timeline-item.stories.ts +1 -1
  297. package/dist/assets/components/timeline/components/timeline-item/timeline-item.vue +1 -1
  298. package/dist/assets/components/timeline/timeline.docs.mdx +0 -10
  299. package/dist/assets/components/timeline/timeline.internal.types.ts +1 -0
  300. package/dist/assets/components/timeline/timeline.stories.ts +1 -1
  301. package/dist/assets/components/timeline/timeline.types.ts +1 -1
  302. package/dist/assets/components/timeline/timeline.vue +1 -1
  303. package/dist/assets/components/toast/components/toast-item/toast-item.vue +1 -1
  304. package/dist/assets/components/toggle/toggle.stories.ts +1 -1
  305. package/dist/assets/components/toggle/toggle.types.ts +1 -1
  306. package/dist/assets/components/toggle/toggle.vue +1 -1
  307. package/dist/assets/components/tutorial/tutorial.stories.ts +1 -1
  308. package/dist/assets/components/typography/typography.stories.ts +1 -1
  309. package/dist/assets/components/typography/typography.types.ts +1 -1
  310. package/dist/assets/components/typography/typography.vue +1 -1
  311. package/dist/assets/components.json +1 -0
  312. package/dist/assets/composables/use-bento-base-filter/index.ts +1 -0
  313. package/dist/assets/composables/use-bento-base-filter/use-bento-base-filter.ts +1 -0
  314. package/dist/assets/composables/use-bento-base-filter/utils/index.ts +1 -0
  315. package/dist/assets/composables/use-bento-base-filter/utils/utils.ts +1 -0
  316. package/dist/assets/composables/use-bento-currency/index.ts +1 -0
  317. package/dist/assets/composables/use-bento-currency/use-bento-currency.stories.ts +1 -1
  318. package/dist/assets/composables/use-bento-currency/use-bento-currency.ts +1 -0
  319. package/dist/assets/composables/use-bento-delayed-hover/index.ts +1 -0
  320. package/dist/assets/composables/use-bento-delayed-hover/use-bento-delayed-hover.stories.ts +1 -1
  321. package/dist/assets/composables/use-bento-delayed-hover/use-bento-delayed-hover.ts +1 -0
  322. package/dist/assets/composables/use-bento-theme/index.ts +1 -0
  323. package/dist/assets/composables/use-bento-theme/install.ts +1 -1
  324. package/dist/assets/composables/use-bento-theme/install.types.ts +1 -1
  325. package/dist/assets/composables/use-bento-theme/use-bento-theme.ts +1 -0
  326. package/dist/assets/composables/use-bento-toast-controller/index.ts +1 -0
  327. package/dist/assets/composables/use-bento-toast-controller/toast-stack.ts +1 -0
  328. package/dist/assets/composables/use-bento-toast-controller/use-bento-toast-controller.ts +1 -0
  329. package/dist/assets/composables/use-click-outside/index.ts +1 -0
  330. package/dist/assets/composables/use-click-outside/use-click-outside.stories.ts +1 -1
  331. package/dist/assets/composables/use-click-outside/use-click-outside.ts +1 -0
  332. package/dist/assets/composables/use-form-validate/index.ts +1 -0
  333. package/dist/assets/composables/use-form-validate/use-form.ts +1 -0
  334. package/dist/assets/composables/use-form-validate/use-form.types.ts +1 -1
  335. package/dist/assets/composables.json +9 -0
  336. package/dist/assets/deprecations.md +139 -243
  337. package/dist/assets/directives/highlight/highlight.stories.ts +1 -1
  338. package/dist/assets/directives/keyboard-navigation/keyboard-navigation.stories.ts +1 -1
  339. package/dist/assets/directives/tooltip/tooltip.internal.types.ts +1 -0
  340. package/dist/assets/directives/tooltip/tooltip.stories.ts +1 -1
  341. package/dist/assets/directives/tooltip/tooltip.types.ts +1 -1
  342. package/dist/assets/icons.json +1 -0
  343. package/dist/assets/index.ts +1 -1
  344. package/dist/assets/install.ts +1 -1
  345. package/dist/assets/tailwind/README.md +3 -3
  346. package/dist/assets/templates/dashboard-template/components/dashboard-section/dashboard-section.stories.ts +1 -1
  347. package/dist/assets/templates/dashboard-template/dashboard-template.stories.ts +1 -1
  348. package/dist/assets/templates/data-grid-template/data-grid-template.stories.ts +1 -1
  349. package/dist/assets/usage.json +81 -80
  350. package/dist/assets/variables.css +152 -140
  351. package/dist/main.js +228 -34
  352. package/package.json +2 -2
  353. package/dist/assets/components/internal/base-button/base-button.types.ts +0 -1
  354. package/dist/assets/components/internal/base-button/base-button.vue +0 -1
  355. package/dist/assets/components/internal/button-actions-with-menu/button-actions-with-menu.stories.ts +0 -1
  356. package/dist/assets/components/internal/button-actions-with-menu/button-actions-with-menu.types.ts +0 -1
  357. package/dist/assets/components/internal/button-actions-with-menu/button-actions-with-menu.vue +0 -1
  358. package/dist/assets/components/internal/calendar/calendar.stories.ts +0 -1
  359. package/dist/assets/components/internal/calendar/calendar.types.ts +0 -1
  360. package/dist/assets/components/internal/calendar/calendar.vue +0 -1
  361. package/dist/assets/components/internal/calendar/components/calendar-month/calendar-month.stories.ts +0 -1
  362. package/dist/assets/components/internal/calendar/components/calendar-month/calendar-month.types.ts +0 -1
  363. package/dist/assets/components/internal/calendar/components/calendar-month/calendar-month.vue +0 -1
  364. package/dist/assets/components/internal/calendar/components/calendar-month/components/calendar-month-day/__test__/calendar-month-day-stub.vue +0 -1
  365. package/dist/assets/components/internal/calendar/components/calendar-month/components/calendar-month-day/calendar-month-day.stories.ts +0 -1
  366. package/dist/assets/components/internal/calendar/components/calendar-month/components/calendar-month-day/calendar-month-day.types.ts +0 -1
  367. package/dist/assets/components/internal/calendar/components/calendar-month/components/calendar-month-day/calendar-month-day.vue +0 -1
  368. package/dist/assets/components/internal/calendar/components/calendar-month/composables/granular-min-max-date.types.ts +0 -1
  369. package/dist/assets/components/internal/calendar/components/calendar-year/calendar-year.types.ts +0 -1
  370. package/dist/assets/components/internal/calendar/components/calendar-year/calendar-year.vue +0 -1
  371. package/dist/assets/components/internal/calendar/components/calendar-year/components/calendar-year-month/__test__/calendar-year-month-stub.vue +0 -1
  372. package/dist/assets/components/internal/calendar/components/calendar-year/components/calendar-year-month/calendar-year-month.types.ts +0 -1
  373. package/dist/assets/components/internal/calendar/components/calendar-year/components/calendar-year-month/calendar-year-month.vue +0 -1
  374. package/dist/assets/components/internal/calendar/components/calendar-year-selector/calendar-year-selector.types.ts +0 -1
  375. package/dist/assets/components/internal/calendar/components/calendar-year-selector/calendar-year-selector.vue +0 -1
  376. package/dist/assets/components/internal/calendar/composables/use-granularity-adjustments.types.ts +0 -1
  377. package/dist/assets/components/internal/calendar/composables/use-range-pane.types.ts +0 -1
  378. package/dist/assets/components/internal/checkbox-input/checkbox-input.stories.ts +0 -1
  379. package/dist/assets/components/internal/checkbox-input/checkbox-input.types.ts +0 -1
  380. package/dist/assets/components/internal/checkbox-input/checkbox-input.vue +0 -1
  381. package/dist/assets/components/internal/controls-group/controls-group.vue +0 -1
  382. package/dist/assets/components/internal/copy/copy.docs.mdx +0 -43
  383. package/dist/assets/components/internal/copy/copy.stories.ts +0 -1
  384. package/dist/assets/components/internal/copy/copy.types.ts +0 -1
  385. package/dist/assets/components/internal/copy/copy.vue +0 -1
  386. package/dist/assets/components/internal/decorative-checkbox/decorative-checkbox.vue +0 -1
  387. package/dist/assets/components/internal/dialog-page/dialog-page.types.ts +0 -1
  388. package/dist/assets/components/internal/dialog-page/dialog-page.vue +0 -1
  389. package/dist/assets/components/internal/error-message/error-message.vue +0 -1
  390. package/dist/assets/components/internal/field-label/field-label.vue +0 -1
  391. package/dist/assets/components/internal/fixed-scroller/fixed-scroller.docs.mdx +0 -21
  392. package/dist/assets/components/internal/fixed-scroller/fixed-scroller.stories.ts +0 -1
  393. package/dist/assets/components/internal/fixed-scroller/fixed-scroller.vue +0 -1
  394. package/dist/assets/components/internal/footer-actions/footer-actions.vue +0 -1
  395. package/dist/assets/components/internal/grid-layout/grid-layout.types.ts +0 -1
  396. package/dist/assets/components/internal/grid-layout/grid-layout.vue +0 -1
  397. package/dist/assets/components/internal/header-meta/header-meta.types.ts +0 -1
  398. package/dist/assets/components/internal/header-meta/header-meta.vue +0 -1
  399. package/dist/assets/components/internal/info-icon-with-popover/info-icon-with-popover.vue +0 -1
  400. package/dist/assets/components/internal/listbox/components/listbox-lazy-load/listbox-lazy-load.types.ts +0 -1
  401. package/dist/assets/components/internal/listbox/components/listbox-lazy-load/listbox-lazy-load.vue +0 -1
  402. package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/components/listbox-multi-select-category/listbox-multi-select-category.types.ts +0 -1
  403. package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/components/listbox-multi-select-category/listbox-multi-select-category.vue +0 -1
  404. package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/components/listbox-multi-select-nested-lazy-load/listbox-multi-select-nested-lazy-load.types.ts +0 -1
  405. package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/components/listbox-multi-select-nested-lazy-load/listbox-multi-select-nested-lazy-load.vue +0 -1
  406. package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/listbox-multi-select-options.types.ts +0 -1
  407. package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/listbox-multi-select-options.vue +0 -1
  408. package/dist/assets/components/internal/listbox/components/listbox-multi-select/listbox-multi-select.types.ts +0 -1
  409. package/dist/assets/components/internal/listbox/components/listbox-multi-select/listbox-multi-select.vue +0 -1
  410. package/dist/assets/components/internal/listbox/components/listbox-option/listbox-option.vue +0 -1
  411. package/dist/assets/components/internal/listbox/components/listbox-option-tag/listbox-option-tag.vue +0 -1
  412. package/dist/assets/components/internal/listbox/components/listbox-single-select/components/listbox-single-select-category/listbox-single-select-category.vue +0 -1
  413. package/dist/assets/components/internal/listbox/components/listbox-single-select/listbox-single-select.vue +0 -1
  414. package/dist/assets/components/internal/listbox/components/listbox-single-select-option/listbox-single-select-option.vue +0 -1
  415. package/dist/assets/components/internal/listbox/listbox.stories.ts +0 -1
  416. package/dist/assets/components/internal/listbox/listbox.types.ts +0 -1
  417. package/dist/assets/components/internal/listbox/listbox.vue +0 -1
  418. package/dist/assets/components/internal/radio-input/radio-input.stories.ts +0 -1
  419. package/dist/assets/components/internal/radio-input/radio-input.types.ts +0 -1
  420. package/dist/assets/components/internal/radio-input/radio-input.vue +0 -1
  421. package/dist/assets/components/internal/teleport/teleport.types.ts +0 -1
  422. package/dist/assets/components/internal/teleport/teleport.vue +0 -1
  423. package/dist/assets/components/internal/tooltip/tooltip.test.vue +0 -1
  424. package/dist/assets/components/internal/tooltip/tooltip.types.ts +0 -1
  425. package/dist/assets/components/internal/tooltip/tooltip.vue +0 -1
  426. package/dist/assets/composables/use-form-validate-zod-4/use-form.types.ts +0 -1
  427. package/dist/assets/composables/use-numeric-input/use-numeric-input.types.ts +0 -1
  428. package/dist/assets/composables/use-section-navigation-keyboard/use-section-navigation-keyboard.types.ts +0 -1
  429. package/dist/assets/composables/use-virtual-list/use-virtual-list.types.ts +0 -1
@@ -1 +1 @@
1
- import { type BentoColumn, BentoColumnOverflow, type BentoDatagridData, type BentoDatagridDataItem, type BentoDatagridDataItemId, BentoDatagridEvent, type BentoDatagridPaginationProps, type BentoDatagridSelection, type BentoDatagridSortByColumn, BentoDatagridSortDirection, } from './data-grid.types'; import { BentoCard } from '@/components/card'; import { action } from '@storybook/addon-actions'; import { type BentoFilterBarModel, type BentoFilterBarSearchBarProps, BentoFilterItemType, type BentoFilterValues, } from '../filter-bar'; import { BentoCurrency } from '@/components/currency'; import { BentoStatus, BentoStatusVariant } from '@/components/status'; import { BentoLink } from '@/components/link'; import { BentoTypography } from '@/components/typography'; import { computed, ref, watch } from 'vue'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import { BentoDate, BentoDateFormat } from '@/components/date'; import { BentoCountry, BentoCountryCode } from '@/components/country'; import type { Meta, StoryObj } from '@storybook/vue'; import BentoDataGrid from './data-grid.vue'; import { isVue2 } from 'vue-demi'; import { BentoButton } from '../button'; import { BentoDashedUnderline } from '../dashed-underline'; import { BentoDataGridSummaryCell, BentoDataGridTagWithTextCell, BentoDataGridTrendCell } from './components'; import type { BentoColumnCellAction, BentoColumnCellActionEvent, BentoColumnCellActionsProp, BentoDataGridRowActionsProp, } from './components/data-grid-cell-actions/data-grid-cell-actions.types'; // Examples import DataGridEverythingBagel from './__tests__/data-grid-everything-bagel.vue?raw'; import DataGridCellActionsExample from './__tests__/data-grid-cell-actions-example.vue?raw'; import DataGridRowActionsExample from './__tests__/data-grid-row-actions-example.vue?raw'; import DataGridFitContentInCardExample from './__tests__/data-grid-fit-content-in-card-example.vue?raw'; import DataGridWithSlotsExample from './__tests__/data-grid-with-slots-example.vue?raw'; import DataGridFilteringExample from './__tests__/data-grid-filtering-example.vue?raw'; import DataGridSelectionExample from './__tests__/data-grid-selection-example.vue?raw'; import DataGridTrendCellExample from './__tests__/data-grid-trend-cell-example.vue?raw'; import DataGridTagWithTextCellExample from './__tests__/data-grid-tag-with-text-cell-example.vue?raw'; import { DEFAULT_DATA } from './__tests__/data-grid-example-data'; const meta: Meta = { title: 'Data Grid', component: BentoDataGrid, argTypes: { // Values lazyLoadType: { control: { type: 'select', }, }, // Filter bar props filters: { table: { type: { summary: 'BentoFilterBarModel' }, }, }, filterSearchTerm: { name: 'filterSearchTerm', defaultValue: undefined, description: "Filter bar search term useful to filter all the data by text. If the value is non-existant (`null` or `undefined`) the search bar won't be enabled.", control: { type: 'text', }, }, // Slots default: { table: { disable: true }, }, header: { name: 'header', defaultValue: '', description: 'header text', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, footer: { name: 'footer', defaultValue: '', description: 'footer text', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, 'head-{columnKey}': { name: 'head-{columnKey}', defaultValue: '', description: 'the column slot where `{columnKey}` is the name of the column key. Allows the Column header to be customized.', table: { type: { summary: 'VNode[]' }, category: 'slots', }, control: { disable: true }, }, 'item-{columnKey}': { name: 'item-{columnKey}', defaultValue: '', description: 'the data item slot where `{columnKey}` is the name of the data item column key. Allow row cells to be customized.', table: { type: { summary: 'VNode[]' }, category: 'slots', }, control: { disable: true }, }, ['pagination-slot']: { control: { type: 'text' }, description: 'Passes content to the default pagination slot', table: { type: { summary: 'VNode[]' }, }, }, // Events [BentoDatagridEvent.COLUMN_RESIZE]: { name: BentoDatagridEvent.COLUMN_RESIZE, defaultValue: '', description: 'Triggered when a column is resized. Provides a field name and the new resized width in pixels.', table: { category: 'events', type: { summary: '({ field, newResizedWidth }) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.SELECT]: { name: BentoDatagridEvent.SELECT, defaultValue: '', description: 'Triggered when a row is selected. Provides an array of data item ids. `BentoDatagridDataItemId[]`', table: { category: 'events', type: { summary: '(selectedDataItemIds) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.NAVIGATE]: { name: BentoDatagridEvent.NAVIGATE, defaultValue: '', description: `Triggered when the navigation controls in the pagination are clicked (i.e. when the arrow buttons to the rightmost of the screen or the dropdown on the right hand are updated). It indicates to which page it should go next.`, table: { category: 'events', type: { summary: '(pageNumber: number) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.ITEMS_PAGE]: { name: BentoDatagridEvent.ITEMS_PAGE, defaultValue: '', description: `Triggered when the number of items per page is changed from the left hand dropdown of the pagination. It indicates the new number of items that will be displayed.`, table: { category: 'events', type: { summary: '(itemsPerPage: number) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.SORT]: { name: BentoDatagridEvent.SORT, defaultValue: '', description: `Triggered when a column is sorted. Provides an array of \`BentoDatagridSortByColumn\` which includes the \`field\` and the sort \`direction\` (\`BentoDatagridSortDirection\`) of the column:`, table: { category: 'events', type: { summary: '(sortByDirections) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.UPDATE_COLUMNS]: { name: BentoDatagridEvent.UPDATE_COLUMNS, defaultValue: '', description: `Triggered when a the columns have been updated. Provides an updated array of columns \`BentoColumn[]\` which should be passed back into the \`columns\` prop (easily achieved using the [sync modifier](https://v2.vuejs.org/v2/guide/components-custom-events.html#sync-Modifier)) e.g. \`:columns.sync="columns"\``, table: { category: 'events', type: { summary: '(columns) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.UPDATE_CONDENSED]: { name: 'update:condensed', defaultValue: '', description: `Triggered when the config panel's condensed view toggle is interacted with. Provides the updated condensed \`boolean\`. (easily achieved using the [sync modifier](https://v2.vuejs.org/v2/guide/components-custom-events.html#sync-Modifier)) e.g. \`:condensed.sync="condensed"\``, table: { category: 'events', type: { summary: '(condensed) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.UPDATE_FILTER_VALUES]: { name: BentoDatagridEvent.UPDATE_FILTER_VALUES, defaultValue: '', description: `Triggered when a the filters in the filterbar have updated. Provides an array of filters \`BentoFilterBarModel[]\` which should be passed back into the \`filter-values\` prop (easily achieved using the [sync modifier](https://v2.vuejs.org/v2/guide/components-custom-events.html#sync-Modifier)) e.g. \`:filter-values.sync="filtersValues"\``, table: { category: 'events', type: { summary: '(filterValues) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.UPDATE_PAGINATION]: { name: BentoDatagridEvent.UPDATE_PAGINATION, defaultValue: '', description: `Triggered when a the pagination state has been updated. Provides an updated \`pagination\` properties object which should be passed back into the \`pagination\` prop (easily achieved using the [sync modifier](https://v2.vuejs.org/v2/guide/components-custom-events.html#sync-Modifier)) e.g. \`:pagination.sync="pagination"\``, table: { category: 'events', type: { summary: '(paginationProps) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.UPDATE_SELECTION]: { name: BentoDatagridEvent.UPDATE_SELECTION, defaultValue: '', description: `Triggered when a the select data rows state has been updated. Provides an array of row IDs \`BentoDatagridDataItemId[]\` which should be passed back into the \`selection\` prop (easily achieved using the [sync modifier](https://v2.vuejs.org/v2/guide/components-custom-events.html#sync-Modifier)) e.g. \`:selection.sync="selection"\``, table: { category: 'events', type: { summary: '(selection) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.UPDATE_SORT_BY]: { name: 'update:sort-by', defaultValue: '', description: `Triggered when a the sorting state has been updated. Provides an array of sorting directions \`BentoDatagridSortByColumn[]\` which should be passed back into the \`sort-by\` prop (easily achieved using the [sync modifier](https://v2.vuejs.org/v2/guide/components-custom-events.html#sync-Modifier)) e.g. \`:sort-by.sync="sortBy"\``, table: { category: 'events', type: { summary: '(sortingDirections) => void' }, }, control: { disable: true }, }, // Filter bar search events [BentoDatagridEvent.FILTER_SEARCH_INPUT]: { name: BentoDatagridEvent.FILTER_SEARCH_INPUT, defaultValue: '', description: "Triggered whenever the filter's search is updated.", table: { category: 'events', type: { summary: '(newSearchTerm) => void' } }, control: { disable: true }, }, [BentoDatagridEvent.FILTER_SEARCH_CLEAR]: { name: BentoDatagridEvent.FILTER_SEARCH_CLEAR, defaultValue: '', description: "Triggered whenever the filter's search is cleared.", table: { category: 'events', type: { summary: '() => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.UPDATE_FILTER_SEARCH_TERM]: { name: BentoDatagridEvent.UPDATE_FILTER_SEARCH_TERM, defaultValue: '', description: "Triggered whenever the filter's search is updated to sync the model.", table: { category: 'events', type: { summary: '(newSearchTerm) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.ROW_CLICK]: { name: BentoDatagridEvent.ROW_CLICK, defaultValue: '', description: 'Triggered whenever a row has been clicked.', table: { category: 'events', type: { summary: '(row: BentoDatagridDataItem, event: MouseEvent) => void' }, }, }, [BentoDatagridEvent.NESTED_CONTENT_TOGGLED]: { name: BentoDatagridEvent.NESTED_CONTENT_TOGGLED, defaultValue: '', description: 'Triggered whenever a data item toggled is nested content', table: { category: 'events', type: { summary: '(dataItem: BentoDatagridDataItem) => void' }, }, control: { disable: true }, }, }, }; export default meta; type Story = StoryObj<typeof BentoDataGrid>; const DEFAULT_COLUMNS: Array<BentoColumn> = [ { field: 'name', label: 'Name', minWidth: 300, mandatory: true }, { field: 'company', label: 'Company', autoWidth: true }, { field: 'payment', label: 'Payment', minWidth: 350 }, ]; const ADDITIONAL_DATA: BentoDatagridData = [ { id: '03c0a799-1ced-4017-aea3-0cebb0106335', name: 'Additional data fetched here', payment: 160405, company: 'Merchant Helium', registered: '2023-06-30T13:56:09.498Z', tags: ['deserunt', 'et', 'esse'], reference: 'UnbQaUncf3eR1D8XUBqn_UnbQaUncf3eR1D8XUBqn_UnbQaUncf3eR1D8XUBqn', paymentStatus: 1, countryCode: BentoCountryCode.NL, }, { id: 'b6d4f1fd-b1f6-40a6-a443-f785c89604ef', name: 'Santos Palmer', payment: 163500, company: 'Merchant B', registered: '2023-04-28T13:11:09.498Z', tags: ['et', 'Lorem', 'sint'], reference: 'IxUZ9FsEPCZ9dFFPpI9C', paymentStatus: 2, countryCode: BentoCountryCode.BE, }, { id: '8f9e7877-1ca2-4929-9217-f1ec78709291', name: 'Joyce Johns', payment: 78500, company: 'Merchant C', registered: '2023-06-30T11:01:09.498Z', tags: ['laborum', 'enim', 'ullamco'], reference: 'y0qAQ0WDszRyqLY2WO9f', paymentStatus: 1, countryCode: BentoCountryCode.UA, }, { id: '0789a012-85a6-4657-87bb-319141938a61', name: 'Lynnette Melendez', payment: -45000, company: 'STRALOY', registered: '2019-08-01T13:56:01.498Z', tags: ['sit', 'consectetur', 'amet'], reference: '2vv5pzbRSwx8YsFoGGOC', paymentStatus: 1, countryCode: BentoCountryCode.BR, }, { id: '0b3981b6-c73b-47ad-81d1-b06f9b95d467', name: 'Wagner Mcintosh', payment: 1112, company: 'Merchant A', registered: '2022-12-30T02:12:09.498Z', tags: ['ad', 'ullamco', 'et'], reference: '54KN4jkpBuaRY5xMfe84', paymentStatus: 1, countryCode: BentoCountryCode.US, }, { id: '51d2b31d-d577-4fca-8329-a583babbbdda', name: 'Evans Zamora', payment: 1153.4, company: 'GEEKWAGON', registered: '2023-06-30T13:51:09.498Z', tags: ['consequat', 'magna', 'sit'], reference: 'Sj84kad0MGxpuozTjEk', paymentStatus: 0, countryCode: BentoCountryCode.FR, }, { id: '9bd59a6e-bd03-4477-813f-b844953b7645', name: 'Anderson Middleton', payment: 181722.23, company: 'BALOOBA', registered: '2021-03-02T01:34:09.498Z', tags: ['aliqua', 'adipisicing', 'magna'], reference: 'MtJ5Bnew0MGxpuozTjEk', paymentStatus: 1, countryCode: BentoCountryCode.IT, }, ]; const DEFAULT_ARGS = { data: DEFAULT_DATA, columns: DEFAULT_COLUMNS, allowColumnDragAndDrop: false, pagination: {}, emptyState: { title: 'No results were found', image: 'no-results-found', variant: 'embedded', action: { title: 'Clear filters', event: action('clear'), }, description: 'Try a different term or reset search filters', }, }; // Default const DefaultCode = ` <template> <bento-data-grid :allow-row-clicks="false" :allow-column-drag-and-drop="false" :bulk-actions="undefined" :condensed="false" :columns="columns" :column-panel="false" :data="data" :empty-state="undefined" :filters="undefined" :filters-search-term="undefined" :fit-content="false" :get-data-item-id="undefined" :has-resizeable-columns="false" :has-nested-content="false" :highlighted-rows="undefined" :is-data-item-disabled="undefined" lazy-load-type="none" :loading="false" :outline="false" :no-spacing-top="false" :pagination="undefinded" :selectable-accross-pages="false" :sticky-pagination="false" :sticky-filters="false" :selectable="false" :selection="undefined" :sort-by="undefined" :tab-title="undefined" :truncate-column-headers="false" /> </template> <script setup lang="ts"> import { BentoColumn, BentoDataGrid, BentoDatagridData } from '@adyen/bento-vue2'; import { ref } from 'vue'; const data = ref<BentoDatagridData>(${JSON.stringify(DEFAULT_DATA)}); const columns = ref<BentoColumn[]>([ { field: 'name', label: 'Name', minWidth: 300, mandatory: true }, { field: 'company', label: 'Reference' }, { field: 'payment', label: 'Payment', width: 200, minWidth: 150 }, ]); </script> `; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" /> `, setup(props) { return { args: isVue2 ? props : _args }; }, }), args: DEFAULT_ARGS, parameters: storybookDocsParameter(DefaultCode), }; // Fluid Columns const FluidTemplateCode = ` <template> <bento-data-grid :data="data" :columns="columns" /> </template> <script setup lang="ts"> import { BentoColumn, BentoDataGrid, BentoDatagridData } from '@adyen/bento-vue2'; import { ref } from 'vue'; const data = ref<BentoDatagridData>(${JSON.stringify(DEFAULT_DATA)}); const columns = ref<BentoColumn[]>([ { field: 'name', label: 'Name', flex: 2, mandatory: true }, { field: 'company', label: 'Company', flex: 1 }, { field: 'payment', label: 'Payment', flex: 1, minWidth: 200 }, ]); </script> `; const rowActionsFluid: BentoDataGridRowActionsProp = (item: BentoDatagridDataItem) => { if (item.id === DEFAULT_DATA[3].id) { return [ { variant: 'edit', event: action('edit'), }, ]; } else if (item.id === DEFAULT_DATA[2].id) { return [ { variant: 'edit', event: action('edit') }, { variant: 'open', isShort: true, menuData: [ { text: 'Cancel payment', event: action('cancel payment'), critical: true, }, { text: 'Transfer payment', event: action('transfer payment'), }, { text: 'Delete payment', event: action('delete payment'), disabled: true, }, ], }, ]; } else if (item.id === DEFAULT_DATA[1].id) { return []; } return [ { variant: 'edit', event: action('edit'), }, { title: 'Delete', critical: true, event: action('Delete'), }, ]; }; export const Fluid: Story = { ...Default, args: { ...DEFAULT_ARGS, columns: [ { field: 'name', label: 'Name', flex: 2, mandatory: true }, { field: 'company', label: 'Company', flex: 1 }, { field: 'payment', label: 'Payment', flex: 1, minWidth: 200 }, ], rowActions: rowActionsFluid, }, parameters: storybookDocsParameter(FluidTemplateCode), }; // Slots export const Slots: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid, BentoLink, BentoTypography, }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" > <template #header> <bento-typography variant="title" el="h2"> Users </bento-typography> </template> <template #head-name="{column}"> <bento-typography variant="caption"> {{ column.label }} </bento-typography> </template> <template #item-name="{item}"> <bento-typography variant="body"> {{ item.name }} </bento-typography> <template v-if="item.company === 'Merchant Helium'"> <div style="display: inline-flex; gap: 4px;"> <bento-typography v-for="itemTag in item.tags" :key="itemTag" variant="caption" :style="{ color: 'var(--b-color-label-secondary)' }" > { {{ itemTag }} } </bento-typography> </div> </template> </template> <template #item-company="{item}"> <bento-link isNotRouting to="https://www.adyen.com" :title="item.company" > {{ item.company }} </bento-link> <bento-typography v-if="item.company === 'Merchant B'" variant="caption" :style="{ color: 'var(--b-color-label-secondary)' }"> {{ item.registered }} </bento-typography> </template> <template #item-payment="{item}"> $ {{ item.payment }} </template> <template #footer> <bento-typography variant="caption"> Footer </bento-typography> </template> </bento-data-grid> `, setup(props) { return { args: isVue2 ? props : _args }; }, }), args: { ...DEFAULT_ARGS, columns: [ { field: 'name', label: 'Name', flex: 2, mandatory: true }, { field: 'company', label: 'Company', flex: 1 }, { field: 'payment', label: 'Payment', flex: 1, minWidth: 200 }, ], }, parameters: storybookDocsParameter(DataGridWithSlotsExample), }; // Sorting const useSort = () => { const sortBy = ref<Array<BentoDatagridSortByColumn>>([]); const data = ref<BentoDatagridData>(DEFAULT_DATA); const sort = (sortedColumns: Array<BentoDatagridSortByColumn>) => { data.value = sortedColumns[0].direction === BentoDatagridSortDirection.ASCENDING ? data.value.sort((a, b) => (a[sortedColumns[0].field] as string).localeCompare(b[sortedColumns[0].field] as string) ) : data.value .sort((a, b) => (a[sortedColumns[0].field] as string).localeCompare(b[sortedColumns[0].field] as string) ) .reverse(); action('sort')(sortedColumns); }; return { data, sortBy, sort }; }; const SortingTemplateCode = ` <template> <bento-data-grid :data="data" :columns="columns" @sort="sort" :sort-by.sync="sortBy" /> </template> <script setup lang="ts"> import { BentoDataGrid, type BentoDatagridSortByColumn, type BentoDatagridData, type BentoColumn, } from '@adyen/bento-vue2' // Sortable fields must have "sortable: true" const columns: BentoColumn = [ { field: 'id', label: 'ID', minWidth: 300, sortable: true, mandatory: true }, { field: 'name', label: 'Name', minWidth: 300, mandatory: true }, ] const data = ref<BentoDatagridData>([ { id: 1, name: 'First' }, { id: 2, name: 'Second' }, ]); const sortBy = ref<Array<BentoDatagridSortByColumn>>([]); const sort = (sortedColumns: Array<BentoDatagridSortByColumn>) => { data.value = sortedColumns[0].direction === BentoDatagridSortDirection.ASCENDING ? data.value.sort((a, b) => (a[sortedColumns[0].field] as number) .toString() .localeCompare(b[sortedColumns[0].field] as string) ) : data.value .sort((a, b) => (a[sortedColumns[0].field] as number) .toString() .localeCompare(b[sortedColumns[0].field] as string) ) .reverse(); } </script> `; export const Sorting: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid }, props: Object.keys(argTypes), template: ` <bento-data-grid :data="data" :columns="columns" :sort-by.sync="sortBy" @sort="sort" /> `, setup(props) { const { data, sortBy, sort } = useSort(); return { args: isVue2 ? props : _args, data, sortBy, sort, }; }, }), args: { ...DEFAULT_ARGS, columns: [ { field: 'name', label: 'Name', minWidth: 300, sortable: true, mandatory: true }, { field: 'company', label: 'Company', minWidth: 150, sortable: true }, { field: 'payment', label: 'Payment', width: 200, minWidth: 150 }, ], sortBy: [], }, parameters: storybookDocsParameter(SortingTemplateCode), }; export const Selection: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid }, props: Object.keys(argTypes), template: ` <div> <bento-data-grid v-bind="args" :data="pagedData" :pagination="pagination" :filters="filtersConfig" :filter-values="filterValues" :is-data-item-disabled="isDataItemDisabled" :selection="selection" :filter-search-term="searchTerm" @update:filter-search-term="searchTerm = $event" @update:pagination="pagination = $event" @update:filter-values="filterValues = $event" @select-all-across-pages="onSelectAllAcrossPages" @select-all-current-results="onSelectAllInCurrentResults" @deselect-all-current-results="onDeselectAllInCurrentResults" @filter-search-clear="onSearchCleared" @update:selection="onSelect" @row-click="rowClickAction" /> </div> `, setup(props) { const args = isVue2 ? props : _args; const selection = ref([]); const filtersConfig = computed<BentoFilterBarModel>(() => args?.filters ?? FILTERS); const filterValues = ref<BentoFilterValues>([]); const searchTerm = ref(''); const data = ref( Array.from({ length: 20 }, (_, i) => ({ id: `id-${i + 1}`, name: `Name ${i + 1}`, payment: (i + 1) * 100, company: `Merchant ${i + 1}`, })) ); const isDataItemDisabled = (row: BentoDatagridDataItem) => { return row.id === data.value[3].id; }; const pagination = ref<BentoDatagridPaginationProps>({ page: 1, size: 10, totalCount: 20, hasNext: true, }); const filteredData = computed<BentoDatagridData>(() => { let internalData = data.value; if (searchTerm.value) { const lowerCaseSearchTerm = searchTerm.value.toLowerCase(); const searchableFields = args.columns.map(column => column.field); internalData = internalData.filter((item: BentoDatagridDataItem) => { return searchableFields.some(field => { const value = String(item[field]); return value.toLowerCase().includes(lowerCaseSearchTerm); }); }); } return internalData.filter(item => filterValues.value.every(filter => filter.value ? String(item[filter.field]).toLowerCase().includes(String(filter.value).toLowerCase()) : true ) ); }); const pagedData = computed<BentoDatagridData>(() => { return filteredData.value.slice( (pagination.value.page - 1) * pagination.value.size, pagination.value.page * pagination.value.size ); }); const enabledIds = computed(() => data.value.filter(item => !isDataItemDisabled(item)).map(x => x.id)); const enabledFilteredIds = computed(() => filteredData.value.filter(item => !isDataItemDisabled(item)).map(x => x.id) ); const onSelect = value => { selection.value = value; action('update:selection')(value); }; const onSelectAllAcrossPages = () => { selection.value = enabledIds.value; action('select-all-across-pages')(); }; const onSelectAllInCurrentResults = () => { selection.value = [...new Set([...selection.value, ...enabledFilteredIds.value])]; action('select-all-current-results')(); }; const onDeselectAllInCurrentResults = () => { selection.value = selection.value.filter(item => !enabledFilteredIds.value.includes(item)); action('deselect-all-current-results')(); }; const onSearchCleared = () => { searchTerm.value = ''; action('search-clear')(); }; watch( filteredData, () => { pagination.value.totalCount = filteredData.value.length; }, { immediate: true } ); return { args, onSelect, onSelectAllAcrossPages, onSelectAllInCurrentResults, onDeselectAllInCurrentResults, pagination, selection, pagedData, filtersConfig, filterValues, searchTerm, rowClickAction: value => action('row-click')(value), isDataItemDisabled, onSearchCleared, }; }, }), args: { ...DEFAULT_ARGS, selectable: true, allowRowClicks: true, selectableAcrossPages: true, bulkActions: [ { title: 'Edit', event: () => true, }, { title: 'Delete', critical: true, event: () => true, }, ], }, parameters: storybookDocsParameter(DataGridSelectionExample), }; // Filtering const FILTERS: BentoFilterBarModel = [ { field: 'name', label: 'Name', type: BentoFilterItemType.INPUT, }, { field: 'company', label: 'Company', type: BentoFilterItemType.INPUT, }, ]; export const Filtering: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid }, props: Object.keys(argTypes), setup(props) { const args = isVue2 ? props : _args; const filtersConfig = computed<BentoFilterBarModel>(() => args?.filters ?? FILTERS); const filterValues = ref<BentoFilterValues>([]); const searchTerm = ref(''); const searchConfig = ref<BentoFilterBarSearchBarProps>({ inputFieldAriaLabel: 'Search for items', placeholder: 'Placeholder', hint: 'Hint', }); const dataSet = computed<BentoDatagridData>(() => { let filteredData = args.data; // Apply global search term filter if (searchTerm.value) { const lowerCaseSearchTerm = searchTerm.value.toLowerCase(); const searchableFields = args.columns.map(column => column.field); filteredData = filteredData.filter((item: BentoDatagridDataItem) => { return searchableFields.some(field => { const value = String(item[field]); return value.toLowerCase().includes(lowerCaseSearchTerm); }); }); } filteredData = filteredData.filter(item => filterValues.value?.every(filter => { return filter.value ? String(item[filter.field]).toLowerCase().includes(String(filter.value).toLowerCase()) : true; }) ); return filteredData; }); watch(filterValues, () => { action('filter-values:update')(filterValues.value); }); const onSearchCleared = action('search-clear'); const onSearchInput = action('search-input'); const onSearchTermUpdated = action('update:search-term'); return { // Values dataSet, filtersConfig, filterValues, searchTerm, searchConfig, // Methods onSearchCleared, onSearchInput, onSearchTermUpdated, // Vue 3 storybook fix args, }; }, template: ` <bento-data-grid v-bind="args" :data="dataSet" :filters="filtersConfig" :filter-values.sync="filterValues" :filter-search-term.sync="searchTerm" :filter-search-config="searchConfig" @filter-search-clear="onSearchCleared" @filter-search-input="onSearchInput" @update:filter-search-term="onSearchTermUpdated" /> `, }), args: DEFAULT_ARGS, parameters: storybookDocsParameter(DataGridFilteringExample), }; // No Results const NoResultsTemplateCode = ` <bento-data-grid :data="[]" :columns="[ { field: 'name', label: 'Name', minWidth: 300, mandatory: true }, { field: 'company', label: 'Reference' }, { field: 'payment', label: 'Payment', width: 200, minWidth: 150 }, ]" :empty-state="{ title: 'No results were found', image: 'no-results-found', variant: 'embedded', action: { title: 'Clear filters', event: clearFiltersFunction, }, description: 'Try a different term or reset search filters', }" /> `; export const NoResults: Story = { ...Filtering, args: { ...DEFAULT_ARGS, data: [], filters: FILTERS, filterValues: [{ field: 'company', value: 'CIA' }], }, parameters: storybookDocsParameter(NoResultsTemplateCode), }; // Pagination const PaginationTemplateCode = ` <template> <bento-data-grid :data="dataGridData" :columns="columnsConfig" :pagination.sync="pagination" @update:pagination="onUpdatePagination" /> </template> <script lang="ts" setup> const data="[{ id: '1', name: 'Jane' }, { id: '1', name: 'John' }]" const pagination = ref({ description: 'datagrid navigation', hasNext: true, size: 10 }); // With API call watch( () => pagination.value, () => { makeAPICall(pagination.value); } ); // Without API call const onUpdatePagination = (newPagination: BentoDatagridPaginationProps) => { pagination.value = { ...newPagination }; const newSetStartIndex = pagination.value.page * pagination.value.size; const amountOfItems = newSetStartIndex + pagination.value.size - 1; data.value = arrayWithFullSetOfValues.slice(newSetStartIndex, amountOfItems); }; </script> `; export const Pagination: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" :data="dataGridData" :pagination.sync="pagination" @update:pagination="updatePagination" @items-page="updateItemsPerPage" /> `, setup(props) { const args = isVue2 ? props : _args; const largeData = [ ...DEFAULT_ARGS.data, ...DEFAULT_ARGS.data.map(dataItem => ({ ...dataItem, id: `${dataItem.id}+1` })), ]; const pagination = ref(args.pagination); const dataGridData = computed(() => { const end = pagination.value.size <= largeData.length ? pagination.value.size : largeData.length; return largeData.slice(pagination.value.page - 1, end); }); const updateItemsPerPage = (itemsPerPage: number) => { action('items-page')(itemsPerPage); }; const updatePagination = (newPagination: BentoDatagridPaginationProps) => { action('navigate')(newPagination.page); action('update:pagination')(newPagination); }; return { // Values dataGridData, pagination, // Methods updateItemsPerPage, updatePagination, // Vue 3 storybook fixes args: isVue2 ? props : _args, }; }, }), args: { ...DEFAULT_ARGS, pagination: { hasNext: true, description: 'datagrid navigation', size: 10, page: 1, totalCount: DEFAULT_ARGS.data.length * 2, }, }, parameters: storybookDocsParameter(PaginationTemplateCode), }; // Payment Status (demo use case for datagrid V2) export const EverythingBagelExample: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid, BentoLink, BentoStatus, BentoCurrency, BentoDate, BentoCountry, BentoButton }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" :data="filteredAndSortedData" :columns.sync="columns" :condensed="isCondensed" :filters="filtersConfig" :filter-values.sync="filterValues" :filter-search-term.sync="searchTerm" :sort-by="sortBy" @update:sort-by="sortBy = $event" @update:condensed="isCondensed = $event" :selection.sync="selection" :is-data-item-disabled="isDataItemDisabledForSelection" :row-actions="rowActions" selectable @row-click="onRowClick" > <template #item-paymentStatus="{item}"> <div style="display: flex"> <bento-status :variant="getPaymentStatus(item.paymentStatus)" /> <span>{{ getPaymentText(item.paymentStatus) }}</span> </div> </template> <template #item-reference="{item}"> <bento-link isNotRouting to="https://www.adyen.com" :title="item.reference" > {{ item.reference }} </bento-link> </template> <template #item-countryCode="{item}"> <bento-country :code="item.countryCode" /> </template> <template #item-payment="{item}"> <bento-currency currency="EUR" :value="item.payment" /> </template> <template #item-date="{item}"> <bento-date :date="new Date(item.registered)" :format='BentoDateFormat.FULL_DATE_TIME_WITH_PERIOD'/> </template> </bento-data-grid> `, setup(props) { const args = isVue2 ? props : _args; const columns = ref<Array<BentoColumn>>(args.columns); const filtersConfig = ref<BentoFilterBarModel>(args.filters); const filterValues = ref<BentoFilterValues>(args?.filterValues); const sortBy = ref<Array<BentoDatagridSortByColumn>>([]); const searchTerm = ref(''); const isCondensed = ref(args.condensed); const getPaymentStatus = (paymentStatus: number) => { switch (paymentStatus) { case 2: return BentoStatusVariant.GREEN; case 1: return BentoStatusVariant.YELLOW; case 0: default: return BentoStatusVariant.RED; } }; const getPaymentText = (paymentStatus: number) => { switch (paymentStatus) { case 2: return 'Paid'; case 1: return 'In progress'; case 0: default: return 'Not paid'; } }; const onRowClick = (item: BentoDatagridDataItem) => { action('row-click')(item); }; // Selection const isDataItemDisabledForSelection = (row: BentoDatagridDataItem) => row.id === DEFAULT_DATA[3].id; const selection = ref<BentoDatagridSelection>([DEFAULT_DATA[1].id]); // Filtering const filteredData = computed(() => // If any filters or search terms have been set filterValues.value?.length === 0 && searchTerm.value === '' ? args.data : args.data.filter(item => { const foundFilteredItem = filterValues.value?.length > 0 ? filterValues.value.every(filter => filter.value ? (item[filter.field] as string) .toLowerCase() .includes((filter.value as string).toLowerCase()) : true ) : true; const foundSearchFilteredItem = searchTerm.value ? (item?.company as string) .toLowerCase() .includes((searchTerm.value as string).toLowerCase()) : true; return foundFilteredItem && foundSearchFilteredItem; }) ); const filteredAndSortedData = computed(() => { if (sortBy.value?.length === 0) { return filteredData.value; } return sortBy.value[0].direction === BentoDatagridSortDirection.ASCENDING ? filteredData.value.sort((a, b) => (a[sortBy.value[0].field] as string).localeCompare(b[sortBy.value[0].field] as string) ) : filteredData.value .sort((a, b) => (a[sortBy.value[0].field] as string).localeCompare(b[sortBy.value[0].field] as string) ) .reverse(); }); const rowActions: BentoDataGridRowActionsProp = (item: BentoDatagridDataItem) => { if (item.id === DEFAULT_DATA[3].id) { return [ { variant: 'edit', event: action('edit'), tooltipText: 'Edit payment', }, ]; } else if (item.id === DEFAULT_DATA[2].id) { return [ { variant: 'edit', event: action('edit'), tooltipText: 'Edit payment' }, { variant: 'open', isShort: true, menuData: [ { text: 'Cancel payment', event: action('cancel payment'), critical: true, }, { text: 'Transfer payment', event: action('transfer payment'), }, { text: 'Delete payment', event: action('delete payment'), disabled: true, }, ], }, ]; } else if (item.id === DEFAULT_DATA[1].id) { return []; } return [ { variant: 'edit', event: action('edit'), tooltipText: 'Edit payment', }, { title: 'Delete', critical: true, event: action('Delete'), tooltipText: 'Delete payment', }, ]; }; return { // Methods getPaymentStatus, getPaymentText, // Functions onRowClick, isDataItemDisabledForSelection, // Values columns, filteredAndSortedData, sortBy, filtersConfig, filterValues, searchTerm, isCondensed, selection, rowActions, // Enums BentoDateFormat, // Vue 3 storybook fix args, }; }, }), args: { ...DEFAULT_ARGS, zebraRows: true, filters: [ { field: 'company', label: 'Company', type: BentoFilterItemType.INPUT, }, { field: 'countryCode', label: 'Country/Region', options: { listboxItems: [ { value: BentoCountryCode.NL, }, { value: BentoCountryCode.BE, }, ], variant: 'name', }, type: BentoFilterItemType.SELECT_COUNTRY, }, ], columns: [ { field: 'company', label: 'Company', sortable: true, mandatory: true, autoWidth: true, frozen: true, minWidth: 200, }, { field: 'paymentStatus', label: 'Status', width: 180, infoIconTooltip: 'For current day' }, { field: 'reference', label: 'Reference', width: 320, overflow: BentoColumnOverflow.ELLIPSIS }, { field: 'countryCode', label: 'Country/Region', width: 320 }, { field: 'payment', label: 'Payment', width: 180, numeric: true }, { field: 'date', label: 'Execution Date', width: 200 }, ], allowRowClicks: true, allowColumnDragAndDrop: true, columnPanel: true, highlightedRows: [DEFAULT_DATA[0].id, DEFAULT_DATA[4].id], }, parameters: storybookDocsParameter(DataGridEverythingBagel), }; export const DisplayOptions = (_args, { argTypes }) => ({ components: { BentoDataGrid, BentoDate }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" :columns.sync="columns" :condensed.sync="isCondensed"> <template #item-date="{item}"> <bento-date :date="new Date(item.registered)" :format='BentoDateFormat.FULL_DATE_TIME_WITH_PERIOD'/> </template> </bento-data-grid> `, setup(props) { const args = isVue2 ? props : _args; const isCondensed = ref(args.condensed); const columns = ref([ { field: 'name', label: 'Name', minWidth: 200, mandatory: true }, { field: 'reference', label: 'Reference', width: 320, overflow: BentoColumnOverflow.ELLIPSIS, frozen: true, }, { field: 'company', label: 'Company', minWidth: 150, width: 250, frozen: true }, { field: 'payment', label: 'Payment', width: 200, minWidth: 150 }, { field: 'countryCode', label: 'Country/Region', width: 280 }, { field: 'date', label: 'Execution Date', width: 300 }, ]); return { // Values columns, isCondensed, // Enums BentoDateFormat, // Vue 3 storybook fix args, }; }, }); DisplayOptions.args = { ...DEFAULT_ARGS, allowColumnDragAndDrop: true, columnPanel: true, }; DisplayOptions.parameters = storybookDocsParameter(` <bento-data-grid column-panel :data="dataArray" :columns.sync="columns" :condensed.sync="isCondensed" />`); export const GridInCard: Story = { render: (_args, { argTypes }) => ({ components: { BentoCard, BentoDataGrid, BentoDate }, props: Object.keys(argTypes), template: ` <div style="max-width: 500px;"> <bento-card> Grid in a card <template #content> <div style="height: 300px;"> <bento-data-grid v-bind="args" :columns.sync="columns" :condensed.sync="isCondensed" :pagination="pagination" fit-content > <template #item-date="{item}"> <bento-date :date="new Date(item.registered)" :format='BentoDateFormat.FULL_DATE_TIME_WITH_PERIOD'/> </template> </bento-data-grid> </div> </template> </bento-card> </div> `, setup(props) { const args = isVue2 ? props : _args; const isCondensed = ref(args.condensed); const pagination = ref({ hasNext: true, size: 20, page: 1, description: 'datagrid navigation', }); const columns = ref([ { field: 'name', label: 'Name', minWidth: 200, mandatory: true }, { field: 'reference', label: 'Reference', width: 320, overflow: BentoColumnOverflow.ELLIPSIS, }, { field: 'company', label: 'Company', minWidth: 150, width: 250 }, { field: 'payment', label: 'Payment', width: 200, minWidth: 150 }, { field: 'countryCode', label: 'Country/Region', width: 280 }, { field: 'date', label: 'Execution Date', width: 300 }, ]); return { // Values columns, isCondensed, pagination, // Enums BentoDateFormat, // Vue 3 storybook fix args, }; }, }), args: { ...DEFAULT_ARGS, columnPanel: false, }, parameters: storybookDocsParameter(DataGridFitContentInCardExample), }; // Default const lazyLoadingCode = ` // With infinite scroll <bento-data-grid :data="dataArray" :columns="[ { field: 'name', label: 'Name', minWidth: 300, mandatory: true }, { field: 'company', label: 'Reference' }, { field: 'payment', label: 'Payment', width: 200, minWidth: 150 }, ]" lazy-load-type="automatic" :loading="yourLoadingLogic" @update:load-more="yourInfiniteScrollHandler" /> // With 'load more' button <bento-data-grid :data="dataArray" :columns="[ { field: 'name', label: 'Name', minWidth: 300, mandatory: true }, { field: 'company', label: 'Reference' }, { field: 'payment', label: 'Payment', width: 200, minWidth: 150 }, ]" lazy-load-type="button" :loading="yourLoadingLogic" @update:load-more="yourInfiniteScrollHandler" />`; export const lazyLoading: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid }, props: Object.keys(argTypes), template: ` <div style="height: 300px;"> <bento-data-grid v-bind="args" :lazy-load-type="lazyLoadType" :loading="loading" @update:show-more="infiniteScrollHandler"/> </div> `, setup(props) { const args = isVue2 ? props : _args; const loading = ref(false); const data = ref(DEFAULT_DATA); const infiniteScrollHandler = () => { loading.value = true; setTimeout(() => { data.value.push(...ADDITIONAL_DATA); loading.value = false; }, 2000); }; return { args, loading, infiniteScrollHandler, }; }, }), args: { ...DEFAULT_ARGS, lazyLoadType: 'automatic', }, parameters: storybookDocsParameter(lazyLoadingCode), }; // Added just to be able to easily play around with the sticky headers/pagination/filters // Not really relevant as a Storybook example, so not adding storybook code example export const LongDataWithStickyFiltersAndPagination: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid }, props: Object.keys(argTypes), setup(props) { const args = isVue2 ? props : _args; const filtersConfig = ref<BentoFilterBarModel>([ { field: 'col1', label: 'Column 1', type: BentoFilterItemType.INPUT, }, { field: 'col2', label: 'Column 2', type: BentoFilterItemType.INPUT, }, ]); const filterValues = ref(); const searchTerm = ref(''); const isCondensed = ref(args.condensed); const columns = ref( Array.from({ length: 20 }, (_, index) => ({ field: `col${index + 1}`, label: `Column ${index + 1}`, width: 200, mandatory: index === 0, })) ); const data = ref( Array.from({ length: 50 }, (_, rowIndex) => columns.value.reduce((acc, col, colIndex) => { acc[col.field] = `Row ${rowIndex + 1} - Col ${colIndex + 1}`; return acc; }, {}) ) ); const dataSet = computed(() => // If any filters or search terms have been set filterValues.value?.length === 0 && searchTerm.value === '' ? data.value : data.value.filter(item => { const foundFilteredItem = filterValues.value?.length > 0 ? filterValues.value.every(filter => filter.value ? (item[filter.field] as string) .toLowerCase() .includes((filter.value as string).toLowerCase()) : true ) : true; const foundSearchFilteredItem = searchTerm.value ? Object.keys(item).some(key => key ? (item[key] as string) .toLowerCase() .includes((searchTerm.value as string).toLowerCase()) : true ) : true; return foundFilteredItem && foundSearchFilteredItem; }) ); const onSearchCleared = action('search-clear'); const onSearchInput = action('search-input'); const onSearchTermUpdated = action('update:search-term'); return { // Values dataSet, filtersConfig, filterValues, searchTerm, columns, isCondensed, // Methods onSearchCleared, onSearchInput, onSearchTermUpdated, // Vue 3 storybook fix args, }; }, template: ` <bento-data-grid v-bind="args" :data="dataSet" :columns.sync="columns" :condensed.sync="isCondensed" :filters="filtersConfig" :filter-values.sync="filterValues" :filter-search-term.sync="searchTerm" @filter-search-clear="onSearchCleared" @filter-search-input="onSearchInput" @update:filter-search-term="onSearchTermUpdated" /> `, }), args: { ...DEFAULT_ARGS, columnPanel: true, stickyPagination: true, stickyFilters: true }, }; // Cell actions export const CellActions: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" :columns="columns"> <template #item-custom="{item}"> Value </template> </bento-data-grid> `, setup(props) { // --- Action Handlers --- const editItem: BentoColumnCellActionEvent = (rowDataItem, columnKey) => { action('edit')(rowDataItem, columnKey); }; const cancelAction: BentoColumnCellActionEvent = (rowDataItem, columnKey) => { action('cancel')(rowDataItem, columnKey); }; const transferAction: BentoColumnCellActionEvent = (rowDataItem, columnKey) => { action('transfer')(rowDataItem, columnKey); }; const deleteAction: BentoColumnCellActionEvent = (rowDataItem, columnKey) => { action('delete')(rowDataItem, columnKey); }; // --- Dynamic Cell Actions Function --- // This function generates actions based on the row's data. const getNameCellActions: BentoColumnCellActionsProp = rowDataItem => { const actions: Array<BentoColumnCellAction> = []; // Conditionally add the 'edit' action only for the first row. if (rowDataItem.id === DEFAULT_DATA[3].id) { actions.push({ variant: 'edit', event: editItem, tooltipText: 'Edit this name' }); } // Add a 'more' menu with dynamic options. actions.push({ variant: 'more', isShort: true, tooltipText: 'Additional actions', menuData: [ { text: 'Cancel payment', event: cancelAction, critical: true, }, { text: 'Transfer payment', event: transferAction, }, { text: 'Delete payment', event: deleteAction, // Example: disable delete for the second row. disabled: rowDataItem.id === DEFAULT_DATA[2].id, }, ], }); return actions; }; // --- Column Definitions --- const columns: Array<BentoColumn> = [ { field: 'name', label: 'Name (Dynamic Actions)', minWidth: 300, mandatory: true, // Use a function for dynamic cell actions cellActions: getNameCellActions, }, { field: 'company', label: 'Reference', autoWidth: true }, { field: 'payment', label: 'Payment (Static Actions)', minWidth: 350, // Use a static array for cell actions cellActions: [ { variant: 'copy', getCopyData: (rowDataItem: BentoDatagridDataItem, columnKey: string) => `${rowDataItem[columnKey]}`, }, { variant: 'open', event: action('open-payment'), tooltipText: 'Open payment details' }, ], }, ]; return { args: isVue2 ? props : _args, columns }; }, }), args: { ...DEFAULT_ARGS, highlightedRows: [DEFAULT_DATA[3].id], columns: [ { field: 'name', label: 'Name (Dynamic Actions)', minWidth: 300, mandatory: true, cellActions: [ () => (rowDataItem: BentoDatagridDataItem) => ({ variant: 'edit', disabled: rowDataItem.id === DEFAULT_DATA[3].id, event: action('edit'), tooltipText: 'Edit this name', }), { variant: 'open', tooltipText: 'Additional actions', menuData: [ { text: 'Cancel payment', event: action('cancel payment'), critical: true, }, { text: 'Transfer payment', event: action('transfer payment'), }, { text: 'Delete payment', event: action('delete payment'), disabled: true, }, ], }, ], }, { field: 'company', label: 'Reference', autoWidth: true }, { field: 'payment', label: 'Payment (Static Actions)', minWidth: 350, cellActions: [ { variant: 'copy', getCopyData: (rowDataItem: BentoDatagridDataItem, columnKey: string) => `$${rowDataItem[columnKey]}`, }, { variant: 'more', tooltipText: 'Additional actions', menuData: [ { text: 'Cancel payment', event: action('cancel payment'), critical: true, }, { text: 'Transfer payment', event: action('transfer payment'), }, { text: 'Delete payment', event: action('delete payment'), disabled: true, }, ], isShort: true, }, ], }, { field: 'custom', label: 'Custom template', minWidth: 200, cellActions: [{ variant: 'edit', event: action('edit'), tooltipText: 'Edit custom' }], }, ], }, parameters: storybookDocsParameter(DataGridCellActionsExample), }; // NestContentSlot const NestedContentSlotTemplateCode = ` <template> <bento-data-grid :data="data" :columns="columns" has-nested-content :should-show-nested-content="filterRowsThatShowNestedContent" > <template #nested-slot="{item}"> <bento-typography>Nested content for {{ item.company }}</bento-typography> </template> </bento-data-grid> </template> <script setup lang="ts"> import { BentoDataGrid, type BentoColumn, type BentoDatagridData, type BentoDatagridShouldShowNestedContent } from '@adyen/bento-vue2' const columns: BentoColumn = [ { field: 'name', label: 'Name', minWidth: 300, mandatory: true }, { field: 'payment', label: 'Payment', minWidth: 300, mandatory: true }, ] const data = ref<BentoDatagridData>([ { id: 1, name: 'First', payment: 20.9 }, { id: 2, name: 'Second', payment: 10.0 }, ]); const filterRowsThatShowNestedContent: BentoDatagridShouldShowNestedContent = (item) => item.id === 2; </script> `; export const NestedContentSlot: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid, BentoLink, BentoTypography, }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" > <template #nested-slot="{item}"> <div style="height: 80px; text-align: center; display: flex; align-items: center;"> <bento-typography>Nested content slot for {{ item.company }}</bento-typography> </div> </template> </bento-data-grid> `, setup(props) { return { args: isVue2 ? props : _args }; }, }), args: { ...DEFAULT_ARGS, hasNestedContent: true, zebraRows: true, shouldShowNestedContent: (item: BentoDatagridDataItem) => item.id !== DEFAULT_ARGS.data[1].id, }, parameters: storybookDocsParameter(NestedContentSlotTemplateCode), }; export const StickyHorizontalScrollbar: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid, BentoButton }, props: Object.keys(argTypes), setup(props) { const args = isVue2 ? props : _args; const filtersConfig = ref<BentoFilterBarModel>([ { field: 'col1', label: 'Column 1', type: BentoFilterItemType.INPUT, }, { field: 'col2', label: 'Column 2', type: BentoFilterItemType.INPUT, }, ]); const filterValues = ref(); const searchTerm = ref(''); const isCondensed = ref(args.condensed); const columns = ref( Array.from({ length: 20 }, (_, index) => ({ field: `col${index + 1}`, label: `Column ${index + 1}`, width: 200, mandatory: index === 0, })) ); const data = ref( Array.from({ length: 50 }, (_, rowIndex) => columns.value.reduce((acc, col, colIndex) => { acc[col.field] = `Row ${rowIndex + 1} - Col ${colIndex + 1}`; return acc; }, {}) ) ); const dataSet = computed(() => // If any filters or search terms have been set filterValues.value?.length === 0 && searchTerm.value === '' ? data.value : data.value.filter(item => { const foundFilteredItem = filterValues.value?.length > 0 ? filterValues.value.every(filter => filter.value ? (item[filter.field] as string) .toLowerCase() .includes((filter.value as string).toLowerCase()) : true ) : true; const foundSearchFilteredItem = searchTerm.value ? Object.keys(item).some(key => key ? (item[key] as string) .toLowerCase() .includes((searchTerm.value as string).toLowerCase()) : true ) : true; return foundFilteredItem && foundSearchFilteredItem; }) ); const onSearchCleared = action('search-clear'); const onSearchInput = action('search-input'); const onSearchTermUpdated = action('update:search-term'); return { // Values dataSet, filtersConfig, filterValues, searchTerm, columns, isCondensed, // Methods onSearchCleared, onSearchInput, onSearchTermUpdated, // Vue 3 storybook fix args, }; }, template: ` <bento-data-grid v-bind="args" :data="dataSet" :columns.sync="columns" :condensed.sync="isCondensed" :filters="filtersConfig" :filter-values.sync="filterValues" :filter-search-term.sync="searchTerm" @filter-search-clear="onSearchCleared" @filter-search-input="onSearchInput" @update:filter-search-term="onSearchTermUpdated" > <template #pagination-slot> <bento-button variant="tertiary"> Pagination slot button </bento-button> </template> </bento-data-grid> `, }), args: { ...DEFAULT_ARGS, pagination: { page: 1, hidePageSize: true }, columnPanel: true, stickyPagination: true, stickyFilters: true, stickyHorizontalScrollbar: true, }, }; const NestedRowsTemplateCode = ` <template> <bento-data-grid :data="data" :columns="columns" has-nested-rows :should-show-nested-row="filterRowsThatShowNestedContent" @nested-content-toggled="onParentRowToggle" /> </template> <script setup lang="ts"> import { BentoDataGrid, type BentoColumn, type BentoDatagridData, type BentoDatagridShouldShowNestedRowsFn } from '@adyen/bento-vue2' const columns: BentoColumn = [ { field: 'name', label: 'Name', minWidth: 300, mandatory: true }, { field: 'payment', label: 'Payment', minWidth: 300, mandatory: true }, ] const data = ref<BentoDatagridData>([ { id: 1, name: 'First', payment: 20.9 }, { id: 2, name: 'Second', payment: 10.0 }, ]); const filterRowsThatShowNestedRows: BentoDatagridShouldShowNestedRowsFn = (item) => item.id === 2; const onParentRowToggle = async (item: BentoDatagridDataItem) => { const childrenForToggledParentItem = await makeAPICallToGetChildren(item.id); dataState.value = dataState.value.map(itemToChange => { if (itemToChange.id === item.id) { return { ...itemToChange, children: childrenForToggledParentItem } } return itemToChange; }); }; </script> `; export const NestedRows: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid, BentoLink, BentoTypography, }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" :data="dataState" @nested-content-toggled="onParentRowToggle" /> `, setup(props) { const dataState = ref<Array<BentoDatagridDataItem>>(DEFAULT_ARGS.data); const selection = ref<BentoDatagridDataItemId>(); const onParentRowToggle = (item: BentoDatagridDataItem) => { setTimeout(() => { const children = [ { id: `03c0a799-1ced-4017-aea3-111111${item.id}`, name: `Child of ${item.name} #1`, payment: 160405, company: 'Merchant Helium', registered: '2023-06-30T13:56:09.498Z', tags: ['deserunt', 'et', 'esse'], reference: 'UnbQaUncf3eR1D8XUBqn_UnbQaUncf3eR1D8XUBqn_UnbQaUncf3eR1D8XUBqn', paymentStatus: 1, countryCode: BentoCountryCode.NL, parentId: DEFAULT_ARGS.data[1].id, }, { id: `03c0a799-1ced-4017-aea3-1111113${item.id}`, name: `Child of ${item.name} #2`, payment: 163500, company: 'Merchant B', registered: '2023-04-28T13:11:09.498Z', tags: ['et', 'Lorem', 'sint'], reference: 'IxUZ9FsEPCZ9dFFPpI9C', paymentStatus: 2, countryCode: BentoCountryCode.BE, parentId: DEFAULT_ARGS.data[1].id, }, { id: `03c0a799-1ced-4017-aea3-1111114${item.id}`, name: `Child of ${item.name} #3`, payment: 78500, company: 'Merchant C', registered: '2023-06-30T11:01:09.498Z', tags: ['laborum', 'enim', 'ullamco'], reference: 'y0qAQ0WDszRyqLY2WO9f', paymentStatus: 1, countryCode: BentoCountryCode.UA, parentId: DEFAULT_ARGS.data[1].id, }, ]; dataState.value = dataState.value.map(itemToChange => { if (itemToChange.id === item.id) { return { ...itemToChange, children, }; } return itemToChange; }); }, 1000); }; return { args: isVue2 ? props : _args, dataState, selection, onParentRowToggle }; }, }), args: { ...DEFAULT_ARGS, hasNestedRows: true, zebraRows: true, shouldShowNestedRows: dataItem => { return dataItem.id !== DEFAULT_ARGS.data[1].id; }, }, parameters: storybookDocsParameter(NestedRowsTemplateCode), }; export const RowActions: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" :row-actions="rowActions" /> `, setup(props) { const rowActions: BentoDataGridRowActionsProp = (item: BentoDatagridDataItem) => { if (item.id === DEFAULT_DATA[0].id) { return [ { variant: 'edit', event: action('edit'), tooltipText: 'Edit row' }, { title: 'Delete', critical: true, event: action('Delete'), tooltipText: 'Delete row', }, ]; } else if (item.id === DEFAULT_DATA[1].id) { return []; } else if (item.id === DEFAULT_DATA[2].id) { return [ { variant: 'edit', event: action('edit'), tooltipText: 'Edit row' }, { variant: 'open', isShort: true, tooltipText: 'More options', menuData: [ { text: 'Cancel payment', event: action('cancel payment'), critical: true, }, { text: 'Transfer payment', event: action('transfer payment'), }, { text: 'Delete payment', event: action('delete payment'), disabled: true, }, ], }, ]; } return [ { variant: 'edit', event: action('edit'), tooltipText: 'Edit row', }, ]; }; return { args: isVue2 ? props : _args, rowActions, }; }, }), args: { ...DEFAULT_ARGS, }, parameters: storybookDocsParameter(DataGridRowActionsExample), }; const SummaryCellTemplateCode = ` <template> <bento-data-grid :columns="columns" :data="dataSet" :filters="filtersConfig" :filter-values.sync="filterValues" :filter-search-term="searchTerm" :filter-search-config="searchConfig" @update:filter-values="filterValues = $event" @update:filter-search-term="searchTerm = $event" @filter-search-clear="onSearchCleared" > <template #item-company="{item}"> <bento-data-grid-summary-cell :label="\`\${item.company.length} merchants\`" :items="item.company" :search-term="companyColumnSearchTerm" /> </template> </bento-data-grid> </template> <script setup lang="ts"> import { BentoColumn, BentoDataGrid, BentoDataGridSummaryCell, BentoDatagridData, BentoFilterBarModel, BentoFilterBarSearchBarProps, BentoFilterItemType, BentoFilterValues, BentoCountryCode, } from '@adyen/bento-vue2'; import { computed, ref } from 'vue'; const columns: Array<BentoColumn> = [ { field: 'name', label: 'Name', flex: 2, mandatory: true }, { field: 'company', label: 'Company', flex: 1 }, { field: 'payment', label: 'Payment', flex: 1, minWidth: 200 }, ]; /** * Data set with array of companies */ const multiData: BentoDatagridData = [ { id: '03c0a799-1ced-4017-aea3-0cebb0106335', name: 'Shepherd Kane', payment: 160405, company: ['Merchant Helium', 'Merchant A'], }, { id: '8f9e7877-1ca2-4929-9217-f1ec78709291', name: 'Joyce Johns', payment: 78500, company: ['Merchant C', 'Merchant Hedra'], }, { id: '51d2b31d-d577-4fca-8329-a583babbbdda', name: 'Evans Zamora', payment: 1153.4, company: [ 'Merchant A', 'Merchant B', 'Merchant C', 'Merchant D', 'Merchant E', 'Merchant F', 'Merchant G', 'Merchant H', 'Merchant I', 'Merchant J', ], }, ]; const filtersConfig = computed<BentoFilterBarModel>(() => [ { field: 'name', label: 'Name', type: BentoFilterItemType.INPUT, }, { field: 'company', label: 'Company', type: BentoFilterItemType.INPUT, }, ]); /** * The values of applied filters. */ const filterValues = ref<BentoFilterValues>(); /** * The current global search term that is being searched with */ const searchTerm = ref(''); /** * Global search configuration */ const searchConfig = ref<BentoFilterBarSearchBarProps>({ inputFieldAriaLabel: 'Descriptive details about the search bar', debounceTime: 1000, // in ms placeholder: 'Find merchants', }); /** * Concatenated search term using the global search and the company filter value */ const companyColumnSearchTerm = computed( () => searchTerm.value || filterValues.value?.find(filter => filter.field === 'company')?.value?.toString() || '' ); /** * Simplified computed data set that filters data depending on applied filters and global search values */ const dataSet = computed<BentoDatagridData>(() => { let filteredData = multiData; // Apply global search term filter if (searchTerm.value) { const lowerCaseSearchTerm = searchTerm.value.toLowerCase(); filteredData = filteredData.filter( item => (item.name as string).toLowerCase().includes(lowerCaseSearchTerm) || (item.company as string[]).some(company => company.toLowerCase().includes(lowerCaseSearchTerm) ) ); } // Apply filterValues filter if (filterValues.value?.length) { filteredData = filteredData.filter(item => filterValues.value?.every(filter => { if (filter.field === 'company') { return filter.value ? (item[filter.field] as string[]).some(company => (company as string) .toLowerCase() .includes((filter.value as string).toLowerCase()) ) : true; } return filter.value ? (item[filter.field] as string) .toLowerCase() .includes((filter.value as string).toLowerCase()) : true; }) ); } return filteredData; }); const onSearchCleared = () => { searchTerm.value = ''; }; </script> `; export const SummaryCell: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid, BentoLink, BentoTypography, BentoDashedUnderline, BentoDataGridSummaryCell, }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" :data="dataSet" :filters="filtersConfig" :filter-values.sync="filterValues" :filter-search-term="searchTerm" :filter-search-config="searchConfig" @update:filter-values="filterValues = $event" @update:filter-search-term="searchTerm = $event" @filter-search-clear="onSearchCleared" > <template #item-company="{item}"> <bento-data-grid-summary-cell :label="\`\${item.company.length} merchants\`" :items="item.company" :search-term="companyColumnSearchTerm" /> </template> </bento-data-grid> `, setup(props) { /** * Data set with array of companies */ const multiData: BentoDatagridData = [ { id: '03c0a799-1ced-4017-aea3-0cebb0106335', name: 'Shepherd Kane', payment: 160405, company: ['Merchant Helium', 'Merchant A'], }, { id: 'b6d4f1fd-b1f6-40a6-a443-f785c89604ef', name: 'Santos Palmer', payment: 163500, company: ['Merchant B'], }, { id: '8f9e7877-1ca2-4929-9217-f1ec78709291', name: 'Joyce Johns', payment: 78500, company: ['Merchant C', 'Merchant Hedra'], }, { id: '0789a012-85a6-4657-87bb-319141938a61', name: 'Lynnette Melendez', payment: -45000, company: ['Merchant A', 'Merchant B', 'Merchant C'], }, { id: '0b3981b6-c73b-47ad-81d1-b06f9b95d467', name: 'Wagner Mcintosh', payment: 1112, company: ['Merchant A'], }, { id: '51d2b31d-d577-4fca-8329-a583babbbdda', name: 'Evans Zamora', payment: 1153.4, company: [ 'Merchant A', 'Merchant B', 'Merchant C', 'Merchant D', 'Merchant E', 'Merchant F', 'Merchant G', 'Merchant H', 'Merchant I', 'Merchant J', 'Merchant K', 'Merchant L', 'Merchant M', 'Merchant N', 'Merchant O', 'Merchant P', 'Merchant Q', 'Merchant R', 'Merchant S', 'Merchant T', ], }, { id: '9bd59a6e-bd03-4477-813f-b844953b7645', name: 'Anderson Middleton', payment: 181722.23, company: ['Merchant A'], }, ]; const filtersConfig = computed<BentoFilterBarModel>(() => [ { field: 'name', label: 'Name', type: BentoFilterItemType.INPUT, }, { field: 'company', label: 'Company', type: BentoFilterItemType.INPUT, }, ]); /** * The values of applied filters. */ const filterValues = ref<BentoFilterValues>(); /** * The current global search term that is being searched with */ const searchTerm = ref(''); /** * Global search configuration */ const searchConfig = ref<BentoFilterBarSearchBarProps>({ inputFieldAriaLabel: 'Descriptive details about the search bar', debounceTime: 1000, // in ms placeholder: 'Find merchants', }); /** * Concatenated search term using the global search and the company filter value */ const companyColumnSearchTerm = computed( () => searchTerm.value || filterValues.value?.find(filter => filter.field === 'company')?.value?.toString() || '' ); /** * Simplified computed data set that filters data depending on applied filters and global search values */ const dataSet = computed<BentoDatagridData>(() => { let filteredData = multiData; // Apply global search term filter if (searchTerm.value) { const lowerCaseSearchTerm = searchTerm.value.toLowerCase(); filteredData = filteredData.filter( item => (item.name as string).toLowerCase().includes(lowerCaseSearchTerm) || (item.company as Array<string>).some(company => company.toLowerCase().includes(lowerCaseSearchTerm) ) ); } // Apply filterValues filter if (filterValues.value?.length) { filteredData = filteredData.filter(item => filterValues.value?.every(filter => { if (filter.field === 'company') { return filter.value ? (item[filter.field] as Array<string>).some(company => (company as string) .toLowerCase() .includes((filter.value as string).toLowerCase()) ) : true; } return filter.value ? (item[filter.field] as string) .toLowerCase() .includes((filter.value as string).toLowerCase()) : true; }) ); } return filteredData; }); const onSearchCleared = () => { searchTerm.value = ''; }; return { args: isVue2 ? props : _args, filtersConfig, filterValues, searchTerm, searchConfig, onSearchCleared, dataSet, companyColumnSearchTerm, }; }, }), args: { ...DEFAULT_ARGS, columns: [ { field: 'name', label: 'Name', flex: 2, mandatory: true }, { field: 'company', label: 'Company', flex: 1 }, { field: 'payment', label: 'Payment', flex: 1, minWidth: 200 }, ], zebraRows: true, }, parameters: storybookDocsParameter(SummaryCellTemplateCode), }; export const TrendCell: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid, BentoDataGridTrendCell, }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args"> <template #item-performance="{ item }"> <bento-data-grid-trend-cell :value="item.performance.value" :direction="item.performance.direction" :variant="item.performance.variant" /> </template> </bento-data-grid> `, setup(props) { const columns: Array<BentoColumn> = [ { field: 'name', label: 'Name', flex: 2 }, { field: 'performance', label: 'Performance', flex: 1, numeric: true }, ]; const data: BentoDatagridData = [ { id: '1', name: 'Shepherd Kane', performance: { value: 25.5, variant: 'green', direction: 'up', }, }, { id: '2', name: 'Santos Palmer', performance: { value: 10.2, variant: 'red', direction: 'down', }, }, { id: '3', name: 'Joyce Johns', performance: { value: 0, variant: 'black', direction: 'none', }, }, { id: '4', name: 'Lynnette Melendez', performance: { value: '3.1428571429%', variant: 'green', direction: 'down', }, }, { id: '5', name: 'Wagner Mcintosh', performance: { value: '15.2%', variant: 'red', direction: 'up', }, }, { id: '6', name: 'Evans Zamora', performance: { value: '1.23', direction: 'up', }, }, { id: '7', name: 'Anderson Middleton', performance: { value: '90', direction: 'down', }, }, ]; return { args: { ...(isVue2 ? props : _args), columns, data }, }; }, }), args: { ...DEFAULT_ARGS, zebraRows: true, }, parameters: storybookDocsParameter(DataGridTrendCellExample), }; export const TagWithTextCell: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid, BentoDataGridTagWithTextCell, }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args"> <template #item-endpoint="{ item }"> <bento-data-grid-tag-with-text-cell :tag="item.endpoint.tag" :value="item.endpoint.value" /> </template> </bento-data-grid> `, setup(props) { const columns = [ { field: 'name', label: 'Name', flex: 2 }, { field: 'endpoint', label: 'Endpoint', flex: 2 }, ]; const data = [ { id: '1', name: 'Get users', endpoint: { tag: { label: 'GET', variant: 'blue' }, value: '/api/users', }, }, { id: '2', name: 'Create user', endpoint: { tag: { label: 'POST', variant: 'green' }, value: '/api/users', }, }, { id: '3', name: 'Update user', endpoint: { tag: { label: 'PUT', variant: 'yellow' }, value: '/api/users/:id', }, }, { id: '4', name: 'Delete user', endpoint: { tag: { label: 'DELETE', variant: 'red' }, value: '/api/users/:id', }, }, ]; return { args: { ...(isVue2 ? props : _args), columns, data }, }; }, }), args: { ...DEFAULT_ARGS, }, parameters: storybookDocsParameter(DataGridTagWithTextCellExample), };
1
+ import { type BentoColumn, BentoColumnOverflow, type BentoDatagridData, type BentoDatagridDataItem, type BentoDatagridDataItemId, BentoDatagridEvent, type BentoDatagridPaginationProps, type BentoDatagridSelection, type BentoDatagridSortByColumn, BentoDatagridSortDirection, } from './data-grid.types'; import { BentoCard } from '@/components/card'; import { action } from '@storybook/addon-actions'; import { type BentoFilterBarModel, type BentoFilterBarSearchBarProps, BentoFilterItemType, type BentoFilterValues, } from '../filter-bar'; import { BentoCurrency } from '@/components/currency'; import { BentoStatus, BentoStatusVariant } from '@/components/status'; import { BentoLink } from '@/components/link'; import { BentoTypography } from '@/components/typography'; import { computed, ref, watch } from 'vue'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import { BentoDate, BentoDateFormat } from '@/components/date'; import { BentoCountry, BentoCountryCode } from '@/components/country'; import type { Meta, StoryObj } from '@storybook/vue'; import BentoDataGrid from './data-grid.vue'; import { isVue2 } from 'vue-demi'; import { BentoButton } from '../button'; import { BentoDashedUnderline } from '../dashed-underline'; import { BentoDataGridSummaryCell, BentoDataGridTagWithTextCell, BentoDataGridTrendCell } from './components'; import type { BentoColumnCellAction, BentoColumnCellActionEvent, BentoColumnCellActionsProp, BentoDataGridRowActionsProp, } from './components/data-grid-cell-actions/data-grid-cell-actions.types'; // Examples const DataGridEverythingBagel = "<template>\n <bento-data-grid\n :data=\"filteredAndSortedData\"\n :columns=\"columns\"\n :condensed=\"isCondensed\"\n :filters=\"filtersConfig\"\n :filter-values=\"filterValues\"\n :filter-search-term=\"searchTerm\"\n :highlighted-rows=\"[DEFAULT_DATA[0].id, DEFAULT_DATA[4].id]\"\n :is-data-item-disabled=\"isDataItemDisabledForSelection\"\n :sort-by=\"sortBy\"\n :selection=\"selection\"\n :row-actions=\"rowActions\"\n allow-row-clicks\n allow-column-drag-and-drop\n column-panel\n selectable\n zebra-rows\n @update:sort-by=\"sortBy = $event\"\n @update:columns=\"columns = $event\"\n @update:filter-values=\"filterValues = $event\"\n @update:condensed=\"isCondensed = $event\"\n @update:selection=\"selection = $event\"\n @update:filter-search-term=\"searchTerm = $event\"\n @row-click=\"onRowClick\"\n >\n <template #item-paymentStatus=\"{ item }\">\n <div style=\"display: flex\">\n <bento-status :variant=\"getPaymentStatus(item.paymentStatus)\" />\n <span>{{ getPaymentText(item.paymentStatus) }}</span>\n </div>\n </template>\n <template #item-reference=\"{ item }\">\n <bento-link is-not-routing to=\"https://www.adyen.com\" :title=\"item.reference\">\n {{ item.reference }}\n </bento-link>\n </template>\n <template #item-countryCode=\"{ item }\">\n <bento-country :code=\"item.countryCode\" />\n </template>\n <template #item-payment=\"{ item }\">\n <bento-currency currency=\"EUR\" :value=\"item.payment\" />\n </template>\n <template #item-date=\"{ item }\">\n <bento-date :date=\"new Date(item.registered)\" :format=\"BentoDateFormat.FULL_DATE_TIME_WITH_PERIOD\" />\n </template>\n </bento-data-grid>\n</template>\n\n<script setup lang=\"ts\">\n import {\n type BentoColumn,\n BentoColumnOverflow,\n BentoCountry,\n BentoCountryCode,\n BentoCurrency,\n BentoDataGrid,\n type BentoDatagridDataItem,\n type BentoDatagridSelection,\n type BentoDatagridSortByColumn,\n BentoDatagridSortDirection,\n BentoDate,\n BentoDateFormat,\n type BentoFilterBarModel,\n BentoFilterItemType,\n type BentoFilterValues,\n BentoLink,\n BentoStatus,\n BentoStatusVariant,\n } from '@adyen/bento-vue2';\n import { computed, ref } from 'vue';\n import { DEFAULT_DATA } from './data-grid-example-data';\n\n const columns = ref<Array<BentoColumn>>([\n {\n field: 'company',\n label: 'Company',\n sortable: true,\n mandatory: true,\n autoWidth: true,\n frozen: true,\n minWidth: 200,\n },\n { field: 'paymentStatus', label: 'Status', width: 180, infoIconTooltip: 'For current day' },\n {\n field: 'reference',\n label: 'Reference',\n width: 320,\n overflow: BentoColumnOverflow.ELLIPSIS,\n },\n { field: 'countryCode', label: 'Country/Region', width: 320 },\n { field: 'payment', label: 'Payment', width: 180, numeric: true },\n { field: 'date', label: 'Execution Date', width: 200 },\n ]);\n const filtersConfig = ref<BentoFilterBarModel>([\n {\n field: 'company',\n label: 'Company',\n type: BentoFilterItemType.INPUT,\n },\n {\n field: 'countryCode',\n label: 'Country/Region',\n options: {\n listboxItems: [\n {\n value: BentoCountryCode.NL,\n },\n {\n value: BentoCountryCode.BE,\n },\n ],\n variant: 'name',\n },\n type: BentoFilterItemType.SELECT_COUNTRY,\n },\n ]);\n const filterValues = ref<BentoFilterValues>([]);\n const sortBy = ref<Array<BentoDatagridSortByColumn>>([]);\n const searchTerm = ref('');\n const isCondensed = ref(false);\n\n const getPaymentStatus = (paymentStatus: number) => {\n switch (paymentStatus) {\n case 2:\n return BentoStatusVariant.GREEN;\n case 1:\n return BentoStatusVariant.YELLOW;\n case 0:\n default:\n return BentoStatusVariant.RED;\n }\n };\n\n const getPaymentText = (paymentStatus: number) => {\n switch (paymentStatus) {\n case 2:\n return 'Paid';\n case 1:\n return 'In progress';\n case 0:\n default:\n return 'Not paid';\n }\n };\n\n // Selection\n const isDataItemDisabledForSelection = (row: BentoDatagridDataItem) => row.id === DEFAULT_DATA[3].id;\n const selection = ref<BentoDatagridSelection>([DEFAULT_DATA[1].id]);\n\n // Filtering\n const filteredData = computed(() =>\n // If any filters or search terms have been set\n filterValues.value?.length === 0 && searchTerm.value === ''\n ? DEFAULT_DATA\n : DEFAULT_DATA.filter(item => {\n const foundFilteredItem =\n filterValues.value?.length > 0\n ? filterValues.value.every(filter =>\n filter.value\n ? (item[filter.field] as string)\n .toLowerCase()\n .includes((filter.value as string).toLowerCase())\n : true\n )\n : true;\n const foundSearchFilteredItem = searchTerm.value\n ? (item?.company as string).toLowerCase().includes((searchTerm.value as string).toLowerCase())\n : true;\n\n return foundFilteredItem && foundSearchFilteredItem;\n })\n );\n\n const filteredAndSortedData = computed(() => {\n if (sortBy.value?.length === 0) {\n return filteredData.value;\n }\n const sorted = [...filteredData.value].sort((a, b) =>\n (a[sortBy.value[0].field] as string).localeCompare(b[sortBy.value[0].field] as string)\n );\n return sortBy.value[0].direction === BentoDatagridSortDirection.ASCENDING ? sorted : sorted.reverse();\n });\n\n const onRowClick = () => true;\n\n const rowActions: InstanceType<typeof BentoDataGrid>['$props']['rowActions'] = (item: BentoDatagridDataItem) => {\n if (item.id === DEFAULT_DATA[3].id) {\n return [\n {\n variant: 'edit',\n event: () => true,\n tooltipText: 'Edit payment',\n },\n ];\n } else if (item.id === DEFAULT_DATA[2].id) {\n return [\n { variant: 'edit', event: () => true, tooltipText: 'Edit payment' },\n {\n variant: 'open',\n isShort: true,\n menuData: [\n {\n text: 'Cancel payment',\n event: () => true,\n critical: true,\n },\n {\n text: 'Transfer payment',\n event: () => true,\n },\n {\n text: 'Delete payment',\n event: () => true,\n disabled: true,\n },\n ],\n },\n ];\n } else if (item.id === DEFAULT_DATA[1].id) {\n return [];\n }\n return [\n {\n variant: 'edit',\n event: () => true,\n tooltipText: 'Edit payment',\n },\n {\n title: 'Delete',\n critical: true,\n event: () => true,\n tooltipText: 'Delete payment',\n },\n ];\n };\n</script>\n"; const DataGridCellActionsExample = "<template>\n <bento-data-grid :data=\"data\" :columns=\"columns\" />\n</template>\n\n<script setup lang=\"ts\">\n /* eslint-disable no-console */\n import {\n type BentoColumn,\n type BentoColumnCellAction,\n type BentoColumnCellActionsProp,\n BentoDataGrid,\n type BentoDatagridDataItem,\n } from '@adyen/bento-vue2';\n import { ref } from 'vue';\n import { DEFAULT_DATA } from './data-grid-example-data';\n\n // --- Action Handlers ---\n const editItem = (rowDataItem, columnKey) => {\n console.log('Edit', rowDataItem, columnKey);\n };\n\n const cancelAction = (rowDataItem, columnKey) => {\n console.log('cancel', rowDataItem, columnKey);\n };\n\n const transferAction = (rowDataItem, columnKey) => {\n console.log('transfer', rowDataItem, columnKey);\n };\n\n const deleteAction = (rowDataItem, columnKey) => {\n console.log('delete', rowDataItem, columnKey);\n };\n\n const openAction = (rowDataItem, columnKey) => {\n console.log('open', rowDataItem, columnKey);\n };\n\n // --- Dynamic Cell Actions Function ---\n const getNameCellActions: BentoColumnCellActionsProp = (rowDataItem: BentoDatagridDataItem) => {\n const actions: Array<BentoColumnCellAction> = [];\n\n // Conditionally add the 'edit' action only for the first row.\n if (rowDataItem.id === DEFAULT_DATA[3].id) {\n actions.push({\n variant: 'edit',\n event: editItem,\n tooltipText: 'Edit this name',\n });\n }\n\n // Add a 'more' menu with dynamic options.\n actions.push({\n variant: 'more',\n isShort: true,\n tooltipText: 'Additional actions',\n menuData: [\n {\n text: 'Cancel payment',\n event: cancelAction,\n critical: true,\n },\n {\n text: 'Transfer payment',\n event: transferAction,\n },\n {\n text: 'Delete payment',\n event: deleteAction,\n // Example: disable delete for the second row.\n disabled: rowDataItem.id === DEFAULT_DATA[1].id,\n },\n ],\n });\n\n return actions;\n };\n\n // --- Column Definitions ---\n const columns = ref<Array<BentoColumn>>([\n {\n field: 'name',\n label: 'Name (Dynamic Actions)',\n minWidth: 300,\n mandatory: true,\n cellActions: getNameCellActions,\n },\n { field: 'company', label: 'Reference', autoWidth: true },\n {\n field: 'payment',\n label: 'Payment (Static Actions)',\n minWidth: 350,\n cellActions: [\n {\n variant: 'copy',\n getCopyData: (rowDataItem: BentoDatagridDataItem, columnKey: string) => `${rowDataItem[columnKey]}`,\n },\n {\n variant: 'open',\n event: openAction,\n tooltipText: 'Open payment details',\n },\n ],\n },\n ]);\n\n // --- Data ---\n const data = ref(DEFAULT_DATA);\n</script>\n"; const DataGridDefaultExample = "<template>\n <bento-data-grid :columns=\"columns\" :data=\"data\" />\n</template>\n\n<script setup lang=\"ts\">\n import { type BentoColumn, BentoDataGrid, type BentoDatagridData } from '@adyen/bento-vue2';\n\n const data: BentoDatagridData = [\n { id: 1, name: 'Shepherd Kane', company: 'Merchant Helium', payment: 160405 },\n { id: 2, name: 'Santos Palmer', company: 'Merchant B', payment: 163500 },\n ];\n const columns: Array<BentoColumn> = [\n { field: 'name', label: 'Name', minWidth: 300, mandatory: true },\n { field: 'company', label: 'Reference' },\n { field: 'payment', label: 'Payment', width: 200, minWidth: 150 },\n ];\n</script>\n"; const DataGridDisplayOptionsExample = "<template>\n <bento-data-grid\n column-panel\n :columns=\"columns\"\n :condensed=\"condensed\"\n :data=\"data\"\n @update:columns=\"columns = $event\"\n @update:condensed=\"condensed = $event\"\n >\n <template #item-date=\"{ item }\">\n <bento-date :date=\"new Date(item.date)\" :format=\"BentoDateFormat.FULL_DATE_TIME_WITH_PERIOD\" />\n </template>\n </bento-data-grid>\n</template>\n\n<script setup lang=\"ts\">\n import { type BentoColumn, BentoDataGrid, BentoDate, BentoDateFormat } from '@adyen/bento-vue2';\n import { ref } from 'vue';\n\n const data = [{ id: 1, name: 'Shepherd Kane', company: 'Merchant Helium', date: '2024-01-01T12:00:00Z' }];\n const columns = ref<Array<BentoColumn>>([\n { field: 'name', label: 'Name', minWidth: 200, mandatory: true },\n { field: 'company', label: 'Company', minWidth: 150, frozen: true },\n { field: 'date', label: 'Execution Date', width: 300 },\n ]);\n const condensed = ref(false);\n</script>\n"; const DataGridFluidExample = "<template>\n <bento-data-grid :columns=\"columns\" :data=\"data\" :row-actions=\"rowActions\" />\n</template>\n\n<script setup lang=\"ts\">\n import {\n type BentoColumn,\n BentoDataGrid,\n type BentoDatagridData,\n type BentoDataGridRowActionsProp,\n } from '@adyen/bento-vue2';\n\n const data: BentoDatagridData = [\n { id: 1, name: 'Shepherd Kane', company: 'Merchant Helium', payment: 160405 },\n { id: 2, name: 'Santos Palmer', company: 'Merchant B', payment: 163500 },\n ];\n const columns: Array<BentoColumn> = [\n { field: 'name', label: 'Name', flex: 2, mandatory: true },\n { field: 'company', label: 'Company', flex: 1 },\n { field: 'payment', label: 'Payment', flex: 1, minWidth: 200 },\n ];\n const rowActions: BentoDataGridRowActionsProp = () => [\n { variant: 'edit', event: () => undefined },\n { title: 'Delete', critical: true, event: () => undefined },\n ];\n</script>\n"; const DataGridRowActionsExample = "<template>\n <bento-data-grid :data=\"data\" :columns=\"columns\" :row-actions=\"getRowActions\" />\n</template>\n\n<script setup lang=\"ts\">\n /* eslint-disable no-console */\n import { ref } from 'vue';\n import {\n type BentoColumn,\n BentoDataGrid,\n type BentoDatagridDataItem,\n type BentoDataGridRowActionsProp,\n } from '@adyen/bento-vue2';\n import { DEFAULT_DATA } from './data-grid-example-data';\n\n const data = ref(DEFAULT_DATA);\n\n const columns: Array<BentoColumn> = [\n { field: 'name', label: 'Name', minWidth: 300, mandatory: true },\n { field: 'company', label: 'Company', autoWidth: true },\n { field: 'payment', label: 'Payment', minWidth: 350 },\n ];\n\n const getRowActions: BentoDataGridRowActionsProp = (item: BentoDatagridDataItem) => {\n if (item.id === DEFAULT_DATA[0].id) {\n return [\n {\n variant: 'edit',\n event: (rowData: BentoDatagridDataItem) => console.log('Editing', rowData),\n tooltipText: 'Edit row',\n },\n {\n title: 'Delete',\n critical: true,\n event: (rowData: BentoDatagridDataItem) => console.log('Deleting', rowData),\n tooltipText: 'Delete row',\n },\n ];\n }\n if (item.id === DEFAULT_DATA[1].id) {\n return [];\n }\n if (item.id === DEFAULT_DATA[2].id) {\n return [\n {\n variant: 'edit',\n event: (rowData: BentoDatagridDataItem) => console.log('Editing', rowData),\n tooltipText: 'Edit row',\n },\n {\n variant: 'open',\n isShort: true,\n tooltipText: 'More options',\n menuData: [\n {\n text: 'Cancel payment',\n event: (rowData: BentoDatagridDataItem) => console.log('Cancel', rowData),\n critical: true,\n },\n {\n text: 'Transfer payment',\n event: (rowData: BentoDatagridDataItem) => console.log('Transfer', rowData),\n },\n {\n text: 'Delete payment',\n event: (rowData: BentoDatagridDataItem) => console.log('Delete', rowData),\n disabled: true,\n },\n ],\n },\n ];\n }\n return [\n {\n variant: 'edit',\n event: (rowData: BentoDatagridDataItem) => console.log('Editing', rowData),\n tooltipText: 'Edit row',\n },\n ];\n };\n</script>\n"; const DataGridFitContentInCardExample = "<template>\n <div style=\"max-width: 500px\">\n <bento-card>\n Data grid inside card\n <template #content>\n <div style=\"height: 300px\">\n <bento-data-grid\n :columns=\"columns\"\n :pagination=\"pagination\"\n :data=\"data\"\n condensed\n fit-content\n outline\n />\n </div>\n </template>\n </bento-card>\n </div>\n</template>\n<script setup lang=\"ts\">\n import { computed, ref } from 'vue';\n import { BentoCard, type BentoColumn, BentoDataGrid } from '@adyen/bento-vue2';\n\n const columns = computed<Array<BentoColumn>>(() => [\n { field: 'name', label: 'Name', minWidth: 200, mandatory: true },\n { field: 'company', label: 'Company', minWidth: 150 },\n { field: 'payment', label: 'Payment', width: 200, minWidth: 150 },\n ]);\n\n const data = ref([\n { id: '1', name: 'Shepherd Kane', payment: 1604, company: 'VURBO' },\n { id: '2', name: 'Santos Palmer', payment: 1635, company: 'POLARAX' },\n { id: '3', name: 'Joyce Johns', payment: 785, company: 'ZENTIA' },\n { id: '4', name: 'Lynnette Melendez', payment: 450, company: 'STRALOY' },\n ]);\n\n const pagination = ref({ hasNext: true, size: 20, page: 1, description: 'datagrid navigation' });\n</script>\n"; const DataGridWithSlotsExample = "<template>\n <bento-data-grid :data=\"data\" :columns=\"columns\">\n <template #header>\n <bento-typography variant=\"title\" el=\"h2\">Users</bento-typography>\n </template>\n\n <!-- Header: Name -->\n <template #head-name=\"{ column }\">\n <bento-typography variant=\"caption\">\n {{ column.label }}\n </bento-typography>\n </template>\n\n <!-- Column: Name -->\n <template #item-name=\"{ item }\">\n <bento-typography variant=\"body\">\n {{ item.name }}\n </bento-typography>\n\n <template v-if=\"item.company === 'Company A'\">\n <div style=\"display: inline-flex; gap: 4px\">\n <bento-typography\n v-for=\"itemTag in item.tags\"\n :key=\"itemTag\"\n variant=\"caption\"\n :style=\"{ color: 'var(--b-color-label-secondary)' }\"\n >\n { {{ itemTag }} }\n </bento-typography>\n </div>\n </template>\n </template>\n\n <!-- Column: Company -->\n <template #item-company=\"{ item }\">\n <bento-link to=\"/to/company/path\" :title=\"item.company\">\n {{ item.company }}\n </bento-link>\n <bento-typography\n v-if=\"item.company === 'Company B'\"\n variant=\"caption\"\n :style=\"{ color: 'var(--b-color-label-secondary)' }\"\n >\n {{ item.registered }}\n </bento-typography>\n </template>\n\n <!-- Column: Payment -->\n <template #item-payment=\"{ item }\">$ {{ item.payment }}</template>\n\n <template #footer>\n <bento-typography variant=\"caption\">Custom footer</bento-typography>\n </template>\n </bento-data-grid>\n</template>\n\n<script setup lang=\"ts\">\n import {\n type BentoColumn,\n BentoDataGrid,\n type BentoDatagridData,\n BentoLink,\n BentoTypography,\n } from '@adyen/bento-vue2';\n import { ref } from 'vue';\n\n const columns: Array<BentoColumn> = [\n { field: 'name', label: 'Name', minWidth: 300, mandatory: true },\n { field: 'company', label: 'Company', minWidth: 300, mandatory: true },\n { field: 'payment', label: 'Payment', minWidth: 300, mandatory: true },\n ];\n\n const data = ref<BentoDatagridData>([\n { id: 1, name: 'First', company: 'Company A', tags: ['Tag 1', 'Tag 2'], payment: 20.9 },\n { id: 2, name: 'Second', company: 'Company B', tags: ['Tag 3', 'Tag 4'], payment: 10.0 },\n ]);\n</script>\n"; const DataGridFilteringExample = "<template>\n <bento-data-grid\n :columns=\"columns\"\n :data=\"filteredData\"\n :empty-state=\"emptyState\"\n :filters=\"filtersConfig\"\n :filter-values=\"filterValues\"\n :filter-search-term=\"searchTerm\"\n :filter-search-config=\"searchConfig\"\n @update:filter-values=\"filterValues = $event\"\n @update:filter-search-term=\"searchTerm = $event\"\n @filter-search-clear=\"onSearchClear\"\n @filter-search-input=\"onSearchInput\"\n />\n</template>\n\n<script setup lang=\"ts\">\n import {\n type BentoColumn,\n BentoDataGrid,\n type BentoDatagridData,\n type BentoDatagridDataItem,\n type BentoFilterBarModel,\n type BentoFilterBarSearchBarProps,\n BentoFilterItemType,\n type BentoFilterValues,\n } from '@adyen/bento-vue2';\n import { computed, ref } from 'vue';\n\n const data: BentoDatagridData = [\n {\n id: '03c0a799-1ced-4017-aea3-0cebb0106335',\n name: 'Shepherd Kane',\n payment: 160405,\n company: 'Merchant Helium',\n },\n {\n id: 'b6d4f1fd-b1f6-40a6-a443-f785c89604ef',\n name: 'Santos Palmer',\n payment: 163500,\n company: 'Merchant B',\n },\n {\n id: '8f9e7877-1ca2-4929-9217-f1ec78709291',\n name: 'Joyce Johns',\n payment: 78500,\n company: 'Merchant C',\n },\n {\n id: '0789a012-85a6-4657-87bb-319141938a61',\n name: 'Lynnette Melendez',\n payment: -45000,\n company: 'STRALOY',\n },\n {\n id: '0b3981b6-c73b-47ad-81d1-b06f9b95d467',\n name: 'Wagner Mcintosh',\n payment: 1112,\n company: 'Merchant A',\n },\n {\n id: '51d2b31d-d577-4fca-8329-a583babbbdda',\n name: 'Evans Zamora',\n payment: 1153.4,\n company: 'GEEKWAGON',\n },\n {\n id: '9bd59a6e-bd03-4477-813f-b844953b7645',\n name: 'Anderson Middleton',\n payment: 181722.23,\n company: 'BALOOBA',\n },\n ];\n\n const columns: Array<BentoColumn> = [\n { field: 'name', label: 'Name', minWidth: 300, mandatory: true },\n { field: 'company', label: 'Company', autoWidth: true },\n { field: 'payment', label: 'Payment', minWidth: 350 },\n ];\n\n const filtersConfig = ref<BentoFilterBarModel>([\n {\n field: 'name',\n label: 'Name',\n type: BentoFilterItemType.INPUT,\n },\n {\n field: 'company',\n label: 'Company',\n type: BentoFilterItemType.INPUT,\n },\n ]);\n\n const filterValues = ref<BentoFilterValues>([]);\n const searchTerm = ref('');\n\n const searchConfig = ref<BentoFilterBarSearchBarProps>({\n inputFieldAriaLabel: 'Search for items',\n placeholder: 'Placeholder',\n hint: 'Hint',\n });\n\n const clearFilters = () => {\n filterValues.value = [];\n searchTerm.value = '';\n };\n\n const emptyState = {\n title: 'No results were found',\n image: 'no-results-found',\n variant: 'embedded',\n action: {\n title: 'Clear filters',\n event: clearFilters,\n },\n description: 'Try a different term or reset search filters',\n };\n\n const filteredData = computed<BentoDatagridData>(() => {\n let internalData = data;\n\n if (searchTerm.value) {\n const lowerCaseSearchTerm = searchTerm.value.toLowerCase();\n const searchableFields = columns.map(column => column.field);\n\n internalData = internalData.filter((item: BentoDatagridDataItem) => {\n return searchableFields.some(field => {\n const value = String(item[field]);\n return value.toLowerCase().includes(lowerCaseSearchTerm);\n });\n });\n }\n\n internalData = internalData.filter(item =>\n filterValues.value?.every(filter => {\n return filter.value\n ? String(item[filter.field]).toLowerCase().includes(String(filter.value).toLowerCase())\n : true;\n })\n );\n return internalData;\n });\n\n const onSearchClear = () => {\n searchTerm.value = '';\n };\n\n const onSearchInput = () => {\n // perform an action when user types on search input\n };\n</script>\n"; const DataGridLazyLoadingExample = "<template>\n <div style=\"height: 300px\">\n <bento-data-grid\n :columns=\"columns\"\n :data=\"data\"\n lazy-load-type=\"automatic\"\n :loading=\"loading\"\n @update:show-more=\"loadMore\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { type BentoColumn, BentoDataGrid } from '@adyen/bento-vue2';\n import { ref } from 'vue';\n\n const columns: Array<BentoColumn> = [\n { field: 'name', label: 'Name', minWidth: 300, mandatory: true },\n { field: 'company', label: 'Reference' },\n ];\n const data = ref([{ id: 1, name: 'Shepherd Kane', company: 'Merchant Helium' }]);\n const loading = ref(false);\n const loadMore = () => {\n loading.value = true;\n setTimeout(() => {\n data.value.push({ id: 2, name: 'Santos Palmer', company: 'Merchant B' });\n loading.value = false;\n }, 500);\n };\n</script>\n"; const DataGridNestedContentExample = "<template>\n <bento-data-grid\n :columns=\"columns\"\n :data=\"data\"\n has-nested-content\n :should-show-nested-content=\"shouldShowNestedContent\"\n >\n <template #nested-slot=\"{ item }\">\n <bento-typography>Nested content for {{ item.company }}</bento-typography>\n </template>\n </bento-data-grid>\n</template>\n\n<script setup lang=\"ts\">\n import {\n type BentoColumn,\n BentoDataGrid,\n type BentoDatagridData,\n type BentoDatagridDataItem,\n BentoTypography,\n } from '@adyen/bento-vue2';\n\n const columns: Array<BentoColumn> = [\n { field: 'name', label: 'Name', minWidth: 300, mandatory: true },\n { field: 'payment', label: 'Payment', minWidth: 300 },\n ];\n const data: BentoDatagridData = [\n { id: 1, name: 'First', company: 'Merchant A', payment: 20.9 },\n { id: 2, name: 'Second', company: 'Merchant B', payment: 10 },\n ];\n const shouldShowNestedContent = (item: BentoDatagridDataItem) => item.id === 2;\n</script>\n"; const DataGridNestedRowsExample = "<template>\n <bento-data-grid\n :columns=\"columns\"\n :data=\"data\"\n has-nested-rows\n :should-show-nested-rows=\"shouldShowNestedRows\"\n @nested-content-toggled=\"loadChildren\"\n />\n</template>\n\n<script setup lang=\"ts\">\n import { type BentoColumn, BentoDataGrid, type BentoDatagridDataItem } from '@adyen/bento-vue2';\n import { ref } from 'vue';\n\n const columns: Array<BentoColumn> = [\n { field: 'name', label: 'Name', minWidth: 300, mandatory: true },\n { field: 'payment', label: 'Payment', minWidth: 300 },\n ];\n const data = ref<Array<BentoDatagridDataItem>>([\n { id: 1, name: 'First', payment: 20.9 },\n { id: 2, name: 'Second', payment: 10 },\n ]);\n const shouldShowNestedRows = (item: BentoDatagridDataItem) => item.id === 2;\n const loadChildren = (item: BentoDatagridDataItem) => {\n data.value = data.value.map(row =>\n row.id === item.id\n ? { ...row, children: [{ id: `${item.id}-1`, name: `Child of ${item.name}`, payment: 5 }] }\n : row\n );\n };\n</script>\n"; const DataGridNoResultsExample = "<template>\n <bento-data-grid :columns=\"columns\" :data=\"[]\" :empty-state=\"emptyState\" />\n</template>\n\n<script setup lang=\"ts\">\n import { type BentoColumn, BentoDataGrid } from '@adyen/bento-vue2';\n\n const columns: Array<BentoColumn> = [\n { field: 'name', label: 'Name', minWidth: 300, mandatory: true },\n { field: 'company', label: 'Reference' },\n { field: 'payment', label: 'Payment', width: 200, minWidth: 150 },\n ];\n const emptyState = {\n title: 'No results were found',\n image: 'no-results-found',\n variant: 'embedded',\n action: {\n title: 'Clear filters',\n event: () => undefined,\n },\n description: 'Try a different term or reset search filters',\n };\n</script>\n"; const DataGridPaginationExample = "<template>\n <bento-data-grid\n :columns=\"columns\"\n :data=\"pagedData\"\n :pagination=\"pagination\"\n @update:pagination=\"pagination = $event\"\n />\n</template>\n\n<script setup lang=\"ts\">\n import { type BentoColumn, BentoDataGrid, type BentoDatagridPaginationProps } from '@adyen/bento-vue2';\n import { computed, ref } from 'vue';\n\n const data = Array.from({ length: 12 }, (_, index) => ({\n id: index + 1,\n name: `Merchant ${index + 1}`,\n }));\n const columns: Array<BentoColumn> = [{ field: 'name', label: 'Name', mandatory: true }];\n const pagination = ref<BentoDatagridPaginationProps>({\n hasNext: true,\n page: 1,\n size: 10,\n totalCount: data.length,\n });\n const pagedData = computed(() => {\n const start = (pagination.value.page - 1) * pagination.value.size;\n return data.slice(start, start + pagination.value.size);\n });\n</script>\n"; const DataGridSelectionExample = "<template>\n <bento-data-grid\n :columns=\"columns\"\n :data=\"pagedData\"\n :empty-state=\"emptyState\"\n selectable\n selectable-across-pages\n :pagination=\"pagination\"\n :filters=\"filtersConfig\"\n :filter-values=\"filterValues\"\n :filter-search-term=\"searchTerm\"\n :selection=\"selection\"\n :is-data-item-disabled=\"isDataItemDisabled\"\n :bulk-actions=\"bulkActions\"\n @update:pagination=\"pagination = $event\"\n @update:filter-values=\"filterValues = $event\"\n @update:filter-search-term=\"searchTerm = $event\"\n @select-all-across-pages=\"onSelectAllAcrossPages\"\n @select-all-current-results=\"onSelectAllInCurrentResults\"\n @deselect-all-current-results=\"onDeselectAllInCurrentResults\"\n @filter-search-clear=\"onSearchCleared\"\n @update:selection=\"onSelect\"\n />\n</template>\n\n<script setup lang=\"ts\">\n import {\n type BentoColumn,\n BentoDataGrid,\n type BentoDatagridData,\n type BentoDatagridDataItem,\n type BentoDatagridPaginationProps,\n type BentoFilterBarModel,\n BentoFilterItemType,\n type BentoFilterValues,\n } from '@adyen/bento-vue2';\n import { computed, ref, watch } from 'vue';\n\n const selection = ref([]);\n const filterValues = ref<BentoFilterValues>([]);\n const searchTerm = ref('');\n\n const data = ref(\n Array.from({ length: 20 }, (_, i) => ({\n id: `id-${i + 1}`,\n name: `Name ${i + 1}`,\n payment: (i + 1) * 100,\n company: `Merchant ${i + 1}`,\n }))\n );\n\n const columns: Array<BentoColumn> = [\n { field: 'name', label: 'Name', minWidth: 300, mandatory: true },\n { field: 'company', label: 'Company', autoWidth: true },\n { field: 'payment', label: 'Payment', minWidth: 350 },\n ];\n\n const filtersConfig = ref<BentoFilterBarModel>([\n {\n field: 'name',\n label: 'Name',\n type: BentoFilterItemType.INPUT,\n },\n {\n field: 'company',\n label: 'Company',\n type: BentoFilterItemType.INPUT,\n },\n ]);\n\n const pagination = ref<BentoDatagridPaginationProps>({\n page: 1,\n size: 10,\n totalCount: 20,\n hasNext: true,\n });\n\n const bulkActions = [\n {\n title: 'Edit',\n event: () => true,\n },\n {\n title: 'Delete',\n critical: true,\n event: () => true,\n },\n ];\n\n const clearFilters = () => {\n filterValues.value = [];\n };\n\n const isDataItemDisabled = (row: BentoDatagridDataItem) => {\n return row.id === data.value[3].id;\n };\n\n const emptyState = {\n title: 'No results were found',\n image: 'no-results-found',\n variant: 'embedded',\n action: {\n title: 'Clear filters',\n event: clearFilters,\n },\n description: 'Try a different term or reset search filters',\n };\n\n const filteredData = computed<BentoDatagridData>(() => {\n let internalData = data.value;\n\n if (searchTerm.value) {\n const lowerCaseSearchTerm = searchTerm.value.toLowerCase();\n const searchableFields = columns.map(column => column.field);\n\n internalData = internalData.filter((item: BentoDatagridDataItem) => {\n return searchableFields.some(field => {\n const value = String(item[field]);\n return value.toLowerCase().includes(lowerCaseSearchTerm);\n });\n });\n }\n return internalData.filter(item =>\n filterValues.value.every(filter =>\n filter.value\n ? String(item[filter.field]).toLowerCase().includes(String(filter.value).toLowerCase())\n : true\n )\n );\n });\n\n const pagedData = computed<BentoDatagridData>(() => {\n return filteredData.value.slice(\n (pagination.value.page - 1) * pagination.value.size,\n pagination.value.page * pagination.value.size\n );\n });\n\n const enabledIds = computed(() => data.value.filter(item => !isDataItemDisabled(item)).map(x => x.id));\n\n const enabledFilteredIds = computed(() =>\n filteredData.value.filter(item => !isDataItemDisabled(item)).map(x => x.id)\n );\n\n const onSelect = (value: Array<string | number>) => {\n selection.value = value;\n };\n\n const onSelectAllAcrossPages = () => {\n selection.value = enabledIds.value;\n };\n\n const onSelectAllInCurrentResults = () => {\n selection.value = [...new Set([...selection.value, ...enabledFilteredIds.value])];\n };\n\n const onDeselectAllInCurrentResults = () => {\n selection.value = selection.value.filter(item => !enabledFilteredIds.value.includes(item));\n };\n\n const onSearchCleared = () => (searchTerm.value = '');\n\n watch(\n filteredData,\n () => {\n pagination.value.totalCount = filteredData.value.length;\n },\n { immediate: true }\n );\n</script>\n"; const DataGridSortingExample = "<template>\n <bento-data-grid\n :columns=\"columns\"\n :data=\"sortedData\"\n :sort-by=\"sortBy\"\n @sort=\"sort\"\n @update:sort-by=\"sortBy = $event\"\n />\n</template>\n\n<script setup lang=\"ts\">\n import {\n type BentoColumn,\n BentoDataGrid,\n type BentoDatagridData,\n type BentoDatagridSortByColumn,\n BentoDatagridSortDirection,\n } from '@adyen/bento-vue2';\n import { computed, ref } from 'vue';\n\n const data: BentoDatagridData = [\n { id: 2, name: 'Second' },\n { id: 1, name: 'First' },\n ];\n const columns: Array<BentoColumn> = [\n { field: 'id', label: 'ID', minWidth: 300, sortable: true, mandatory: true },\n { field: 'name', label: 'Name', minWidth: 300 },\n ];\n const sortBy = ref<Array<BentoDatagridSortByColumn>>([]);\n const sortedData = computed(() => {\n const [sortColumn] = sortBy.value;\n if (!sortColumn) {\n return data;\n }\n\n const direction = sortColumn.direction === BentoDatagridSortDirection.ASCENDING ? 1 : -1;\n return [...data].sort(\n (first, second) =>\n String(first[sortColumn.field] ?? '').localeCompare(String(second[sortColumn.field] ?? '')) * direction\n );\n });\n const sort = (value: Array<BentoDatagridSortByColumn>) => {\n sortBy.value = value;\n };\n</script>\n"; const DataGridSummaryCellExample = "<template>\n <bento-data-grid\n :columns=\"columns\"\n :data=\"dataSet\"\n :filter-search-config=\"searchConfig\"\n :filter-search-term=\"searchTerm\"\n :filter-values=\"filterValues\"\n :filters=\"filters\"\n @filter-search-clear=\"searchTerm = ''\"\n @update:filter-search-term=\"searchTerm = $event\"\n @update:filter-values=\"filterValues = $event\"\n >\n <template #item-company=\"{ item }\">\n <bento-data-grid-summary-cell\n :items=\"item.company\"\n :label=\"`${item.company.length} merchants`\"\n :search-term=\"companyColumnSearchTerm\"\n />\n </template>\n </bento-data-grid>\n</template>\n\n<script setup lang=\"ts\">\n import {\n type BentoColumn,\n BentoDataGrid,\n type BentoDatagridData,\n BentoDataGridSummaryCell,\n type BentoFilterBarModel,\n type BentoFilterBarSearchBarProps,\n BentoFilterItemType,\n type BentoFilterValues,\n } from '@adyen/bento-vue2';\n import { computed, ref } from 'vue';\n\n const columns: Array<BentoColumn> = [\n { field: 'name', label: 'Name', flex: 2, mandatory: true },\n { field: 'company', label: 'Company', flex: 1 },\n { field: 'payment', label: 'Payment', flex: 1, minWidth: 200 },\n ];\n const data: BentoDatagridData = [\n { id: 1, name: 'Shepherd Kane', payment: 160405, company: ['Merchant Helium', 'Merchant A'] },\n { id: 2, name: 'Joyce Johns', payment: 78500, company: ['Merchant C', 'Merchant Hedra'] },\n {\n id: 3,\n name: 'Evans Zamora',\n payment: 1153.4,\n company: [\n 'Merchant A',\n 'Merchant B',\n 'Merchant C',\n 'Merchant D',\n 'Merchant E',\n 'Merchant F',\n 'Merchant G',\n 'Merchant H',\n 'Merchant I',\n 'Merchant J',\n ],\n },\n ];\n const filters = computed<BentoFilterBarModel>(() => [\n { field: 'name', label: 'Name', type: BentoFilterItemType.INPUT },\n { field: 'company', label: 'Company', type: BentoFilterItemType.INPUT },\n ]);\n const filterValues = ref<BentoFilterValues>([]);\n const searchTerm = ref('');\n const searchConfig: BentoFilterBarSearchBarProps = {\n debounceTime: 1000,\n inputFieldAriaLabel: 'Descriptive details about the search bar',\n placeholder: 'Find merchants',\n };\n const companyColumnSearchTerm = computed(\n () => searchTerm.value || filterValues.value.find(filter => filter.field === 'company')?.value?.toString() || ''\n );\n const dataSet = computed<BentoDatagridData>(() =>\n data.filter(item => {\n const matchesSearch =\n !searchTerm.value ||\n (item.name as string).toLowerCase().includes(searchTerm.value.toLowerCase()) ||\n (item.company as Array<string>).some(company =>\n company.toLowerCase().includes(searchTerm.value.toLowerCase())\n );\n const matchesFilters = filterValues.value.every(filter => {\n if (!filter.value) {\n return true;\n }\n if (filter.field === 'company') {\n return (item.company as Array<string>).some(company =>\n company.toLowerCase().includes((filter.value as string).toLowerCase())\n );\n }\n return (item[filter.field] as string).toLowerCase().includes((filter.value as string).toLowerCase());\n });\n return matchesSearch && matchesFilters;\n })\n );\n</script>\n"; const DataGridTrendCellExample = "<template>\n <bento-data-grid :columns=\"columns\" :data=\"data\">\n <template #item-performance=\"{ item }\">\n <bento-data-grid-trend-cell\n :value=\"item.performance.value\"\n :direction=\"item.performance.direction\"\n :variant=\"item.performance.variant\"\n />\n </template>\n </bento-data-grid>\n</template>\n\n<script setup lang=\"ts\">\n import {\n type BentoColumn,\n BentoDataGrid,\n type BentoDatagridData,\n BentoDataGridTrendCell,\n } from '@/components/data-grid';\n\n const columns: Array<BentoColumn> = [\n { field: 'name', label: 'Name', flex: 2 },\n { field: 'performance', label: 'Performance', flex: 1, numeric: true },\n ];\n\n const data: BentoDatagridData = [\n {\n id: '1',\n name: 'Shepherd Kane',\n performance: {\n value: 25.5,\n variant: 'green',\n direction: 'up',\n },\n },\n {\n id: '2',\n name: 'Santos Palmer',\n performance: {\n value: 10.2,\n variant: 'red',\n direction: 'down',\n },\n },\n {\n id: '3',\n name: 'Joyce Johns',\n performance: {\n value: 0,\n variant: 'black',\n direction: 'none',\n },\n },\n {\n id: '4',\n name: 'Lynnette Melendez',\n performance: {\n value: '3.1428571429%',\n variant: 'green',\n direction: 'down',\n },\n },\n {\n id: '5',\n name: 'Wagner Mcintosh',\n performance: {\n value: '15.2%',\n variant: 'red',\n direction: 'up',\n },\n },\n {\n id: '6',\n name: 'Evans Zamora',\n performance: {\n value: '1.23',\n direction: 'up',\n },\n },\n {\n id: '7',\n name: 'Anderson Middleton',\n performance: {\n value: '90',\n direction: 'down',\n },\n },\n ];\n</script>\n"; const DataGridTagWithTextCellExample = "<template>\n <bento-data-grid :columns=\"columns\" :data=\"data\">\n <template #item-endpoint=\"{ item }\">\n <bento-data-grid-tag-with-text-cell :tag=\"item.endpoint.tag\" :value=\"item.endpoint.value\" />\n </template>\n </bento-data-grid>\n</template>\n\n<script setup lang=\"ts\">\n import {\n type BentoColumn,\n BentoDataGrid,\n type BentoDatagridData,\n BentoDataGridTagWithTextCell,\n } from '@adyen/bento-vue2';\n\n const columns: Array<BentoColumn> = [\n { field: 'name', label: 'Name', flex: 2 },\n { field: 'endpoint', label: 'Endpoint', flex: 2 },\n ];\n\n const data: BentoDatagridData = [\n {\n id: '1',\n name: 'Get users',\n endpoint: {\n tag: { label: 'GET', variant: 'blue' },\n value: '/api/users',\n },\n },\n {\n id: '2',\n name: 'Create user',\n endpoint: {\n tag: { label: 'POST', variant: 'green' },\n value: '/api/users',\n },\n },\n {\n id: '3',\n name: 'Update user',\n endpoint: {\n tag: { label: 'PUT', variant: 'yellow' },\n value: '/api/users/:id',\n },\n },\n {\n id: '4',\n name: 'Delete user',\n endpoint: {\n tag: { label: 'DELETE', variant: 'red' },\n value: '/api/users/:id',\n },\n },\n {\n id: '5',\n name: 'Get payments',\n endpoint: {\n tag: { label: 'GET', variant: 'blue' },\n value: '/api/payments',\n },\n },\n ];\n</script>\n"; import { DEFAULT_DATA } from './__tests__/data-grid-example-data'; const meta: Meta = { title: 'Data Grid', component: BentoDataGrid, argTypes: { // Values lazyLoadType: { control: { type: 'select', }, }, // Filter bar props filters: { table: { type: { summary: 'BentoFilterBarModel' }, }, }, filterSearchTerm: { name: 'filterSearchTerm', defaultValue: undefined, description: "Filter bar search term useful to filter all the data by text. If the value is non-existant (`null` or `undefined`) the search bar won't be enabled.", control: { type: 'text', }, }, // Slots default: { table: { disable: true }, }, header: { name: 'header', defaultValue: '', description: 'header text', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, footer: { name: 'footer', defaultValue: '', description: 'footer text', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, 'head-{columnKey}': { name: 'head-{columnKey}', defaultValue: '', description: 'the column slot where `{columnKey}` is the name of the column key. Allows the Column header to be customized.', table: { type: { summary: 'VNode[]' }, category: 'slots', }, control: { disable: true }, }, 'item-{columnKey}': { name: 'item-{columnKey}', defaultValue: '', description: 'the data item slot where `{columnKey}` is the name of the data item column key. Allow row cells to be customized.', table: { type: { summary: 'VNode[]' }, category: 'slots', }, control: { disable: true }, }, ['pagination-slot']: { control: { type: 'text' }, description: 'Passes content to the default pagination slot', table: { type: { summary: 'VNode[]' }, }, }, // Events [BentoDatagridEvent.COLUMN_RESIZE]: { name: BentoDatagridEvent.COLUMN_RESIZE, defaultValue: '', description: 'Triggered when a column is resized. Provides a field name and the new resized width in pixels.', table: { category: 'events', type: { summary: '({ field, newResizedWidth }) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.SELECT]: { name: BentoDatagridEvent.SELECT, defaultValue: '', description: 'Triggered when a row is selected. Provides an array of data item ids. `BentoDatagridDataItemId[]`', table: { category: 'events', type: { summary: '(selectedDataItemIds) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.NAVIGATE]: { name: BentoDatagridEvent.NAVIGATE, defaultValue: '', description: `Triggered when the navigation controls in the pagination are clicked (i.e. when the arrow buttons to the rightmost of the screen or the dropdown on the right hand are updated). It indicates to which page it should go next.`, table: { category: 'events', type: { summary: '(pageNumber: number) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.ITEMS_PAGE]: { name: BentoDatagridEvent.ITEMS_PAGE, defaultValue: '', description: `Triggered when the number of items per page is changed from the left hand dropdown of the pagination. It indicates the new number of items that will be displayed.`, table: { category: 'events', type: { summary: '(itemsPerPage: number) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.SORT]: { name: BentoDatagridEvent.SORT, defaultValue: '', description: `Triggered when a column is sorted. Provides an array of \`BentoDatagridSortByColumn\` which includes the \`field\` and the sort \`direction\` (\`BentoDatagridSortDirection\`) of the column:`, table: { category: 'events', type: { summary: '(sortByDirections) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.UPDATE_COLUMNS]: { name: BentoDatagridEvent.UPDATE_COLUMNS, defaultValue: '', description: `Triggered when a the columns have been updated. Provides an updated array of columns \`BentoColumn[]\` which should be passed back into the \`columns\` prop (easily achieved using the [sync modifier](https://v2.vuejs.org/v2/guide/components-custom-events.html#sync-Modifier)) e.g. \`:columns.sync="columns"\``, table: { category: 'events', type: { summary: '(columns) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.UPDATE_CONDENSED]: { name: 'update:condensed', defaultValue: '', description: `Triggered when the config panel's condensed view toggle is interacted with. Provides the updated condensed \`boolean\`. (easily achieved using the [sync modifier](https://v2.vuejs.org/v2/guide/components-custom-events.html#sync-Modifier)) e.g. \`:condensed.sync="condensed"\``, table: { category: 'events', type: { summary: '(condensed) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.UPDATE_FILTER_VALUES]: { name: BentoDatagridEvent.UPDATE_FILTER_VALUES, defaultValue: '', description: `Triggered when a the filters in the filterbar have updated. Provides an array of filters \`BentoFilterBarModel[]\` which should be passed back into the \`filter-values\` prop (easily achieved using the [sync modifier](https://v2.vuejs.org/v2/guide/components-custom-events.html#sync-Modifier)) e.g. \`:filter-values.sync="filtersValues"\``, table: { category: 'events', type: { summary: '(filterValues) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.UPDATE_PAGINATION]: { name: BentoDatagridEvent.UPDATE_PAGINATION, defaultValue: '', description: `Triggered when a the pagination state has been updated. Provides an updated \`pagination\` properties object which should be passed back into the \`pagination\` prop (easily achieved using the [sync modifier](https://v2.vuejs.org/v2/guide/components-custom-events.html#sync-Modifier)) e.g. \`:pagination.sync="pagination"\``, table: { category: 'events', type: { summary: '(paginationProps) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.UPDATE_SELECTION]: { name: BentoDatagridEvent.UPDATE_SELECTION, defaultValue: '', description: `Triggered when a the select data rows state has been updated. Provides an array of row IDs \`BentoDatagridDataItemId[]\` which should be passed back into the \`selection\` prop (easily achieved using the [sync modifier](https://v2.vuejs.org/v2/guide/components-custom-events.html#sync-Modifier)) e.g. \`:selection.sync="selection"\``, table: { category: 'events', type: { summary: '(selection) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.UPDATE_SORT_BY]: { name: 'update:sort-by', defaultValue: '', description: `Triggered when a the sorting state has been updated. Provides an array of sorting directions \`BentoDatagridSortByColumn[]\` which should be passed back into the \`sort-by\` prop (easily achieved using the [sync modifier](https://v2.vuejs.org/v2/guide/components-custom-events.html#sync-Modifier)) e.g. \`:sort-by.sync="sortBy"\``, table: { category: 'events', type: { summary: '(sortingDirections) => void' }, }, control: { disable: true }, }, // Filter bar search events [BentoDatagridEvent.FILTER_SEARCH_INPUT]: { name: BentoDatagridEvent.FILTER_SEARCH_INPUT, defaultValue: '', description: "Triggered whenever the filter's search is updated.", table: { category: 'events', type: { summary: '(newSearchTerm) => void' } }, control: { disable: true }, }, [BentoDatagridEvent.FILTER_SEARCH_CLEAR]: { name: BentoDatagridEvent.FILTER_SEARCH_CLEAR, defaultValue: '', description: "Triggered whenever the filter's search is cleared.", table: { category: 'events', type: { summary: '() => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.UPDATE_FILTER_SEARCH_TERM]: { name: BentoDatagridEvent.UPDATE_FILTER_SEARCH_TERM, defaultValue: '', description: "Triggered whenever the filter's search is updated to sync the model.", table: { category: 'events', type: { summary: '(newSearchTerm) => void' }, }, control: { disable: true }, }, [BentoDatagridEvent.ROW_CLICK]: { name: BentoDatagridEvent.ROW_CLICK, defaultValue: '', description: 'Triggered whenever a row has been clicked.', table: { category: 'events', type: { summary: '(row: BentoDatagridDataItem, event: MouseEvent) => void' }, }, }, [BentoDatagridEvent.NESTED_CONTENT_TOGGLED]: { name: BentoDatagridEvent.NESTED_CONTENT_TOGGLED, defaultValue: '', description: 'Triggered whenever a data item toggled is nested content', table: { category: 'events', type: { summary: '(dataItem: BentoDatagridDataItem) => void' }, }, control: { disable: true }, }, }, }; export default meta; type Story = StoryObj<typeof BentoDataGrid>; const DEFAULT_COLUMNS: Array<BentoColumn> = [ { field: 'name', label: 'Name', minWidth: 300, mandatory: true }, { field: 'company', label: 'Company', autoWidth: true }, { field: 'payment', label: 'Payment', minWidth: 350 }, ]; const ADDITIONAL_DATA: BentoDatagridData = [ { id: '03c0a799-1ced-4017-aea3-0cebb0106335', name: 'Additional data fetched here', payment: 160405, company: 'Merchant Helium', registered: '2023-06-30T13:56:09.498Z', tags: ['deserunt', 'et', 'esse'], reference: 'UnbQaUncf3eR1D8XUBqn_UnbQaUncf3eR1D8XUBqn_UnbQaUncf3eR1D8XUBqn', paymentStatus: 1, countryCode: BentoCountryCode.NL, }, { id: 'b6d4f1fd-b1f6-40a6-a443-f785c89604ef', name: 'Santos Palmer', payment: 163500, company: 'Merchant B', registered: '2023-04-28T13:11:09.498Z', tags: ['et', 'Lorem', 'sint'], reference: 'IxUZ9FsEPCZ9dFFPpI9C', paymentStatus: 2, countryCode: BentoCountryCode.BE, }, { id: '8f9e7877-1ca2-4929-9217-f1ec78709291', name: 'Joyce Johns', payment: 78500, company: 'Merchant C', registered: '2023-06-30T11:01:09.498Z', tags: ['laborum', 'enim', 'ullamco'], reference: 'y0qAQ0WDszRyqLY2WO9f', paymentStatus: 1, countryCode: BentoCountryCode.UA, }, { id: '0789a012-85a6-4657-87bb-319141938a61', name: 'Lynnette Melendez', payment: -45000, company: 'STRALOY', registered: '2019-08-01T13:56:01.498Z', tags: ['sit', 'consectetur', 'amet'], reference: '2vv5pzbRSwx8YsFoGGOC', paymentStatus: 1, countryCode: BentoCountryCode.BR, }, { id: '0b3981b6-c73b-47ad-81d1-b06f9b95d467', name: 'Wagner Mcintosh', payment: 1112, company: 'Merchant A', registered: '2022-12-30T02:12:09.498Z', tags: ['ad', 'ullamco', 'et'], reference: '54KN4jkpBuaRY5xMfe84', paymentStatus: 1, countryCode: BentoCountryCode.US, }, { id: '51d2b31d-d577-4fca-8329-a583babbbdda', name: 'Evans Zamora', payment: 1153.4, company: 'GEEKWAGON', registered: '2023-06-30T13:51:09.498Z', tags: ['consequat', 'magna', 'sit'], reference: 'Sj84kad0MGxpuozTjEk', paymentStatus: 0, countryCode: BentoCountryCode.FR, }, { id: '9bd59a6e-bd03-4477-813f-b844953b7645', name: 'Anderson Middleton', payment: 181722.23, company: 'BALOOBA', registered: '2021-03-02T01:34:09.498Z', tags: ['aliqua', 'adipisicing', 'magna'], reference: 'MtJ5Bnew0MGxpuozTjEk', paymentStatus: 1, countryCode: BentoCountryCode.IT, }, ]; const DEFAULT_ARGS = { data: DEFAULT_DATA, columns: DEFAULT_COLUMNS, allowColumnDragAndDrop: false, pagination: {}, emptyState: { title: 'No results were found', image: 'no-results-found', variant: 'embedded', action: { title: 'Clear filters', event: action('clear'), }, description: 'Try a different term or reset search filters', }, }; // Default export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" /> `, setup(props) { return { args: isVue2 ? props : _args }; }, }), args: DEFAULT_ARGS, parameters: storybookDocsParameter(DataGridDefaultExample), }; // Fluid Columns const rowActionsFluid: BentoDataGridRowActionsProp = (item: BentoDatagridDataItem) => { if (item.id === DEFAULT_DATA[3].id) { return [ { variant: 'edit', event: action('edit'), }, ]; } else if (item.id === DEFAULT_DATA[2].id) { return [ { variant: 'edit', event: action('edit') }, { variant: 'open', isShort: true, menuData: [ { text: 'Cancel payment', event: action('cancel payment'), critical: true, }, { text: 'Transfer payment', event: action('transfer payment'), }, { text: 'Delete payment', event: action('delete payment'), disabled: true, }, ], }, ]; } else if (item.id === DEFAULT_DATA[1].id) { return []; } return [ { variant: 'edit', event: action('edit'), }, { title: 'Delete', critical: true, event: action('Delete'), }, ]; }; export const Fluid: Story = { ...Default, args: { ...DEFAULT_ARGS, columns: [ { field: 'name', label: 'Name', flex: 2, mandatory: true }, { field: 'company', label: 'Company', flex: 1 }, { field: 'payment', label: 'Payment', flex: 1, minWidth: 200 }, ], rowActions: rowActionsFluid, }, parameters: storybookDocsParameter(DataGridFluidExample), }; // Slots export const Slots: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid, BentoLink, BentoTypography, }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" > <template #header> <bento-typography variant="title" el="h2"> Users </bento-typography> </template> <template #head-name="{column}"> <bento-typography variant="caption"> {{ column.label }} </bento-typography> </template> <template #item-name="{item}"> <bento-typography variant="body"> {{ item.name }} </bento-typography> <template v-if="item.company === 'Merchant Helium'"> <div style="display: inline-flex; gap: 4px;"> <bento-typography v-for="itemTag in item.tags" :key="itemTag" variant="caption" :style="{ color: 'var(--b-color-label-secondary)' }" > { {{ itemTag }} } </bento-typography> </div> </template> </template> <template #item-company="{item}"> <bento-link isNotRouting to="https://www.adyen.com" :title="item.company" > {{ item.company }} </bento-link> <bento-typography v-if="item.company === 'Merchant B'" variant="caption" :style="{ color: 'var(--b-color-label-secondary)' }"> {{ item.registered }} </bento-typography> </template> <template #item-payment="{item}"> $ {{ item.payment }} </template> <template #footer> <bento-typography variant="caption"> Footer </bento-typography> </template> </bento-data-grid> `, setup(props) { return { args: isVue2 ? props : _args }; }, }), args: { ...DEFAULT_ARGS, columns: [ { field: 'name', label: 'Name', flex: 2, mandatory: true }, { field: 'company', label: 'Company', flex: 1 }, { field: 'payment', label: 'Payment', flex: 1, minWidth: 200 }, ], }, parameters: storybookDocsParameter(DataGridWithSlotsExample), }; // Sorting const useSort = () => { const sortBy = ref<Array<BentoDatagridSortByColumn>>([]); const data = ref<BentoDatagridData>(DEFAULT_DATA); const sort = (sortedColumns: Array<BentoDatagridSortByColumn>) => { data.value = sortedColumns[0].direction === BentoDatagridSortDirection.ASCENDING ? data.value.sort((a, b) => (a[sortedColumns[0].field] as string).localeCompare(b[sortedColumns[0].field] as string) ) : data.value .sort((a, b) => (a[sortedColumns[0].field] as string).localeCompare(b[sortedColumns[0].field] as string) ) .reverse(); action('sort')(sortedColumns); }; return { data, sortBy, sort }; }; export const Sorting: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid }, props: Object.keys(argTypes), template: ` <bento-data-grid :data="data" :columns="columns" :sort-by.sync="sortBy" @sort="sort" /> `, setup(props) { const { data, sortBy, sort } = useSort(); return { args: isVue2 ? props : _args, data, sortBy, sort, }; }, }), args: { ...DEFAULT_ARGS, columns: [ { field: 'name', label: 'Name', minWidth: 300, sortable: true, mandatory: true }, { field: 'company', label: 'Company', minWidth: 150, sortable: true }, { field: 'payment', label: 'Payment', width: 200, minWidth: 150 }, ], sortBy: [], }, parameters: storybookDocsParameter(DataGridSortingExample), }; export const Selection: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid }, props: Object.keys(argTypes), template: ` <div> <bento-data-grid v-bind="args" :data="pagedData" :pagination="pagination" :filters="filtersConfig" :filter-values="filterValues" :is-data-item-disabled="isDataItemDisabled" :selection="selection" :filter-search-term="searchTerm" @update:filter-search-term="searchTerm = $event" @update:pagination="pagination = $event" @update:filter-values="filterValues = $event" @select-all-across-pages="onSelectAllAcrossPages" @select-all-current-results="onSelectAllInCurrentResults" @deselect-all-current-results="onDeselectAllInCurrentResults" @filter-search-clear="onSearchCleared" @update:selection="onSelect" @row-click="rowClickAction" /> </div> `, setup(props) { const args = isVue2 ? props : _args; const selection = ref([]); const filtersConfig = computed<BentoFilterBarModel>(() => args?.filters ?? FILTERS); const filterValues = ref<BentoFilterValues>([]); const searchTerm = ref(''); const data = ref( Array.from({ length: 20 }, (_, i) => ({ id: `id-${i + 1}`, name: `Name ${i + 1}`, payment: (i + 1) * 100, company: `Merchant ${i + 1}`, })) ); const isDataItemDisabled = (row: BentoDatagridDataItem) => { return row.id === data.value[3].id; }; const pagination = ref<BentoDatagridPaginationProps>({ page: 1, size: 10, totalCount: 20, hasNext: true, }); const filteredData = computed<BentoDatagridData>(() => { let internalData = data.value; if (searchTerm.value) { const lowerCaseSearchTerm = searchTerm.value.toLowerCase(); const searchableFields = args.columns.map(column => column.field); internalData = internalData.filter((item: BentoDatagridDataItem) => { return searchableFields.some(field => { const value = String(item[field]); return value.toLowerCase().includes(lowerCaseSearchTerm); }); }); } return internalData.filter(item => filterValues.value.every(filter => filter.value ? String(item[filter.field]).toLowerCase().includes(String(filter.value).toLowerCase()) : true ) ); }); const pagedData = computed<BentoDatagridData>(() => { return filteredData.value.slice( (pagination.value.page - 1) * pagination.value.size, pagination.value.page * pagination.value.size ); }); const enabledIds = computed(() => data.value.filter(item => !isDataItemDisabled(item)).map(x => x.id)); const enabledFilteredIds = computed(() => filteredData.value.filter(item => !isDataItemDisabled(item)).map(x => x.id) ); const onSelect = value => { selection.value = value; action('update:selection')(value); }; const onSelectAllAcrossPages = () => { selection.value = enabledIds.value; action('select-all-across-pages')(); }; const onSelectAllInCurrentResults = () => { selection.value = [...new Set([...selection.value, ...enabledFilteredIds.value])]; action('select-all-current-results')(); }; const onDeselectAllInCurrentResults = () => { selection.value = selection.value.filter(item => !enabledFilteredIds.value.includes(item)); action('deselect-all-current-results')(); }; const onSearchCleared = () => { searchTerm.value = ''; action('search-clear')(); }; watch( filteredData, () => { pagination.value.totalCount = filteredData.value.length; }, { immediate: true } ); return { args, onSelect, onSelectAllAcrossPages, onSelectAllInCurrentResults, onDeselectAllInCurrentResults, pagination, selection, pagedData, filtersConfig, filterValues, searchTerm, rowClickAction: value => action('row-click')(value), isDataItemDisabled, onSearchCleared, }; }, }), args: { ...DEFAULT_ARGS, selectable: true, allowRowClicks: true, selectableAcrossPages: true, bulkActions: [ { title: 'Edit', event: () => true, }, { title: 'Delete', critical: true, event: () => true, }, ], }, parameters: storybookDocsParameter(DataGridSelectionExample), }; // Filtering const FILTERS: BentoFilterBarModel = [ { field: 'name', label: 'Name', type: BentoFilterItemType.INPUT, }, { field: 'company', label: 'Company', type: BentoFilterItemType.INPUT, }, ]; export const Filtering: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid }, props: Object.keys(argTypes), setup(props) { const args = isVue2 ? props : _args; const filtersConfig = computed<BentoFilterBarModel>(() => args?.filters ?? FILTERS); const filterValues = ref<BentoFilterValues>([]); const searchTerm = ref(''); const searchConfig = ref<BentoFilterBarSearchBarProps>({ inputFieldAriaLabel: 'Search for items', placeholder: 'Placeholder', hint: 'Hint', }); const dataSet = computed<BentoDatagridData>(() => { let filteredData = args.data; // Apply global search term filter if (searchTerm.value) { const lowerCaseSearchTerm = searchTerm.value.toLowerCase(); const searchableFields = args.columns.map(column => column.field); filteredData = filteredData.filter((item: BentoDatagridDataItem) => { return searchableFields.some(field => { const value = String(item[field]); return value.toLowerCase().includes(lowerCaseSearchTerm); }); }); } filteredData = filteredData.filter(item => filterValues.value?.every(filter => { return filter.value ? String(item[filter.field]).toLowerCase().includes(String(filter.value).toLowerCase()) : true; }) ); return filteredData; }); watch(filterValues, () => { action('filter-values:update')(filterValues.value); }); const onSearchCleared = action('search-clear'); const onSearchInput = action('search-input'); const onSearchTermUpdated = action('update:search-term'); return { // Values dataSet, filtersConfig, filterValues, searchTerm, searchConfig, // Methods onSearchCleared, onSearchInput, onSearchTermUpdated, // Vue 3 storybook fix args, }; }, template: ` <bento-data-grid v-bind="args" :data="dataSet" :filters="filtersConfig" :filter-values.sync="filterValues" :filter-search-term.sync="searchTerm" :filter-search-config="searchConfig" @filter-search-clear="onSearchCleared" @filter-search-input="onSearchInput" @update:filter-search-term="onSearchTermUpdated" /> `, }), args: DEFAULT_ARGS, parameters: storybookDocsParameter(DataGridFilteringExample), }; // No Results export const NoResults: Story = { ...Filtering, args: { ...DEFAULT_ARGS, data: [], filters: FILTERS, filterValues: [{ field: 'company', value: 'CIA' }], }, parameters: storybookDocsParameter(DataGridNoResultsExample), }; // Pagination export const Pagination: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" :data="dataGridData" :pagination.sync="pagination" @update:pagination="updatePagination" @items-page="updateItemsPerPage" /> `, setup(props) { const args = isVue2 ? props : _args; const largeData = [ ...DEFAULT_ARGS.data, ...DEFAULT_ARGS.data.map(dataItem => ({ ...dataItem, id: `${dataItem.id}+1` })), ]; const pagination = ref(args.pagination); const dataGridData = computed(() => { const end = pagination.value.size <= largeData.length ? pagination.value.size : largeData.length; return largeData.slice(pagination.value.page - 1, end); }); const updateItemsPerPage = (itemsPerPage: number) => { action('items-page')(itemsPerPage); }; const updatePagination = (newPagination: BentoDatagridPaginationProps) => { action('navigate')(newPagination.page); action('update:pagination')(newPagination); }; return { // Values dataGridData, pagination, // Methods updateItemsPerPage, updatePagination, // Vue 3 storybook fixes args: isVue2 ? props : _args, }; }, }), args: { ...DEFAULT_ARGS, pagination: { hasNext: true, description: 'datagrid navigation', size: 10, page: 1, totalCount: DEFAULT_ARGS.data.length * 2, }, }, parameters: storybookDocsParameter(DataGridPaginationExample), }; // Payment Status (demo use case for datagrid V2) export const EverythingBagelExample: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid, BentoLink, BentoStatus, BentoCurrency, BentoDate, BentoCountry, BentoButton }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" :data="filteredAndSortedData" :columns.sync="columns" :condensed="isCondensed" :filters="filtersConfig" :filter-values.sync="filterValues" :filter-search-term.sync="searchTerm" :sort-by="sortBy" @update:sort-by="sortBy = $event" @update:condensed="isCondensed = $event" :selection.sync="selection" :is-data-item-disabled="isDataItemDisabledForSelection" :row-actions="rowActions" selectable @row-click="onRowClick" > <template #item-paymentStatus="{item}"> <div style="display: flex"> <bento-status :variant="getPaymentStatus(item.paymentStatus)" /> <span>{{ getPaymentText(item.paymentStatus) }}</span> </div> </template> <template #item-reference="{item}"> <bento-link isNotRouting to="https://www.adyen.com" :title="item.reference" > {{ item.reference }} </bento-link> </template> <template #item-countryCode="{item}"> <bento-country :code="item.countryCode" /> </template> <template #item-payment="{item}"> <bento-currency currency="EUR" :value="item.payment" /> </template> <template #item-date="{item}"> <bento-date :date="new Date(item.registered)" :format='BentoDateFormat.FULL_DATE_TIME_WITH_PERIOD'/> </template> </bento-data-grid> `, setup(props) { const args = isVue2 ? props : _args; const columns = ref<Array<BentoColumn>>(args.columns); const filtersConfig = ref<BentoFilterBarModel>(args.filters); const filterValues = ref<BentoFilterValues>(args?.filterValues); const sortBy = ref<Array<BentoDatagridSortByColumn>>([]); const searchTerm = ref(''); const isCondensed = ref(args.condensed); const getPaymentStatus = (paymentStatus: number) => { switch (paymentStatus) { case 2: return BentoStatusVariant.GREEN; case 1: return BentoStatusVariant.YELLOW; case 0: default: return BentoStatusVariant.RED; } }; const getPaymentText = (paymentStatus: number) => { switch (paymentStatus) { case 2: return 'Paid'; case 1: return 'In progress'; case 0: default: return 'Not paid'; } }; const onRowClick = (item: BentoDatagridDataItem) => { action('row-click')(item); }; // Selection const isDataItemDisabledForSelection = (row: BentoDatagridDataItem) => row.id === DEFAULT_DATA[3].id; const selection = ref<BentoDatagridSelection>([DEFAULT_DATA[1].id]); // Filtering const filteredData = computed(() => // If any filters or search terms have been set filterValues.value?.length === 0 && searchTerm.value === '' ? args.data : args.data.filter(item => { const foundFilteredItem = filterValues.value?.length > 0 ? filterValues.value.every(filter => filter.value ? (item[filter.field] as string) .toLowerCase() .includes((filter.value as string).toLowerCase()) : true ) : true; const foundSearchFilteredItem = searchTerm.value ? (item?.company as string) .toLowerCase() .includes((searchTerm.value as string).toLowerCase()) : true; return foundFilteredItem && foundSearchFilteredItem; }) ); const filteredAndSortedData = computed(() => { if (sortBy.value?.length === 0) { return filteredData.value; } return sortBy.value[0].direction === BentoDatagridSortDirection.ASCENDING ? filteredData.value.sort((a, b) => (a[sortBy.value[0].field] as string).localeCompare(b[sortBy.value[0].field] as string) ) : filteredData.value .sort((a, b) => (a[sortBy.value[0].field] as string).localeCompare(b[sortBy.value[0].field] as string) ) .reverse(); }); const rowActions: BentoDataGridRowActionsProp = (item: BentoDatagridDataItem) => { if (item.id === DEFAULT_DATA[3].id) { return [ { variant: 'edit', event: action('edit'), tooltipText: 'Edit payment', }, ]; } else if (item.id === DEFAULT_DATA[2].id) { return [ { variant: 'edit', event: action('edit'), tooltipText: 'Edit payment' }, { variant: 'open', isShort: true, menuData: [ { text: 'Cancel payment', event: action('cancel payment'), critical: true, }, { text: 'Transfer payment', event: action('transfer payment'), }, { text: 'Delete payment', event: action('delete payment'), disabled: true, }, ], }, ]; } else if (item.id === DEFAULT_DATA[1].id) { return []; } return [ { variant: 'edit', event: action('edit'), tooltipText: 'Edit payment', }, { title: 'Delete', critical: true, event: action('Delete'), tooltipText: 'Delete payment', }, ]; }; return { // Methods getPaymentStatus, getPaymentText, // Functions onRowClick, isDataItemDisabledForSelection, // Values columns, filteredAndSortedData, sortBy, filtersConfig, filterValues, searchTerm, isCondensed, selection, rowActions, // Enums BentoDateFormat, // Vue 3 storybook fix args, }; }, }), args: { ...DEFAULT_ARGS, zebraRows: true, filters: [ { field: 'company', label: 'Company', type: BentoFilterItemType.INPUT, }, { field: 'countryCode', label: 'Country/Region', options: { listboxItems: [ { value: BentoCountryCode.NL, }, { value: BentoCountryCode.BE, }, ], variant: 'name', }, type: BentoFilterItemType.SELECT_COUNTRY, }, ], columns: [ { field: 'company', label: 'Company', sortable: true, mandatory: true, autoWidth: true, frozen: true, minWidth: 200, }, { field: 'paymentStatus', label: 'Status', width: 180, infoIconTooltip: 'For current day' }, { field: 'reference', label: 'Reference', width: 320, overflow: BentoColumnOverflow.ELLIPSIS }, { field: 'countryCode', label: 'Country/Region', width: 320 }, { field: 'payment', label: 'Payment', width: 180, numeric: true }, { field: 'date', label: 'Execution Date', width: 200 }, ], allowRowClicks: true, allowColumnDragAndDrop: true, columnPanel: true, highlightedRows: [DEFAULT_DATA[0].id, DEFAULT_DATA[4].id], }, parameters: storybookDocsParameter(DataGridEverythingBagel), }; export const DisplayOptions = (_args, { argTypes }) => ({ components: { BentoDataGrid, BentoDate }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" :columns.sync="columns" :condensed.sync="isCondensed"> <template #item-date="{item}"> <bento-date :date="new Date(item.registered)" :format='BentoDateFormat.FULL_DATE_TIME_WITH_PERIOD'/> </template> </bento-data-grid> `, setup(props) { const args = isVue2 ? props : _args; const isCondensed = ref(args.condensed); const columns = ref([ { field: 'name', label: 'Name', minWidth: 200, mandatory: true }, { field: 'reference', label: 'Reference', width: 320, overflow: BentoColumnOverflow.ELLIPSIS, frozen: true, }, { field: 'company', label: 'Company', minWidth: 150, width: 250, frozen: true }, { field: 'payment', label: 'Payment', width: 200, minWidth: 150 }, { field: 'countryCode', label: 'Country/Region', width: 280 }, { field: 'date', label: 'Execution Date', width: 300 }, ]); return { // Values columns, isCondensed, // Enums BentoDateFormat, // Vue 3 storybook fix args, }; }, }); DisplayOptions.args = { ...DEFAULT_ARGS, allowColumnDragAndDrop: true, columnPanel: true, }; DisplayOptions.parameters = storybookDocsParameter(DataGridDisplayOptionsExample); export const GridInCard: Story = { render: (_args, { argTypes }) => ({ components: { BentoCard, BentoDataGrid, BentoDate }, props: Object.keys(argTypes), template: ` <div style="max-width: 500px;"> <bento-card> Grid in a card <template #content> <div style="height: 300px;"> <bento-data-grid v-bind="args" :columns.sync="columns" :condensed.sync="isCondensed" :pagination="pagination" fit-content > <template #item-date="{item}"> <bento-date :date="new Date(item.registered)" :format='BentoDateFormat.FULL_DATE_TIME_WITH_PERIOD'/> </template> </bento-data-grid> </div> </template> </bento-card> </div> `, setup(props) { const args = isVue2 ? props : _args; const isCondensed = ref(args.condensed); const pagination = ref({ hasNext: true, size: 20, page: 1, description: 'datagrid navigation', }); const columns = ref([ { field: 'name', label: 'Name', minWidth: 200, mandatory: true }, { field: 'reference', label: 'Reference', width: 320, overflow: BentoColumnOverflow.ELLIPSIS, }, { field: 'company', label: 'Company', minWidth: 150, width: 250 }, { field: 'payment', label: 'Payment', width: 200, minWidth: 150 }, { field: 'countryCode', label: 'Country/Region', width: 280 }, { field: 'date', label: 'Execution Date', width: 300 }, ]); return { // Values columns, isCondensed, pagination, // Enums BentoDateFormat, // Vue 3 storybook fix args, }; }, }), args: { ...DEFAULT_ARGS, columnPanel: false, }, parameters: storybookDocsParameter(DataGridFitContentInCardExample), }; // Default export const lazyLoading: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid }, props: Object.keys(argTypes), template: ` <div style="height: 300px;"> <bento-data-grid v-bind="args" :lazy-load-type="lazyLoadType" :loading="loading" @update:show-more="infiniteScrollHandler"/> </div> `, setup(props) { const args = isVue2 ? props : _args; const loading = ref(false); const data = ref(DEFAULT_DATA); const infiniteScrollHandler = () => { loading.value = true; setTimeout(() => { data.value.push(...ADDITIONAL_DATA); loading.value = false; }, 2000); }; return { args, loading, infiniteScrollHandler, }; }, }), args: { ...DEFAULT_ARGS, lazyLoadType: 'automatic', }, parameters: storybookDocsParameter(DataGridLazyLoadingExample), }; // Added just to be able to easily play around with the sticky headers/pagination/filters // Not really relevant as a Storybook example, so not adding storybook code example export const LongDataWithStickyFiltersAndPagination: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid }, props: Object.keys(argTypes), setup(props) { const args = isVue2 ? props : _args; const filtersConfig = ref<BentoFilterBarModel>([ { field: 'col1', label: 'Column 1', type: BentoFilterItemType.INPUT, }, { field: 'col2', label: 'Column 2', type: BentoFilterItemType.INPUT, }, ]); const filterValues = ref(); const searchTerm = ref(''); const isCondensed = ref(args.condensed); const columns = ref( Array.from({ length: 20 }, (_, index) => ({ field: `col${index + 1}`, label: `Column ${index + 1}`, width: 200, mandatory: index === 0, })) ); const data = ref( Array.from({ length: 50 }, (_, rowIndex) => columns.value.reduce((acc, col, colIndex) => { acc[col.field] = `Row ${rowIndex + 1} - Col ${colIndex + 1}`; return acc; }, {}) ) ); const dataSet = computed(() => // If any filters or search terms have been set filterValues.value?.length === 0 && searchTerm.value === '' ? data.value : data.value.filter(item => { const foundFilteredItem = filterValues.value?.length > 0 ? filterValues.value.every(filter => filter.value ? (item[filter.field] as string) .toLowerCase() .includes((filter.value as string).toLowerCase()) : true ) : true; const foundSearchFilteredItem = searchTerm.value ? Object.keys(item).some(key => key ? (item[key] as string) .toLowerCase() .includes((searchTerm.value as string).toLowerCase()) : true ) : true; return foundFilteredItem && foundSearchFilteredItem; }) ); const onSearchCleared = action('search-clear'); const onSearchInput = action('search-input'); const onSearchTermUpdated = action('update:search-term'); return { // Values dataSet, filtersConfig, filterValues, searchTerm, columns, isCondensed, // Methods onSearchCleared, onSearchInput, onSearchTermUpdated, // Vue 3 storybook fix args, }; }, template: ` <bento-data-grid v-bind="args" :data="dataSet" :columns.sync="columns" :condensed.sync="isCondensed" :filters="filtersConfig" :filter-values.sync="filterValues" :filter-search-term.sync="searchTerm" @filter-search-clear="onSearchCleared" @filter-search-input="onSearchInput" @update:filter-search-term="onSearchTermUpdated" /> `, }), args: { ...DEFAULT_ARGS, columnPanel: true, stickyPagination: true, stickyFilters: true }, }; // Cell actions export const CellActions: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" :columns="columns"> <template #item-custom="{item}"> Value </template> </bento-data-grid> `, setup(props) { // --- Action Handlers --- const editItem: BentoColumnCellActionEvent = (rowDataItem, columnKey) => { action('edit')(rowDataItem, columnKey); }; const cancelAction: BentoColumnCellActionEvent = (rowDataItem, columnKey) => { action('cancel')(rowDataItem, columnKey); }; const transferAction: BentoColumnCellActionEvent = (rowDataItem, columnKey) => { action('transfer')(rowDataItem, columnKey); }; const deleteAction: BentoColumnCellActionEvent = (rowDataItem, columnKey) => { action('delete')(rowDataItem, columnKey); }; // --- Dynamic Cell Actions Function --- // This function generates actions based on the row's data. const getNameCellActions: BentoColumnCellActionsProp = rowDataItem => { const actions: Array<BentoColumnCellAction> = []; // Conditionally add the 'edit' action only for the first row. if (rowDataItem.id === DEFAULT_DATA[3].id) { actions.push({ variant: 'edit', event: editItem, tooltipText: 'Edit this name' }); } // Add a 'more' menu with dynamic options. actions.push({ variant: 'more', isShort: true, tooltipText: 'Additional actions', menuData: [ { text: 'Cancel payment', event: cancelAction, critical: true, }, { text: 'Transfer payment', event: transferAction, }, { text: 'Delete payment', event: deleteAction, // Example: disable delete for the second row. disabled: rowDataItem.id === DEFAULT_DATA[2].id, }, ], }); return actions; }; // --- Column Definitions --- const columns: Array<BentoColumn> = [ { field: 'name', label: 'Name (Dynamic Actions)', minWidth: 300, mandatory: true, // Use a function for dynamic cell actions cellActions: getNameCellActions, }, { field: 'company', label: 'Reference', autoWidth: true }, { field: 'payment', label: 'Payment (Static Actions)', minWidth: 350, // Use a static array for cell actions cellActions: [ { variant: 'copy', getCopyData: (rowDataItem: BentoDatagridDataItem, columnKey: string) => `${rowDataItem[columnKey]}`, }, { variant: 'open', event: action('open-payment'), tooltipText: 'Open payment details' }, ], }, ]; return { args: isVue2 ? props : _args, columns }; }, }), args: { ...DEFAULT_ARGS, highlightedRows: [DEFAULT_DATA[3].id], columns: [ { field: 'name', label: 'Name (Dynamic Actions)', minWidth: 300, mandatory: true, cellActions: [ () => (rowDataItem: BentoDatagridDataItem) => ({ variant: 'edit', disabled: rowDataItem.id === DEFAULT_DATA[3].id, event: action('edit'), tooltipText: 'Edit this name', }), { variant: 'open', tooltipText: 'Additional actions', menuData: [ { text: 'Cancel payment', event: action('cancel payment'), critical: true, }, { text: 'Transfer payment', event: action('transfer payment'), }, { text: 'Delete payment', event: action('delete payment'), disabled: true, }, ], }, ], }, { field: 'company', label: 'Reference', autoWidth: true }, { field: 'payment', label: 'Payment (Static Actions)', minWidth: 350, cellActions: [ { variant: 'copy', getCopyData: (rowDataItem: BentoDatagridDataItem, columnKey: string) => `$${rowDataItem[columnKey]}`, }, { variant: 'more', tooltipText: 'Additional actions', menuData: [ { text: 'Cancel payment', event: action('cancel payment'), critical: true, }, { text: 'Transfer payment', event: action('transfer payment'), }, { text: 'Delete payment', event: action('delete payment'), disabled: true, }, ], isShort: true, }, ], }, { field: 'custom', label: 'Custom template', minWidth: 200, cellActions: [{ variant: 'edit', event: action('edit'), tooltipText: 'Edit custom' }], }, ], }, parameters: storybookDocsParameter(DataGridCellActionsExample), }; // NestContentSlot export const NestedContentSlot: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid, BentoLink, BentoTypography, }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" > <template #nested-slot="{item}"> <div style="height: 80px; text-align: center; display: flex; align-items: center;"> <bento-typography>Nested content slot for {{ item.company }}</bento-typography> </div> </template> </bento-data-grid> `, setup(props) { return { args: isVue2 ? props : _args }; }, }), args: { ...DEFAULT_ARGS, hasNestedContent: true, zebraRows: true, shouldShowNestedContent: (item: BentoDatagridDataItem) => item.id !== DEFAULT_ARGS.data[1].id, }, parameters: storybookDocsParameter(DataGridNestedContentExample), }; export const StickyHorizontalScrollbar: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid, BentoButton }, props: Object.keys(argTypes), setup(props) { const args = isVue2 ? props : _args; const filtersConfig = ref<BentoFilterBarModel>([ { field: 'col1', label: 'Column 1', type: BentoFilterItemType.INPUT, }, { field: 'col2', label: 'Column 2', type: BentoFilterItemType.INPUT, }, ]); const filterValues = ref(); const searchTerm = ref(''); const isCondensed = ref(args.condensed); const columns = ref( Array.from({ length: 20 }, (_, index) => ({ field: `col${index + 1}`, label: `Column ${index + 1}`, width: 200, mandatory: index === 0, })) ); const data = ref( Array.from({ length: 50 }, (_, rowIndex) => columns.value.reduce((acc, col, colIndex) => { acc[col.field] = `Row ${rowIndex + 1} - Col ${colIndex + 1}`; return acc; }, {}) ) ); const dataSet = computed(() => // If any filters or search terms have been set filterValues.value?.length === 0 && searchTerm.value === '' ? data.value : data.value.filter(item => { const foundFilteredItem = filterValues.value?.length > 0 ? filterValues.value.every(filter => filter.value ? (item[filter.field] as string) .toLowerCase() .includes((filter.value as string).toLowerCase()) : true ) : true; const foundSearchFilteredItem = searchTerm.value ? Object.keys(item).some(key => key ? (item[key] as string) .toLowerCase() .includes((searchTerm.value as string).toLowerCase()) : true ) : true; return foundFilteredItem && foundSearchFilteredItem; }) ); const onSearchCleared = action('search-clear'); const onSearchInput = action('search-input'); const onSearchTermUpdated = action('update:search-term'); return { // Values dataSet, filtersConfig, filterValues, searchTerm, columns, isCondensed, // Methods onSearchCleared, onSearchInput, onSearchTermUpdated, // Vue 3 storybook fix args, }; }, template: ` <bento-data-grid v-bind="args" :data="dataSet" :columns.sync="columns" :condensed.sync="isCondensed" :filters="filtersConfig" :filter-values.sync="filterValues" :filter-search-term.sync="searchTerm" @filter-search-clear="onSearchCleared" @filter-search-input="onSearchInput" @update:filter-search-term="onSearchTermUpdated" > <template #pagination-slot> <bento-button variant="tertiary"> Pagination slot button </bento-button> </template> </bento-data-grid> `, }), args: { ...DEFAULT_ARGS, pagination: { page: 1, hidePageSize: true }, columnPanel: true, stickyPagination: true, stickyFilters: true, stickyHorizontalScrollbar: true, }, }; export const NestedRows: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid, BentoLink, BentoTypography, }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" :data="dataState" @nested-content-toggled="onParentRowToggle" /> `, setup(props) { const dataState = ref<Array<BentoDatagridDataItem>>(DEFAULT_ARGS.data); const selection = ref<BentoDatagridDataItemId>(); const onParentRowToggle = (item: BentoDatagridDataItem) => { setTimeout(() => { const children = [ { id: `03c0a799-1ced-4017-aea3-111111${item.id}`, name: `Child of ${item.name} #1`, payment: 160405, company: 'Merchant Helium', registered: '2023-06-30T13:56:09.498Z', tags: ['deserunt', 'et', 'esse'], reference: 'UnbQaUncf3eR1D8XUBqn_UnbQaUncf3eR1D8XUBqn_UnbQaUncf3eR1D8XUBqn', paymentStatus: 1, countryCode: BentoCountryCode.NL, parentId: DEFAULT_ARGS.data[1].id, }, { id: `03c0a799-1ced-4017-aea3-1111113${item.id}`, name: `Child of ${item.name} #2`, payment: 163500, company: 'Merchant B', registered: '2023-04-28T13:11:09.498Z', tags: ['et', 'Lorem', 'sint'], reference: 'IxUZ9FsEPCZ9dFFPpI9C', paymentStatus: 2, countryCode: BentoCountryCode.BE, parentId: DEFAULT_ARGS.data[1].id, }, { id: `03c0a799-1ced-4017-aea3-1111114${item.id}`, name: `Child of ${item.name} #3`, payment: 78500, company: 'Merchant C', registered: '2023-06-30T11:01:09.498Z', tags: ['laborum', 'enim', 'ullamco'], reference: 'y0qAQ0WDszRyqLY2WO9f', paymentStatus: 1, countryCode: BentoCountryCode.UA, parentId: DEFAULT_ARGS.data[1].id, }, ]; dataState.value = dataState.value.map(itemToChange => { if (itemToChange.id === item.id) { return { ...itemToChange, children, }; } return itemToChange; }); }, 1000); }; return { args: isVue2 ? props : _args, dataState, selection, onParentRowToggle }; }, }), args: { ...DEFAULT_ARGS, hasNestedRows: true, zebraRows: true, shouldShowNestedRows: dataItem => { return dataItem.id !== DEFAULT_ARGS.data[1].id; }, }, parameters: storybookDocsParameter(DataGridNestedRowsExample), }; export const RowActions: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" :row-actions="rowActions" /> `, setup(props) { const rowActions: BentoDataGridRowActionsProp = (item: BentoDatagridDataItem) => { if (item.id === DEFAULT_DATA[0].id) { return [ { variant: 'edit', event: action('edit'), tooltipText: 'Edit row' }, { title: 'Delete', critical: true, event: action('Delete'), tooltipText: 'Delete row', }, ]; } else if (item.id === DEFAULT_DATA[1].id) { return []; } else if (item.id === DEFAULT_DATA[2].id) { return [ { variant: 'edit', event: action('edit'), tooltipText: 'Edit row' }, { variant: 'open', isShort: true, tooltipText: 'More options', menuData: [ { text: 'Cancel payment', event: action('cancel payment'), critical: true, }, { text: 'Transfer payment', event: action('transfer payment'), }, { text: 'Delete payment', event: action('delete payment'), disabled: true, }, ], }, ]; } return [ { variant: 'edit', event: action('edit'), tooltipText: 'Edit row', }, ]; }; return { args: isVue2 ? props : _args, rowActions, }; }, }), args: { ...DEFAULT_ARGS, }, parameters: storybookDocsParameter(DataGridRowActionsExample), }; export const SummaryCell: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid, BentoLink, BentoTypography, BentoDashedUnderline, BentoDataGridSummaryCell, }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args" :data="dataSet" :filters="filtersConfig" :filter-values.sync="filterValues" :filter-search-term="searchTerm" :filter-search-config="searchConfig" @update:filter-values="filterValues = $event" @update:filter-search-term="searchTerm = $event" @filter-search-clear="onSearchCleared" > <template #item-company="{item}"> <bento-data-grid-summary-cell :label="\`\${item.company.length} merchants\`" :items="item.company" :search-term="companyColumnSearchTerm" /> </template> </bento-data-grid> `, setup(props) { /** * Data set with array of companies */ const multiData: BentoDatagridData = [ { id: '03c0a799-1ced-4017-aea3-0cebb0106335', name: 'Shepherd Kane', payment: 160405, company: ['Merchant Helium', 'Merchant A'], }, { id: 'b6d4f1fd-b1f6-40a6-a443-f785c89604ef', name: 'Santos Palmer', payment: 163500, company: ['Merchant B'], }, { id: '8f9e7877-1ca2-4929-9217-f1ec78709291', name: 'Joyce Johns', payment: 78500, company: ['Merchant C', 'Merchant Hedra'], }, { id: '0789a012-85a6-4657-87bb-319141938a61', name: 'Lynnette Melendez', payment: -45000, company: ['Merchant A', 'Merchant B', 'Merchant C'], }, { id: '0b3981b6-c73b-47ad-81d1-b06f9b95d467', name: 'Wagner Mcintosh', payment: 1112, company: ['Merchant A'], }, { id: '51d2b31d-d577-4fca-8329-a583babbbdda', name: 'Evans Zamora', payment: 1153.4, company: [ 'Merchant A', 'Merchant B', 'Merchant C', 'Merchant D', 'Merchant E', 'Merchant F', 'Merchant G', 'Merchant H', 'Merchant I', 'Merchant J', 'Merchant K', 'Merchant L', 'Merchant M', 'Merchant N', 'Merchant O', 'Merchant P', 'Merchant Q', 'Merchant R', 'Merchant S', 'Merchant T', ], }, { id: '9bd59a6e-bd03-4477-813f-b844953b7645', name: 'Anderson Middleton', payment: 181722.23, company: ['Merchant A'], }, ]; const filtersConfig = computed<BentoFilterBarModel>(() => [ { field: 'name', label: 'Name', type: BentoFilterItemType.INPUT, }, { field: 'company', label: 'Company', type: BentoFilterItemType.INPUT, }, ]); /** * The values of applied filters. */ const filterValues = ref<BentoFilterValues>(); /** * The current global search term that is being searched with */ const searchTerm = ref(''); /** * Global search configuration */ const searchConfig = ref<BentoFilterBarSearchBarProps>({ inputFieldAriaLabel: 'Descriptive details about the search bar', debounceTime: 1000, // in ms placeholder: 'Find merchants', }); /** * Concatenated search term using the global search and the company filter value */ const companyColumnSearchTerm = computed( () => searchTerm.value || filterValues.value?.find(filter => filter.field === 'company')?.value?.toString() || '' ); /** * Simplified computed data set that filters data depending on applied filters and global search values */ const dataSet = computed<BentoDatagridData>(() => { let filteredData = multiData; // Apply global search term filter if (searchTerm.value) { const lowerCaseSearchTerm = searchTerm.value.toLowerCase(); filteredData = filteredData.filter( item => (item.name as string).toLowerCase().includes(lowerCaseSearchTerm) || (item.company as Array<string>).some(company => company.toLowerCase().includes(lowerCaseSearchTerm) ) ); } // Apply filterValues filter if (filterValues.value?.length) { filteredData = filteredData.filter(item => filterValues.value?.every(filter => { if (filter.field === 'company') { return filter.value ? (item[filter.field] as Array<string>).some(company => (company as string) .toLowerCase() .includes((filter.value as string).toLowerCase()) ) : true; } return filter.value ? (item[filter.field] as string) .toLowerCase() .includes((filter.value as string).toLowerCase()) : true; }) ); } return filteredData; }); const onSearchCleared = () => { searchTerm.value = ''; }; return { args: isVue2 ? props : _args, filtersConfig, filterValues, searchTerm, searchConfig, onSearchCleared, dataSet, companyColumnSearchTerm, }; }, }), args: { ...DEFAULT_ARGS, columns: [ { field: 'name', label: 'Name', flex: 2, mandatory: true }, { field: 'company', label: 'Company', flex: 1 }, { field: 'payment', label: 'Payment', flex: 1, minWidth: 200 }, ], zebraRows: true, }, parameters: storybookDocsParameter(DataGridSummaryCellExample), }; export const TrendCell: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid, BentoDataGridTrendCell, }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args"> <template #item-performance="{ item }"> <bento-data-grid-trend-cell :value="item.performance.value" :direction="item.performance.direction" :variant="item.performance.variant" /> </template> </bento-data-grid> `, setup(props) { const columns: Array<BentoColumn> = [ { field: 'name', label: 'Name', flex: 2 }, { field: 'performance', label: 'Performance', flex: 1, numeric: true }, ]; const data: BentoDatagridData = [ { id: '1', name: 'Shepherd Kane', performance: { value: 25.5, variant: 'green', direction: 'up', }, }, { id: '2', name: 'Santos Palmer', performance: { value: 10.2, variant: 'red', direction: 'down', }, }, { id: '3', name: 'Joyce Johns', performance: { value: 0, variant: 'black', direction: 'none', }, }, { id: '4', name: 'Lynnette Melendez', performance: { value: '3.1428571429%', variant: 'green', direction: 'down', }, }, { id: '5', name: 'Wagner Mcintosh', performance: { value: '15.2%', variant: 'red', direction: 'up', }, }, { id: '6', name: 'Evans Zamora', performance: { value: '1.23', direction: 'up', }, }, { id: '7', name: 'Anderson Middleton', performance: { value: '90', direction: 'down', }, }, ]; return { args: { ...(isVue2 ? props : _args), columns, data }, }; }, }), args: { ...DEFAULT_ARGS, zebraRows: true, }, parameters: storybookDocsParameter(DataGridTrendCellExample), }; export const TagWithTextCell: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGrid, BentoDataGridTagWithTextCell, }, props: Object.keys(argTypes), template: ` <bento-data-grid v-bind="args"> <template #item-endpoint="{ item }"> <bento-data-grid-tag-with-text-cell :tag="item.endpoint.tag" :value="item.endpoint.value" /> </template> </bento-data-grid> `, setup(props) { const columns = [ { field: 'name', label: 'Name', flex: 2 }, { field: 'endpoint', label: 'Endpoint', flex: 2 }, ]; const data = [ { id: '1', name: 'Get users', endpoint: { tag: { label: 'GET', variant: 'blue' }, value: '/api/users', }, }, { id: '2', name: 'Create user', endpoint: { tag: { label: 'POST', variant: 'green' }, value: '/api/users', }, }, { id: '3', name: 'Update user', endpoint: { tag: { label: 'PUT', variant: 'yellow' }, value: '/api/users/:id', }, }, { id: '4', name: 'Delete user', endpoint: { tag: { label: 'DELETE', variant: 'red' }, value: '/api/users/:id', }, }, ]; return { args: { ...(isVue2 ? props : _args), columns, data }, }; }, }), args: { ...DEFAULT_ARGS, }, parameters: storybookDocsParameter(DataGridTagWithTextCellExample), };