@adyen/bento-mcp 0.0.0 → 0.1.1
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.
- package/CHANGELOG.md +26 -0
- package/LICENSE +21 -0
- package/README.md +58 -0
- package/dist/assets/components/accordion/accordion.docs.mdx +77 -0
- package/dist/assets/components/accordion/accordion.stories.ts +1 -0
- package/dist/assets/components/accordion/accordion.vue +1 -0
- package/dist/assets/components/accordion/components/accordion-item.stories.ts +1 -0
- package/dist/assets/components/accordion/components/accordion-item.vue +1 -0
- package/dist/assets/components/action-bar/action-bar.docs.mdx +103 -0
- package/dist/assets/components/action-bar/action-bar.stories.ts +1 -0
- package/dist/assets/components/action-bar/action-bar.vue +1 -0
- package/dist/assets/components/ai-tag/ai-tag.docs.mdx +75 -0
- package/dist/assets/components/ai-tag/ai-tag.stories.ts +1 -0
- package/dist/assets/components/ai-tag/ai-tag.vue +1 -0
- package/dist/assets/components/alert/alert.docs.mdx +106 -0
- package/dist/assets/components/alert/alert.stories.ts +1 -0
- package/dist/assets/components/alert/alert.vue +1 -0
- package/dist/assets/components/avatar/avatar.docs.mdx +44 -0
- package/dist/assets/components/avatar/avatar.stories.ts +1 -0
- package/dist/assets/components/avatar/avatar.vue +1 -0
- package/dist/assets/components/avatar/components/avatar-image/avatar-image.vue +1 -0
- package/dist/assets/components/button/button.docs.mdx +137 -0
- package/dist/assets/components/button/button.stories.ts +1 -0
- package/dist/assets/components/button/button.vue +1 -0
- package/dist/assets/components/button/components/ai-button/ai-button.docs.mdx +40 -0
- package/dist/assets/components/button/components/ai-button/ai-button.stories.ts +1 -0
- package/dist/assets/components/button/components/ai-button/ai-button.vue +1 -0
- package/dist/assets/components/button/components/button-actions/button-actions.docs.mdx +169 -0
- package/dist/assets/components/button/components/button-actions/button-actions.stories.ts +1 -0
- package/dist/assets/components/button/components/button-actions/button-actions.vue +1 -0
- package/dist/assets/components/button/components/loading-button/loading-button.docs.mdx +106 -0
- package/dist/assets/components/button/components/loading-button/loading-button.stories.ts +1 -0
- package/dist/assets/components/button/components/loading-button/loading-button.vue +1 -0
- package/dist/assets/components/button/components/toggle-button/toggle-button.docs.mdx +81 -0
- package/dist/assets/components/button/components/toggle-button/toggle-button.stories.ts +1 -0
- package/dist/assets/components/button/components/toggle-button/toggle-button.vue +1 -0
- package/dist/assets/components/card/card.docs.mdx +166 -0
- package/dist/assets/components/card/card.stories.ts +1 -0
- package/dist/assets/components/card/card.vue +1 -0
- package/dist/assets/components/checkbox/checkbox.docs.mdx +116 -0
- package/dist/assets/components/checkbox/checkbox.stories.ts +1 -0
- package/dist/assets/components/checkbox/checkbox.vue +1 -0
- package/dist/assets/components/checkbox/components/checkbox-group/checkbox-group.docs.mdx +134 -0
- package/dist/assets/components/checkbox/components/checkbox-group/checkbox-group.stories.ts +1 -0
- package/dist/assets/components/checkbox/components/checkbox-group/checkbox-group.vue +1 -0
- package/dist/assets/components/chip/chip.docs.mdx +51 -0
- package/dist/assets/components/chip/chip.stories.ts +1 -0
- package/dist/assets/components/chip/chip.vue +1 -0
- package/dist/assets/components/click-outside/click-outside.docs.mdx +30 -0
- package/dist/assets/components/click-outside/click-outside.stories.ts +1 -0
- package/dist/assets/components/code-snippet/code-snippet.docs.mdx +73 -0
- package/dist/assets/components/code-snippet/code-snippet.stories.ts +1 -0
- package/dist/assets/components/code-snippet/code-snippet.vue +1 -0
- package/dist/assets/components/country/country.docs.mdx +61 -0
- package/dist/assets/components/country/country.stories.ts +1 -0
- package/dist/assets/components/country/country.vue +1 -0
- package/dist/assets/components/currency/currency.docs.mdx +38 -0
- package/dist/assets/components/currency/currency.stories.ts +1 -0
- package/dist/assets/components/currency/currency.vue +1 -0
- package/dist/assets/components/dashed-underline/dashed-underline.docs.mdx +57 -0
- package/dist/assets/components/dashed-underline/dashed-underline.stories.ts +1 -0
- package/dist/assets/components/dashed-underline/dashed-underline.vue +1 -0
- package/dist/assets/components/data-grid/components/data-grid-cell/data-grid-cell.vue +1 -0
- package/dist/assets/components/data-grid/components/data-grid-cell-actions/data-grid-cell-actions.vue +1 -0
- package/dist/assets/components/data-grid/components/data-grid-columns/data-grid-columns.vue +1 -0
- package/dist/assets/components/data-grid/components/data-grid-config-settings/components/data-grid-config-settings-column-row/data-grid-config-settings-column-row.vue +1 -0
- package/dist/assets/components/data-grid/components/data-grid-config-settings/data-grid-config-settings.vue +1 -0
- package/dist/assets/components/data-grid/components/data-grid-lazy-load/data-grid-lazy-load.vue +1 -0
- package/dist/assets/components/data-grid/components/data-grid-row/data-grid-row.vue +1 -0
- package/dist/assets/components/data-grid/components/data-grid-static-icon/data-grid-static-icon.docs.mdx +61 -0
- package/dist/assets/components/data-grid/components/data-grid-static-icon/data-grid-static-icon.stories.ts +1 -0
- package/dist/assets/components/data-grid/components/data-grid-static-icon/data-grid-static-icon.vue +1 -0
- package/dist/assets/components/data-grid/components/data-grid-summary-cell/data-grid-summary-cell.docs.mdx +56 -0
- package/dist/assets/components/data-grid/components/data-grid-summary-cell/data-grid-summary-cell.stories.ts +1 -0
- package/dist/assets/components/data-grid/components/data-grid-summary-cell/data-grid-summary-cell.vue +1 -0
- package/dist/assets/components/data-grid/components/data-grid-tag-with-text-cell/data-grid-tag-with-text-cell.docs.mdx +35 -0
- package/dist/assets/components/data-grid/components/data-grid-tag-with-text-cell/data-grid-tag-with-text-cell.stories.ts +1 -0
- package/dist/assets/components/data-grid/components/data-grid-tag-with-text-cell/data-grid-tag-with-text-cell.vue +1 -0
- package/dist/assets/components/data-grid/components/data-grid-trend-cell/data-grid-trend-cell.docs.mdx +48 -0
- package/dist/assets/components/data-grid/components/data-grid-trend-cell/data-grid-trend-cell.stories.ts +1 -0
- package/dist/assets/components/data-grid/components/data-grid-trend-cell/data-grid-trend-cell.vue +1 -0
- package/dist/assets/components/data-grid/data-grid.docs.mdx +963 -0
- package/dist/assets/components/data-grid/data-grid.stories.ts +1 -0
- package/dist/assets/components/data-grid/data-grid.vue +1 -0
- package/dist/assets/components/date/date.docs.mdx +49 -0
- package/dist/assets/components/date/date.stories.ts +1 -0
- package/dist/assets/components/date/date.vue +1 -0
- package/dist/assets/components/date-picker/date-picker.docs.mdx +69 -0
- package/dist/assets/components/date-picker/date-picker.stories.ts +1 -0
- package/dist/assets/components/date-picker/date-picker.vue +1 -0
- package/dist/assets/components/date-range-picker/components/date-range-picker-calendar/date-range-picker-calendar.vue +1 -0
- package/dist/assets/components/date-range-picker/date-range-picker.docs.mdx +168 -0
- package/dist/assets/components/date-range-picker/date-range-picker.stories.ts +1 -0
- package/dist/assets/components/date-range-picker/date-range-picker.vue +1 -0
- package/dist/assets/components/divider/divider.docs.mdx +27 -0
- package/dist/assets/components/divider/divider.stories.ts +1 -0
- package/dist/assets/components/divider/divider.vue +1 -0
- package/dist/assets/components/draggable-handle/draggable-handle.docs.mdx +61 -0
- package/dist/assets/components/draggable-handle/draggable-handle.stories.ts +1 -0
- package/dist/assets/components/draggable-handle/draggable-handle.vue +1 -0
- package/dist/assets/components/dropdown/components/dropdown-base-textbox/dropdown-base-textbox.vue +1 -0
- package/dist/assets/components/dropdown/components/dropdown-default-textbox/dropdown-default-textbox.vue +1 -0
- package/dist/assets/components/dropdown/components/dropdown-options-container/dropdown-options-container.vue +1 -0
- package/dist/assets/components/dropdown/components/dropdown-small-textbox/dropdown-small-textbox.vue +1 -0
- package/dist/assets/components/dropdown/components/variants/dropdown-avatar/dropdown-avatar.stories.ts +1 -0
- package/dist/assets/components/dropdown/components/variants/dropdown-avatar/dropdown-avatar.vue +1 -0
- package/dist/assets/components/dropdown/components/variants/dropdown-country/dropdown-country.stories.ts +1 -0
- package/dist/assets/components/dropdown/components/variants/dropdown-country/dropdown-country.vue +1 -0
- package/dist/assets/components/dropdown/components/variants/dropdown-currency/dropdown-currency.stories.ts +1 -0
- package/dist/assets/components/dropdown/components/variants/dropdown-currency/dropdown-currency.vue +1 -0
- package/dist/assets/components/dropdown/components/variants/dropdown-payment-method/dropdown-payment-method.stories.ts +1 -0
- package/dist/assets/components/dropdown/components/variants/dropdown-payment-method/dropdown-payment-method.vue +1 -0
- package/dist/assets/components/dropdown/components/variants/dropdown-tag/dropdown-tag.stories.ts +1 -0
- package/dist/assets/components/dropdown/components/variants/dropdown-tag/dropdown-tag.vue +1 -0
- package/dist/assets/components/dropdown/dropdown.docs.mdx +420 -0
- package/dist/assets/components/dropdown/dropdown.stories.ts +1 -0
- package/dist/assets/components/dropdown/dropdown.vue +1 -0
- package/dist/assets/components/empty-state/empty-state.docs.mdx +115 -0
- package/dist/assets/components/empty-state/empty-state.stories.ts +1 -0
- package/dist/assets/components/empty-state/empty-state.vue +1 -0
- package/dist/assets/components/file-uploader/components/file-uploader-file-card/components/file-uploader-file-card-animation/file-uploader-file-card-animation.vue +1 -0
- package/dist/assets/components/file-uploader/components/file-uploader-file-card/file-uploader-file-card.stories.ts +1 -0
- package/dist/assets/components/file-uploader/components/file-uploader-file-card/file-uploader-file-card.vue +1 -0
- package/dist/assets/components/file-uploader/components/file-uploader-restrictions/file-uploader-restrictions.stories.ts +1 -0
- package/dist/assets/components/file-uploader/components/file-uploader-restrictions/file-uploader-restrictions.vue +1 -0
- package/dist/assets/components/file-uploader/file-uploader.docs.mdx +117 -0
- package/dist/assets/components/file-uploader/file-uploader.stories.ts +1 -0
- package/dist/assets/components/file-uploader/file-uploader.vue +1 -0
- package/dist/assets/components/filter-bar/components/all-filters-modal/all-filters-modal.stories.ts +1 -0
- package/dist/assets/components/filter-bar/components/all-filters-modal/all-filters-modal.vue +1 -0
- package/dist/assets/components/filter-bar/components/all-filters-modal/components/all-filters-modal-button/all-filters-modal-button.vue +1 -0
- package/dist/assets/components/filter-bar/components/base-filter/base-filter.docs.mdx +90 -0
- package/dist/assets/components/filter-bar/components/base-filter/base-filter.stories.ts +1 -0
- package/dist/assets/components/filter-bar/components/base-filter/base-filter.vue +1 -0
- package/dist/assets/components/filter-bar/components/base-filter-button/base-filter-button.vue +1 -0
- package/dist/assets/components/filter-bar/components/boolean-filter/boolean-filter.vue +1 -0
- package/dist/assets/components/filter-bar/components/checkbox-group-filter/checkbox-group-filter.stories.ts +1 -0
- package/dist/assets/components/filter-bar/components/checkbox-group-filter/checkbox-group-filter.vue +1 -0
- package/dist/assets/components/filter-bar/components/date-filter/date-filter.stories.ts +1 -0
- package/dist/assets/components/filter-bar/components/date-filter/date-filter.vue +1 -0
- package/dist/assets/components/filter-bar/components/date-range-filter/date-range-filter.stories.ts +1 -0
- package/dist/assets/components/filter-bar/components/date-range-filter/date-range-filter.vue +1 -0
- package/dist/assets/components/filter-bar/components/filter-bar-button/filter-bar-button.vue +1 -0
- package/dist/assets/components/filter-bar/components/filter-bar-button-group/filter-bar-button-group.vue +1 -0
- package/dist/assets/components/filter-bar/components/input-filter/input-filter.docs.mdx +18 -0
- package/dist/assets/components/filter-bar/components/input-filter/input-filter.stories.ts +1 -0
- package/dist/assets/components/filter-bar/components/input-filter/input-filter.vue +1 -0
- package/dist/assets/components/filter-bar/components/input-with-dropdown-filter/input-with-dropdown-filter.docs.mdx +18 -0
- package/dist/assets/components/filter-bar/components/input-with-dropdown-filter/input-with-dropdown-filter.stories.ts +1 -0
- package/dist/assets/components/filter-bar/components/input-with-dropdown-filter/input-with-dropdown-filter.vue +1 -0
- package/dist/assets/components/filter-bar/components/radio-group-filter/radio-group-filter.stories.ts +1 -0
- package/dist/assets/components/filter-bar/components/radio-group-filter/radio-group-filter.vue +1 -0
- package/dist/assets/components/filter-bar/components/range-filter/range-filter.vue +1 -0
- package/dist/assets/components/filter-bar/components/select-filter/components/select-filter-button/select-filter-button.vue +1 -0
- package/dist/assets/components/filter-bar/components/select-filter/components/select-filter-dropdown/select-filter-dropdown.vue +1 -0
- package/dist/assets/components/filter-bar/components/select-filter/select-filter.stories.ts +1 -0
- package/dist/assets/components/filter-bar/components/select-filter/select-filter.vue +1 -0
- package/dist/assets/components/filter-bar/components/select-filter/variants/select-avatar-filter/select-avatar-filter.stories.ts +1 -0
- package/dist/assets/components/filter-bar/components/select-filter/variants/select-avatar-filter/select-avatar-filter.vue +1 -0
- package/dist/assets/components/filter-bar/components/select-filter/variants/select-country-filter/select-country-filter.stories.ts +1 -0
- package/dist/assets/components/filter-bar/components/select-filter/variants/select-country-filter/select-country-filter.vue +1 -0
- package/dist/assets/components/filter-bar/components/select-filter/variants/select-currency-filter/select-currency-filter.stories.ts +1 -0
- package/dist/assets/components/filter-bar/components/select-filter/variants/select-currency-filter/select-currency-filter.vue +1 -0
- package/dist/assets/components/filter-bar/components/select-filter/variants/select-payment-method-filter/select-payment-method-filter.stories.ts +1 -0
- package/dist/assets/components/filter-bar/components/select-filter/variants/select-payment-method-filter/select-payment-method-filter.vue +1 -0
- package/dist/assets/components/filter-bar/components/select-filter/variants/select-tag-filter/select-tag-filter.stories.ts +1 -0
- package/dist/assets/components/filter-bar/components/select-filter/variants/select-tag-filter/select-tag-filter.vue +1 -0
- package/dist/assets/components/filter-bar/components/toggle-filter/toggle-filter.stories.ts +1 -0
- package/dist/assets/components/filter-bar/components/toggle-filter/toggle-filter.vue +1 -0
- package/dist/assets/components/filter-bar/filter-bar.docs.mdx +1005 -0
- package/dist/assets/components/filter-bar/filter-bar.stories.ts +1 -0
- package/dist/assets/components/filter-bar/filter-bar.vue +1 -0
- package/dist/assets/components/focus-trap/focus-trap.docs.mdx +10 -0
- package/dist/assets/components/focus-trap/focus-trap.stories.ts +1 -0
- package/dist/assets/components/focus-trap/focus-trap.vue +1 -0
- package/dist/assets/components/form-layout/components/form-layout-field-tip/form-layout-field-tip.vue +1 -0
- package/dist/assets/components/form-layout/components/form-layout-group/form-layout-group.vue +1 -0
- package/dist/assets/components/form-layout/components/form-layout-title/form-layout-title.vue +1 -0
- package/dist/assets/components/form-layout/form-layout.docs.mdx +452 -0
- package/dist/assets/components/form-layout/form-layout.stories.ts +1 -0
- package/dist/assets/components/form-layout/form-layout.vue +1 -0
- package/dist/assets/components/header/header.docs.mdx +85 -0
- package/dist/assets/components/header/header.stories.ts +1 -0
- package/dist/assets/components/header/header.vue +1 -0
- package/dist/assets/components/header-with-views/components/header-with-views-all-views/header-with-views-all-views.vue +1 -0
- package/dist/assets/components/header-with-views/components/header-with-views-item-edit-form/header-with-views-edit-form.vue +1 -0
- package/dist/assets/components/header-with-views/header-with-views.docs.mdx +103 -0
- package/dist/assets/components/header-with-views/header-with-views.stories.ts +1 -0
- package/dist/assets/components/header-with-views/header-with-views.vue +1 -0
- package/dist/assets/components/image/image.docs.mdx +34 -0
- package/dist/assets/components/image/image.stories.ts +1 -0
- package/dist/assets/components/image/image.vue +1 -0
- package/dist/assets/components/info-icon/info-icon.docs.mdx +57 -0
- package/dist/assets/components/info-icon/info-icon.stories.ts +1 -0
- package/dist/assets/components/info-icon/info-icon.vue +1 -0
- package/dist/assets/components/input-field/input-field.docs.mdx +141 -0
- package/dist/assets/components/input-field/input-field.stories.ts +1 -0
- package/dist/assets/components/input-field/input-field.vue +1 -0
- package/dist/assets/components/input-field-password/input-field-password.docs.mdx +292 -0
- package/dist/assets/components/input-field-password/input-field-password.stories.ts +1 -0
- package/dist/assets/components/input-field-password/input-field-password.vue +1 -0
- package/dist/assets/components/input-field-phone-number/input-field-phone-number.docs.mdx +72 -0
- package/dist/assets/components/input-field-phone-number/input-field-phone-number.stories.ts +1 -0
- package/dist/assets/components/input-field-phone-number/input-field-phone-number.vue +1 -0
- package/dist/assets/components/inspector/inspector.docs.mdx +118 -0
- package/dist/assets/components/inspector/inspector.stories.ts +1 -0
- package/dist/assets/components/inspector/inspector.vue +1 -0
- package/dist/assets/components/internal/base-button/base-button.vue +1 -0
- package/dist/assets/components/internal/button-actions-with-menu/button-actions-with-menu.stories.ts +1 -0
- package/dist/assets/components/internal/button-actions-with-menu/button-actions-with-menu.vue +1 -0
- package/dist/assets/components/internal/calendar/calendar.stories.ts +1 -0
- package/dist/assets/components/internal/calendar/calendar.vue +1 -0
- package/dist/assets/components/internal/calendar/components/calendar-month/calendar-month.stories.ts +1 -0
- package/dist/assets/components/internal/calendar/components/calendar-month/calendar-month.vue +1 -0
- package/dist/assets/components/internal/calendar/components/calendar-month/components/calendar-month-day/__test__/calendar-month-day-stub.vue +1 -0
- package/dist/assets/components/internal/calendar/components/calendar-month/components/calendar-month-day/calendar-month-day.stories.ts +1 -0
- package/dist/assets/components/internal/calendar/components/calendar-month/components/calendar-month-day/calendar-month-day.vue +1 -0
- package/dist/assets/components/internal/calendar/components/calendar-year/calendar-year.vue +1 -0
- package/dist/assets/components/internal/calendar/components/calendar-year/components/calendar-year-month/__test__/calendar-year-month-stub.vue +1 -0
- package/dist/assets/components/internal/calendar/components/calendar-year/components/calendar-year-month/calendar-year-month.vue +1 -0
- package/dist/assets/components/internal/checkbox-input/checkbox-input.stories.ts +1 -0
- package/dist/assets/components/internal/checkbox-input/checkbox-input.vue +1 -0
- package/dist/assets/components/internal/controls-group/controls-group.vue +1 -0
- package/dist/assets/components/internal/copy/copy.docs.mdx +43 -0
- package/dist/assets/components/internal/copy/copy.stories.ts +1 -0
- package/dist/assets/components/internal/copy/copy.vue +1 -0
- package/dist/assets/components/internal/decorative-checkbox/decorative-checkbox.vue +1 -0
- package/dist/assets/components/internal/dialog-page/dialog-page.vue +1 -0
- package/dist/assets/components/internal/error-message/error-message.vue +1 -0
- package/dist/assets/components/internal/field-label/field-label.vue +1 -0
- package/dist/assets/components/internal/fixed-scroller/fixed-scroller.docs.mdx +21 -0
- package/dist/assets/components/internal/fixed-scroller/fixed-scroller.stories.ts +1 -0
- package/dist/assets/components/internal/fixed-scroller/fixed-scroller.vue +1 -0
- package/dist/assets/components/internal/footer-actions/footer-actions.vue +1 -0
- package/dist/assets/components/internal/grid-layout/grid-layout.vue +1 -0
- package/dist/assets/components/internal/header-meta/header-meta.vue +1 -0
- package/dist/assets/components/internal/info-icon-with-popover/info-icon-with-popover.vue +1 -0
- package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/components/listbox-multi-select-category/listbox-multi-select-category.vue +1 -0
- package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/listbox-multi-select-options.vue +1 -0
- package/dist/assets/components/internal/listbox/components/listbox-multi-select/listbox-multi-select.vue +1 -0
- package/dist/assets/components/internal/listbox/components/listbox-option/listbox-option.vue +1 -0
- package/dist/assets/components/internal/listbox/components/listbox-option-tag/listbox-option-tag.vue +1 -0
- package/dist/assets/components/internal/listbox/components/listbox-single-select/components/listbox-single-select-category/listbox-single-select-category.vue +1 -0
- package/dist/assets/components/internal/listbox/components/listbox-single-select/listbox-single-select.vue +1 -0
- package/dist/assets/components/internal/listbox/components/listbox-single-select-option/listbox-single-select-option.vue +1 -0
- package/dist/assets/components/internal/listbox/listbox.stories.ts +1 -0
- package/dist/assets/components/internal/listbox/listbox.vue +1 -0
- package/dist/assets/components/internal/radio-input/radio-input.stories.ts +1 -0
- package/dist/assets/components/internal/radio-input/radio-input.vue +1 -0
- package/dist/assets/components/internal/teleport/teleport.vue +1 -0
- package/dist/assets/components/internal/tooltip/tooltip.test.vue +1 -0
- package/dist/assets/components/internal/tooltip/tooltip.vue +1 -0
- package/dist/assets/components/layout/components/layout-row/layout-row.stories.ts +1 -0
- package/dist/assets/components/layout/components/layout-row/layout-row.vue +1 -0
- package/dist/assets/components/layout/layout.docs.mdx +108 -0
- package/dist/assets/components/layout/layout.stories.ts +1 -0
- package/dist/assets/components/layout/layout.vue +1 -0
- package/dist/assets/components/link/link.docs.mdx +119 -0
- package/dist/assets/components/link/link.stories.ts +1 -0
- package/dist/assets/components/link/link.vue +1 -0
- package/dist/assets/components/loading-indicator/loading-indicator.docs.mdx +65 -0
- package/dist/assets/components/loading-indicator/loading-indicator.stories.ts +1 -0
- package/dist/assets/components/loading-indicator/loading-indicator.vue +1 -0
- package/dist/assets/components/menu/components/menu-item/menu-item.vue +1 -0
- package/dist/assets/components/menu/components/menu-item-list/menu-item-list.vue +1 -0
- package/dist/assets/components/menu/components/menu-list-container/menu-list-container.vue +1 -0
- package/dist/assets/components/menu/components/sub-menu-item-list/sub-menu-item-list.vue +1 -0
- package/dist/assets/components/menu/menu.docs.mdx +121 -0
- package/dist/assets/components/menu/menu.stories.ts +1 -0
- package/dist/assets/components/menu/menu.vue +1 -0
- package/dist/assets/components/modal/components/base-modal/base-modal.vue +1 -0
- package/dist/assets/components/modal/components/modal-default/modal-default.vue +1 -0
- package/dist/assets/components/modal/components/modal-dialog/modal-dialog.vue +1 -0
- package/dist/assets/components/modal/components/modal-page/modal-page.vue +1 -0
- package/dist/assets/components/modal/modal.docs.mdx +215 -0
- package/dist/assets/components/modal/modal.stories.ts +1 -0
- package/dist/assets/components/modal/modal.vue +1 -0
- package/dist/assets/components/modal-fullscreen/components/modal-fullscreen-page.vue +1 -0
- package/dist/assets/components/modal-fullscreen/modal-fullscreen.docs.mdx +217 -0
- package/dist/assets/components/modal-fullscreen/modal-fullscreen.stories.ts +1 -0
- package/dist/assets/components/modal-fullscreen/modal-fullscreen.vue +1 -0
- package/dist/assets/components/pagination/components/pagination-context/pagination-context.vue +1 -0
- package/dist/assets/components/pagination/components/pagination-controls/pagination-controls.vue +1 -0
- package/dist/assets/components/pagination/components/pagination-results-per-page/pagination-results-per-page.vue +1 -0
- package/dist/assets/components/pagination/pagination.docs.mdx +116 -0
- package/dist/assets/components/pagination/pagination.stories.ts +1 -0
- package/dist/assets/components/pagination/pagination.vue +1 -0
- package/dist/assets/components/payment-method/payment-method.docs.mdx +34 -0
- package/dist/assets/components/payment-method/payment-method.stories.ts +1 -0
- package/dist/assets/components/payment-method/payment-method.vue +1 -0
- package/dist/assets/components/popover/components/popover-dismiss-button/popover-dismiss-button.vue +1 -0
- package/dist/assets/components/popover/components/popover-image/popover-image.vue +1 -0
- package/dist/assets/components/popover/components/popover-title/popover-title.vue +1 -0
- package/dist/assets/components/popover/popover.docs.mdx +89 -0
- package/dist/assets/components/popover/popover.stories.ts +1 -0
- package/dist/assets/components/popover/popover.vue +1 -0
- package/dist/assets/components/popper-container/popper-container.docs.mdx +11 -0
- package/dist/assets/components/popper-container/popper-container.stories.ts +1 -0
- package/dist/assets/components/popper-container/popper-container.vue +1 -0
- package/dist/assets/components/promo-banner/promo-banner.docs.mdx +94 -0
- package/dist/assets/components/promo-banner/promo-banner.stories.ts +1 -0
- package/dist/assets/components/promo-banner/promo-banner.vue +1 -0
- package/dist/assets/components/radio-group/components/radio-button/radio-button.docs.mdx +76 -0
- package/dist/assets/components/radio-group/components/radio-button/radio-button.stories.ts +1 -0
- package/dist/assets/components/radio-group/components/radio-button/radio-button.vue +1 -0
- package/dist/assets/components/radio-group/radio-group.docs.mdx +154 -0
- package/dist/assets/components/radio-group/radio-group.stories.ts +1 -0
- package/dist/assets/components/radio-group/radio-group.vue +1 -0
- package/dist/assets/components/rich-text-editor/components/rich-text-editor-content-area/rich-text-editor-content-area.vue +1 -0
- package/dist/assets/components/rich-text-editor/components/rich-text-editor-renderer/components/rich-text-editor-code-block/rich-text-editor-code-block.vue +1 -0
- package/dist/assets/components/rich-text-editor/components/rich-text-editor-renderer/components/rich-text-editor-inline-code/rich-text-editor-inline-code.vue +1 -0
- package/dist/assets/components/rich-text-editor/components/rich-text-editor-renderer/components/rich-text-editor-link/rich-text-editor-link.vue +1 -0
- package/dist/assets/components/rich-text-editor/components/rich-text-editor-renderer/components/rich-text-editor-list-item/rich-text-editor-list-item.vue +1 -0
- package/dist/assets/components/rich-text-editor/components/rich-text-editor-renderer/components/rich-text-editor-table/rich-text-editor-table.vue +1 -0
- package/dist/assets/components/rich-text-editor/rich-text-editor.docs.mdx +52 -0
- package/dist/assets/components/rich-text-editor/rich-text-editor.stories.ts +1 -0
- package/dist/assets/components/rich-text-editor/rich-text-editor.vue +1 -0
- package/dist/assets/components/search-bar/search-bar.docs.mdx +117 -0
- package/dist/assets/components/search-bar/search-bar.stories.ts +1 -0
- package/dist/assets/components/search-bar/search-bar.vue +1 -0
- package/dist/assets/components/secondary-nav/components/secondary-nav-category/secondary-nav-category.vue +1 -0
- package/dist/assets/components/secondary-nav/components/secondary-nav-item/secondary-nav-item.vue +1 -0
- package/dist/assets/components/secondary-nav/secondary-nav.docs.mdx +40 -0
- package/dist/assets/components/secondary-nav/secondary-nav.stories.ts +1 -0
- package/dist/assets/components/secondary-nav/secondary-nav.vue +1 -0
- package/dist/assets/components/segmented-control/components/segmented-control-button/segmented-control-button.vue +1 -0
- package/dist/assets/components/segmented-control/segmented-control.docs.mdx +90 -0
- package/dist/assets/components/segmented-control/segmented-control.stories.ts +1 -0
- package/dist/assets/components/segmented-control/segmented-control.vue +1 -0
- package/dist/assets/components/selection-card/components/selection-card-group/selection-card-group.docs.mdx +119 -0
- package/dist/assets/components/selection-card/components/selection-card-group/selection-card-group.stories.ts +1 -0
- package/dist/assets/components/selection-card/components/selection-card-group/selection-card-group.vue +1 -0
- package/dist/assets/components/selection-card/selection-card.docs.mdx +108 -0
- package/dist/assets/components/selection-card/selection-card.stories.ts +1 -0
- package/dist/assets/components/selection-card/selection-card.vue +1 -0
- package/dist/assets/components/sidepanel/components/sidepanel-page.stories.ts +1 -0
- package/dist/assets/components/sidepanel/components/sidepanel-page.vue +1 -0
- package/dist/assets/components/sidepanel/sidepanel.docs.mdx +129 -0
- package/dist/assets/components/sidepanel/sidepanel.stories.ts +1 -0
- package/dist/assets/components/sidepanel/sidepanel.vue +1 -0
- package/dist/assets/components/status/status.docs.mdx +62 -0
- package/dist/assets/components/status/status.stories.ts +1 -0
- package/dist/assets/components/status/status.vue +1 -0
- package/dist/assets/components/stepper/components/step/step.stories.ts +1 -0
- package/dist/assets/components/stepper/components/step/step.vue +1 -0
- package/dist/assets/components/stepper/stepper.docs.mdx +127 -0
- package/dist/assets/components/stepper/stepper.stories.ts +1 -0
- package/dist/assets/components/stepper/stepper.vue +1 -0
- package/dist/assets/components/structured-list/components/structered-list-item/structured-list-item.stories.ts +1 -0
- package/dist/assets/components/structured-list/components/structered-list-item/structured-list-item.vue +1 -0
- package/dist/assets/components/structured-list/structured-list.docs.mdx +68 -0
- package/dist/assets/components/structured-list/structured-list.stories.ts +1 -0
- package/dist/assets/components/structured-list/structured-list.vue +1 -0
- package/dist/assets/components/summary-grid/components/summary-grid-item/summary-grid-item.vue +1 -0
- package/dist/assets/components/summary-grid/components/summary-grid-item-amount/summary-grid-item-amount.stories.ts +1 -0
- package/dist/assets/components/summary-grid/components/summary-grid-item-amount/summary-grid-item-amount.vue +1 -0
- package/dist/assets/components/summary-grid/components/summary-grid-item-custom/summary-grid-item-custom.stories.ts +1 -0
- package/dist/assets/components/summary-grid/components/summary-grid-item-custom/summary-grid-item-custom.vue +1 -0
- package/dist/assets/components/summary-grid/components/summary-grid-item-numeric/summary-grid-item-numeric.stories.ts +1 -0
- package/dist/assets/components/summary-grid/components/summary-grid-item-numeric/summary-grid-item-numeric.vue +1 -0
- package/dist/assets/components/summary-grid/components/summary-grid-item-percentage/summary-grid-item-percentage.stories.ts +1 -0
- package/dist/assets/components/summary-grid/components/summary-grid-item-percentage/summary-grid-item-percentage.vue +1 -0
- package/dist/assets/components/summary-grid/components/summary-grid-item-text/summary-grid-item-text.stories.ts +1 -0
- package/dist/assets/components/summary-grid/components/summary-grid-item-text/summary-grid-item-text.vue +1 -0
- package/dist/assets/components/summary-grid/summary-grid.docs.mdx +152 -0
- package/dist/assets/components/summary-grid/summary-grid.stories.ts +1 -0
- package/dist/assets/components/summary-grid/summary-grid.vue +1 -0
- package/dist/assets/components/tabs/components/tab.vue +1 -0
- package/dist/assets/components/tabs/tabs.docs.mdx +98 -0
- package/dist/assets/components/tabs/tabs.stories.ts +1 -0
- package/dist/assets/components/tabs/tabs.vue +1 -0
- package/dist/assets/components/tag/tag.docs.mdx +137 -0
- package/dist/assets/components/tag/tag.stories.ts +1 -0
- package/dist/assets/components/tag/tag.vue +1 -0
- package/dist/assets/components/textarea/textarea.docs.mdx +53 -0
- package/dist/assets/components/textarea/textarea.stories.ts +1 -0
- package/dist/assets/components/textarea/textarea.vue +1 -0
- package/dist/assets/components/timeline/components/timeline-item/timeline-item.stories.ts +1 -0
- package/dist/assets/components/timeline/components/timeline-item/timeline-item.vue +1 -0
- package/dist/assets/components/timeline/timeline.docs.mdx +131 -0
- package/dist/assets/components/timeline/timeline.stories.ts +1 -0
- package/dist/assets/components/timeline/timeline.vue +1 -0
- package/dist/assets/components/toast/components/toast-item/toast-item.vue +1 -0
- package/dist/assets/components/toast/components/toast-shadow-stack/toast-shadow-stack.vue +1 -0
- package/dist/assets/components/toast/toast.docs.mdx +151 -0
- package/dist/assets/components/toast/toast.stories.ts +1 -0
- package/dist/assets/components/toast/toast.vue +1 -0
- package/dist/assets/components/toggle/toggle.docs.mdx +81 -0
- package/dist/assets/components/toggle/toggle.stories.ts +1 -0
- package/dist/assets/components/toggle/toggle.vue +1 -0
- package/dist/assets/components/tutorial/components/tutorial-popover/components/tutorial-indicator/tutorial-indicator.vue +1 -0
- package/dist/assets/components/tutorial/components/tutorial-popover/tutorial-popover.vue +1 -0
- package/dist/assets/components/tutorial/tutorial.docs.mdx +85 -0
- package/dist/assets/components/tutorial/tutorial.stories.ts +1 -0
- package/dist/assets/components/tutorial/tutorial.vue +1 -0
- package/dist/assets/components/typography/typography.docs.mdx +124 -0
- package/dist/assets/components/typography/typography.stories.ts +1 -0
- package/dist/assets/components/typography/typography.vue +1 -0
- package/dist/assets/composables/use-bento-currency/use-bento-currency.docs.mdx +28 -0
- package/dist/assets/composables/use-bento-currency/use-bento-currency.stories.ts +1 -0
- package/dist/assets/composables/use-click-outside/use-click-outside.docs.mdx +10 -0
- package/dist/assets/composables/use-click-outside/use-click-outside.stories.ts +1 -0
- package/dist/assets/directives/highlight/highlight.docs.mdx +64 -0
- package/dist/assets/directives/highlight/highlight.stories.ts +1 -0
- package/dist/assets/directives/keyboard-navigation/keyboard-navigation.docs.mdx +41 -0
- package/dist/assets/directives/keyboard-navigation/keyboard-navigation.stories.ts +1 -0
- package/dist/assets/directives/tooltip/tooltip.docs.mdx +86 -0
- package/dist/assets/directives/tooltip/tooltip.stories.ts +1 -0
- package/dist/assets/index.ts +1 -0
- package/dist/assets/templates/dashboard-template/components/dashboard-section/dashboard-section.stories.ts +1 -0
- package/dist/assets/templates/dashboard-template/components/dashboard-section/dashboard-section.vue +1 -0
- package/dist/assets/templates/dashboard-template/dashboard-template.docs.mdx +148 -0
- package/dist/assets/templates/dashboard-template/dashboard-template.stories.ts +1 -0
- package/dist/assets/templates/dashboard-template/dashboard-template.vue +1 -0
- package/dist/assets/templates/data-grid-template/data-grid-template.docs.mdx +117 -0
- package/dist/assets/templates/data-grid-template/data-grid-template.stories.ts +1 -0
- package/dist/assets/templates/data-grid-template/data-grid-template.vue +1 -0
- package/dist/main.js +30051 -0
- package/package.json +46 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.1 (2026-03-04)
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
- updated `@modelcontextprotocol/sdk` to fix `CVE-2026-25536`, `CVE-2026-25536` ([15f9b8fd1](https://github.com/Adyen/bento/commit/15f9b8fd1))
|
|
8
|
+
|
|
9
|
+
### Documentation
|
|
10
|
+
|
|
11
|
+
- updated MCP docs with standard config for models ([471b7fa80](https://github.com/Adyen/bento/commit/471b7fa80))
|
|
12
|
+
|
|
13
|
+
### ❤️ Thank You
|
|
14
|
+
|
|
15
|
+
- daver
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## 0.1.0 (2026-02-25)
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
- added `@adyen/bento-mcp` to NX release ([8ada8c531](https://github.com/Adyen/bento/commit/8ada8c531))
|
|
23
|
+
|
|
24
|
+
### ❤️ Thank You
|
|
25
|
+
|
|
26
|
+
- daver
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Adyen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Bento MCP Server
|
|
2
|
+
|
|
3
|
+
Bento Model Context Protocol (MCP) server. This package provides context about the Bento design system to large language
|
|
4
|
+
models (LLMs) to interact with Bento's codebase, documentation, and components.
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
- **Component Context**: Provide component definitions and usage guidelines to LLMs.
|
|
9
|
+
- **Changelog Access**: (Planned) Query and retrieve information from the Bento changelog.
|
|
10
|
+
- **Design Tokens**: (Planned) Access design token values and documentation.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
You can use this server as a tool with various AI assistant clients that support the Model Context Protocol.
|
|
15
|
+
|
|
16
|
+
To configure the MCP server, add the following to your client's settings file:
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"mcpServers": {
|
|
21
|
+
"bento": {
|
|
22
|
+
"type": "stdio",
|
|
23
|
+
"command": "npx",
|
|
24
|
+
"args": ["@adyen/bento-mcp@latest"]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The location of this file may vary depending on your client and setup. For project-level and global configuration, you
|
|
31
|
+
can typically use:
|
|
32
|
+
|
|
33
|
+
| Client | Local Path | Global Path |
|
|
34
|
+
| -------- | ----------------------------- | ------------------------------------- |
|
|
35
|
+
| Claude | `.claude/settings.local.json` | `~/.claude/settings.json` |
|
|
36
|
+
| Gemini | `.gemini/settings.json` | `~/.gemini/settings.json` |
|
|
37
|
+
| Windsurf | `-` | `~/.codeium/windsurf/mcp_config.json` |
|
|
38
|
+
|
|
39
|
+
Once configured, you can invoke the tool by its name (`bento`).
|
|
40
|
+
|
|
41
|
+
## Available Tools
|
|
42
|
+
|
|
43
|
+
The server exposes the following tools to the language model:
|
|
44
|
+
|
|
45
|
+
### `get_component`
|
|
46
|
+
|
|
47
|
+
Retrieves the documentation, stories, and Vue implementation for a list of components.
|
|
48
|
+
|
|
49
|
+
- **Arguments:** `componentNames` (Array<string>): A list of component names (e.g., `["button", "modal"]`).
|
|
50
|
+
- **Returns:** A Markdown formatted string containing the contents of the `.docs.mdx`, `.stories.ts`, and `.vue` files
|
|
51
|
+
for the requested components.
|
|
52
|
+
|
|
53
|
+
### `get_all_components`
|
|
54
|
+
|
|
55
|
+
Retrieves the main index file that exports all available Bento components. Use this to understand which components are
|
|
56
|
+
available in the library.
|
|
57
|
+
|
|
58
|
+
- **Returns:** The raw content of the `packages/vue2/src/index.ts` file.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Canvas, Meta, Story } from '@storybook/blocks';
|
|
2
|
+
import * as AccordionStories from './accordion.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={AccordionStories} />
|
|
5
|
+
|
|
6
|
+
# Accordion
|
|
7
|
+
|
|
8
|
+
An accordion is a vertical stack of interactive headers used to reveal or hide sections of content associated with this
|
|
9
|
+
headers.
|
|
10
|
+
|
|
11
|
+
<Canvas withSource="closed">
|
|
12
|
+
<Story of={AccordionStories.Default} />
|
|
13
|
+
</Canvas>
|
|
14
|
+
|
|
15
|
+
## Use Cases
|
|
16
|
+
|
|
17
|
+
Use accordions only when:
|
|
18
|
+
|
|
19
|
+
- Users need only a few pieces of information on the page
|
|
20
|
+
- The information in each section is independent and users are unlikely to need simultaneous access to multiple
|
|
21
|
+
sections
|
|
22
|
+
- When the content is long and the window size is small (example: mobile)
|
|
23
|
+
|
|
24
|
+
Some valid usage examples:
|
|
25
|
+
|
|
26
|
+
- Organize additional information (reduce clutter)
|
|
27
|
+
- Reduce page length (when information is not crucial) or when content can’t be displayed all at once due to limited
|
|
28
|
+
space (mobile)
|
|
29
|
+
- Improve scannability of page
|
|
30
|
+
|
|
31
|
+
### Do not use
|
|
32
|
+
|
|
33
|
+
Please do not use accordions when your audience requires the majority or all the content on the page to find answers to
|
|
34
|
+
their questions. Also we do not recommend to use accordions when there is a little content on the page or content has a
|
|
35
|
+
deep hierarchy with sublevels.
|
|
36
|
+
|
|
37
|
+
## Modifiers
|
|
38
|
+
|
|
39
|
+
### Title size
|
|
40
|
+
|
|
41
|
+
Providing `small` title size renders smaller accordion item titles.
|
|
42
|
+
|
|
43
|
+
Use this for more compact layouts.
|
|
44
|
+
|
|
45
|
+
## Accessibility
|
|
46
|
+
|
|
47
|
+
The accordion items follow the HTML structure recommended by the
|
|
48
|
+
[accordion pattern](https://www.w3.org/WAI/ARIA/apg/patterns/accordion/).
|
|
49
|
+
|
|
50
|
+
The title section is focusable and clickable.
|
|
51
|
+
|
|
52
|
+
### Keyboard interaction
|
|
53
|
+
|
|
54
|
+
The accordion items are reachable through keyboard navigation and follows the logical navigation flow of the page. A
|
|
55
|
+
detailed list of keyboard interactions is provided in the table below.
|
|
56
|
+
|
|
57
|
+
| Keyboard interaction | Output |
|
|
58
|
+
| -------------------- | -------------------------------------------------------------------- |
|
|
59
|
+
| `Tab` | Moves focus to the next accordion title section. |
|
|
60
|
+
| `Shift` + `Tab` | Moves focus to the previous accordion title section. |
|
|
61
|
+
| `Space`/`Enter` | When focus is on the accordion title, expands/collapses the content. |
|
|
62
|
+
|
|
63
|
+
### Roles, states and properties
|
|
64
|
+
|
|
65
|
+
| ARIA attribute | is automatic? | fallback used | manual override |
|
|
66
|
+
| ----------------- | ------------------------------------------------------------- | ------------- | --------------- |
|
|
67
|
+
| `role="heading"` | Yes, through the semantic `h3` element. | - | - |
|
|
68
|
+
| `role="button"` | Yes, through the semantic `button` element. | - | - |
|
|
69
|
+
| `role="region"` | Yes, role set on the content `div`. | - | - |
|
|
70
|
+
| `aria-controls` | Yes, set to the content `id` attribute. | - | - |
|
|
71
|
+
| `aria-expanded` | Yes, "true" or "false" based on the expanded/collapsed state. | - | - |
|
|
72
|
+
| `aria-labelledby` | Yes, set to the button `id` attribute. | - | - |
|
|
73
|
+
|
|
74
|
+
## Resources
|
|
75
|
+
|
|
76
|
+
- [Figma link](https://www.figma.com/file/uLabwF3243jdMDsNSP7U9I/Bento---Components?type=design&node-id=17009-76072&t=UTkCtnqxxUOuopRB-4)
|
|
77
|
+
- [WAI-ARIA guidelines](https://www.w3.org/WAI/ARIA/apg/patterns/accordion/)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { ref } from 'vue'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import { isVue2 } from 'vue-demi'; import BentoAccordion from './accordion.vue'; import BentoAccordionItem from './components/accordion-item.vue'; import { BentoButton } from '@/components/button'; import { BentoTypography } from '@/components/typography'; import type { Meta, StoryObj } from '@storybook/vue'; import { BentoAccordionTitleSizeOptions } from './accordion.types'; export default { title: 'Accordion', component: BentoAccordion, argTypes: { titleSize: { options: BentoAccordionTitleSizeOptions, control: { type: 'select', }, }, default: { control: false, table: { type: { summary: 'BentoAccordionItem[]' }, }, }, }, } as Meta; type Story = StoryObj<typeof BentoAccordion>; const DEFAULT_PROPS = { titleSize: 'default', }; const defaultCode = ` <template> <bento-accordion> <bento-accordion-item title="Alderaan" :is-expanded.sync="toggle"> <bento-typography> Alderaan had a reputation as one of the most peaceful and cultured worlds in the Galaxy, an idyllic locale for vacation or education in high demand among the denizens of Star Wars' most cultured and aspirational. </bento-typography> </bento-accordion-item> <bento-accordion-item title="Coruscant" is-expanded> <bento-typography> Coruscant is among the most diverse locales in the Galaxy, though it tends to be humans who hold wealth and power. Although it appears a flawless futuristic paradise on its surface, the lower you descend into the city's levels, the more crime and poverty you'll find. </bento-typography> </bento-accordion-item> <bento-accordion-item title="Dagobah"> <bento-typography> A swamp planet teeming with so much life that any manner of Force detection is rendered irrelevant, Dagobah is where Jedi Grandmaster in exile Yoda made his home for the last years of his life following the fall of the Jedi Order, awaiting the arrival of his final pupil and the Galaxy's last hope. </bento-typography> </bento-accordion-item> <bento-accordion-item title="Hoth"> <bento-typography> This snowy ice planet was home to the Rebellion's Echo Base, which Leia, Han, and Luke called home when the Empire titularly struck back in The Empire Strikes Back. Luke fights a wampa, Han guts a tauntaun for warmth, and the rebels hogtie some elephantine AT-AT imperial walkers with their snowspeeders here before beating a hasty retreat from the Empire. </bento-typography> </bento-accordion-item> </bento-accordion> <bento-button type="button" style="margin-top: 1rem" @click="toggle = !toggle">Toggle "Alderaan"</bento-button> </template> <script setup lang="ts"> import { BentoAccordion, BentoAccordionItem, BentoTypography, BentoButton } from '@adyen/bento-vue2' const toggle = ref(false); </script> `; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoAccordion, BentoAccordionItem, BentoButton, BentoTypography }, props: Object.keys(argTypes), template: ` <div> <bento-accordion v-bind="args"> <bento-accordion-item title="Alderaan" :is-expanded.sync="toggle"> <bento-typography> Alderaan had a reputation as one of the most peaceful and cultured worlds in the Galaxy, an idyllic locale for vacation or education in high demand among the denizens of Star Wars' most cultured and aspirational. </bento-typography> </bento-accordion-item> <bento-accordion-item title="Coruscant" is-expanded> <bento-typography> Coruscant is among the most diverse locales in the Galaxy, though it tends to be humans who hold wealth and power. Although it appears a flawless futuristic paradise on its surface, the lower you descend into the city's levels, the more crime and poverty you'll find. </bento-typography> </bento-accordion-item> <bento-accordion-item title="Dagobah"> <bento-typography> A swamp planet teeming with so much life that any manner of Force detection is rendered irrelevant, Dagobah is where Jedi Grandmaster in exile Yoda made his home for the last years of his life following the fall of the Jedi Order, awaiting the arrival of his final pupil and the Galaxy's last hope. </bento-typography> </bento-accordion-item> <bento-accordion-item title="Hoth"> <bento-typography> This snowy ice planet was home to the Rebellion's Echo Base, which Leia, Han, and Luke called home when the Empire titularly struck back in The Empire Strikes Back. Luke fights a wampa, Han guts a tauntaun for warmth, and the rebels hogtie some elephantine AT-AT imperial walkers with their snowspeeders here before beating a hasty retreat from the Empire. </bento-typography> </bento-accordion-item> </bento-accordion> <bento-button type="button" style="margin-top: 1rem" @click="toggle = !toggle">Toggle "Alderaan"</bento-button> </div> `, setup(props) { const toggle = ref(false); return { args: isVue2 ? props : _args, toggle }; }, }), args: DEFAULT_PROPS, parameters: storybookDocsParameter(defaultCode), };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<template> <div class="b-accordion"> <slot /> </div> </template> <script setup lang="ts"> import { type PropType, provide, toRef } from 'vue'; import { ACCORDION_TITLE_SIZE_INJECTION_KEY } from './accordion.keys'; import type { BentoAccordionTitleSize } from './accordion.types'; const props = defineProps({ /** * Controls accordion title size. * @values default, small */ titleSize: { type: String as PropType<BentoAccordionTitleSize>, default: 'default', }, }); provide(ACCORDION_TITLE_SIZE_INJECTION_KEY, toRef(props, 'titleSize')); </script> <script lang="ts"> /** * An accordion is a vertical stack of interactive headers used to reveal or hide * sections of content associated with these headers. * * This component must only have `BentoAccordionItem` components in its default slot. * * Accordion items should be collapsed by default. * * @example * import { BentoAccordion, BentoAccordionItem } from '@adyen/bento-vue2'; * * export default { * components: { BentoAccordion, BentoAccordionItem }, * template: ` * <bento-accordion> * <bento-accordion-item title="Item 1"> * Content for item 1 * </bento-accordion-item> * <bento-accordion-item title="Item 2"> * Content for item 2 * </bento-accordion-item> * </bento-accordion> * ` * } */ export default {}; </script> <style lang="scss" scoped src="./accordion.scss" />
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { isVue2 } from 'vue-demi'; import BentoAccordionItem from './accordion-item.vue'; import { BentoTypography } from '@/components/typography'; import type { Meta, StoryObj } from '@storybook/vue'; export default { title: 'Accordion/Accordion Item', component: BentoAccordionItem, argTypes: { default: { name: 'default', type: { name: 'string', required: false }, description: 'Content of the BentoAccordionItem', control: 'text', table: { type: { summary: 'VNode[]' }, }, }, 'update:is-expanded': { control: false, table: { type: { summary: '($event) => void' }, }, }, }, } as Meta; type Story = StoryObj<typeof BentoAccordionItem>; const DEFAULT_PROPS = { title: 'Default title', default: 'Are you threatening me, Master Jedi? Once more the Sith will rule the galaxy.', isExpanded: true, }; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoAccordionItem, BentoTypography }, props: Object.keys(argTypes), template: ` <bento-accordion-item v-bind="args"> <bento-typography> {{ args.default }} </bento-typography> </bento-accordion-item> `, setup(props) { return { args: isVue2 ? props : _args }; }, }), args: DEFAULT_PROPS, };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<template> <div class="b-accordion-item"> <bento-typography el="h3" :variant="titleSize === 'small' ? 'body' : 'title'" :strongest="titleSize === 'small'" > <button :id="buttonId" :aria-controls="contentId" :aria-expanded="`${isOpen}`" type="button" class="b-accordion-item__button" @click="isOpen = !isOpen" > <chevron-up-icon v-if="isOpen" class="b-accordion-item__icon" :svg-title="t('collapse')" aria-hidden="true" /> <chevron-down-icon v-else class="b-accordion-item__icon" :svg-title="t('expand')" aria-hidden="true" /> {{ title }} </button> </bento-typography> <Transition :name="CONTENT_TRANSITION_NAME"> <div v-if="isOpen" :id="contentId" :aria-labelledby="buttonId" role="region" :style="contentMaxHeight"> <div ref="contentDiv" class="b-accordion-item__content"> <slot /> </div> </div> </Transition> </div> </template> <script setup lang="ts"> import { computed, inject, ref, watch } from 'vue'; import { BentoTypography } from '@/components/typography'; import ChevronDownIcon from '@adyen/ui-assets-icons-16/vue/chevron-down'; import ChevronUpIcon from '@adyen/ui-assets-icons-16/vue/chevron-up'; import { generateUid } from '@/core/utils/ts'; import { observeSizeOfElement } from '@/utils/ts/resize'; import { useI18n } from '@/utils/ts/i18n'; import { ACCORDION_TITLE_SIZE_INJECTION_KEY } from '../accordion.keys'; import type { BentoAccordionTitleSize } from '../accordion.types'; import { useExpandableContentHeight } from '@/composables/use-expandable-content-height/use-expandable-content-height'; import messages from './messages.json'; type MessageSchema = (typeof messages)['en-US']; const CONTENT_TRANSITION_NAME = 'b-accordion-item__animation--content'; const props = defineProps({ /** * Sets the title of the accordion item. */ title: { type: String, required: true, }, /** * Controls if the content is visible or hidden. */ isExpanded: { type: Boolean, default: false, }, }); const emit = defineEmits<{ /** * Emits update event when content is toggled */ (e: 'update:is-expanded', value: boolean): void; }>(); const { t } = useI18n<{ message: MessageSchema }>({ messages }); // Refs const contentDiv = ref<HTMLDivElement>(null); const isOpen = ref(props.isExpanded); // Generating IDs const buttonId = generateUid('accordionItemButton'); const contentId = generateUid('accordionItemContent'); // Injecting prop from parent const titleSize = inject<`${BentoAccordionTitleSize}`>(ACCORDION_TITLE_SIZE_INJECTION_KEY, 'default'); // Getting and setting the item height to be able to handle height animation const { updateContentHeight, contentHeight } = useExpandableContentHeight(contentDiv, isOpen); const contentMaxHeight = computed(() => (contentHeight.value ? { 'max-height': contentHeight.value } : {})); watch( () => props.isExpanded, value => { isOpen.value = value; } ); watch( () => contentDiv.value, () => { let observer: ResizeObserver | null = null; if (!observer && contentDiv.value) { observer = observeSizeOfElement(contentDiv.value, () => { if (contentDiv.value) { updateContentHeight(); } }); } } ); watch( isOpen, value => { // Enable two-way data binding for `isExpanded` emit('update:is-expanded', value); updateContentHeight(); }, { immediate: true } ); </script> <script lang="ts"> /** * An accordion item is an interactive header used to reveal or hide a * section of content associated with this header. * * This component must always be wrapped by a `BentoAccordion` component. * * @example * import { BentoAccordion, BentoAccordionItem } from '@adyen/bento-vue2'; * * export default { * components: { BentoAccordion, BentoAccordionItem }, * template: ` * <bento-accordion> * <bento-accordion-item title="Item 1"> * Content for item 1 * </bento-accordion-item> * <bento-accordion-item title="Item 2"> * Content for item 2 * </bento-accordion-item> * </bento-accordion> * ` * } */ export default { i18n: { messages }, }; </script> <style lang="scss" scoped src="./accordion-item.scss" />
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Canvas, Meta } from '@storybook/blocks';
|
|
2
|
+
import * as ActionBarStories from './action-bar.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={ActionBarStories} />
|
|
5
|
+
|
|
6
|
+
# ActionBar
|
|
7
|
+
|
|
8
|
+
Action bar is a floating bar that provides users with quick access to key actions that can be applied to a single or
|
|
9
|
+
multiple items at the same time.
|
|
10
|
+
|
|
11
|
+
<Canvas of={ActionBarStories.Default} />
|
|
12
|
+
|
|
13
|
+
## Use Cases
|
|
14
|
+
|
|
15
|
+
Use when you want to enable user to perform single or bulk selection on data grid (or other components)
|
|
16
|
+
|
|
17
|
+
- Selecting rows on data grid and performing single or bulk actions on selected rows
|
|
18
|
+
- Selecting cards and and performing single or bulk actions on selected cards
|
|
19
|
+
- Any other similar scenarios.
|
|
20
|
+
|
|
21
|
+
## Placement
|
|
22
|
+
|
|
23
|
+
Action bar always appear stays centered at the bottom part of the screen.
|
|
24
|
+
|
|
25
|
+
Margin from bottom side of the viewport should be `16px` (default) OR `48px` (`extraBottomSpacing`) on pages where there
|
|
26
|
+
is a sticky element at the bottom part of the screen. Example: Data grid with bottom sticky pagination.
|
|
27
|
+
|
|
28
|
+
Action bar appears on top of your content. You should always allow scrolling and additional space for users to be able
|
|
29
|
+
to view the content underneath.
|
|
30
|
+
|
|
31
|
+
For example if the action bar appears on data grid then the user should be able to scroll to the last row and select it
|
|
32
|
+
as well. Ensure that all your content is available when the action bar is present.
|
|
33
|
+
|
|
34
|
+
## Actions
|
|
35
|
+
|
|
36
|
+
By default, the Action Bar will display up to 4 actions, if there is enough space for the 4 actions to be rendered. If
|
|
37
|
+
more than 4 actions are passed or there is not enough space to render all actions, the component will show a menu button
|
|
38
|
+
where the rest of the actions will be hidden.
|
|
39
|
+
|
|
40
|
+
Additionally, if you want to display less than 4 actions, you can pass the prop `visibleActions` with the amount of
|
|
41
|
+
actions you want displayed outside the menu. You should pass a **number** to the prop no larger than 4.
|
|
42
|
+
|
|
43
|
+
Make essential and often performed actions visible and hide actions that are rarely used but still needed from time to
|
|
44
|
+
time.
|
|
45
|
+
|
|
46
|
+
All actions in the Action Bar are **secondary buttons** with **inverse color** set (this will be enforced internally by
|
|
47
|
+
the component). Critical buttons are also supported.
|
|
48
|
+
|
|
49
|
+
### Critical actions
|
|
50
|
+
|
|
51
|
+
You can use **1** critical button on action bar.
|
|
52
|
+
|
|
53
|
+
When you use a critical action we recommend you to pair it with additional confirmation (i.e. use `bento-modal` dialog)
|
|
54
|
+
to ensure the user does not perform destructive actions accidentally.
|
|
55
|
+
|
|
56
|
+
### Confirmation
|
|
57
|
+
|
|
58
|
+
When the user applies an action, be sure to use `bento-toast` to inform about the result of the action.
|
|
59
|
+
|
|
60
|
+
Consider adding an “Undo” button if the price of the mistake is high.
|
|
61
|
+
|
|
62
|
+
After applying an action the action bar will remain with the selected set until the user closes it.
|
|
63
|
+
|
|
64
|
+
## Variants
|
|
65
|
+
|
|
66
|
+
The Action bar component comes in two variants - `default` and `confirmation`.
|
|
67
|
+
|
|
68
|
+
### Default
|
|
69
|
+
|
|
70
|
+
The default variant should be used for any generic case, accepts all props.
|
|
71
|
+
|
|
72
|
+
### Confirmation
|
|
73
|
+
|
|
74
|
+
To be used to confirm changes in a page. Only takes the `itemCounter` prop, the `selectionLabel` will always be 'unsaved
|
|
75
|
+
changes' and the `actions` are always 'Save' and 'Cancel'. It also has no close button.
|
|
76
|
+
|
|
77
|
+
## Modifiers
|
|
78
|
+
|
|
79
|
+
### Extra bottom spacing
|
|
80
|
+
|
|
81
|
+
This modifier will add extra spacing between the bottom of the screen and the action bar to allow elements sticking to
|
|
82
|
+
the bottom (like sticky pagination) to be visible.
|
|
83
|
+
|
|
84
|
+
## Accessibility
|
|
85
|
+
|
|
86
|
+
### Keyboard interaction
|
|
87
|
+
|
|
88
|
+
| Keyboard interaction | Output |
|
|
89
|
+
| -------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
90
|
+
| `Tab` | Focus visibly moves in logical order to actions inside of the action bar (close action should be last) |
|
|
91
|
+
| `Shift` + `Tab` | Moves focus to the previous actions. |
|
|
92
|
+
| `Space`/`Enter` | Button is activated |
|
|
93
|
+
|
|
94
|
+
### Roles, states and properties
|
|
95
|
+
|
|
96
|
+
| ARIA attribute | is automatic? | fallback used | manual override |
|
|
97
|
+
| --------------- | -------------------------------------------- | ------------- | --------------- |
|
|
98
|
+
| `role="region"` | Yes, through the semantic `section` element. | - | - |
|
|
99
|
+
| `aria-label` | Yes, it is set by default to 'Action bar' | - | - |
|
|
100
|
+
|
|
101
|
+
## Resources
|
|
102
|
+
|
|
103
|
+
- [Figma link](https://www.figma.com/design/uLabwF3243jdMDsNSP7U9I/Bento---Components?node-id=23466-201772&t=fUgRFhiNubQnT2RN-0)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { action } from '@storybook/addon-actions'; import { isVue2, ref } from 'vue-demi'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import BentoActionBar from './action-bar.vue'; import { BentoButton } from '@/components/button'; import type { Meta, StoryObj } from '@storybook/vue'; import BinIcon from '@adyen/ui-assets-icons-16/vue/bin'; import EditIcon from '@adyen/ui-assets-icons-16/vue/edit-1'; const meta: Meta = { title: 'Action bar', component: BentoActionBar, argTypes: { variant: { options: ['default', 'confirmation'], control: { type: 'select', }, }, }, parameters: { layout: 'fullscreen', }, }; export default meta; type Story = StoryObj<typeof BentoActionBar>; const DEFAULT_ACTIONS = [ { title: 'Assign to...', disabled: true, event: () => true, }, { title: 'Snooze', event: () => true, }, { title: 'Edit', icon: EditIcon, event: () => true, }, { title: 'Delete', critical: true, icon: BinIcon, event: () => true, }, { title: 'Extra option', event: () => true, }, ]; const DEFAULT_PROPS = { actions: DEFAULT_ACTIONS, selectionLabel: 'selected', itemCounter: 3 }; const defaultCode = ` <template> <bento-action-bar :actions="[ { title: 'Assign to...', event: () => true, }, { title: 'Snooze', event: () => true, }, { title: 'Edit', icon: EditIcon, event: () => true, }, { title: 'Delete', critical: true, icon: BinIcon, event: () => true, }, { title: 'Extra option', event: () => true, } ]" @close="closeAction" :item-counter="3" /> <script setup> const closeAction = () => { // unselect selected items and reset itemCounter } </script> </template>`; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoActionBar, BentoButton }, props: Object.keys(argTypes), template: ` <div style="height:140px"> <bento-button @click='toggleActionBar = !toggleActionBar'>Toggle action bar</bento-button> <bento-action-bar v-if='toggleActionBar' v-bind="args" @close="closeAction" @cancel="cancelAction" @save="saveAction" /> </div> `, setup(props) { const closeAction = () => action('close')(); const cancelAction = () => action('cancel')(); const saveAction = () => action('save')(); const toggleActionBar = ref(true); return { // Values args: isVue2 ? props : _args, toggleActionBar, // Events closeAction, cancelAction, saveAction, }; }, }), args: { ...DEFAULT_PROPS, }, parameters: storybookDocsParameter(defaultCode), };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<template> <Transition name="b-action-bar__animation" appear> <section class="b-action-bar" :class="conditionalClasses" :aria-label="t('actionBar')"> <div ref="actionBar" class="b-action-bar__container"> <div v-if="!isConfirmationVariant" class="b-action-bar__close-button"> <bento-button variant="tertiary" inverse :aria-label="t('close')" @click="emit('close')"> <template #iconLeft><cross-icon :aria-hidden="true" /></template> </bento-button> </div> <bento-typography el="span" stronger class="b-action-bar__selection"> <template v-if="isConfirmationVariant && noItemCounter"> {{ tc('unsavedChanges', 0) }} </template> <template v-else> {{ n(itemCounter) }} {{ isConfirmationVariant ? tc('unsavedChanges', itemCounter) : label }} </template> </bento-typography> <bento-button-actions v-if="isConfirmationVariant" :actions="confirmationActions" class="b-action-bar__actions" inverse /> <button-actions-with-menu v-else :actions="actionsInternal" class="b-action-bar__actions" :displayed-actions="internalDisplayedActions" menu-position="top-end" disable-responsive-behavior inverse /> </div> </section> </Transition> </template> <script setup lang="ts"> import { computed, nextTick, type PropType, provide, ref, toRefs, watch } from 'vue'; import { BentoButton, BentoButtonActions, type BentoButtonActionsList } from '@/components/button'; import { BentoTypography } from '@/components/typography'; import { type BentoActionBarVariant } from '@/components/action-bar/action-bar.types'; import ButtonActionsWithMenu from '@/components/internal/button-actions-with-menu/button-actions-with-menu.vue'; import CrossIcon from '@adyen/ui-assets-icons-16/vue/cross'; import { useI18n } from '@/utils/ts/i18n'; import { useWindowSize } from '@vueuse/core'; import messages from './messages.json'; import { POPOVER_OFFSET_INJECTION_KEY } from '@/components/popover/popover.keys'; type MessageSchema = (typeof messages)['en-US']; // Constants const AVERAGE_BUTTON_SIZE = 100; const MENU_OFFSET = 7; const RESPONSIVE_BREAKPOINT = 500; const SPACING = 32; const props = defineProps({ /** * List of actions that will be used to render the buttons. * Required and used for the `default` variant. * * Each object in the list should have a `title`, an `event` and, * optionally, an `icon`. * * The component will display 4 actions and the hide the rest inside a menu. * * @see BentoButton for a list of all the other props supported by each button action. */ actions: { type: Array as PropType<BentoButtonActionsList>, default: () => [], }, /** * How many actions should be visible outside the menu, cannot be more than 4 */ visibleActions: { type: Number, default: 4, validator: (value: number) => value > 0 && value <= 4, }, /** * Use when there are sticky elements at the bottom, like sticky pagination */ extraBottomSpacing: { type: Boolean, default: false, }, /** * Show how many items are selected. * When omitted in the `confirmation` variant, a generic "Unsaved changes" label is displayed. */ itemCounter: { type: Number, default: null, }, /** * Label for the selection, e.g. 'selected'/'changed' */ selectionLabel: { type: String, default: null, }, /** * Variant for the action bar * @values default, confirmation */ variant: { type: String as PropType<BentoActionBarVariant>, default: 'default', }, }); const emit = defineEmits<{ /** * Event emitted when the user click the close button */ (e: 'close'): void; (e: 'cancel'): void; (e: 'save'): void; }>(); const { t, tc, n } = useI18n<{ message: MessageSchema }>({ messages }); const label = computed(() => (props.selectionLabel ? props.selectionLabel : t('selected'))); // Refs const actionBar = ref<HTMLDivElement>(null); const { extraBottomSpacing, visibleActions } = toRefs(props); const { width } = useWindowSize(); const internalDisplayedActions = ref(null); const internalVisibleActions = ref(null); const isConfirmationVariant = computed(() => props.variant === 'confirmation'); watch( () => visibleActions.value, value => { internalVisibleActions.value = value <= 4 ? value : 4; internalDisplayedActions.value = internalVisibleActions.value; }, { immediate: true } ); // Styling const conditionalClasses = computed(() => ({ 'b-action-bar--extra-spacing': extraBottomSpacing.value, 'b-action-bar--confirmation': isConfirmationVariant.value, })); // Provide POPOVER_OFFSET_INJECTION_KEY to change the value of the popover offset provide(POPOVER_OFFSET_INJECTION_KEY, MENU_OFFSET); // Manipulate actions array to display as intended const actionsInternal = computed(() => { // All buttons should be of type secondary in the action bar const actions = props.actions.map(action => ({ ...action, variant: 'secondary', })) as BentoButtonActionsList; // Shown actions should display from left to right in action bar, instead of right to left which is the button actions default const shownActions = actions.slice(0, internalDisplayedActions.value).reverse(); const hiddenActions = actions.slice(internalDisplayedActions.value); return [...shownActions, ...hiddenActions]; }); const confirmationActions = computed<BentoButtonActionsList>(() => [ { title: t('save'), event: () => emit('save'), }, { title: t('cancel'), variant: 'secondary', event: () => emit('cancel'), }, ]); const noItemCounter = computed(() => { return props.itemCounter == null || props.itemCounter < 1; }); // Recursive functions to determine how many actions should be visible/hidden based on the screens width const showActions = async () => { await nextTick(); if ( width.value > actionBar.value.clientWidth + SPACING + AVERAGE_BUTTON_SIZE && internalDisplayedActions.value < internalVisibleActions.value ) { internalDisplayedActions.value += 1; showActions(); } }; const hideActions = async () => { await nextTick(); if (width.value < actionBar.value.clientWidth + SPACING && internalDisplayedActions.value > 0) { internalDisplayedActions.value -= 1; hideActions(); } }; // Screen width watcher to toggle hidden/visible actions watch( () => width.value, async (newValue, oldValue) => { await nextTick(); if (!actionBar.value) { return; } const isIncreasing = newValue > oldValue; if (width.value < RESPONSIVE_BREAKPOINT) { internalDisplayedActions.value = 0; } else if (isIncreasing) { showActions(); } else { hideActions(); } }, { immediate: true } ); </script> <script lang="ts"> /** * Action bar is a floating bar that provides users with quick access to key actions that can be applied to one or multiple items. * * @example * import { BentoActionBar } from '@adyen/bento-vue2'; * * export default { * components: { BentoActionBar }, * template: ` * <bento-action-bar * :actions='[ * { * title: 'Delete', * critical: true, * icon: BinIcon, * event: () => true, * }, * { * title: 'Edit', * icon: EditIcon, * event: () => true, * } * ]' * @close="closeAction" * :item-counter="5" * /> * ` * } */ export default { i18n: { messages }, }; </script> <style lang="scss" scoped src="./action-bar.scss" />
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Canvas, Meta } from '@storybook/blocks';
|
|
2
|
+
import * as AiTagStories from './ai-tag.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={AiTagStories} />
|
|
5
|
+
|
|
6
|
+
# AI tag
|
|
7
|
+
|
|
8
|
+
The AI tag is a component used to transparently identify content, data, or experiences that have been generated or
|
|
9
|
+
enhanced by artificial intelligence. Its primary purpose is to build user trust by clearly attributing AI's role.
|
|
10
|
+
|
|
11
|
+
It can be used standalone—placed next to the affected value—or embedded within other Bento components (e.g.,
|
|
12
|
+
b-input-field, b-card) via their designated slots. Clicking the tag opens an Explainability Popover with a short,
|
|
13
|
+
contextual summary of what the AI did.
|
|
14
|
+
|
|
15
|
+
<Canvas of={AiTagStories.Default} />
|
|
16
|
+
|
|
17
|
+
## Use Cases
|
|
18
|
+
|
|
19
|
+
- **To label AI-generated content:** Use it next to text, images, or data that was fully created by an AI model (e.g., a
|
|
20
|
+
generated summary, a generated data prediction).
|
|
21
|
+
- **To label AI-enhanced content:** Use it when AI has modified or significantly assisted in creating content (e.g., "AI
|
|
22
|
+
suggested these edits," "AI prefilled this input fields").
|
|
23
|
+
- **To identify AI-powered features:** Use it when a specific feature is an AI-driven system (e.g., “AI assistant chat”)
|
|
24
|
+
- **To identify AI-generated pages:** Use it when an entire page is generated by AI
|
|
25
|
+
|
|
26
|
+
### Do not use
|
|
27
|
+
|
|
28
|
+
- **For non-AI automation:** Do not use it for simple rules-based logic or standard algorithms (e.g., sorting a list
|
|
29
|
+
alphabetically).
|
|
30
|
+
- **For values that are not influenced by AI**, or where the AI role is irrelevant to the user’s decision.
|
|
31
|
+
- **As a decorative label** without an attached Explainability Popover.
|
|
32
|
+
|
|
33
|
+
### Best practices
|
|
34
|
+
|
|
35
|
+
- Place the AI tag on the right side of the AI-influenced value or in the component’s designated meta/info slot (also
|
|
36
|
+
usually on the right side).
|
|
37
|
+
- Keep Explainability Popover content concise and plain-language
|
|
38
|
+
- Prefer actionable transparency: include a “Learn more” action when deeper context or policy details exist.
|
|
39
|
+
|
|
40
|
+
## Placement
|
|
41
|
+
|
|
42
|
+
There are two primary ways to place the AI Tag:
|
|
43
|
+
|
|
44
|
+
- **Standalone**: AI tag is a standalone element placed directly on the right side of the AI-generated or enhanced
|
|
45
|
+
label/content/feature/page. Use this for freeform content.
|
|
46
|
+
- **Embedded**: AI tag is placed inside of an existing component, typically on the right side. This shows that the AI is
|
|
47
|
+
acting within or upon that specific component (e.t., an AI suggestion inside a input field, dropdown, etc).
|
|
48
|
+
|
|
49
|
+
## Accessibility
|
|
50
|
+
|
|
51
|
+
### Keyboard interaction
|
|
52
|
+
|
|
53
|
+
| Keyboard interaction | Action |
|
|
54
|
+
| ---------------------- | ---------------------------------------------------------------------------------------- |
|
|
55
|
+
| `Tab` | Moves focus to the AI tag trigger or away from it. |
|
|
56
|
+
| `Space` / `Enter` | Activates the trigger and toggles the visibility of the Explainability Popover. |
|
|
57
|
+
| `Esc` | Closes the Popover and returns focus to the trigger button. |
|
|
58
|
+
| `Tab` (inside Popover) | Cycles focus through the interactive elements within the Popover (e.g., action buttons). |
|
|
59
|
+
|
|
60
|
+
### Roles, states and properties
|
|
61
|
+
|
|
62
|
+
The AI tag follows the [disclosure pattern](https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/) for the trigger and
|
|
63
|
+
the [dialog pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/) for the popover content.
|
|
64
|
+
|
|
65
|
+
| ARIA attribute | Is automatic? | Description |
|
|
66
|
+
| --------------- | ------------- | ---------------------------------------------------------------------------------------- |
|
|
67
|
+
| `role="button"` | Yes | The trigger is a semantic button. |
|
|
68
|
+
| `aria-expanded` | Yes | Set to `true` when the popover is visible, `false` otherwise. |
|
|
69
|
+
| `aria-controls` | Yes | Points to the `id` of the popover content. |
|
|
70
|
+
| `role="dialog"` | Yes | The popover container has the dialog role. |
|
|
71
|
+
| `aria-label` | Yes | The popover uses "AI explained" as its accessible label (derived from the header title). |
|
|
72
|
+
|
|
73
|
+
## Resources
|
|
74
|
+
|
|
75
|
+
- [Figma link](https://www.figma.com/design/uLabwF3243jdMDsNSP7U9I/Bento---Components?node-id=49373-138087&m=dev)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import BentoAiTag from './ai-tag.vue'; import AiTagDefault from './__tests__/ai-tag-default.vue?raw'; import { action } from '@storybook/addon-actions'; import { isVue2 } from 'vue-demi'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import type { Meta, StoryObj } from '@storybook/vue'; const meta: Meta = { title: 'AI tag', component: BentoAiTag, }; export default meta; type Story = StoryObj<typeof BentoAiTag>; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoAiTag }, props: Object.keys(argTypes), template: ` <bento-ai-tag v-bind="args" @update:toggled="onToggleAction"/> `, setup(props) { const onToggleAction = (value: boolean) => action('update:toggled')(value); return { // Values args: isVue2 ? props : _args, // Events onToggleAction, }; }, }), args: { title: 'Input fields auto-filled by AI', description: 'Based on your documents uploaded, AI has auto-filled some information for you. You can change that information any time.', influencedValue: '30%', action: { title: 'Learn more', event: () => action('action-click')('Learn more clicked'), }, }, parameters: storybookDocsParameter(AiTagDefault), };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<template> <div ref="aiTagRef" class="b-ai-tag" @keydown.esc="closePopover"> <bento-toggle-button ref="targetElement" :toggled="toggled" :aria-controls="popoverId" variant="secondary" condensed class="b-ai-tag__trigger" @update:toggled="onToggle" > <template #iconLeft> <artificial-intelligence-ai-icon class="b-ai-tag__trigger-icon" :aria-hidden="true" /> </template> {{ t('ai') }} </bento-toggle-button> <bento-popover v-if="targetElement" :id="popoverId" :open="toggled" :target-element="targetElement" :actions="popoverActions" actions-layout="fill-container" :title="t('aiExplained')" trap-all :trap-all-options="{ onDeactivate: closePopover, allowOutsideClick: true }" fixed-positioning overflow-visible @dismiss="closePopover" > <template #headerIcon> <artificial-intelligence-ai-icon class="b-ai-tag__popover-header-icon" :aria-hidden="true" /> </template> <div class="b-ai-tag__popover-content"> <bento-typography v-if="influencedValue" variant="title" medium class="b-ai-tag__influenced-value"> {{ influencedValue }} </bento-typography> <bento-typography variant="title"> {{ title }} </bento-typography> <bento-typography> {{ description }} </bento-typography> </div> </bento-popover> </div> </template> <script setup lang="ts"> import { computed, ref, watch } from 'vue'; import { BentoPopover } from '@/components/popover'; import { BentoToggleButton } from '@/components/button'; import { BentoTypography } from '@/components/typography'; import { useClickOutside } from '@/composables'; import { useI18n } from '@/utils/ts/i18n'; import { generateUid } from '@/core/utils/ts'; import type { BentoButtonActionsList } from '@/components/button/components/button-actions/button-actions.types'; import ArtificialIntelligenceAiIcon from '@adyen/ui-assets-icons-16/vue/artificial-intelligence-ai-filled'; import type { BentoAiTagProps } from './ai-tag.types'; import messages from './messages.json'; type MessageSchema = (typeof messages)['en-US']; const props = withDefaults(defineProps<BentoAiTagProps>(), { influencedValue: undefined, toggled: false, action: undefined, }); const { t } = useI18n<{ message: MessageSchema }>({ messages }); const toggled = ref(props.toggled); const aiTagRef = ref<HTMLElement | null>(null); const targetElement = ref<InstanceType<typeof BentoToggleButton> | null>(null); const popoverId = generateUid('b-ai-tag-popover'); watch( () => props.toggled, value => { toggled.value = value; } ); useClickOutside(aiTagRef, () => { closePopover(); }); const popoverActions = computed<BentoButtonActionsList>(() => props.action ? [ { ...props.action, variant: 'secondary', }, ] : undefined ); const emit = defineEmits<{ /** * Triggered when the popover is toggled */ (e: 'update:toggled', toggled: boolean): void; }>(); const onToggle = (value: boolean) => { toggled.value = value; emit('update:toggled', value); }; const closePopover = () => { if (toggled.value) { onToggle(false); } }; </script> <script lang="ts"> /** * The AI tag is a component used to transparently identify content, data, or experiences that have been generated or * enhanced by artificial intelligence. * * @example * import { BentoAiTag } from '@adyen/bento-vue2'; * * export default { * components: { BentoAiTag }, * template: ` * <bento-ai-tag * title="Input fields auto-filled by AI" * description="Based on your documents uploaded, AI has auto-filled some information for you." * /> * ` * } */ export default { i18n: { messages }, }; </script> <style lang="scss" scoped src="./ai-tag.scss" />
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Canvas, Meta } from '@storybook/blocks';
|
|
2
|
+
import * as AlertStories from './alert.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={AlertStories} />
|
|
5
|
+
|
|
6
|
+
# Alert
|
|
7
|
+
|
|
8
|
+
Alert is a persistent notification containing information important to the user. It should be used to inform about
|
|
9
|
+
changes, explain a problem or provide a solution. It may be triggered by a user action or not.
|
|
10
|
+
|
|
11
|
+
<Canvas of={AlertStories.Default} />
|
|
12
|
+
|
|
13
|
+
## Use Cases
|
|
14
|
+
|
|
15
|
+
Use alerts for important messages, explanations or errors that require user to take action.
|
|
16
|
+
|
|
17
|
+
Use alerts for:
|
|
18
|
+
|
|
19
|
+
- Warning users about potential problems, risks, or actions required like update their password.
|
|
20
|
+
- Informing users with helpful information or tips, such as feature announcements, usage guidelines, or updates about
|
|
21
|
+
system status.
|
|
22
|
+
- Displaying system-generated notifications, such as scheduled maintenance, security alerts, or updates about the
|
|
23
|
+
availability of new features or versions of the software.
|
|
24
|
+
|
|
25
|
+
### Do not use
|
|
26
|
+
|
|
27
|
+
Do not use alerts for non-critical feedback about the app’s processes after user takes an action:
|
|
28
|
+
|
|
29
|
+
For example:
|
|
30
|
+
|
|
31
|
+
- confirmation message that a setting has been saved. In this case, prefer the `toast` component instead
|
|
32
|
+
|
|
33
|
+
### Guidelines
|
|
34
|
+
|
|
35
|
+
The component allows you to pass `actions` slot where action buttons may be placed
|
|
36
|
+
|
|
37
|
+
According to the Design system guidelines:
|
|
38
|
+
|
|
39
|
+
- You are restricted to use only `Button` component with `tertiary` variant
|
|
40
|
+
- The amount of buttons may be other 1 or 2, not more
|
|
41
|
+
|
|
42
|
+
## Variants
|
|
43
|
+
|
|
44
|
+
The Alert component comes in two variants - default and tip.
|
|
45
|
+
|
|
46
|
+
### Default
|
|
47
|
+
|
|
48
|
+
The default variant should be used for longer content alerts and in places where there’s enough space, for example,
|
|
49
|
+
above a form. It has optional title, buttons and dismiss icon.
|
|
50
|
+
|
|
51
|
+
### Tip
|
|
52
|
+
|
|
53
|
+
For cramped spaces and short tips, use tip variant instead. It’s like an exposed tooltip that, for example, can warn
|
|
54
|
+
user of a specific setting’s consequences. It doesn’t have a title, buttons or dismiss icon, however, you can link parts
|
|
55
|
+
of the text, if needed.
|
|
56
|
+
|
|
57
|
+
## Modifiers
|
|
58
|
+
|
|
59
|
+
### Type
|
|
60
|
+
|
|
61
|
+
Determines the type of alert that is displayed. By setting the `type` property, the Alert component will render a
|
|
62
|
+
corresponding visual representation of the alert type with predefined icon and background.
|
|
63
|
+
|
|
64
|
+
It accepts one of the following values:
|
|
65
|
+
|
|
66
|
+
- `'success'`
|
|
67
|
+
- `'highlight'`
|
|
68
|
+
- `'warning'`
|
|
69
|
+
- `'critical'`
|
|
70
|
+
|
|
71
|
+
### Close Button
|
|
72
|
+
|
|
73
|
+
The `closeButton` boolean property adds a Close Button icon that is displayed on the right side of the Alert component
|
|
74
|
+
|
|
75
|
+
Clicking on it, a `close-alert` event is emitted
|
|
76
|
+
|
|
77
|
+
## Accessibility
|
|
78
|
+
|
|
79
|
+
### Keyboard Interaction
|
|
80
|
+
|
|
81
|
+
When a user uses the feature that triggers the alert they can SEE it appear (but focus DOES NOT transfer automatically
|
|
82
|
+
when alert appears).
|
|
83
|
+
|
|
84
|
+
### Screenreader
|
|
85
|
+
|
|
86
|
+
When a user uses the feature that triggers the alert:
|
|
87
|
+
|
|
88
|
+
- User can HEAR the alert is read when it appears (but focus DOES NOT transfer automatically when alert appears).
|
|
89
|
+
- `Success`, `Warning` and `Critical` types will be identified by an alert sound before the alert is read.
|
|
90
|
+
|
|
91
|
+
### Colors
|
|
92
|
+
|
|
93
|
+
Different type options can be used to differentiate between alerts or to add additional meaning. Make sure you don’t
|
|
94
|
+
rely on color only, though, as users with color blindness may struggle with discerning them.
|
|
95
|
+
|
|
96
|
+
### Aria attributes
|
|
97
|
+
|
|
98
|
+
Adhering to the [WAI-ARIA 1.2](https://www.w3.org/TR/wai-aria-1.2/) standard we apply the following:
|
|
99
|
+
|
|
100
|
+
| ARIA attribute | is automatic? | fallback used | manual override |
|
|
101
|
+
| -------------- | ---------------------------------------------------------------------------- | ------------- | --------------- |
|
|
102
|
+
| `role` | Yes, based on `type` property value, either `alert` or `status` role is used | - | - |
|
|
103
|
+
|
|
104
|
+
## Resources
|
|
105
|
+
|
|
106
|
+
- [Figma link](https://www.figma.com/file/uLabwF3243jdMDsNSP7U9I/Bento---Components?node-id=2748-62103&t=88jDJJzCcALwP5KP-0)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { action } from '@storybook/addon-actions'; import { BentoAlertTypeOption, BentoAlertVariant } from './alert.types'; import { BentoButton } from '@/components/button'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import { type Meta, type StoryObj } from '@storybook/vue'; import { isVue2 } from 'vue-demi'; import BentoAlert from './alert.vue'; export default { title: 'Alert', component: BentoAlert, parameters: { layout: 'centered', }, argTypes: { default: { name: 'default', defaultValue: '', description: 'Heading title', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, variant: { options: Object.values(BentoAlertVariant), defaultValue: BentoAlertVariant.TIP, mapping: BentoAlertVariant, control: { type: 'select', }, }, type: { options: Object.values(BentoAlertTypeOption), defaultValue: BentoAlertTypeOption.HIGHLIGHT, mapping: BentoAlertTypeOption, control: { type: 'select', }, }, description: { name: 'description', defaultValue: '', description: 'Description in alert body', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, actions: { name: 'actions', defaultValue: '', description: 'Actions in the footer', table: { type: { summary: 'VNode[]' }, }, control: { disable: true, }, }, }, } as Meta; type Story = StoryObj<typeof BentoAlert>; const DEFAULT_ALERT_PROPS = { default: 'Alert title', type: 'highlight', description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent ultrices leo massa, at accumsan lorem sagittis vehicula. Ut elit orci, finibus id neque quis, cursus posuere metus. Proin sed convallis odio, ut porttitor turpis.', closeButton: true, variant: 'default', }; const defaultCode = ` <bento-alert @close-alert='clickedCloseAction'> <template #default> ${DEFAULT_ALERT_PROPS.default} </template> <template #description> ${DEFAULT_ALERT_PROPS.description} </template> </bento-alert> `; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoAlert }, props: Object.keys(argTypes), template: ` <bento-alert v-bind='args' @close-alert='clickedCloseAction' style="width: 100vw;max-width: 700px;"> <template #default v-if='args.default'> {{ args.default }} </template> <template #description v-if='args.description'> {{ args.description }} </template> </bento-alert> `, setup(props) { return { clickedCloseAction: action('onClickCloseButton'), args: isVue2 ? props : _args, }; }, }), args: { ...DEFAULT_ALERT_PROPS }, parameters: storybookDocsParameter(defaultCode), }; export const WithActions: Story = { render: (_args, { argTypes }) => ({ components: { BentoAlert, BentoButton }, props: Object.keys(argTypes), template: ` <bento-alert v-bind='args' @close-alert='clickedCloseAction' style="width: 100vw;max-width: 700px;"> <template #default v-if='args.default'> {{ args.default }} </template> <template #description v-if='args.description'> {{ args.description }} </template> <template #actions> <bento-button @click='clickedAction' variant="tertiary">Cancel</bento-button> <bento-button @click='clickedAction' variant="tertiary">Confirm</bento-button> </template> </bento-alert> `, setup(props) { return { clickedCloseAction: action('onClickCloseButton'), clickedAction: action('onClickAction'), args: isVue2 ? props : _args, }; }, }), args: { ...DEFAULT_ALERT_PROPS }, parameters: storybookDocsParameter(defaultCode), };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<template> <div class="b-alert" :role="computedRole"> <div class="b-alert__inner-container" :class="alertConditionalClasses"> <div class="b-alert__icon"> <component :is="iconComponent" aria-hidden="true" :svg-title="iconSvgTitle" /> </div> <div class="b-alert__content"> <bento-typography v-if="hasSlot('default') && !isTipVariant" class="b-alert__title" el="div" variant="body" strongest wide > <slot /> </bento-typography> <bento-typography v-if="hasSlot('description')" class="b-alert__description" v-bind="descriptionTypography" data-testid="alert-description" > <slot name="description" /> </bento-typography> <div v-if="hasSlot('actions') && !isTipVariant" class="b-alert__actions" data-testid="alert-actions"> <slot name="actions" /> </div> </div> <bento-button v-if="closeButton && !isTipVariant" class="b-alert__close-button" variant="tertiary" type="button" @click="onCloseButtonClick" > <cross-small :svg-title="t('close')" /> </bento-button> </div> </div> </template> <script setup lang="ts"> import { computed, onMounted, useSlots } from 'vue'; // Component import { BentoAlertEvent, BentoAlertTypeOption, BentoAlertVariant } from '@/components/alert/alert.types'; import { BentoTypography, BentoTypographyElement, BentoTypographyVariant } from '@/components/typography'; import { BentoButton } from '@/components/button'; import CrossSmall from '@adyen/ui-assets-icons-16/vue/cross-small'; import Warning from '@adyen/ui-assets-icons-16/vue/warning-filled'; import CrossCircle from '@adyen/ui-assets-icons-16/vue/cross-circle-fill'; import CheckedCircle from '@adyen/ui-assets-icons-16/vue/checkmark-circle-fill'; import Info from '@adyen/ui-assets-icons-16/vue/info-filled'; // Utils import { useHasSlot } from '@/composables'; import { useI18n } from '@/utils/ts/i18n'; import messages from './messages.json'; type MessageSchema = (typeof messages)['en-US']; const slots = useSlots(); const hasSlot = useHasSlot(slots); const emit = defineEmits<{ /** * Emits event when the alert is closed. `closeButton` must be `true` */ (e: 'close-alert'); }>(); const props = withDefaults( defineProps<{ /** * Adds a close button on the right side of the alert */ closeButton?: boolean; /** * Type of a alert; set a distinctive icon and color. Defaults to highlight. * @values HIGHLIGHT, SUCCESS, CRITICAL, WARNING */ type?: BentoAlertTypeOption | `${BentoAlertTypeOption}`; /** * Variant for the alert * @values DEFAULT, TIP */ variant?: BentoAlertVariant | `${BentoAlertVariant}`; }>(), { closeButton: false, type: BentoAlertTypeOption.HIGHLIGHT, variant: BentoAlertVariant.DEFAULT, } ); const { t } = useI18n<{ message: MessageSchema }>({ messages }); const isTipVariant = computed(() => props.variant === BentoAlertVariant.TIP); const alertConditionalClasses = computed(() => ({ [`b-alert--${props.type}`]: props.type, [`b-alert--${BentoAlertVariant.TIP}`]: isTipVariant.value, })); const iconSvgTitle = computed(() => t(`${props.type}Icon`)); const iconComponent = computed(() => { switch (props.type) { case BentoAlertTypeOption.CRITICAL: return CrossCircle; case BentoAlertTypeOption.SUCCESS: return CheckedCircle; case BentoAlertTypeOption.WARNING: return Warning; case BentoAlertTypeOption.HIGHLIGHT: default: return Info; } }); const descriptionTypography = computed(() => ({ el: BentoTypographyElement.DIV, variant: isTipVariant.value ? BentoTypographyVariant.CAPTION : BentoTypographyVariant.BODY, wide: true, })); const computedRole = computed(() => (props.type === BentoAlertTypeOption.HIGHLIGHT ? 'status' : 'alert')); const onCloseButtonClick = () => { emit(BentoAlertEvent.CLOSE_ALERT); }; onMounted(() => { if (!slots.default && !slots.description) { throw new Error('Alert Component requires a title or a description'); } }); </script> <script lang="ts"> /** * An Alert component is used to display a persistent * notification containing information important to the user * * @example * import { BentoAlert, BentoAlertTypeOption } from '@adyen/bento-vue2'; * * export default { * components: { BentoAlert }, * template: ` * <bento-alert type="highlight"> * Title of the Alert * </bento-alert> * ` * } */ export default { i18n: { messages }, name: 'bento-alert', }; </script> <style lang="scss" scoped src="./alert.scss" />
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Canvas, Story, Meta } from '@storybook/blocks';
|
|
2
|
+
import * as AvatarStories from './avatar.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={AvatarStories} />
|
|
5
|
+
|
|
6
|
+
# Avatar
|
|
7
|
+
|
|
8
|
+
An Avatar is a visual representation of a user. It can display a user’s name paired with an icon containing a chosen
|
|
9
|
+
image or the initials of their name.
|
|
10
|
+
|
|
11
|
+
<Canvas withSource="closed">
|
|
12
|
+
<Story of={AvatarStories.Default} />
|
|
13
|
+
</Canvas>
|
|
14
|
+
|
|
15
|
+
## Use Cases
|
|
16
|
+
|
|
17
|
+
Use an Avatar if you want to visually represent a user, combined with their name.
|
|
18
|
+
|
|
19
|
+
## Variations
|
|
20
|
+
|
|
21
|
+
### Icon only
|
|
22
|
+
|
|
23
|
+
Displays the Avatar with an icon only
|
|
24
|
+
|
|
25
|
+
## Modifiers
|
|
26
|
+
|
|
27
|
+
There are currently no modifiers for this component.
|
|
28
|
+
|
|
29
|
+
## Accessibility
|
|
30
|
+
|
|
31
|
+
The Avatar component is not reachable through keyboard navigation since it's a non-interactive element that displays a
|
|
32
|
+
property related to a user name.
|
|
33
|
+
|
|
34
|
+
### Aria attributes
|
|
35
|
+
|
|
36
|
+
Adhering to the [WAI-ARIA 1.2](https://www.w3.org/TR/wai-aria-1.2/) standard we apply the following:
|
|
37
|
+
|
|
38
|
+
| ARIA attribute | is automatic? | fallback used | manual override |
|
|
39
|
+
| -------------- | -------------------------------------------------------------------------------- | ------------- | --------------- |
|
|
40
|
+
| `aria-label` | Yes, set to the username value if the component renders in an icon only variant. | - | - |
|
|
41
|
+
|
|
42
|
+
## Resources
|
|
43
|
+
|
|
44
|
+
- [Figma link](https://www.figma.com/file/uLabwF3243jdMDsNSP7U9I/Bento---Components?type=design&node-id=3546-77563&mode=design&t=5dC1Iux4QIcnK7zH-0)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { type StoryObj } from '@storybook/vue'; import BentoAvatar from './avatar.vue'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import { isVue2 } from 'vue-demi'; const meta = { title: 'Avatar', component: BentoAvatar, argTypes: { username: { name: 'username', description: 'Name of user', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, src: { name: 'src', description: 'Image src of user profile picture', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, }, }; export default meta; type Story = StoryObj<typeof BentoAvatar>; const DEFAULT_USERNAME = 'John'; const ICON_ONLY = false; const defaultCode = ` <bento-avatar username="John" /> `; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoAvatar }, props: Object.keys(argTypes), setup: props => ({ args: isVue2 ? props : _args }), template: ` <bento-avatar v-bind="args"/> `, }), args: { username: DEFAULT_USERNAME, iconOnly: ICON_ONLY, }, parameters: storybookDocsParameter(defaultCode), };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<template> <div class="b-avatar" :role="iconOnly ? 'img' : null" :aria-label="computedAriaLabel"> <avatar-image :src="src" :username="computedUsername" :variant="BentoAvatarImageVariant.SMALL" :color="avatarColor" /> <bento-typography v-if="!iconOnly" class="b-avatar__label" el="span" variant="body"> {{ username }} </bento-typography> </div> </template> <script setup lang="ts"> import { computed, toRefs } from 'vue'; import { AvatarImage, BentoAvatarImageColor, BentoAvatarImageVariant } from './components/avatar-image'; import { BentoTypography } from '@/components/typography'; import { useInitials } from '@/composables'; const props = withDefaults( defineProps<{ /** * Displays the user profile without the label. */ iconOnly?: boolean; /** * Image src to load the profile picture. */ src?: string; /** * Name of the user that will be used both in the label and to extract initials to display default value. * John => J * John Smith => JS * John Smith Doe => JD * John Smith Doe Holly => JH */ username: string; }>(), { iconOnly: false, src: null, } ); const { username } = toRefs(props); const computedAriaLabel = computed(() => (props.iconOnly ? props.username : null)); const computedUsername = computed(() => (!props.src ? props.username : null)); const initials = useInitials(username); // Returns the UTF-16 char code const charCode = computed(() => (initials.value ? initials.value.charCodeAt(0) - 65 : null)); // Returns a computed color based on the letter passed const avatarColor = computed(() => { const numberOfAlphabetLetters = 26; const numberOfColors = Object.keys(BentoAvatarImageColor).length; const rangeStep = numberOfAlphabetLetters / numberOfColors; if (charCode.value <= rangeStep) { return BentoAvatarImageColor.YELLOW; } if (charCode.value <= rangeStep * 2) { return BentoAvatarImageColor.BLUE; } if (charCode.value <= rangeStep * 3) { return BentoAvatarImageColor.GREEN; } return BentoAvatarImageColor.RED; }); </script> <script lang="ts"> /** * Displays an user profile including an avatar and optionally a label. * * @example * import { BentoAvatar } from '@adyen/bento-vue2'; * * export default { * components: { BentoAvatar }, * template: `<bento-avatar :src="userAvatarSrc" username="Jane" />` * } */ export default { name: 'bento-avatar', }; </script> <style lang="scss" scoped src="./avatar.scss" />
|