@adyen/bento-mcp 0.1.3 → 0.2.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.
Files changed (195) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +50 -5
  3. package/SKILL.md +138 -0
  4. package/bin/add-skill.js +46 -0
  5. package/dist/assets/components/accordion/accordion.types.ts +1 -0
  6. package/dist/assets/components/action-bar/action-bar.docs.mdx +40 -4
  7. package/dist/assets/components/action-bar/action-bar.stories.ts +1 -1
  8. package/dist/assets/components/action-bar/action-bar.types.ts +1 -0
  9. package/dist/assets/components/action-bar/action-bar.vue +1 -1
  10. package/dist/assets/components/ai-tag/ai-tag.types.ts +1 -0
  11. package/dist/assets/components/alert/alert.types.ts +1 -0
  12. package/dist/assets/components/anchor-scroller/anchor-scroller.types.ts +1 -0
  13. package/dist/assets/components/anchor-scroller/components/anchor-scroller-list/anchor-scroller-list.types.ts +1 -0
  14. package/dist/assets/components/avatar/components/avatar-image/avatar-image.types.ts +1 -0
  15. package/dist/assets/components/button/button.types.ts +1 -0
  16. package/dist/assets/components/button/components/ai-button/ai-button.types.ts +1 -0
  17. package/dist/assets/components/button/components/button-actions/button-actions.types.ts +1 -0
  18. package/dist/assets/components/button/components/loading-button/loading-button.types.ts +1 -0
  19. package/dist/assets/components/button/components/toggle-button/toggle.types.ts +1 -0
  20. package/dist/assets/components/card/card.types.ts +1 -0
  21. package/dist/assets/components/checkbox/checkbox.types.ts +1 -0
  22. package/dist/assets/components/checkbox/components/checkbox-group/checkbox-group.types.ts +1 -0
  23. package/dist/assets/components/chip/chip.types.ts +1 -0
  24. package/dist/assets/components/code-snippet/code-snippet.types.ts +1 -0
  25. package/dist/assets/components/country/country.types.ts +1 -0
  26. package/dist/assets/components/currency/currency.types.ts +1 -0
  27. package/dist/assets/components/dashed-underline/dashed-underline.types.ts +1 -0
  28. package/dist/assets/components/data-grid/components/data-grid-cell/data-grid-cell.types.ts +1 -0
  29. package/dist/assets/components/data-grid/components/data-grid-cell-actions/data-grid-cell-actions.types.ts +1 -0
  30. package/dist/assets/components/data-grid/components/data-grid-columns/data-grid-columns.types.ts +1 -0
  31. package/dist/assets/components/data-grid/components/data-grid-config-settings/data-grid-config-settings.types.ts +1 -0
  32. package/dist/assets/components/data-grid/components/data-grid-row/data-grid-row.types.ts +1 -0
  33. package/dist/assets/components/data-grid/components/data-grid-static-icon/data-grid-static-icon.types.ts +1 -0
  34. package/dist/assets/components/data-grid/components/data-grid-summary-cell/data-grid-summary-cell.types.ts +1 -0
  35. package/dist/assets/components/data-grid/components/data-grid-tag-with-text-cell/data-grid-tag-with-text-cell.types.ts +1 -0
  36. package/dist/assets/components/data-grid/components/data-grid-trend-cell/data-grid-trend-cell.types.ts +1 -0
  37. package/dist/assets/components/data-grid/composables/use-calculate-column-width/use-calculate-column-width.types.ts +1 -0
  38. package/dist/assets/components/data-grid/composables/use-column-hovering/use-column-hovering.types.ts +1 -0
  39. package/dist/assets/components/data-grid/composables/use-config-settings/use-config.settings.types.ts +1 -0
  40. package/dist/assets/components/data-grid/composables/use-keyboard-navigator/use-keyboard-navigator.types.ts +1 -0
  41. package/dist/assets/components/data-grid/data-grid.types.ts +1 -0
  42. package/dist/assets/components/date/date.types.ts +1 -0
  43. package/dist/assets/components/date-picker/composables/use-date-picker-single-calendar-text.types.ts +1 -0
  44. package/dist/assets/components/date-picker/date-picker.types.ts +1 -0
  45. package/dist/assets/components/date-range-picker/components/date-range-picker-calendar/date-range-picker-calendar.types.ts +1 -0
  46. package/dist/assets/components/date-range-picker/components/date-range-picker-calendar/date-range-picker-calendar.vue +1 -1
  47. package/dist/assets/components/date-range-picker/composables/use-date-range-picker-calendar-text.types.ts +1 -0
  48. package/dist/assets/components/date-range-picker/composables/use-granularity-memory.types.ts +1 -0
  49. package/dist/assets/components/date-range-picker/date-range-picker.types.ts +1 -0
  50. package/dist/assets/components/divider/divider.types.ts +1 -0
  51. package/dist/assets/components/draggable-handle/draggable-handle.types.ts +1 -0
  52. package/dist/assets/components/dropdown/components/dropdown-base-textbox/dropdown-base-textbox.types.ts +1 -0
  53. package/dist/assets/components/dropdown/components/dropdown-options-container/dropdown-options-container.vue +1 -1
  54. package/dist/assets/components/dropdown/components/variants/dropdown-avatar/dropdown-avatar.types.ts +1 -0
  55. package/dist/assets/components/dropdown/components/variants/dropdown-country/dropdown-country.types.ts +1 -0
  56. package/dist/assets/components/dropdown/components/variants/dropdown-currency/dropdown-currency.types.ts +1 -0
  57. package/dist/assets/components/dropdown/components/variants/dropdown-payment-method/dropdown-payment-method.types.ts +1 -0
  58. package/dist/assets/components/dropdown/components/variants/dropdown-tag/dropdown-tag.types.ts +1 -0
  59. package/dist/assets/components/dropdown/composables/use-display-value.types.ts +1 -0
  60. package/dist/assets/components/dropdown/composables/use-keyboard-navigation.types.ts +1 -0
  61. package/dist/assets/components/dropdown/dropdown.stories.ts +1 -1
  62. package/dist/assets/components/dropdown/dropdown.types.ts +1 -0
  63. package/dist/assets/components/dropdown/dropdown.vue +1 -1
  64. package/dist/assets/components/empty-state/empty-state.types.ts +1 -0
  65. package/dist/assets/components/file-uploader/components/file-uploader-file-card/file-uploader-file-card.types.ts +1 -0
  66. package/dist/assets/components/file-uploader/components/file-uploader-restrictions/file-uploader-restrictions.types.ts +1 -0
  67. package/dist/assets/components/file-uploader/composables/use-drag-drop-state/use-drag-drop-state.types.ts +1 -0
  68. package/dist/assets/components/file-uploader/file-uploader.types.ts +1 -0
  69. package/dist/assets/components/filter-bar/components/all-filters-modal/all-filters-modal.types.ts +1 -0
  70. package/dist/assets/components/filter-bar/components/all-filters-modal/all-filters-modal.vue +1 -1
  71. package/dist/assets/components/filter-bar/components/base-filter/base-filter.types.ts +1 -0
  72. package/dist/assets/components/filter-bar/components/checkbox-group-filter/checkbox-group-filter.types.ts +1 -0
  73. package/dist/assets/components/filter-bar/components/filter-bar-button-group/filter-bar-button-group.types.ts +1 -0
  74. package/dist/assets/components/filter-bar/components/input-filter/input-filter.types.ts +1 -0
  75. package/dist/assets/components/filter-bar/components/radio-group-filter/radio-group-filter.types.ts +1 -0
  76. package/dist/assets/components/filter-bar/components/toggle-filter/toggle-filter.types.ts +1 -0
  77. package/dist/assets/components/filter-bar/filter-bar.types.ts +1 -0
  78. package/dist/assets/components/focus-trap/focus-trap.types.ts +1 -0
  79. package/dist/assets/components/form-layout/components/form-layout-field-tip/form-layout-tip.types.ts +1 -0
  80. package/dist/assets/components/form-layout/components/form-layout-group/form-layout-group.types.ts +1 -0
  81. package/dist/assets/components/form-layout/form-layout.types.ts +1 -0
  82. package/dist/assets/components/header/header.types.ts +1 -0
  83. package/dist/assets/components/header-with-views/components/header-with-views-all-views/header-with-views-all-views.types.ts +1 -0
  84. package/dist/assets/components/header-with-views/components/header-with-views-item-edit-form/header-with-views-edit-form.types.ts +1 -0
  85. package/dist/assets/components/header-with-views/header-with-views.types.ts +1 -0
  86. package/dist/assets/components/image/image.types.ts +1 -0
  87. package/dist/assets/components/info-icon/info-icon.types.ts +1 -0
  88. package/dist/assets/components/input-field/input-field.stories.ts +1 -1
  89. package/dist/assets/components/input-field/input-field.types.ts +1 -0
  90. package/dist/assets/components/input-field-password/input-field-password.stories.ts +1 -1
  91. package/dist/assets/components/input-field-password/input-field-password.types.ts +1 -0
  92. package/dist/assets/components/input-field-phone-number/input-field-phone-number.stories.ts +1 -1
  93. package/dist/assets/components/input-field-phone-number/input-field-phone-number.types.ts +1 -0
  94. package/dist/assets/components/inspector/inspector.types.ts +1 -0
  95. package/dist/assets/components/internal/base-button/base-button.types.ts +1 -0
  96. package/dist/assets/components/internal/button-actions-with-menu/button-actions-with-menu.types.ts +1 -0
  97. package/dist/assets/components/internal/calendar/calendar.types.ts +1 -0
  98. package/dist/assets/components/internal/calendar/components/calendar-month/calendar-month.types.ts +1 -0
  99. package/dist/assets/components/internal/calendar/components/calendar-month/components/calendar-month-day/calendar-month-day.types.ts +1 -0
  100. package/dist/assets/components/internal/calendar/components/calendar-month/composables/granular-min-max-date.types.ts +1 -0
  101. package/dist/assets/components/internal/calendar/components/calendar-year/calendar-year.types.ts +1 -0
  102. package/dist/assets/components/internal/calendar/components/calendar-year/components/calendar-year-month/calendar-year-month.types.ts +1 -0
  103. package/dist/assets/components/internal/calendar/composables/use-granularity-adjustments.types.ts +1 -0
  104. package/dist/assets/components/internal/checkbox-input/checkbox-input.types.ts +1 -0
  105. package/dist/assets/components/internal/copy/copy.types.ts +1 -0
  106. package/dist/assets/components/internal/dialog-page/dialog-page.types.ts +1 -0
  107. package/dist/assets/components/internal/grid-layout/grid-layout.types.ts +1 -0
  108. package/dist/assets/components/internal/header-meta/header-meta.types.ts +1 -0
  109. package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/components/listbox-multi-select-category/listbox-multi-select-category.types.ts +1 -0
  110. package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/listbox-multi-select-options.types.ts +1 -0
  111. package/dist/assets/components/internal/listbox/components/listbox-multi-select/listbox-multi-select.types.ts +1 -0
  112. package/dist/assets/components/internal/listbox/listbox.types.ts +1 -0
  113. package/dist/assets/components/internal/radio-input/radio-input.types.ts +1 -0
  114. package/dist/assets/components/internal/radio-input/radio-input.vue +1 -1
  115. package/dist/assets/components/internal/teleport/teleport.types.ts +1 -0
  116. package/dist/assets/components/internal/tooltip/tooltip.types.ts +1 -0
  117. package/dist/assets/components/layout/layout.types.ts +1 -0
  118. package/dist/assets/components/link/link.types.ts +1 -0
  119. package/dist/assets/components/list/components/list-item/list-item.stories.ts +1 -0
  120. package/dist/assets/components/list/components/list-item/list-item.types.ts +1 -0
  121. package/dist/assets/components/list/components/list-item/list-item.vue +1 -0
  122. package/dist/assets/components/list/list.docs.mdx +97 -0
  123. package/dist/assets/components/list/list.stories.ts +1 -0
  124. package/dist/assets/components/list/list.types.ts +1 -0
  125. package/dist/assets/components/list/list.vue +1 -0
  126. package/dist/assets/components/loading-indicator/loading-indicator.types.ts +1 -0
  127. package/dist/assets/components/menu/components/menu-item/menu-item.types.ts +1 -0
  128. package/dist/assets/components/menu/menu.types.ts +1 -0
  129. package/dist/assets/components/modal/components/modal-page/modal-page.types.ts +1 -0
  130. package/dist/assets/components/modal/modal.types.ts +1 -0
  131. package/dist/assets/components/pagination/pagination.types.ts +1 -0
  132. package/dist/assets/components/payment-method/payment-method.types.ts +1 -0
  133. package/dist/assets/components/popover/popover.types.ts +1 -0
  134. package/dist/assets/components/popper-container/popper-container.types.ts +1 -0
  135. package/dist/assets/components/promo-banner/promo-banner.types.ts +1 -0
  136. package/dist/assets/components/radio-group/components/radio-button/radio-button.types.ts +1 -0
  137. package/dist/assets/components/radio-group/radio-group.types.ts +1 -0
  138. package/dist/assets/components/rich-text-editor/components/rich-text-editor-content-area/rich-text-editor-content-area.types.ts +1 -0
  139. package/dist/assets/components/rich-text-editor/components/rich-text-editor-renderer/components/rich-text-editor-code-block/rich-text-editor-code-block.types.ts +1 -0
  140. package/dist/assets/components/rich-text-editor/components/rich-text-editor-renderer/components/rich-text-editor-inline-code/rich-text-editor-inline-code.types.ts +1 -0
  141. package/dist/assets/components/rich-text-editor/components/rich-text-editor-renderer/components/rich-text-editor-link/rich-text-editor-link.types.ts +1 -0
  142. package/dist/assets/components/rich-text-editor/components/rich-text-editor-renderer/components/rich-text-editor-list-item/rich-text-editor-list-item.types.ts +1 -0
  143. package/dist/assets/components/rich-text-editor/components/rich-text-editor-renderer/rich-text-editor-renderer.types.ts +1 -0
  144. package/dist/assets/components/rich-text-editor/rich-text-editor.types.ts +1 -0
  145. package/dist/assets/components/search-bar/search-bar.types.ts +1 -0
  146. package/dist/assets/components/secondary-nav/secondary-nav.types.ts +1 -0
  147. package/dist/assets/components/segmented-control/segmented-control.types.ts +1 -0
  148. package/dist/assets/components/selection-card/components/selection-card-group/selection-card-group.types.ts +1 -0
  149. package/dist/assets/components/selection-card/selection-card.types.ts +1 -0
  150. package/dist/assets/components/sidepanel/sidepanel.types.ts +1 -0
  151. package/dist/assets/components/status/status.types.ts +1 -0
  152. package/dist/assets/components/stepper/stepper.types.ts +1 -0
  153. package/dist/assets/components/structured-list/structured-list.types.ts +1 -0
  154. package/dist/assets/components/summary-grid/components/summary-grid-item/summary-grid-item.types.ts +1 -0
  155. package/dist/assets/components/summary-grid/components/summary-grid-item-amount/summary-grid-item-amount.types.ts +1 -0
  156. package/dist/assets/components/summary-grid/components/summary-grid-item-custom/summary-grid-item-custom.types.ts +1 -0
  157. package/dist/assets/components/summary-grid/components/summary-grid-item-numeric/summary-grid-item-numeric.types.ts +1 -0
  158. package/dist/assets/components/summary-grid/components/summary-grid-item-percentage/summary-grid-item-percentage.types.ts +1 -0
  159. package/dist/assets/components/summary-grid/components/summary-grid-item-text/summary-grid-item-text.types.ts +1 -0
  160. package/dist/assets/components/summary-grid/summary-grid.types.ts +1 -0
  161. package/dist/assets/components/tabs/components/tab.types.ts +1 -0
  162. package/dist/assets/components/tabs/tabs.types.ts +1 -0
  163. package/dist/assets/components/tag/tag.types.ts +1 -0
  164. package/dist/assets/components/textarea/textarea.types.ts +1 -0
  165. package/dist/assets/components/timeline/components/timeline-item/timeline-item.vue +1 -1
  166. package/dist/assets/components/timeline/timeline.stories.ts +1 -1
  167. package/dist/assets/components/timeline/timeline.types.ts +1 -0
  168. package/dist/assets/components/toast/components/toast-shadow-stack/toast-shadow-stack.types.ts +1 -0
  169. package/dist/assets/components/toggle/toggle.types.ts +1 -0
  170. package/dist/assets/components/tutorial/tutorial.types.ts +1 -0
  171. package/dist/assets/components/typography/typography.types.ts +1 -0
  172. package/dist/assets/components.json +101 -0
  173. package/dist/assets/composables/use-bento-theme/install.ts +1 -0
  174. package/dist/assets/composables/use-bento-theme/install.types.ts +1 -0
  175. package/dist/assets/composables/use-bento-theme/use-bento-theme.types.ts +1 -0
  176. package/dist/assets/composables/use-bento-toast-controller/install.ts +1 -0
  177. package/dist/assets/composables/use-bento-toast-controller/use-bento-toast-controller.types.ts +1 -0
  178. package/dist/assets/composables/use-form-validate/use-form.types.ts +1 -0
  179. package/dist/assets/composables/use-form-validate-zod-4/use-form.types.ts +1 -0
  180. package/dist/assets/composables/use-virtual-list/use-virtual-list.types.ts +1 -0
  181. package/dist/assets/deprecations.md +330 -0
  182. package/dist/assets/directives/keyboard-navigation/keyboard-navigation.types.ts +1 -0
  183. package/dist/assets/directives/tooltip/tooltip.types.ts +1 -0
  184. package/dist/assets/icons.json +415 -0
  185. package/dist/assets/index.ts +1 -1
  186. package/dist/assets/install.ts +1 -0
  187. package/dist/assets/tailwind/README.md +89 -0
  188. package/dist/assets/templates/dashboard-template/dashboard-template.types.ts +1 -0
  189. package/dist/assets/templates/data-grid-template/data-grid-template.stories.ts +1 -1
  190. package/dist/assets/templates/data-grid-template/data-grid-template.types.ts +1 -0
  191. package/dist/assets/utility-classes.md +92 -0
  192. package/dist/assets/utils/ts/currency/currency.types.ts +1 -0
  193. package/dist/assets/variables.css +309 -0
  194. package/dist/main.js +395 -29
  195. package/package.json +15 -6
@@ -0,0 +1 @@
1
+ import { type Ref } from 'vue'; import { type BentoFileUploaderProps } from '@/components/file-uploader/file-uploader.types'; export interface useDragDropStateProps { accept: Ref<BentoFileUploaderProps['accept']>; maxCount: Ref<BentoFileUploaderProps['maxCount']>; }
@@ -0,0 +1 @@
1
+ import { type FormField } from '../../types/form-field'; export type BentoFileUploaderValue = string | Array<string> | File | Array<File> | FileList; export interface BentoFileUploaderProps extends FormField { /** * A string that defines the file types the file input should accept. * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept * @default null */ accept?: HTMLInputElement['accept']; /** * Reduces the size of the uploader area. * @default false */ condensed?: boolean; /** * Sets a maximum file count. Allows for uploading multiple files. * @default 1 */ maxCount?: number; /** * Sets a maximum image size (for image file types only). * @default null */ maxDimensions?: { width?: number; height?: number }; /** * Sets a maximum file size in Bytes. Also accepts an array of FileMaxSize objects to specify different sizes for different file types. * @default null */ maxSize?: number | Array<FileMaxSize>; /** * Used to support `v-model`. Can be used to set value of FileUploader if FileList * @default null */ modelValue?: BentoFileUploaderValue; /** * Placeholder is coming from FormField and is not allowed for FileUploader, so we're explicitly disabling it here */ placeholder?: never; } /** * Private types */ export enum FileState { LOADING = 'loading', SUCCESS = 'success', ERROR = 'error', } export enum FileErrorType { ERROR_SIZE = 'error-size', ERROR_LOAD = 'error-load', ERROR_DIMENSIONS = 'error-dimensions', ERROR_TYPE = 'error-type', } export enum FileUploaderState { DISABLED = 'disabled', DRAG_OVER = 'drag-over', ERROR = 'error', READONLY = 'readonly', } export enum FileType { TABLE = 'table', IMAGE = 'image', VIDEO = 'video', AUDIO = 'audio', TEXT = 'text', PDF = 'pdf', SLIDES = 'slides', COMPRESSED = 'compressed', GENERIC = 'generic', } export interface FileMaxSize { fileType: HTMLInputElement['accept']; maxSize: number; } export interface FileObject { id: string; data: File; state: FileState; errors: Array<FileErrorType>; type: FileType; progress: number | null; dimensions?: { width: number; height: number }; } export type SupportedFileTypes = string;
@@ -0,0 +1 @@
1
+ export enum AllFiltersModalEvent { INPUT = 'input', }
@@ -1 +1 @@
1
- <template> <div class="b-all-filters-modal"> <filter-bar-button :is-filter-open="isModalOpen" :applied-filters-count="numberOfActiveFilters" no-applied-state-styles @click="onClickAllFiltersModal" > {{ t('allFilters') }} <template #iconLeft> <sliders-icon aria-hidden="true" /> </template> </filter-bar-button> <bento-modal class="'b-all-filters-modal__modal'" :is-open="isModalOpen" :with-column-layout="true" size="large" :actions="modalActions" :is-dismissible="false" hide-close-button @close-modal="cancel" > <template #default> {{ t('allFilters') }} </template> <template #content-col-1> <div ref="allFiltersModalFiltersSection" class="b-all-filters-modal__filters" @keydown.right="onKeydownRight" > <bento-search-bar class="b-all-filters-modal__search-bar" :value="searchTerm" :input-field-aria-label="t('searchBar').toString()" @input="searchTerm = $event" @clear="onSearchbarClear" /> <div v-if="isEmptyResultForSearchFilter" class="b-all-filters-modal__empty-search-message"> <bento-typography el="span"> {{ t('noFiltersMatchThisSearch') }}</bento-typography> </div> <div v-if="activeFilters.length" class="b-all-filters-modal__filters-section"> <bento-typography :id="`active-filters-${allFiltersModalUniqueId}`" class="b-all-filters-modal__filters-section-title" el="span" variant="caption" > {{ t('activeFilters') }} </bento-typography> <ul class="b-all-filters-modal__filters-list" :aria-labelledby="`active-filters-${allFiltersModalUniqueId}`" > <li v-for="item in activeFilters" :key="`${item.label}-${item.field}`"> <all-filters-modal-button :ref="el => (allFiltersModalFilterButtons[item.label] = el)" :label="item.label" :applied-filters-count="getFilterCount(item)" :is-filter-open="selectedFilter.label === item.label" :disabled="item.disabled" @click="selectFilter(item.label, item.field)" /> </li> </ul> </div> <div v-if="otherFilters.length" class="b-all-filters-modal__filters-section"> <bento-typography v-if="activeFilters.length" :id="`other-filters-${allFiltersModalUniqueId}`" class="b-all-filters-modal__filters-section-title" el="span" variant="caption" > {{ t('otherFilters') }} </bento-typography> <ul class="b-all-filters-modal__filters-list" :aria-labelledby="`other-filters-${allFiltersModalUniqueId}`" > <li v-for="item in otherFilters" :key="`${item.label}-${item.field}`"> <all-filters-modal-button :ref="el => (allFiltersModalFilterButtons[item.label] = el)" :label="item.label" :disabled="item.disabled" :applied-filters-count="getFilterCount(item)" :is-filter-open="selectedFilter.label === item.label" @click="selectFilter(item.label, item.field)" /> </li> </ul> </div> </div> </template> <template #content-col-2> <div class="b-all-filters-modal__selected-filter-content" @keydown.left="onKeydownLeft"> <div v-if="shouldShowFilterTitle" class="b-all-filters-modal__selected-filter-text"> <bento-typography :id="selectedFilter.labelId" el="div" variant="title" medium> {{ selectedFilter.label }} </bento-typography> <bento-typography v-if="selectedFilter.description" el="div" variant="body" wide> {{ selectedFilter.description }} </bento-typography> </div> <div class="b-all-filters-modal__selected-filter-component"> <component :is="selectedFilter.type" ref="selectedFilterRef" :key="selectedFilter.field" :description="selectedFilter.description" :field="selectedFilter.field" :label="selectedFilter.label" :options="selectedFilter.options" :value="selectedFilter.value" :default-value="selectedFilter.defaultValue" :only-slot="true" :disabled="selectedFilter.disabled" :aria-labelledby="selectedFilter.labelId" @input="updateFilter" /> </div> <div class="b-all-filters-modal__clear-button"> <bento-button variant="secondary" :disabled="isClearButtonDisabled" @click="clearFilter">{{ t('clear') }}</bento-button> </div> </div> </template> </bento-modal> </div> </template> <script lang="ts"> import { computed, defineComponent, onBeforeUpdate, onMounted, type PropType, ref, toRef, watch } from 'vue'; import BentoModal from '@/components/modal/modal.vue'; import { BentoButton } from '@/components/button'; import { type BentoFilterBarModel, BentoFilterItemType, type BentoFilterModel, type BentoSelectFilterOptions, } from '@/components/filter-bar/filter-bar.types'; import { BentoBooleanFilter, BentoCheckboxGroupFilter, BentoDateFilter, BentoDateRangeFilter, BentoInputFilter, BentoInputWithDropdownFilter, BentoRadioGroupFilter, BentoRangeFilter, BentoSelectAvatarFilter, BentoSelectCountryFilter, BentoSelectCurrencyFilter, BentoSelectFilter, BentoSelectPaymentMethodFilter, BentoSelectTagFilter, BentoToggleFilter, } from '../index'; import { type BentoDateRangePickerValue } from '@/components/date-range-picker'; import BentoSearchBar from '@/components/search-bar/search-bar.vue'; import { BentoTypography } from '@/components/typography'; import { useSearchBarFilter } from '@/components/search-bar'; import { generateUid } from '@/core/utils/ts'; import { getNextFocusableElement } from '@/utils/ts/focus-trap.utils'; import { FilterBarButton } from '../filter-bar-button'; import { AllFiltersModalEvent } from './all-filters-modal.types'; import { useI18n } from '@/utils/ts/i18n'; import AllFiltersModalButton from './components/all-filters-modal-button/all-filters-modal-button.vue'; import SlidersIcon from '@adyen/ui-assets-icons-16/vue/sliders-1'; import messages from './messages.json'; import { type BentoCheckboxGroupFilterOptions } from '../checkbox-group-filter'; type MessageSchema = (typeof messages)['en-US']; /** * A modal that acts as sort of filter manager for the BentoFilterBar. * * @example * import { BentoAllFiltersModal } from '@adyen/bento-vue2'; * * export default { * components: { BentoAllFiltersModal }, * template: ` * <bento-all-filters-modal> * ...Example code of the component * </bento-all-filters-modal> * ` * } */ export default defineComponent({ i18n: { messages }, name: 'all-filters-modal', components: { AllFiltersModalButton, BentoBooleanFilter, BentoButton, BentoCheckboxGroupFilter, BentoDateFilter, BentoDateRangeFilter, BentoInputFilter, BentoInputWithDropdownFilter, BentoModal, BentoRadioGroupFilter, BentoRangeFilter, BentoSearchBar, BentoSelectAvatarFilter, BentoSelectCurrencyFilter, BentoSelectCountryFilter, BentoSelectFilter, BentoSelectPaymentMethodFilter, BentoSelectTagFilter, BentoToggleFilter, BentoTypography, FilterBarButton, SlidersIcon, }, props: { /** * Array of filters based on {@see FilterBarModel}. * Each one of the elements in the array correspond to a filter that will * be created and rendered in the AllFiltersModal. * * Can be used with v-model or independently with the @input event. * * @example * [{ * field: 'company', * label: 'Company', * value: '200', * type: FilterType.TEXT, * }, { * field: 'name', * label: 'Name', * value: null, * type: FilterType.TEXT, * }] */ value: { type: Array as PropType<BentoFilterBarModel>, default: () => [], }, }, emits: [AllFiltersModalEvent.INPUT], setup(props, { emit }) { const filtersInModal = ref(props.value); const allFiltersModalUniqueId = generateUid('all-filters-modal'); const allFiltersModalFiltersSection = ref([]); const isModalOpen = ref(false); const selectedFilterIndex = ref(0); const selectedFilterRef = ref(null); const searchTerm = ref<string>(''); const { t, n } = useI18n<{ message: MessageSchema }>({ messages }); const filteredItems = useSearchBarFilter<BentoFilterModel>(searchTerm, toRef(filtersInModal, 'value')); const allFiltersModalFilterButtons = ref({}); onBeforeUpdate(() => { allFiltersModalFilterButtons.value = []; }); watch( () => props.value, () => { /** * Values need to be preserve when the modal is opened given that * when the "select" filter is enabled with external filtering inside the modal * the "searchTerm" gets reset and doing so resets all the unsaved values of the array */ if (isModalOpen.value) { filtersInModal.value = props.value.map((filter, index) => { return { ...filter, value: filtersInModal.value[index].value }; }); } else { filtersInModal.value = props.value; } } ); const sortAlphabetically = (array: BentoFilterBarModel) => array.sort((a, b) => (a.label > b.label ? 1 : b.label > a.label ? -1 : 0)); const activeFilters = computed(() => sortAlphabetically( filteredItems.value.filter(el => Array.isArray(el.value) ? el.value?.length && el.value?.find(item => item !== '') : el.value ) ) ); const otherFilters = computed(() => sortAlphabetically( filteredItems.value.filter(el => Array.isArray(el.value) ? el.value?.length === 0 || el.value?.every(item => item === '') : !el.value ) ) ); const isEmptyResultForSearchFilter = computed(() => searchTerm.value && filteredItems.value?.length === 0); const selectedFilter = computed(() => ({ ...filtersInModal.value[selectedFilterIndex.value], labelId: generateUid(filtersInModal.value[selectedFilterIndex.value]?.field), })); const selectOpenedFilter = () => { const openedFilter = activeFilters.value.length ? activeFilters.value[0] : otherFilters.value[0]; const openedFilterIndex = filtersInModal.value.findIndex( el => el.label === openedFilter.label && el.field === openedFilter.field ); selectedFilterIndex.value = openedFilterIndex; }; onMounted(() => { selectOpenedFilter(); }); const computeCounts = (filterValue: BentoFilterBarModel) => filterValue.map(filter => { switch (filter.type) { case BentoFilterItemType.SELECT: case BentoFilterItemType.SELECT_AVATAR: case BentoFilterItemType.SELECT_COUNTRY: case BentoFilterItemType.SELECT_CURRENCY: case BentoFilterItemType.SELECT_PAYMENT_METHOD: case BentoFilterItemType.SELECT_TAG: switch ((filter.options as BentoSelectFilterOptions)?.multiple) { case true: return { label: filter.label, field: filter.field, count: (filter.value as Array<string | number>)?.length ? (filter.value as Array<string | number>)?.length : null, }; default: return { label: filter.label, field: filter.field, count: filter.value == null ? null : 1, }; } case BentoFilterItemType.DATE_RANGE: return { label: filter.label, field: filter.field, count: (filter.value as BentoDateRangePickerValue)?.startDate != null && (filter.value as BentoDateRangePickerValue)?.endDate != null ? 1 : null, }; case BentoFilterItemType.RANGE: return { label: filter.label, field: filter.field, count: (filter.value as Array<string>)?.find(el => el !== '') ? 1 : null, }; case BentoFilterItemType.CHECKBOX_GROUP: return { label: filter.label, field: filter.field, count: (filter.value as Array<string | number>)?.length ? (filter.value as Array<string | number>)?.length : null, }; case BentoFilterItemType.TOGGLE: return { label: filter.label, field: filter.field, count: filter.value ? 1 : null, }; case BentoFilterItemType.INPUT: case BentoFilterItemType.BOOLEAN: case BentoFilterItemType.DATE: case BentoFilterItemType.RADIO_GROUP: default: return { label: filter.label, field: filter.field, count: filter.value != null ? 1 : null, }; } }); const hasValueSelected = computed(() => Array.isArray(selectedFilter.value.value) ? selectedFilter.value?.value.length && selectedFilter.value.value.find(item => item !== '') : !!filtersInModal.value[selectedFilterIndex.value].value ); /** * Hides filter title if the selected filter is Toggle. * The Toggle filter shows a checkbox next to the "title". */ const shouldShowFilterTitle = computed(() => { return selectedFilter.value.type !== BentoFilterItemType.TOGGLE; }); const isClearButtonDisabled = computed(() => !hasValueSelected.value || selectedFilter.value.disabled); const numberOfActiveFilters = computed( () => computeCounts(props.value)?.filter(({ count }) => !!count).length ); const onClickAllFiltersModal = () => { if (!isModalOpen.value) { isModalOpen.value = true; } else { isModalOpen.value = false; } }; const getFilterCount = (filter: BentoFilterModel) => { const filterCount = computeCounts(filtersInModal.value).find(el => el.field === filter.field).count; const isBentoSelectFilter = typeof filter.type === 'string' && // Type guard to avoid casting filter.type.includes('BentoSelect') && (filter.options as BentoSelectFilterOptions)?.multiple && filterCount === (filter.options as BentoSelectFilterOptions)?.listboxItems?.length; const isBentoCheckboxGroupFilter = typeof filter.type === 'string' && filter.type === BentoFilterItemType.CHECKBOX_GROUP && filterCount === (filter.options as BentoCheckboxGroupFilterOptions)?.checkboxItems?.length; if (isBentoSelectFilter || isBentoCheckboxGroupFilter) { return t('all'); } return filterCount === null ? null : n(filterCount); }; const selectFilter = (filterLabel: string, filterField: string) => { selectedFilterIndex.value = filtersInModal.value.findIndex( el => el.label === filterLabel && el.field === filterField ); }; const onSearchbarClear = () => { searchTerm.value = ''; }; const cancel = () => { isModalOpen.value = false; filtersInModal.value = props.value; onSearchbarClear(); selectOpenedFilter(); // TODO: scroll filters section to top }; const updateFilter = (updatedFilter: BentoFilterModel) => { const updatedFilters = filtersInModal.value.map(({ value, ...otherFields }, index) => { if (index === selectedFilterIndex.value) { return { value: updatedFilter.value, ...otherFields }; } return { value, ...otherFields }; }); filtersInModal.value = updatedFilters; }; const clearFilter = () => { updateFilter({ field: selectedFilter.value.field, label: selectedFilter.value.label, type: selectedFilter.value.type, value: undefined, }); }; const clearAll = () => { filtersInModal.value = props.value.map(({ value, ...otherFields }) => ({ ...otherFields, value: undefined, })); }; const applyAll = () => { emit(AllFiltersModalEvent.INPUT, filtersInModal.value); isModalOpen.value = false; }; const isApplyAllButtonDisabled = computed( () => JSON.stringify(filtersInModal.value) === JSON.stringify(props.value) ); const modalActions = computed(() => [ { title: t('applyAll'), disabled: isApplyAllButtonDisabled.value, event: applyAll, }, { title: t('cancel'), event: cancel, }, { title: t('clearAll'), disabled: !numberOfActiveFilters.value, event: clearAll, }, ]); const onKeydownRight = () => { const focusableEl = getNextFocusableElement(1, selectedFilterRef.value.$el); focusableEl.focus(); }; const onKeydownLeft = () => { allFiltersModalFilterButtons.value[selectedFilter.value.label].$el.focus(); }; return { // Values allFiltersModalUniqueId, allFiltersModalFiltersSection, allFiltersModalFilterButtons, numberOfActiveFilters, isEmptyResultForSearchFilter, isModalOpen, isClearButtonDisabled, activeFilters, otherFilters, modalActions, selectedFilter, selectedFilterRef, searchTerm, shouldShowFilterTitle, // Methods onClickAllFiltersModal, getFilterCount, cancel, selectFilter, clearFilter, updateFilter, onSearchbarClear, onKeydownRight, onKeydownLeft, // Translations t, }; }, }); </script> <style lang="scss" scoped src="./all-filters-modal.scss" />
1
+ <template> <div class="b-all-filters-modal"> <filter-bar-button :is-filter-open="isModalOpen" :applied-filters-count="numberOfActiveFilters" no-applied-state-styles @click="onClickAllFiltersModal" > {{ t('allFilters') }} <template #iconLeft> <sliders-icon aria-hidden="true" /> </template> </filter-bar-button> <bento-modal class="'b-all-filters-modal__modal'" :is-open="isModalOpen" :with-column-layout="true" size="large" :actions="modalActions" :is-dismissible="false" hide-close-button @close-modal="cancel" > <template #default> {{ t('allFilters') }} </template> <template #content-col-1> <div ref="allFiltersModalFiltersSection" class="b-all-filters-modal__filters" @keydown.right="onKeydownRight" > <bento-search-bar class="b-all-filters-modal__search-bar" :value="searchTerm" :input-field-aria-label="t('searchBar').toString()" @input="searchTerm = $event" @clear="onSearchbarClear" /> <div v-if="isEmptyResultForSearchFilter" class="b-all-filters-modal__empty-search-message"> <bento-typography el="span"> {{ t('noFiltersMatchThisSearch') }}</bento-typography> </div> <div v-if="activeFilters.length" class="b-all-filters-modal__filters-section"> <bento-typography :id="`active-filters-${allFiltersModalUniqueId}`" class="b-all-filters-modal__filters-section-title" el="span" variant="caption" > {{ t('activeFilters') }} </bento-typography> <ul class="b-all-filters-modal__filters-list" :aria-labelledby="`active-filters-${allFiltersModalUniqueId}`" > <li v-for="item in activeFilters" :key="`${item.label}-${item.field}`"> <all-filters-modal-button :ref="el => (allFiltersModalFilterButtons[item.label] = el)" :label="item.label" :applied-filters-count="getFilterCount(item)" :is-filter-open="selectedFilter.label === item.label" :disabled="item.disabled" @click="selectFilter(item.label, item.field)" /> </li> </ul> </div> <div v-if="otherFilters.length" class="b-all-filters-modal__filters-section"> <bento-typography v-if="activeFilters.length" :id="`other-filters-${allFiltersModalUniqueId}`" class="b-all-filters-modal__filters-section-title" el="span" variant="caption" > {{ t('otherFilters') }} </bento-typography> <ul class="b-all-filters-modal__filters-list" :aria-labelledby="`other-filters-${allFiltersModalUniqueId}`" > <li v-for="item in otherFilters" :key="`${item.label}-${item.field}`"> <all-filters-modal-button :ref="el => (allFiltersModalFilterButtons[item.label] = el)" :label="item.label" :disabled="item.disabled" :applied-filters-count="getFilterCount(item)" :is-filter-open="selectedFilter.label === item.label" @click="selectFilter(item.label, item.field)" /> </li> </ul> </div> </div> </template> <template #content-col-2> <div class="b-all-filters-modal__selected-filter-content" @keydown.left="onKeydownLeft"> <div v-if="shouldShowFilterTitle" class="b-all-filters-modal__selected-filter-text"> <bento-typography :id="selectedFilter.labelId" el="div" variant="title" medium> {{ selectedFilter.label }} </bento-typography> <bento-typography v-if="selectedFilter.description" el="div" variant="body" wide> {{ selectedFilter.description }} </bento-typography> </div> <div class="b-all-filters-modal__selected-filter-component"> <component :is="selectedFilter.type" ref="selectedFilterRef" :key="selectedFilter.field" :description="selectedFilter.description" :field="selectedFilter.field" :label="selectedFilter.label" :options="selectedFilter.options" :value="selectedFilter.value" :default-value="selectedFilter.defaultValue" :only-slot="true" :disabled="selectedFilter.disabled" :aria-labelledby="selectedFilter.labelId" @input="updateFilter" /> </div> <div class="b-all-filters-modal__clear-button"> <bento-button variant="secondary" :disabled="isClearButtonDisabled" @click="clearFilter">{{ t('clear') }}</bento-button> </div> </div> </template> </bento-modal> </div> </template> <script setup lang="ts"> import { computed, onBeforeUpdate, onMounted, ref, toRef, watch } from 'vue'; import BentoModal from '@/components/modal/modal.vue'; import { BentoButton } from '@/components/button'; import { type BentoFilterBarModel, BentoFilterItemType, type BentoFilterModel, type BentoSelectFilterOptions, } from '@/components/filter-bar/filter-bar.types'; import { type BentoDateRangePickerValue } from '@/components/date-range-picker'; import BentoSearchBar from '@/components/search-bar/search-bar.vue'; import { BentoTypography } from '@/components/typography'; import { useSearchBarFilter } from '@/components/search-bar'; import { generateUid } from '@/core/utils/ts'; import { getNextFocusableElement } from '@/utils/ts/focus-trap.utils'; import { FilterBarButton } from '../filter-bar-button'; import { AllFiltersModalEvent } from './all-filters-modal.types'; import { useI18n } from '@/utils/ts/i18n'; import AllFiltersModalButton from './components/all-filters-modal-button/all-filters-modal-button.vue'; import SlidersIcon from '@adyen/ui-assets-icons-16/vue/sliders-1'; import messages from './messages.json'; import { type BentoCheckboxGroupFilterOptions } from '../checkbox-group-filter'; type MessageSchema = (typeof messages)['en-US']; const props = withDefaults( defineProps<{ /** * Array of filters based on {@see FilterBarModel}. * Each one of the elements in the array correspond to a filter that will * be created and rendered in the AllFiltersModal. * * Can be used with v-model or independently with the @input event. * * @example * [{ * field: 'company', * label: 'Company', * value: '200', * type: FilterType.TEXT, * }, { * field: 'name', * label: 'Name', * value: null, * type: FilterType.TEXT, * }] */ value?: BentoFilterBarModel; }>(), { value: () => [], } ); const emit = defineEmits([AllFiltersModalEvent.INPUT]); const filtersInModal = ref<BentoFilterBarModel>(props.value); const allFiltersModalUniqueId = generateUid('all-filters-modal'); const allFiltersModalFiltersSection = ref([]); const isModalOpen = ref(false); const selectedFilterIndex = ref(0); const selectedFilterRef = ref(null); const searchTerm = ref<string>(''); const { t, n } = useI18n<{ message: MessageSchema }>({ messages }); const filteredItems = useSearchBarFilter<BentoFilterModel>(searchTerm, toRef(filtersInModal, 'value')); const allFiltersModalFilterButtons = ref({}); onBeforeUpdate(() => { allFiltersModalFilterButtons.value = []; }); watch( () => props.value, () => { /** * Values need to be preserve when the modal is opened given that * when the "select" filter is enabled with external filtering inside the modal * the "searchTerm" gets reset and doing so resets all the unsaved values of the array */ if (isModalOpen.value) { filtersInModal.value = props.value.map((filter, index) => { return { ...filter, value: filtersInModal.value[index].value }; }); } else { filtersInModal.value = props.value; } } ); const sortAlphabetically = (array: BentoFilterBarModel) => array.sort((a, b) => (a.label > b.label ? 1 : b.label > a.label ? -1 : 0)); const activeFilters = computed(() => sortAlphabetically( filteredItems.value.filter(el => Array.isArray(el.value) ? el.value?.length && el.value?.find(item => item !== '') : el.value ) ) ); const otherFilters = computed(() => sortAlphabetically( filteredItems.value.filter(el => Array.isArray(el.value) ? el.value?.length === 0 || el.value?.every(item => item === '') : !el.value ) ) ); const isEmptyResultForSearchFilter = computed(() => searchTerm.value && filteredItems.value?.length === 0); const selectedFilter = computed(() => ({ ...filtersInModal.value[selectedFilterIndex.value], labelId: generateUid(filtersInModal.value[selectedFilterIndex.value]?.field), })); const selectOpenedFilter = () => { const openedFilter = activeFilters.value.length ? activeFilters.value[0] : otherFilters.value[0]; const openedFilterIndex = filtersInModal.value.findIndex( el => el.label === openedFilter.label && el.field === openedFilter.field ); selectedFilterIndex.value = openedFilterIndex; }; onMounted(() => { selectOpenedFilter(); }); const computeCounts = (filterValue: BentoFilterBarModel) => filterValue.map(filter => { switch (filter.type) { case BentoFilterItemType.SELECT: case BentoFilterItemType.SELECT_AVATAR: case BentoFilterItemType.SELECT_COUNTRY: case BentoFilterItemType.SELECT_CURRENCY: case BentoFilterItemType.SELECT_PAYMENT_METHOD: case BentoFilterItemType.SELECT_TAG: switch ((filter.options as BentoSelectFilterOptions)?.multiple) { case true: return { label: filter.label, field: filter.field, count: (filter.value as Array<string | number>)?.length ? (filter.value as Array<string | number>)?.length : null, }; default: return { label: filter.label, field: filter.field, count: filter.value == null ? null : 1, }; } case BentoFilterItemType.DATE_RANGE: return { label: filter.label, field: filter.field, count: (filter.value as BentoDateRangePickerValue)?.startDate != null && (filter.value as BentoDateRangePickerValue)?.endDate != null ? 1 : null, }; case BentoFilterItemType.RANGE: return { label: filter.label, field: filter.field, count: (filter.value as Array<string>)?.find(el => el !== '') ? 1 : null, }; case BentoFilterItemType.CHECKBOX_GROUP: return { label: filter.label, field: filter.field, count: (filter.value as Array<string | number>)?.length ? (filter.value as Array<string | number>)?.length : null, }; case BentoFilterItemType.TOGGLE: return { label: filter.label, field: filter.field, count: filter.value ? 1 : null, }; case BentoFilterItemType.INPUT: case BentoFilterItemType.BOOLEAN: case BentoFilterItemType.DATE: case BentoFilterItemType.RADIO_GROUP: default: return { label: filter.label, field: filter.field, count: filter.value != null ? 1 : null, }; } }); const hasValueSelected = computed(() => Array.isArray(selectedFilter.value.value) ? selectedFilter.value?.value.length && selectedFilter.value.value.find(item => item !== '') : !!filtersInModal.value[selectedFilterIndex.value].value ); /** * Hides filter title if the selected filter is Toggle. * The Toggle filter shows a checkbox next to the "title". */ const shouldShowFilterTitle = computed(() => { return selectedFilter.value.type !== BentoFilterItemType.TOGGLE; }); const isClearButtonDisabled = computed(() => !hasValueSelected.value || selectedFilter.value.disabled); const numberOfActiveFilters = computed(() => computeCounts(props.value)?.filter(({ count }) => !!count).length); const onClickAllFiltersModal = () => { if (!isModalOpen.value) { isModalOpen.value = true; } else { isModalOpen.value = false; } }; const getFilterCount = (filter: BentoFilterModel) => { const filterCount = computeCounts(filtersInModal.value).find(el => el.field === filter.field).count; const isBentoSelectFilter = typeof filter.type === 'string' && // Type guard to avoid casting filter.type.includes('BentoSelect') && (filter.options as BentoSelectFilterOptions)?.multiple && filterCount === (filter.options as BentoSelectFilterOptions)?.listboxItems?.length; const isBentoCheckboxGroupFilter = typeof filter.type === 'string' && filter.type === BentoFilterItemType.CHECKBOX_GROUP && filterCount === (filter.options as BentoCheckboxGroupFilterOptions)?.checkboxItems?.length; if (isBentoSelectFilter || isBentoCheckboxGroupFilter) { return t('all'); } return filterCount === null ? null : n(filterCount); }; const selectFilter = (filterLabel: string, filterField: string) => { selectedFilterIndex.value = filtersInModal.value.findIndex( el => el.label === filterLabel && el.field === filterField ); }; const onSearchbarClear = () => { searchTerm.value = ''; }; const cancel = () => { isModalOpen.value = false; filtersInModal.value = props.value; onSearchbarClear(); selectOpenedFilter(); }; const updateFilter = (updatedFilter: BentoFilterModel) => { const updatedFilters = filtersInModal.value.map(({ value, ...otherFields }, index) => { if (index === selectedFilterIndex.value) { return { value: updatedFilter.value, ...otherFields }; } return { value, ...otherFields }; }); filtersInModal.value = updatedFilters; }; const clearFilter = () => { updateFilter({ field: selectedFilter.value.field, label: selectedFilter.value.label, type: selectedFilter.value.type, value: undefined, }); }; const clearAll = () => { filtersInModal.value = props.value.map(({ value, ...otherFields }) => ({ ...otherFields, value: undefined, })); }; const applyAll = () => { emit(AllFiltersModalEvent.INPUT, filtersInModal.value); isModalOpen.value = false; }; const isApplyAllButtonDisabled = computed( () => JSON.stringify(filtersInModal.value) === JSON.stringify(props.value) ); const modalActions = computed(() => [ { title: t('applyAll'), disabled: isApplyAllButtonDisabled.value, event: applyAll, }, { title: t('cancel'), event: cancel, }, { title: t('clearAll'), disabled: !numberOfActiveFilters.value, event: clearAll, }, ]); const onKeydownRight = () => { const focusableEl = getNextFocusableElement(1, selectedFilterRef.value.$el); focusableEl.focus(); }; const onKeydownLeft = () => { allFiltersModalFilterButtons.value[selectedFilter.value.label].$el.focus(); }; </script> <script lang="ts"> import { BentoBooleanFilter, BentoCheckboxGroupFilter, BentoDateFilter, BentoDateRangeFilter, BentoInputFilter, BentoInputWithDropdownFilter, BentoRadioGroupFilter, BentoRangeFilter, BentoSelectAvatarFilter, BentoSelectCountryFilter, BentoSelectCurrencyFilter, BentoSelectFilter, BentoSelectPaymentMethodFilter, BentoSelectTagFilter, BentoToggleFilter, } from '../index'; /** * A modal that acts as sort of filter manager for the BentoFilterBar. * * @example * import { BentoAllFiltersModal } from '@adyen/bento-vue2'; * * export default { * components: { BentoAllFiltersModal }, * template: ` * <bento-all-filters-modal> * ...Example code of the component * </bento-all-filters-modal> * ` * } */ export default { name: 'all-filters-modal', i18n: { messages }, components: { BentoBooleanFilter, BentoCheckboxGroupFilter, BentoDateFilter, BentoDateRangeFilter, BentoInputFilter, BentoInputWithDropdownFilter, BentoRadioGroupFilter, BentoRangeFilter, BentoSelectAvatarFilter, BentoSelectCountryFilter, BentoSelectCurrencyFilter, BentoSelectFilter, BentoSelectPaymentMethodFilter, BentoSelectTagFilter, BentoToggleFilter, }, }; </script> <style lang="scss" scoped src="./all-filters-modal.scss" />
@@ -0,0 +1 @@
1
+ import { type BentoTooltipPosition } from '../../../../directives/tooltip/tooltip.types'; /** * Private */ export enum BaseFilterEvent { APPLY = 'apply', CLEAR = 'clear', OPEN = 'open', CLOSE = 'close', RESET = 'reset', CANCEL = 'cancel', } /** * Public */ export interface BentoBaseFilterProps<Value, Field> { /** * Total count of applied filters */ appliedFiltersCount?: string | number; /** * Overrides the label of the popover visibility toggle button text. */ buttonLabel?: string; /** * Sets the secondary label text of the popover visibility toggle button text. */ buttonSecondaryLabel?: string; /** * Disables the filter from being interacted with. */ disabled?: boolean; /** * Default value of the filter to reset to. */ defaultValue?: Value; /** * Renders the base filter's slot content only - leaving out the button and the popover. * Used for the allFiltersModal component. */ onlySlot?: boolean; /** * Allows to handle the controls (apply/clear) from outside * of the component */ controlled?: boolean; /** * Disable the "apply" button */ disableApplyButton?: boolean; /** * Disable the secondary button action. */ disableSecondaryButton?: boolean; /** * Filter name/key referencing the actual property name in the data set. * Should be unique per filter bar. */ field: Field; /** * Label text to be displayed */ label: string; /** * Sets the size of the container to fit its content */ fitContent?: boolean; /** * Attaches a `BentoTooltip` if present. Text showed in the tooltip on hover. */ tooltipText?: string; /** * Position the tooltip should take if space is available. */ tooltipPosition?: `${BentoTooltipPosition}`; /** * The current value of the filter, used for v-model. */ value?: Value; }
@@ -0,0 +1 @@
1
+ import { type BentoCheckboxGroupItems } from '../../../checkbox/components/checkbox-group/checkbox-group.types'; import { type BentoTooltipPosition } from '@/directives/tooltip/tooltip.types'; export interface BentoCheckboxGroupFilterOptions { /** * An array of objects to create the checkboxes. Each object must have a `label` and `value`. * It can also have a `disabled` property. */ checkboxItems: BentoCheckboxGroupItems; /** * Attaches a `BentoTooltip` if present. Text showed in the tooltip on hover. */ tooltipText?: string; /** * Position the tooltip should take if space is available. */ tooltipPosition?: BentoTooltipPosition | `${BentoTooltipPosition}`; } export type BentoCheckboxGroupFilterValue = Array<number | string | null>; export interface BentoCheckboxGroupFilterProps { /** * Disables the filter from being interacted with. */ disabled?: boolean; /** * Default value of the filter to reset to. */ defaultValue?: BentoCheckboxGroupFilterValue; /** * Filter name/key referencing the actual property name in the data set. * Should be unique per filter bar. */ field: string; /** * Label text to be displayed */ label: string; /** * Renders the base filter's slot content only - leaving out the button and the popover. * Used for the allFiltersModal component. */ onlySlot?: boolean; /** * List of options that are needed to setup the filter */ options?: BentoCheckboxGroupFilterOptions; /** * Current value of the filter */ value?: BentoCheckboxGroupFilterValue; }
@@ -0,0 +1 @@
1
+ export interface BentoFilterBarButtonGroupProps { /** * Whether the button group is active. */ isActive?: boolean; /** * Whether to skip grouping the buttons. Used to simplify usage of multiple v-ifs. */ skipGrouping?: boolean; }
@@ -0,0 +1 @@
1
+ import type { BentoInputFieldProps } from '../../../input-field/input-field.types'; import type { BentoTooltipPosition } from '@/directives/tooltip/tooltip.types'; /** * @deprecated from version 2.0.0. Use BentoFilterItemType.INPUT_DROPDOWN instead. */ export interface BentoInputFilterInputAndDropdownValues { inputValue: string | null; dropdownValue?: string; } export type BentoInputFilterValue = string | null | BentoInputFilterInputAndDropdownValues; export interface BentoInputFilterOptions { /** * @deprecated BentoInputFilter "options" no longer supports "dropdown". Use the "BentoFilterItemType.INPUT_DROPDOWN" instead of "BentoFilterItemType.INPUT" */ dropdown?: any; /** * @deprecated BentoInputFilter "options" no longer supports "dropdownPosition". Use the "BentoFilterItemType.INPUT_DROPDOWN" instead of "BentoFilterItemType.INPUT" */ dropdownPosition?: any; /** * Sets a placeholder in the input field */ placeholder?: BentoInputFieldProps['placeholder']; /** * @deprecated from version 2.0.0. BentoInputFilter "options" no longer supports "variant". Use the "BentoFilterItemType.INPUT_DROPDOWN" instead of "BentoFilterItemType.INPUT" */ variant?: 'dropdown'; /** * Attaches a `BentoTooltip` if present. Text showed in the tooltip on hover. */ tooltipText?: string; /** * Position the tooltip should take if space is available. */ tooltipPosition?: BentoTooltipPosition | `${BentoTooltipPosition}`; } export interface BentoInputFilterProps { /** * Default value of the filter to reset to. */ defaultValue?: string; /** * Disables the filter from being interacted with. */ disabled?: boolean; /** * Filter name/key referencing the actual property name in the data set. * Should be unique per filter bar. */ field: string; /** * Label text to be displayed */ label: string; /** * Renders the base filter's slot content only - leaving out the button and the popover. * Used for the allFiltersModal component. */ onlySlot?: boolean; /** * List of options that are needed to setup the filter * Available options: * - placeholder: allows to set a placeholder to the search bar * - dropdown (deprecated): all the dropdown properties that can be set in the inner dropdown of the input field. @see BentoDropdown for more info. * - dropdownPosition (deprecated): allow the user to set the dropdown on the left or right side. Accepts the `start` or `end` values. * - variant (deprecated): can be `undefined` or set to `dropdown`. Enables dropdown input variant. * - tooltipPosition: The position of the tooltip attached to the filter button * - tooltipText: The content of the tooltip attached to the filter button */ options?: BentoInputFilterOptions; /** * Current value of the filter. * If the options.variant is equal to 'dropdown', the value should be of type `{ inputValue: string | null; dropdownValue?: string }`. */ value?: BentoInputFilterValue; }
@@ -0,0 +1 @@
1
+ import { type BentoRadioGroupItems, type BentoRadioGroupValue } from '@/components/radio-group/radio-group.types'; import { type BentoTooltipPosition } from '@/directives/tooltip/tooltip.types'; export interface BentoRadioGroupFilterOptions { /** * List of radio group options */ items: BentoRadioGroupItems; /** * Attaches a `BentoTooltip` if present. Text showed in the tooltip on hover. */ tooltipText?: string; /** * Position the tooltip should take if space is available. */ tooltipPosition?: BentoTooltipPosition | `${BentoTooltipPosition}`; } export type BentoRadioGroupFilterValue = BentoRadioGroupValue; export interface BentoRadioGroupFilterProps { /** * Disables the filter from being interacted with. */ disabled?: boolean; /** * Default value of the filter to reset to. */ defaultValue?: BentoRadioGroupFilterValue; /** * Filter name/key referencing the actual property name in the data set. * Should be unique per filter bar. */ field: string; /** * Label text to be displayed */ label: string; /** * List of options that are needed to setup the filter * Available options: * - items: Radio group elements containing "value" and "label" */ options: BentoRadioGroupFilterOptions; /** * Renders the base filter's slot content only - leaving out the button and the popover. * Used for the allFiltersModal component. */ onlySlot?: boolean; /** * The current value of the filter, used for v-model. */ value?: BentoRadioGroupFilterValue; }
@@ -0,0 +1 @@
1
+ import { type BentoTooltipPosition } from '../../../../directives/tooltip/tooltip.types'; export type BentoToggleFilterValue = boolean; export interface BentoToggleFilterOptions { /** * Position the tooltip should take if space is available. */ tooltipPosition?: BentoTooltipPosition | `${BentoTooltipPosition}`; /** * Attaches a `BentoTooltip` if present. Text showed in the tooltip on hover. */ tooltipText?: string; } export interface BentoToggleFilterProps { /** * Provides an optional description of the filter. Used in the "All filters" modal to add more context to the filter */ description?: string; /** * Disables the filter from being interacted with. */ disabled?: boolean; /** * Filter name/key referencing the actual property name in the data set. * Should be unique per filter bar. */ field: string; /** * Label text to be displayed */ label: string; /** * Renders the base filter's slot content only - leaving out the button and the popover. * Used for the allFiltersModal component. */ onlySlot?: boolean; /** * List of options that are needed to setup the filter * Available options: * - description: Additional information related to the toggle filter. Used in the "All filters" modal. */ options?: BentoToggleFilterOptions; /** * The current value of the filter, used for v-model. */ value?: BentoToggleFilterValue; }
@@ -0,0 +1 @@
1
+ import { type BentoAvatarListboxOptions } from '@/components/dropdown/components/variants/dropdown-avatar/dropdown-avatar.types'; import { type BentoListboxEmptyStateProps, type BentoListboxIsOptionDisabled, type BentoListboxLazyLoadType, type BentoListboxOptions, type BentoListboxSearchOptions, type BentoListboxSelectedValue, type BentoListboxVirtulisationOptions, } from '@/types/listbox'; import { type OmitStrict } from '@/types/omit-strict'; import { type VueNodeElement } from '@/types/elements'; import { type BentoCountryListboxOptions } from '@/components/dropdown/components/variants/dropdown-country/dropdown-country.types'; import { type BentoTagListboxOptions } from '@/components/dropdown/components/variants/dropdown-tag/dropdown-tag.types'; import { type BentoCountryVariant } from '@/components/country'; import { type BentoCurrencyListboxOptions } from '@/components/dropdown/components/variants/dropdown-currency/dropdown-currency.types'; import { type BentoPaymentMethodListboxOptions } from '@/components/dropdown/components/variants/dropdown-payment-method/dropdown-payment-method.types'; import { type BentoInputDropdownProps, type BentoInputFieldElementPosition, type BentoInputFieldValue, } from '@/components/input-field'; import { type BentoDatePickerFirstDayOfWeek, type BentoDatePickerIsDateDisabled, type BentoDatePickerVariant, } from '@/components/date-picker'; import { type BentoDateRangePickerGranularityConfig, type BentoDateRangePickerValue, type BentoDateRangePickerVariant, } from '@/components/date-range-picker'; import { type BentoRadioGroupFilterOptions, type BentoRadioGroupFilterValue, } from './components/radio-group-filter/radio-group-filter.types'; import { type DateRangePickerCalendarRangeSelectorItems } from '../date-range-picker/components/date-range-picker-calendar/date-range-picker-calendar.types'; import { type BentoSearchBarProps } from '@/components/search-bar/search-bar.types'; import type { BentoInputFilterOptions, BentoInputFilterValue } from './components/input-filter/input-filter.types'; import type { BentoToggleFilterOptions, BentoToggleFilterValue } from './components/toggle-filter/toggle-filter.types'; import type { BentoTooltipPosition } from '@/directives'; import { type BentoCheckboxGroupFilterOptions, type BentoCheckboxGroupFilterValue, } from './components/checkbox-group-filter/checkbox-group-filter.types'; /** * Re-export filter component types */ export type * from './components/input-filter/input-filter.types'; export type * from './components/radio-group-filter/radio-group-filter.types'; export type * from './components/toggle-filter/toggle-filter.types'; export interface BentoSelectFilterOptions { /** * Empty state props that will be used with the inner empty state component to be displayed when no search results are found. */ emptyState?: BentoListboxEmptyStateProps; /** * Option items for the list-box */ listboxItems: BentoListboxOptions; /** * Defines if the list-box should be a multi-select filter */ multiple?: boolean; /** * @deprecated from version 2.0.0. The persistent filter label now uses a counter instead of custom strings. This property is now redundant. * The translation object to handle any custom transations. e.g. perisistent filter labels. */ messages?: { [key: string]: { persistentButtonLabelPartiallySelected?: string; persistentButtonLabelAllSelected?: string; [key: string]: string; }; }; /** * @deprecated from version 2.0.0. The persistent filter label now uses a counter instead of custom strings. This property is now redundant. * The unique key to use in the messages translation object to use for the persistent button label * when the select filter has partially selected items. */ messagesPersistentButtonLabelPartiallySelectedKey?: string; /** * @deprecated from version 2.0.0. The persistent filter label now uses a counter instead of custom strings. This property is now redundant. * The unique key to use in the messages translation object to use for the persistent button label * when the select filter has all items selected. */ messagesPersistentButtonLabelAllSelectedKey?: string; /** * The event fire when the filter is opened. */ onOpen?: () => void; lazy?: { /** * Indicates whether there are more items to load */ hasMoreItems: boolean; /** * The type of `Lazy Load`. * Type "automatic" will enable infinite scrolling * Type "button" will enable lazy loading with "Show more" button */ lazyLoadType: BentoListboxLazyLoadType | `${BentoListboxLazyLoadType}`; /** * Indicates if new options are loading. */ loading: boolean; /** * The click event that fires when the user press on the "show more" button OR when the user * scrolls down to bottom of the select filter box. */ showMoreEvent?: () => void; }; /** * Toggles the loading state of the listbox. */ loading?: boolean; /** * Search options and events for the listbox filtering. */ search?: BentoListboxSearchOptions; /** * Defines if the list-box should support static categories */ staticCategories?: boolean; /** * A function that defines which option in the list-box is disabled */ isOptionDisabled?: BentoListboxIsOptionDisabled; /** * Enables virtual scrolling if set to true or by providing an object with itemHeight function. * The itemHeight function is used to calculate the height of rendered item given it's index. */ virtualScroll?: BentoListboxVirtulisationOptions; /** * Attaches a `BentoTooltip` if present. Text showed in the tooltip on hover. */ tooltipText?: string; /** * Position the tooltip should take if space is available. */ tooltipPosition?: BentoTooltipPosition | `${BentoTooltipPosition}`; /** * Enables value/label value handling. When `true`, the component expects and emits value/label * pair objects instead of primitive values. * * This affects both the `value` prop and the `input` event payload. * * - **Input (`value` prop):** Expects a `{ value: string | number, label: string }` object (or an array of them for multi-select). * - **Output (`input` event):** Emits a `{ value: string | number, label: string }` object (or an array of them) upon selection. * * This is particularly useful when a selected item's label is not available in the `items` prop, * allowing the component to display the correct label for values loaded from external sources. * @default false */ enableValueLabelPair?: boolean; /** * Enables a search bar that dynamically filters values * @default true */ dynamicFiltering?: boolean; } export type BentoSelectAvatarFilterOptions = OmitStrict<BentoSelectFilterOptions, 'listboxItems'> & { listboxItems: BentoAvatarListboxOptions; }; export type BentoSelectCountryFilterOptions = OmitStrict<BentoSelectFilterOptions, 'listboxItems'> & { listboxItems: BentoCountryListboxOptions; variant?: BentoCountryVariant | `${BentoCountryVariant}`; }; export type BentoSelectCurrencyFilterOptions = OmitStrict<BentoSelectFilterOptions, 'listboxItems'> & { listboxItems: BentoCurrencyListboxOptions; }; export type BentoSelectTagFilterOptions = OmitStrict<BentoSelectFilterOptions, 'listboxItems'> & { listboxItems: BentoTagListboxOptions; }; export type BentoSelectPaymentMethodFilterOptions = OmitStrict<BentoSelectFilterOptions, 'listboxItems'> & { listboxItems: BentoPaymentMethodListboxOptions; }; export interface BentoBooleanFilterOption { label: string; value: string | boolean; } export interface BentoBooleanFilterOptions { positiveOption?: BentoBooleanFilterOption; negativeOption?: BentoBooleanFilterOption; tooltipText?: string; tooltipPosition?: BentoTooltipPosition | `${BentoTooltipPosition}`; } export interface BentoInputWithDropdownFilterOptions { dropdown: BentoInputDropdownProps; dropdownPosition?: BentoInputFieldElementPosition | `${BentoInputFieldElementPosition}`; tooltipText?: string; tooltipPosition?: BentoTooltipPosition | `${BentoTooltipPosition}`; } export interface BentoRangeFilterOptions { tooltipText?: string; tooltipPosition?: BentoTooltipPosition | `${BentoTooltipPosition}`; } // Date export interface BentoDateFilterOptions { firstDayOfWeek?: BentoDatePickerFirstDayOfWeek; isDateDisabled?: BentoDatePickerIsDateDisabled; variant?: `${BentoDatePickerVariant}`; tooltipText?: string; tooltipPosition?: BentoTooltipPosition | `${BentoTooltipPosition}`; } export interface BentoDateRangeFilterOptions { allowTimeInput?: boolean; firstDayOfWeek?: BentoDatePickerFirstDayOfWeek; isDateDisabled?: BentoDatePickerIsDateDisabled; granularities?: Array<BentoDateRangePickerGranularityConfig>; maxRange?: number; min?: Date; max?: Date; numberOfMonths?: number; showEndDateOnOpen?: boolean; quickSelectRanges?: DateRangePickerCalendarRangeSelectorItems | boolean; variant?: `${BentoDateRangePickerVariant}`; tooltipText?: string; tooltipPosition?: BentoTooltipPosition | `${BentoTooltipPosition}`; } export interface BentoInpuWithDropdowntFilterValue { inputValue: BentoInputFieldValue; dropdownValue: BentoInputDropdownProps['value']; } export type BentoSelectFilterValue = BentoListboxSelectedValue; export type BentoBooleanFilterValue = string | null; export type BentoDateFilterValue = Date | null; export type BentoDateRangeFilterValue = BentoDateRangePickerValue | null; export type BentoFilterBarValue = | BentoInputFilterValue | BentoInpuWithDropdowntFilterValue | BentoSelectFilterValue | BentoBooleanFilterValue | BentoDateFilterValue | BentoDateRangeFilterValue | BentoRadioGroupFilterValue | BentoCheckboxGroupFilterValue | BentoToggleFilterValue; export type BentoFilterOptions = | BentoSelectFilterOptions | BentoSelectAvatarFilterOptions | BentoSelectCountryFilterOptions | BentoSelectCurrencyFilterOptions | BentoSelectPaymentMethodFilterOptions | BentoSelectTagFilterOptions | BentoDateFilterOptions | BentoDateRangeFilterOptions | BentoBooleanFilterOptions | BentoInputFilterOptions | BentoInputWithDropdownFilterOptions | BentoRadioGroupFilterOptions | BentoCheckboxGroupFilterOptions | BentoToggleFilterOptions | undefined; export enum BentoFilterEvent { // Fires upon the user interacting with the filter INPUT = 'input', // Fires on the (new) filter values being applied UPDATE = 'update', } export enum BentoFilterBarEvent { INPUT = 'input', UPDATE_FILTER_VALUES_OBJECT = 'update:filter-values-object', UPDATE_FILTER_VALUES_ARRAY = 'update:filter-values', } export enum BentoFilterItemType { /** * @deprecated Use "BentoFilterItemType.RADIO_GROUP" instead */ BOOLEAN = 'BentoBooleanFilter', RANGE = 'BentoRangeFilter', // Input INPUT = 'BentoInputFilter', INPUT_DROPDOWN = 'BentoInputWithDropdownFilter', // Select SELECT = 'BentoSelectFilter', SELECT_AVATAR = 'BentoSelectAvatarFilter', SELECT_COUNTRY = 'BentoSelectCountryFilter', SELECT_CURRENCY = 'BentoSelectCurrencyFilter', SELECT_PAYMENT_METHOD = 'BentoSelectPaymentMethodFilter', SELECT_TAG = 'BentoSelectTagFilter', // Date DATE = 'BentoDateFilter', DATE_RANGE = 'BentoDateRangeFilter', // Radio group RADIO_GROUP = 'BentoRadioGroupFilter', // Checkbox CHECKBOX_GROUP = 'BentoCheckboxGroupFilter', // Toggle TOGGLE = 'BentoToggleFilter', } export interface BentoFilterValue { field: string; value?: BentoFilterBarValue; } export interface BentoFilterModel<CustomOptions = any> extends BentoFilterValue { label: string; description?: string; options?: BentoFilterOptions | CustomOptions; disabled?: boolean; defaultValue?: BentoFilterBarValue; visible?: boolean; /** * Defines the filter to be used. * * Can be one filter defined in the {@link BentoFilterItemType} enum or a * custom filter component defined as a {@link VueNodeElement} */ type: BentoFilterItemType | VueNodeElement; /** * @deprecated This property will be removed in version 2.0, please use `config` & `filter-values` properties. */ value?: BentoFilterBarValue; } export type BentoFilterBarModel<CustomOptions = any> = Array<BentoFilterModel<CustomOptions>>; export type BentoFilterValues = Array<BentoFilterValue>; export type BentoFilterValueObject<T extends PropertyKey = string, CustomValue = BentoFilterBarValue> = Record< T, CustomValue >; export type BentoFilterBarSearchBarProps = OmitStrict<BentoSearchBarProps, 'value' | 'condensed'>; export type BentoFilterBarSearchTerm = BentoSearchBarProps['value']; export type BentoFilterBarScreenOptionsLayout = 'one-line' | 'multi-line'; export interface BentoFilterBarContainerSizeLayout { /** * @default 'one-line' */ medium?: BentoFilterBarScreenOptionsLayout; /** * @default 'multi-line' */ small?: BentoFilterBarScreenOptionsLayout; } export interface BentoFilterBarProps<CustomValue = BentoFilterBarValue | any, CustomOptions = any> { /** * Array of filters based on @see {@link BentoFilterBarModel}. * Each one of the elements in the array correspond to a filter that will * be created and rendered in the FilterBar. * * @example * [{ * field: 'company', * label: 'Company', * type: FilterType.TEXT, * }, { * field: 'name', * label: 'Name', * type: FilterType.TEXT, * }] */ config?: BentoFilterBarModel<CustomOptions>; /** * An array of the values for each filter in the filter bar. * @see {@link BentoFilterValues} * * @example * [{ * field: 'company', * value: '200', * }, { * field: 'name', * value: 'some text', * }] */ filterValues?: BentoFilterValues; /** * Defines the layout (multi-line or one-line) to be used in the filter bar for different * container sizes: * - Large (>=700px): Always multi-line * - Medium (>=430px & <700px) * - Small (<430px) * * @example * { * medium: 'multi-line', * small: 'one-line' * } */ containerSizeLayout?: BentoFilterBarContainerSizeLayout; /** * Search bar properties with which the placeholder, hint and other * "bento-search-bar" properties can be set. @see {@link BentoFilterBarSearchBarProps} */ search?: BentoFilterBarSearchBarProps; /** * Search term useful to filter all the data by text. * If the value is non-existant (null or undefined) the search bar won't be enabled. * Can be used with `.sync` */ searchTerm?: BentoFilterBarSearchTerm; /** * Will show all applied filters even if their visibility is set to false. */ showAppliedHiddenFilters?: boolean; /** * Array of filters based on @see {@link BentoFilterBarModel}. * Each one of the elements in the array correspond to a filter that will * be created and rendered in the FilterBar. * * Can be used with v-model or independently with the @input event. * * @example * [{ * field: 'company', * label: 'Company', * value: '200', * type: FilterType.TEXT, * }, { * field: 'name', * label: 'Name', * value: null, * type: FilterType.TEXT, * }] * * @deprecated from version 2.0.0. Use the config property instead. */ value?: BentoFilterBarModel; /** * An object of the values for each filter in the filter bar where key is a the field name and the value is the BentoFilterBarValue. * * @example * { * 'company': '200', * 'name': 'some text' * }, */ filterValuesObject?: BentoFilterValueObject<string, CustomValue>; }
@@ -0,0 +1 @@
1
+ export enum BentoFocusTrapArrowNavigationDirection { VERTICAL = 'vertical', HORIZONTAL = 'horizontal', } export enum BentoFocusTrapVerticalNavigationEvent { ARROW_UP = 'arrowup', ARROW_DOWN = 'arrowdown', } export enum BentoFocusTrapHorizontalNavigationEvent { ARROW_LEFT = 'arrowleft', ARROW_RIGHT = 'arrowright', } export interface BentoFocusTrapFocusableIn { node: HTMLElement; /** * tab index */ index: number; /** * true, if this node belongs to a Lock */ lockItem: boolean; /** * true, if this node is a focus-guard (system node) */ guard: boolean; }
@@ -0,0 +1 @@
1
+ import { type BentoAlertTypeOption } from '@/components/alert/alert.types'; export type BentoFormLayoutFieldTipTypeOption = `${BentoAlertTypeOption}`; export const BentoFormLayoutFieldTipTypeOptions = ['warning', 'critical', 'highlight', 'success'];
@@ -0,0 +1 @@
1
+ export type BentoLayoutGroupProportions = | '33-33-33' | '50-50' | '25-75' | '75-25' | '33-66' | '66-33' | '25' | '33' | '50' | '100'; export const BentoLayoutGroupProportions = [ '100', '50', '33', '25', '66-33', '33-66', '75-25', '25-75', '50-50', '33-33-33', ];
@@ -0,0 +1 @@
1
+ export const FORM_LAYOUT_LOADING_INJECTION_KEY = Symbol('form layout loading injection key');
@@ -0,0 +1 @@
1
+ import { type BentoLoadingButtonState } from '../button/components/loading-button/loading-button.types'; /** * @deprecated for usage with properties since version 2.0. Use the string literal instead. */ export enum BentoHeaderVariant { PAGE = 'page', COMPONENT = 'component', } export interface BentoHeaderReloadButton { title: string; event?: (event: Event) => void; state?: `${BentoLoadingButtonState}`; }
@@ -0,0 +1 @@
1
+ // eslint-disable-next-line @typescript-eslint/consistent-type-imports import { BentoMenu, type BentoMenuItem } from '@/components/menu'; import { type BentoHeaderWithViewsItem } from '../../header-with-views.types'; export interface HeaderWithViewsAllViewsProps { menuCloseOnClickOutsideOptions?: InstanceType<typeof BentoMenu>['$props']['closeOnClickOutsideOptions']; menuItems: Array<BentoHeaderWithViewsItem>; menuItemsActions: Array<BentoMenuItem>; }
@@ -0,0 +1 @@
1
+ import { type BentoHeaderWithViewsItemAdditionalConfig, type BentoHeaderWithViewsItemErrors, type BentoHeaderWithViewsItemIcon, type BentoHeaderWithViewsItemIconColor, } from '../../header-with-views.types'; type HeaderWithViewsEditFormContext = `${HeaderWithViewsEditFormContextEnum}`; export enum HeaderWithViewsEditFormContextEnum { EDIT = 'edit', CREATE = 'create', } export interface HeaderWithViewsEditFormProps { additionalFormItem?: BentoHeaderWithViewsItemAdditionalConfig; context?: HeaderWithViewsEditFormContext; disableCustomization?: boolean; errors?: BentoHeaderWithViewsItemErrors; icon?: BentoHeaderWithViewsItemIcon; iconColor?: BentoHeaderWithViewsItemIconColor; label?: string; }
@@ -0,0 +1 @@
1
+ import { type BentoButtonActionsList } from '@/components/button'; import { type VueNodeElement } from '@/types/elements'; import type { HeaderMetaProps } from '@/internal'; import BagIcon from '@adyen/ui-assets-icons-16/vue/bag'; import CarIcon from '@adyen/ui-assets-icons-16/vue/car'; import CashStackIcon from '@adyen/ui-assets-icons-16/vue/cash-stack'; import CloudIcon from '@adyen/ui-assets-icons-16/vue/cloud'; import DiamondIcon from '@adyen/ui-assets-icons-16/vue/diamond'; import EducationIcon from '@adyen/ui-assets-icons-16/vue/education'; import EmoticonHappyIcon from '@adyen/ui-assets-icons-16/vue/emoticon-happy'; import HotelIcon from '@adyen/ui-assets-icons-16/vue/gambling'; import GamingIcon from '@adyen/ui-assets-icons-16/vue/gaming'; import GiftIcon from '@adyen/ui-assets-icons-16/vue/gift'; import HandRockIcon from '@adyen/ui-assets-icons-16/vue/hand-rock'; import HashtagIcon from '@adyen/ui-assets-icons-16/vue/hashtag'; import HeartIcon from '@adyen/ui-assets-icons-16/vue/heart'; import HospitalityIcon from '@adyen/ui-assets-icons-16/vue/hospitality'; import HourglassIcon from '@adyen/ui-assets-icons-16/vue/hourglass'; import LeafIcon from '@adyen/ui-assets-icons-16/vue/leaf'; import LightningIcon from '@adyen/ui-assets-icons-16/vue/lightning'; import LockIcon from '@adyen/ui-assets-icons-16/vue/lock'; import NewsIcon from '@adyen/ui-assets-icons-16/vue/news'; import NotificationIcon from '@adyen/ui-assets-icons-16/vue/notification'; import PrizeIcon from '@adyen/ui-assets-icons-16/vue/prize'; import RetailIcon from '@adyen/ui-assets-icons-16/vue/retail'; import ShoppingCartIcon from '@adyen/ui-assets-icons-16/vue/shopping-cart'; import SleepIcon from '@adyen/ui-assets-icons-16/vue/sleep'; import StackIcon from '@adyen/ui-assets-icons-16/vue/stack'; import StarIcon from '@adyen/ui-assets-icons-16/vue/star'; import SupportIcon from '@adyen/ui-assets-icons-16/vue/support'; import TargetIcon from '@adyen/ui-assets-icons-16/vue/target'; import ThumbsDownIcon from '@adyen/ui-assets-icons-16/vue/thumb-down'; import ThumbsUpIcon from '@adyen/ui-assets-icons-16/vue/thumb-up'; import TravelBagIcon from '@adyen/ui-assets-icons-16/vue/travel-bag'; import WarningDiamondIcon from '@adyen/ui-assets-icons-16/vue/warning-diamond'; import WorldIcon from '@adyen/ui-assets-icons-16/vue/world'; /* Public */ export type BentoHeaderWithViewsItemIconColor = `${BentoHeaderWithViewsItemIconColorEnum}`; export type BentoHeaderWithViewsItemIcon = `${BentoHeaderWithViewsItemIconEnum}`; export interface BentoHeaderWithViewsItemAdditionalConfig { /** * Label for an additional view setting (e.g. a checkbox or toggle). */ label: string; /** * Boolean value indicating the state of the additional view setting (e.g. checked or toggled). */ value: boolean; } export interface BentoHeaderWithViewsItem { /** * Optional icon to display for the view item. */ icon?: BentoHeaderWithViewsItemIcon; /** * Optional color of the icon for the view item. */ iconColor?: BentoHeaderWithViewsItemIconColor; /** * Text label for the view item. */ label: string; /** * Optional boolean indicating if this view item is the default or currently active view. */ isDefault?: boolean; /** * Optional configuration for an additional view setting, such as a filter or option. */ additionalViewSetting?: BentoHeaderWithViewsItemAdditionalConfig; /** * Optional boolean indicating if this view can be edited or deleted. */ isFixed?: boolean; } export interface BentoHeaderWithViewsProps { /** * Optional list of actions (buttons) to display in the header. * The structure of each action is defined by the `BentoButtonActionsList` type. * * {@link [BentoButtonActionsList](https://adyen-bento.netlify.app/?path=/docs/components-button-button-actions--docs#variations)} */ actions?: BentoButtonActionsList; /** * Main title text for the header. This prop is required. */ title: string; /** * Optional array of view items to display as selectable views or tabs. * * Each view should have the following property: * - `icon` (BentoHeaderWithViewsItemIcon, optional): Optional icon to display. * - `iconColor` (BentoHeaderWithViewsItemIconColor, optional): Optional color of the icon. * - `label` (string): Text label for the view item. * - `isDefault` (boolean, optional): Indicates if this view item is the default or currently active view. * - `additionalViewSetting` (BentoHeaderWithViewsItemAdditionalConfig, optional): Optional configuration for an additional view setting. * - `isFixed` (boolean, optional): Indicates if this view can be edited or deleted. * @see {@link BentoHeaderWithViewsItem} */ views?: Array<BentoHeaderWithViewsItem>; /** * Optional configuration for an additional view setting, such as a filter or option. * Defined by the `BentoHeaderWithViewsItemAdditionalConfig` interface. * * @see {@link BentoHeaderWithViewsItemAdditionalConfig} */ additionalViewSetting?: BentoHeaderWithViewsItemAdditionalConfig; /** * Boolean indicating whether there are unsaved changes on the page. * This might be used to visually indicate to the user that they need to save their work. */ hasChanges: boolean; /** * String indicating whether to display a prompt, reminding the user to save their changes whenever they switch view tabs. * If null, no prompt is shown and changes will always be restored to it's previous settings on view tab change. */ skipUnsavedChangesText: string | null; /** * Boolean indicating whether icon and icon selection is allowed on view creation and edit. */ disableCustomization?: boolean; /** * Text showed in the info-icon tooltip on hover */ infoIconTooltipText?: string; /** * Meta description for the header component */ description?: string; /** * JavaScript "Date" object for when the content was last updated */ lastUpdated?: Date | number; /** * Reload button which shows next to the header's timestamp * @see HeaderMetaProps['reloadButton'] */ reloadButton?: HeaderMetaProps['reloadButton']; /** * Whether or not to automatically select a view on mount */ disableAutoSelect?: boolean; /** * The active view index. Supports two-way binding via v-model:active-view-index. * When provided, this takes precedence over `isDefault` on individual views for initial selection. * Changes from outside the component will update the active view. * Has no effect when `disableAutoSelect` is true. */ activeViewIndex?: number; } export interface BentoHeaderWithViewsItemUpdate { newViews: Array<BentoHeaderWithViewsItem>; oldViews: Array<BentoHeaderWithViewsItem>; targetViewLabel: BentoHeaderWithViewsItem['label']; } /* Private */ export enum BentoHeaderWithViewsItemIconColorEnum { BLUE = 'blue', GREEN = 'green', ORANGE = 'orange', PRIMARY = 'primary', RED = 'red', YELLOW = 'yellow', } export enum BentoHeaderWithViewsItemIconEnum { STACK = 'stack', LEAF = 'leaf', HAND_ROCK = 'hand-rock', CAR = 'car', EDUCATION = 'education', HOTEL = 'hotel', TRAVEL_BAG = 'travel-bag', LIGHTNING = 'lightning', NEWS = 'news', PRIZE = 'prize', LOCK = 'lock', BAG = 'bag', DIAMOND = 'diamond', TARGET = 'target', GIFT = 'gift', CASH_STACK = 'cash-stack', HASHTAG = 'hashtag', CLOUD = 'cloud', HOSPITALITY = 'hospitality', SHOPPING_CART = 'shopping-cart', SLEEP = 'sleep', NOTIFICATION = 'notification', THUMBS_UP = 'thumb-up', THUMBS_DOWN = 'thumb-down', STAR = 'star', WARNING_DIAMOND = 'warning-diamond', RETAIL = 'retail', EMOTICON_HAPPY = 'emoticon-happy', GAMING = 'gaming', SUPPORT = 'support', HEART = 'heart', HOURGLASS = 'hourglass', WORLD = 'world', } export const BentoHeaderWithViewsItemIconElement: Record<BentoHeaderWithViewsItemIcon, VueNodeElement> = { [BentoHeaderWithViewsItemIconEnum.STACK]: StackIcon, [BentoHeaderWithViewsItemIconEnum.LEAF]: LeafIcon, [BentoHeaderWithViewsItemIconEnum.HAND_ROCK]: HandRockIcon, [BentoHeaderWithViewsItemIconEnum.CAR]: CarIcon, [BentoHeaderWithViewsItemIconEnum.EDUCATION]: EducationIcon, [BentoHeaderWithViewsItemIconEnum.HOTEL]: HotelIcon, [BentoHeaderWithViewsItemIconEnum.TRAVEL_BAG]: TravelBagIcon, [BentoHeaderWithViewsItemIconEnum.LIGHTNING]: LightningIcon, [BentoHeaderWithViewsItemIconEnum.NEWS]: NewsIcon, [BentoHeaderWithViewsItemIconEnum.PRIZE]: PrizeIcon, [BentoHeaderWithViewsItemIconEnum.LOCK]: LockIcon, [BentoHeaderWithViewsItemIconEnum.BAG]: BagIcon, [BentoHeaderWithViewsItemIconEnum.DIAMOND]: DiamondIcon, [BentoHeaderWithViewsItemIconEnum.TARGET]: TargetIcon, [BentoHeaderWithViewsItemIconEnum.GIFT]: GiftIcon, [BentoHeaderWithViewsItemIconEnum.CASH_STACK]: CashStackIcon, [BentoHeaderWithViewsItemIconEnum.HASHTAG]: HashtagIcon, [BentoHeaderWithViewsItemIconEnum.CLOUD]: CloudIcon, [BentoHeaderWithViewsItemIconEnum.HOSPITALITY]: HospitalityIcon, [BentoHeaderWithViewsItemIconEnum.SHOPPING_CART]: ShoppingCartIcon, [BentoHeaderWithViewsItemIconEnum.SLEEP]: SleepIcon, [BentoHeaderWithViewsItemIconEnum.NOTIFICATION]: NotificationIcon, [BentoHeaderWithViewsItemIconEnum.THUMBS_UP]: ThumbsUpIcon, [BentoHeaderWithViewsItemIconEnum.THUMBS_DOWN]: ThumbsDownIcon, [BentoHeaderWithViewsItemIconEnum.STAR]: StarIcon, [BentoHeaderWithViewsItemIconEnum.WARNING_DIAMOND]: WarningDiamondIcon, [BentoHeaderWithViewsItemIconEnum.RETAIL]: RetailIcon, [BentoHeaderWithViewsItemIconEnum.EMOTICON_HAPPY]: EmoticonHappyIcon, [BentoHeaderWithViewsItemIconEnum.GAMING]: GamingIcon, [BentoHeaderWithViewsItemIconEnum.SUPPORT]: SupportIcon, [BentoHeaderWithViewsItemIconEnum.HEART]: HeartIcon, [BentoHeaderWithViewsItemIconEnum.HOURGLASS]: HourglassIcon, [BentoHeaderWithViewsItemIconEnum.WORLD]: WorldIcon, }; export interface BentoHeaderWithViewsEmits { /** * Emitted when a new view is added to the list of views. */ (e: 'add:view', value: BentoHeaderWithViewsItemUpdate): void; /** * Emitted when a view is deleted from the list of views. */ (e: 'delete:view', value: BentoHeaderWithViewsItemUpdate): void; /** * Emitted when a view is duplicated. */ (e: 'duplicate:view', value: BentoHeaderWithViewsItemUpdate): void; /** * Emitted when the user reorganizes the order of the views. * No `targetViewLabel` is emitted as the views are reordered as a whole. */ (e: 'reorder:view', value: Omit<BentoHeaderWithViewsItemUpdate, 'targetViewLabel'>): void; /** * Emitted when the user requests to restore a previously saved or default view. */ (e: 'restore:view', value: BentoHeaderWithViewsItem['label']): void; /** * Emitted when the user requests to save the current view. */ (e: 'save:view', value: BentoHeaderWithViewsItem['label']): void; /** * Emitted when the user selects a different view from the available options. */ (e: 'select:view', value: BentoHeaderWithViewsItem['label']): void; /** * Emitted when a property of a view is updated. */ (e: 'update:view', value: BentoHeaderWithViewsItemUpdate): void; /** * Emitted when the user selects the prompt checkbox and closes the modal with a valid button action. * Only works when a string is pass into the `skipUnsavedChangesText` prop. */ (e: 'update:skip-unsaved-changes', value: boolean): void; /** * Emitted when the active view index changes. Used for two-way binding with v-model:active-view-index. */ (e: 'update:active-view-index', value: number | null): void; } export type BentoHeaderWithViewsItemErrors = { /** * Object where the keys correspond to the properties of `BentoHeaderWithViewsItem`, * and the values are strings representing any validation errors for that property. */ [K in keyof BentoHeaderWithViewsItem]: string; };
@@ -0,0 +1 @@
1
+ export enum BentoImageAspectRatio { LANDSCAPE = 'landscape', P4_3 = '4:3', P3_3 = '3:3', P16_9 = '16:9', P2_1 = '2:1', PORTRAIT = 'portrait', P3_4 = '3:4', P2_3 = '2:3', P9_16 = '9:16', P1_2 = '1:2', SQUARE = 'square', P1_1 = '1:1', } export enum BentoImageObjectFit { COVER = 'cover', FILL = 'fill', CONTAIN = 'contain', } export interface BentoImageProps { /** Url to image, same as src attribute of `<img>` tag */ src: string; /** Accessible text describing the image, same as alt attribute of `<img>` tag */ alt: string; /** Aspect ratio of the image, maps to css aspect-ratio */ aspectRatio?: BentoImageAspectRatio | `${BentoImageAspectRatio}` | null; /** Object fitting strategy, maps to css object-fit */ objectFit?: BentoImageObjectFit | `${BentoImageObjectFit}` | null; }
@@ -0,0 +1 @@
1
+ import { type PopperContainerPosition } from '@/components/popper-container'; export interface BentoInfoIconProps { /** * Text showed in the info-icon tooltip on hover */ tooltipText: string; /** * Position the tooltip should take if space is available. Defaults to 'auto' */ tooltipPosition?: PopperContainerPosition | `${PopperContainerPosition}`; }
@@ -1 +1 @@
1
- import { action } from '@storybook/addon-actions'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import { type BentoInputDropdownProps, BentoInputFieldElementPosition, BentoInputFieldType, BentoInputFieldVariant, } from './input-field.types'; import { type BentoListboxSelectedValue } from '@/types/listbox'; import { ref, watch } from 'vue'; import type { Meta, StoryObj } from '@storybook/vue'; import { isVue2 } from 'vue-demi'; import BentoInputField from './input-field.vue'; import CheckmarkCircleFill from '@adyen/ui-assets-icons-16/vue/checkmark-circle-fill'; import PaymentMethodTypes from '@adyen/ui-assets-icons-16/vue/payment-method-types'; import './input-field.stories.scss?module'; const meta: Meta = { title: 'Input field', component: BentoInputField, argTypes: { variant: { options: Object.values(BentoInputFieldVariant), mapping: BentoInputFieldVariant, defaultValue: BentoInputFieldVariant.DEFAULT, control: { type: 'select', }, }, type: { options: Object.values(BentoInputFieldType), mapping: BentoInputFieldType, defaultValue: BentoInputFieldType.TEXT, control: { type: 'select', }, }, default: { name: 'default', defaultValue: '', description: 'Label for the input field', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, description: { name: 'description', defaultValue: '', description: 'Description below input', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, dropdownPosition: { options: Object.values(BentoInputFieldElementPosition), mapping: BentoInputFieldElementPosition, defaultValue: BentoInputFieldElementPosition.START, control: { type: 'select', }, }, staticValue: { name: 'staticValue', defaultValue: '', description: 'Static text that displayed before or after input value', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, staticValuePosition: { options: Object.values(BentoInputFieldElementPosition), mapping: BentoInputFieldElementPosition, defaultValue: BentoInputFieldElementPosition.START, control: { type: 'select', }, }, defaultIconBefore: { name: 'defaultIconBefore', defaultValue: '', description: 'Optional `icon` at the left side', table: { type: { summary: 'VNode[]' }, category: 'Deprecated', }, control: { disable: true, }, }, iconBefore: { name: 'iconBefore', defaultValue: '', description: 'Optional `icon` at the left side', table: { type: { summary: 'VNode[]' }, }, control: { disable: true, }, }, iconAfter: { name: 'iconAfter', defaultValue: '', description: 'Optional `icon` at the right side', table: { type: { summary: 'VNode[]' }, }, control: { disable: true, }, }, error: { control: { type: 'boolean' }, table: { category: 'Deprecated' }, }, value: { control: { type: 'text' }, table: { category: 'Deprecated' }, description: 'Deprecated for usage with properties since version 2.0. Use `v-model` or `model-value` property instead', }, // Events input: { table: { type: { summary: '(value: BentoInputFieldValue) => void' }, category: 'Deprecated', }, control: { disable: true }, description: 'Deprecated since version 2.0. Use `v-model` or `update:model-value` instead', }, 'update:model-value': { table: { type: { summary: '(value: BentoInputFieldValue) => void' }, }, control: { disable: true }, }, }, }; export default meta; type Story = StoryObj<typeof BentoInputField>; const INPUT_FIELD_DEFAULT_LABEL = 'Label above'; const INPUT_FIELD_DEFAULT_VALUE = 'Entered Text'; const INPUT_FIELD_DEFAULT_DESCRIPTION = 'Description below'; const DEFAULT_INPUT_FIELD_PROPS = { disabled: false, variant: 'default', description: INPUT_FIELD_DEFAULT_DESCRIPTION, modelValue: INPUT_FIELD_DEFAULT_VALUE, staticValue: 'EUR', }; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoInputField }, props: Object.keys(argTypes), template: ` <bento-input-field class="b-input-field-story" v-bind="args" :model-value="inputValue" @update:model-value="inputAction" @change="changeAction" @focus="focusAction" @blur="blurAction" > <template #default v-if="args.default">{{ args.default }}</template> <template #description>{{ args.description }}</template> </bento-input-field> `, setup(props) { const args = isVue2 ? props : _args; const inputValue = ref(args.modelValue); const inputAction = (value: string) => { inputValue.value = value; action('input')(value); }; const changeAction = (value: string) => action('change')(value); const focusAction = (value: string) => action('focus')(value); const blurAction = (value: string) => action('blur')(value); watch( () => args.modelValue, () => { inputValue.value = args.modelValue; } ); return { args, inputValue, inputAction, changeAction, focusAction, blurAction, }; }, }), args: { ...DEFAULT_INPUT_FIELD_PROPS, default: INPUT_FIELD_DEFAULT_LABEL, }, parameters: storybookDocsParameter(` <bento-input-field variant="default" :model-value="inputValue" @update:model-value="inputAction" @change="changeAction" @focus="focusAction" @blur="blurAction" > ${INPUT_FIELD_DEFAULT_LABEL} <template #description> ${INPUT_FIELD_DEFAULT_DESCRIPTION} </template> </bento-input-field> `), }; export const DefaultWithIcons = { render: (_args, { argTypes }) => ({ components: { BentoInputField, CheckmarkCircleFill }, props: Object.keys(argTypes), template: ` <bento-input-field class="b-input-field-story" v-bind="args" @update:model-value="inputAction" @change="changeAction" @focus="focusAction" @blur="blurAction" > <template #default v-if="args.default">{{ args.default }}</template> <template #iconBefore> <checkmark-circle-fill svg-title="checkmark-circle-fill" /> </template> <template #iconAfter> <checkmark-circle-fill svg-title="checkmark-circle-fill" /> </template> <template #description>{{ args.description }}</template> </bento-input-field> `, setup(props) { const inputAction = (value: string) => action('input')(value); const changeAction = (value: string) => action('change')(value); const focusAction = (value: string) => action('focus')(value); const blurAction = (value: string) => action('blur')(value); return { args: isVue2 ? props : _args, inputAction, changeAction, focusAction, blurAction, }; }, }), args: { ...DEFAULT_INPUT_FIELD_PROPS, default: 'With Icons', }, parameters: storybookDocsParameter(` <bento-input-field variant="default" :model-value="inputValue" @update:model-value="inputAction" @change="changeAction" @focus="focusAction" @blur="blurAction" > ${INPUT_FIELD_DEFAULT_LABEL} <template #description> ${INPUT_FIELD_DEFAULT_DESCRIPTION} </template> <template #iconBefore> <checkmark-circle-fill svg-title="checkmark-circle-fill" /> </template> <template #iconAfter> <checkmark-circle-fill svg-title="checkmark-circle-fill" /> </template> </bento-input-field> `), }; export const PaymentsMethod = { render: (_args, { argTypes }) => ({ components: { BentoInputField, CheckmarkCircleFill, PaymentMethodTypes }, props: Object.keys(argTypes), template: ` <bento-input-field class="b-input-field-story" v-bind="args" @update:model-value="inputAction" @change="changeAction" @focus="focusAction" @blur="blurAction" > <template #default v-if="args.default">{{ args.default }}</template> <template #paymentMethod> <payment-method-types svg-title="payment-method-types" /> </template> <template #iconAfter> <checkmark-circle-fill svg-title="checkmark-circle-fill" /> </template> <template #description>{{ args.description }}</template> <template #staticValue> EUR </template> </bento-input-field> `, setup(props) { const inputAction = (value: string) => action('input')(value); const changeAction = (value: string) => action('change')(value); const focusAction = (value: string) => action('focus')(value); const blurAction = (value: string) => action('blur')(value); return { args: isVue2 ? props : _args, inputAction, changeAction, focusAction, blurAction, }; }, }), args: { ...DEFAULT_INPUT_FIELD_PROPS, default: 'Payment Method Variant', variant: 'payment-method', }, parameters: storybookDocsParameter(` <bento-input-field variant="payment-method" :model-value="inputValue" @update:model-value="inputAction" @change="changeAction" @focus="focusAction" @blur="blurAction" > ${INPUT_FIELD_DEFAULT_LABEL} <template #description> ${INPUT_FIELD_DEFAULT_DESCRIPTION} </template> <template #paymentMethod> <bento-payment-method svg-title="payment-method" /> </template> <template #iconAfter> <checkmark-circle-fill svg-title="checkmark-circle-fill" /> </template> </bento-input-field> `), }; export const StaticValue = { ...PaymentsMethod, args: { ...DEFAULT_INPUT_FIELD_PROPS, default: 'Static Value Variant', variant: 'static-value', }, parameters: storybookDocsParameter(` <bento-input-field variant="static-value" :model-value="inputValue" @update:model-value="inputAction" @change="changeAction" @focus="focusAction" @blur="blurAction" > ${INPUT_FIELD_DEFAULT_LABEL} <template #description> ${INPUT_FIELD_DEFAULT_DESCRIPTION} </template> <template #staticValue> EUR </template> <template #iconAfter> <checkmark-circle-fill svg-title="checkmark-circle-fill" /> </template> </bento-input-field> `), }; const DROPDOWN_DEFAULT_OPTIONS = [ { label: 'EUR', value: 'EUR' }, { label: 'USD', value: 'USD' }, ]; export const Dropdown: Story = { render: (_args, { argTypes }) => ({ components: { BentoInputField, CheckmarkCircleFill, PaymentMethodTypes }, props: Object.keys(argTypes), template: ` <bento-input-field class="b-input-field-story" v-bind="args" :dropdown.sync="dropdownProps" @update:model-value="inputAction" @change="changeAction" @focus="focusAction" @blur="blurAction" > <template #default v-if="args.default">{{ args.default }}</template> <template #paymentMethod> <payment-method-types svg-title="payment-method-types" /> </template> <template #iconAfter> <checkmark-circle-fill svg-title="checkmark-circle-fill" /> </template> <template #description>{{ args.description }}</template> </bento-input-field> `, setup(props) { const args = isVue2 ? props : _args; const dropdownProps = ref({ ...args?.dropdown }); const inputAction = (value: string) => action('input')(value); const changeAction = (value: string) => action('change')(value); const focusAction = (value: string) => action('focus')(value); const blurAction = (value: string) => action('blur')(value); const dropdownInputAction = (value: BentoListboxSelectedValue) => { action('dropdown-input')(value); }; watch( () => args.dropdown, () => { Object.assign(dropdownProps.value, args.dropdown); } ); return { args, inputAction, changeAction, focusAction, blurAction, dropdownInputAction, dropdownProps, }; }, }), args: { default: 'Dropdown Variant', description: INPUT_FIELD_DEFAULT_DESCRIPTION, modelValue: INPUT_FIELD_DEFAULT_VALUE, variant: 'dropdown', dropdown: { items: DROPDOWN_DEFAULT_OPTIONS, modelValue: DROPDOWN_DEFAULT_OPTIONS[0].value, readonly: false, 'aria-label': 'Dropdown aria label', dynamicFiltering: false, } satisfies BentoInputDropdownProps, }, };
1
+ import { action } from '@storybook/addon-actions'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import { type BentoInputDropdownProps, BentoInputFieldElementPosition, BentoInputFieldType, BentoInputFieldVariant, } from './input-field.types'; import { type BentoListboxSelectedValue } from '@/types/listbox'; import { ref, watch } from 'vue'; import type { Meta, StoryObj } from '@storybook/vue'; import { isVue2 } from 'vue-demi'; import BentoInputField from './input-field.vue'; import CheckmarkCircleFill from '@adyen/ui-assets-icons-16/vue/checkmark-circle-fill'; import PaymentMethodTypes from '@adyen/ui-assets-icons-16/vue/payment-method-types'; import './input-field.stories.scss?module'; const meta: Meta = { title: 'Input field', component: BentoInputField, argTypes: { variant: { options: Object.values(BentoInputFieldVariant), mapping: BentoInputFieldVariant, defaultValue: BentoInputFieldVariant.DEFAULT, control: { type: 'select', }, }, type: { options: Object.values(BentoInputFieldType), mapping: BentoInputFieldType, defaultValue: BentoInputFieldType.TEXT, control: { type: 'select', }, }, default: { name: 'default', defaultValue: '', description: 'Label for the input field', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, description: { name: 'description', description: 'If set, displays a description text for the input.', table: { category: 'props', type: { summary: 'string' }, }, control: { type: 'text', }, }, 'slot:description': { name: 'description', defaultValue: '', description: 'If set, displays a description text for the input. Overrides the `description` prop when provided.', table: { type: { summary: 'VNode[]' }, category: 'slots', }, control: { type: 'text', }, }, dropdownPosition: { options: Object.values(BentoInputFieldElementPosition), mapping: BentoInputFieldElementPosition, defaultValue: BentoInputFieldElementPosition.START, control: { type: 'select', }, }, staticValue: { name: 'staticValue', defaultValue: '', description: 'Static text that displayed before or after input value', table: { type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, staticValuePosition: { options: Object.values(BentoInputFieldElementPosition), mapping: BentoInputFieldElementPosition, defaultValue: BentoInputFieldElementPosition.START, control: { type: 'select', }, }, defaultIconBefore: { name: 'defaultIconBefore', defaultValue: '', description: 'Optional `icon` at the left side', table: { type: { summary: 'VNode[]' }, category: 'Deprecated', }, control: { disable: true, }, }, iconBefore: { name: 'iconBefore', defaultValue: '', description: 'Optional `icon` at the left side', table: { type: { summary: 'VNode[]' }, }, control: { disable: true, }, }, iconAfter: { name: 'iconAfter', defaultValue: '', description: 'Optional `icon` at the right side', table: { type: { summary: 'VNode[]' }, }, control: { disable: true, }, }, error: { control: { type: 'boolean' }, table: { category: 'Deprecated' }, }, value: { control: { type: 'text' }, table: { category: 'Deprecated' }, description: 'Deprecated for usage with properties since version 2.0. Use `v-model` or `model-value` property instead', }, // Events input: { table: { type: { summary: '(value: BentoInputFieldValue) => void' }, category: 'Deprecated', }, control: { disable: true }, description: 'Deprecated since version 2.0. Use `v-model` or `update:model-value` instead', }, 'update:model-value': { table: { type: { summary: '(value: BentoInputFieldValue) => void' }, }, control: { disable: true }, }, }, }; export default meta; type Story = StoryObj<typeof BentoInputField>; const INPUT_FIELD_DEFAULT_LABEL = 'Label above'; const INPUT_FIELD_DEFAULT_VALUE = 'Entered Text'; const INPUT_FIELD_DEFAULT_DESCRIPTION = 'Description below'; const DEFAULT_INPUT_FIELD_PROPS = { disabled: false, variant: 'default', description: INPUT_FIELD_DEFAULT_DESCRIPTION, modelValue: INPUT_FIELD_DEFAULT_VALUE, staticValue: 'EUR', }; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoInputField }, props: Object.keys(argTypes), template: ` <bento-input-field class="b-input-field-story" v-bind="args" :model-value="inputValue" @update:model-value="inputAction" @change="changeAction" @focus="focusAction" @blur="blurAction" > <template #default v-if="args.default">{{ args.default }}</template> <template #description v-if="args['slot:description']">{{ args['slot:description'] }}</template> </bento-input-field> `, setup(props) { const args = isVue2 ? props : _args; const inputValue = ref(args.modelValue); const inputAction = (value: string) => { inputValue.value = value; action('input')(value); }; const changeAction = (value: string) => action('change')(value); const focusAction = (value: string) => action('focus')(value); const blurAction = (value: string) => action('blur')(value); watch( () => args.modelValue, () => { inputValue.value = args.modelValue; } ); return { args, inputValue, inputAction, changeAction, focusAction, blurAction, }; }, }), args: { ...DEFAULT_INPUT_FIELD_PROPS, default: INPUT_FIELD_DEFAULT_LABEL, }, parameters: storybookDocsParameter(` <bento-input-field variant="default" :model-value="inputValue" @update:model-value="inputAction" @change="changeAction" @focus="focusAction" @blur="blurAction" > ${INPUT_FIELD_DEFAULT_LABEL} <template #description> ${INPUT_FIELD_DEFAULT_DESCRIPTION} </template> </bento-input-field> `), }; export const DefaultWithIcons = { render: (_args, { argTypes }) => ({ components: { BentoInputField, CheckmarkCircleFill }, props: Object.keys(argTypes), template: ` <bento-input-field class="b-input-field-story" v-bind="args" @update:model-value="inputAction" @change="changeAction" @focus="focusAction" @blur="blurAction" > <template #default v-if="args.default">{{ args.default }}</template> <template #iconBefore> <checkmark-circle-fill svg-title="checkmark-circle-fill" /> </template> <template #iconAfter> <checkmark-circle-fill svg-title="checkmark-circle-fill" /> </template> <template #description v-if="args['slot:description']">{{ args['slot:description'] }}</template> </bento-input-field> `, setup(props) { const inputAction = (value: string) => action('input')(value); const changeAction = (value: string) => action('change')(value); const focusAction = (value: string) => action('focus')(value); const blurAction = (value: string) => action('blur')(value); return { args: isVue2 ? props : _args, inputAction, changeAction, focusAction, blurAction, }; }, }), args: { ...DEFAULT_INPUT_FIELD_PROPS, default: 'With Icons', }, parameters: storybookDocsParameter(` <bento-input-field variant="default" :model-value="inputValue" @update:model-value="inputAction" @change="changeAction" @focus="focusAction" @blur="blurAction" > ${INPUT_FIELD_DEFAULT_LABEL} <template #description> ${INPUT_FIELD_DEFAULT_DESCRIPTION} </template> <template #iconBefore> <checkmark-circle-fill svg-title="checkmark-circle-fill" /> </template> <template #iconAfter> <checkmark-circle-fill svg-title="checkmark-circle-fill" /> </template> </bento-input-field> `), }; export const PaymentsMethod = { render: (_args, { argTypes }) => ({ components: { BentoInputField, CheckmarkCircleFill, PaymentMethodTypes }, props: Object.keys(argTypes), template: ` <bento-input-field class="b-input-field-story" v-bind="args" @update:model-value="inputAction" @change="changeAction" @focus="focusAction" @blur="blurAction" > <template #default v-if="args.default">{{ args.default }}</template> <template #paymentMethod> <payment-method-types svg-title="payment-method-types" /> </template> <template #iconAfter> <checkmark-circle-fill svg-title="checkmark-circle-fill" /> </template> <template #description v-if="args['slot:description']">{{ args['slot:description'] }}</template> <template #staticValue> EUR </template> </bento-input-field> `, setup(props) { const inputAction = (value: string) => action('input')(value); const changeAction = (value: string) => action('change')(value); const focusAction = (value: string) => action('focus')(value); const blurAction = (value: string) => action('blur')(value); return { args: isVue2 ? props : _args, inputAction, changeAction, focusAction, blurAction, }; }, }), args: { ...DEFAULT_INPUT_FIELD_PROPS, default: 'Payment Method Variant', variant: 'payment-method', }, parameters: storybookDocsParameter(` <bento-input-field variant="payment-method" :model-value="inputValue" @update:model-value="inputAction" @change="changeAction" @focus="focusAction" @blur="blurAction" > ${INPUT_FIELD_DEFAULT_LABEL} <template #description> ${INPUT_FIELD_DEFAULT_DESCRIPTION} </template> <template #paymentMethod> <bento-payment-method svg-title="payment-method" /> </template> <template #iconAfter> <checkmark-circle-fill svg-title="checkmark-circle-fill" /> </template> </bento-input-field> `), }; export const StaticValue = { ...PaymentsMethod, args: { ...DEFAULT_INPUT_FIELD_PROPS, default: 'Static Value Variant', variant: 'static-value', }, parameters: storybookDocsParameter(` <bento-input-field variant="static-value" :model-value="inputValue" @update:model-value="inputAction" @change="changeAction" @focus="focusAction" @blur="blurAction" > ${INPUT_FIELD_DEFAULT_LABEL} <template #description> ${INPUT_FIELD_DEFAULT_DESCRIPTION} </template> <template #staticValue> EUR </template> <template #iconAfter> <checkmark-circle-fill svg-title="checkmark-circle-fill" /> </template> </bento-input-field> `), }; const DROPDOWN_DEFAULT_OPTIONS = [ { label: 'EUR', value: 'EUR' }, { label: 'USD', value: 'USD' }, ]; export const Dropdown: Story = { render: (_args, { argTypes }) => ({ components: { BentoInputField, CheckmarkCircleFill, PaymentMethodTypes }, props: Object.keys(argTypes), template: ` <bento-input-field class="b-input-field-story" v-bind="args" :dropdown.sync="dropdownProps" @update:model-value="inputAction" @change="changeAction" @focus="focusAction" @blur="blurAction" > <template #default v-if="args.default">{{ args.default }}</template> <template #paymentMethod> <payment-method-types svg-title="payment-method-types" /> </template> <template #iconAfter> <checkmark-circle-fill svg-title="checkmark-circle-fill" /> </template> <template #description v-if="args['slot:description']">{{ args['slot:description'] }}</template> </bento-input-field> `, setup(props) { const args = isVue2 ? props : _args; const dropdownProps = ref({ ...args?.dropdown }); const inputAction = (value: string) => action('input')(value); const changeAction = (value: string) => action('change')(value); const focusAction = (value: string) => action('focus')(value); const blurAction = (value: string) => action('blur')(value); const dropdownInputAction = (value: BentoListboxSelectedValue) => { action('dropdown-input')(value); }; watch( () => args.dropdown, () => { Object.assign(dropdownProps.value, args.dropdown); } ); return { args, inputAction, changeAction, focusAction, blurAction, dropdownInputAction, dropdownProps, }; }, }), args: { default: 'Dropdown Variant', description: INPUT_FIELD_DEFAULT_DESCRIPTION, modelValue: INPUT_FIELD_DEFAULT_VALUE, variant: 'dropdown', dropdown: { items: DROPDOWN_DEFAULT_OPTIONS, modelValue: DROPDOWN_DEFAULT_OPTIONS[0].value, readonly: false, 'aria-label': 'Dropdown aria label', dynamicFiltering: false, } satisfies BentoInputDropdownProps, }, };
@@ -0,0 +1 @@
1
+ import { type BentoDropdownProps } from '../dropdown/dropdown.types'; import { type FormField } from '../../types/form-field'; /** * @deprecated for usage with properties since version 2.0. Use the string literal instead. */ export enum BentoInputFieldVariant { DEFAULT = 'default', PAYMENT_METHOD = 'payment-method', STATIC_VALUE = 'static-value', DROPDOWN = 'dropdown', } /** * @deprecated for usage with properties since version 2.0. Use the string literal instead. */ export enum BentoInputFieldElementPosition { START = 'start', END = 'end', } export enum BentoInputFieldStateClass { CONDENSED = 'condensed', DISABLED = 'disabled', READONLY = 'readonly', ERROR = 'error', } /** * @deprecated for usage with properties since version 2.0. Use the string literal instead. */ export enum BentoInputFieldType { SEARCH = 'search', TEXT = 'text', NUMBER = 'number', } export type BentoInputFieldValue = string | number; type DropdownProps = BentoDropdownProps; export interface BentoInputDropdownProps { /** * Text that labels the dropdown element */ 'aria-label'?: string; /** * Enables dynamic filtering */ dynamicFiltering?: DropdownProps['dynamicFiltering']; /** * List of available items */ items: DropdownProps['items']; /** * Sets the dropdown in read-only mode */ readonly?: DropdownProps['readonly']; /** * Selected value of the dropdown * @deprecated Use `model-value` instead. */ value?: DropdownProps['value']; /** * Selected value of the dropdown */ modelValue?: DropdownProps['modelValue']; } /** * @deprecated The use of these enums is no longer supported. * Use `v-on:` or `@` to listen to the events being emitted. * This enum will be removed in 2.0. */ export enum BentoInputFieldEvent { INPUT = 'input', ESCAPE_PRESSED = 'escape-pressed', UPDATE_DROPDOWN = 'update:dropdown', DROPDOWN_INPUT = 'dropdown-input', FOCUS = 'focus', CHANGE = 'change', BLUR = 'blur', KEYDOWN = 'keydown', } export interface BentoInputFieldProps extends FormField { /** * Indicates whether the element is exposed to an accessibility API. */ ariaHidden?: boolean; /** * Text that labels an the input element * * @deprecated from version 2.0.0. Use the aria-label attribute instead. */ ariaLabel?: string; /** * Reduces height of the input */ condensed?: boolean; /** * Dropdown props for the small selectable dropdown menu. * Properties supported: * * - `aria-label`: Text that labels the dropdown element * - `dynamicFiltering`: Enables dynamic filtering * - `items`: List of available items * - `readonly`: Sets the dropdown in read-only mode * - `value`: Selected value of the dropdown */ dropdown?: BentoInputDropdownProps; /** * Position of the dropdown before or after input value */ dropdownPosition?: BentoInputFieldElementPosition | `${BentoInputFieldElementPosition}`; /** * Adds error validation class for outlining input-field. * * @deprecated Use "errorMessage" prop instead */ error?: boolean; /** * Text displayed as the value of the input-field */ modelValue?: BentoInputFieldValue; /** * Renders a font numeric style with slashed zeros instead of normal ones. */ slashedZero?: boolean; /** * Static text that displayed before or after input value * Applicable to the Static Value variant */ staticValue?: string; /** * Position of Static Value before or after input value */ staticValuePosition?: BentoInputFieldElementPosition | `${BentoInputFieldElementPosition}`; /** * A string specifying the type of control to render. * All `input` types are available but only `search`, `text` and `number` are fully supported. * * If `type` is `search`, use `bento-search-bar` instead. */ type?: BentoInputFieldType | `${BentoInputFieldType}` | HTMLInputElement['type']; /** * Text displayed as the value of the input-field * @deprecated for usage with properties since version 2.0. Use `v-model` or `model-value` instead. */ value?: BentoInputFieldValue; /** * Describes the different variants for the input element */ variant?: BentoInputFieldVariant | `${BentoInputFieldVariant}`; }
@@ -1 +1 @@
1
- import { action } from '@storybook/addon-actions'; import { isVue2 } from 'vue-demi'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import BentoInputFieldPassword from './input-field-password.vue'; import type { Meta, StoryObj } from '@storybook/vue'; import { minLength } from '@/components/input-field-password/utilities/input-field-password.validation'; import { type BentoInputFieldPasswordValidation } from './input-field-password.types'; const meta: Meta = { title: 'Input Field Password', component: BentoInputFieldPassword, argTypes: { condensed: { table: { type: { summary: 'boolean' }, }, }, disabled: { table: { type: { summary: 'boolean' }, }, }, errorMessage: { table: { type: { summary: 'string' }, }, }, placeholder: { table: { type: { summary: 'string' }, }, }, readonly: { table: { type: { summary: 'boolean' }, }, }, modelValue: { control: { type: 'text' }, table: { type: { summary: 'string | number' }, }, }, label: { table: { type: { summary: 'string' }, }, }, // Events 'input:valid': { table: { type: { summary: '() => void' }, }, control: { disable: true }, }, // Deprecated input: { description: 'Deprecated since version 2.0. Use `v-model` or `update:model-value instead', table: { category: 'Deprecated' }, control: { disable: true }, }, value: { control: { type: 'text' }, table: { category: 'Deprecated' }, description: 'Deprecated for usage with properties since version 2.0. Use `v-model` or `model-value` property instead', }, }, }; export default meta; type Story = StoryObj<typeof BentoInputFieldPassword>; const DEFAULT_PROPS = { label: 'Password', withHint: true, condensed: false, disabled: false, readonly: false, description: 'Enter your password', }; const CUSTOM_VALIDATION: BentoInputFieldPasswordValidation = { extendDefaultValidation: true, list: [ { label: 'Always true', key: 'alwaysTrue', validate: () => true, }, { label: '18 characters', key: 'minLength', validate: minLength, additionalArgs: [18], }, { key: 'requireSpecialCharacter', disabled: true, }, ], }; const defaultCode = ` <template> <bento-input-field-password label="Label" :error-message="errors.password" @update:model-value="updateModelValue" @input:valid="inputValidAction" @input:error="inputErrorAction" /> </template> <script setup lang="ts"> import { BentoInputFieldPassword } from '@adyen/bento-vue2' import { reactive } from 'vue'; const errors = reactive({ password: '', }); const updateModelValue = () => { // do something when the input value changes } const inputValidAction = () => { // do something when password is valid } const inputErrorAction = () => { errors.password = 'Password field has an error'; } </script> `; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoInputFieldPassword }, props: Object.keys(argTypes), template: ` <bento-input-field-password v-bind="args" @update:model-value="updateModelValue" @input:valid="inputValidAction" @input:error="inputErrorAction" /> `, setup(props) { return { // Values args: isVue2 ? props : _args, // Events updateModelValue: (value: string) => action('update:model-value')(value), inputErrorAction: (value: string) => action('input:error')(value), inputValidAction: action('input:valid'), }; }, }), args: DEFAULT_PROPS, parameters: storybookDocsParameter(defaultCode), }; const customValidationCode = ` <template> <bento-input-field-password label="Label" :error-message="errors.password" :validation="{ extendDefaultValidation: true, list: [ { // custom rule label: 'Always true', key: 'alwaysTrue', validate: () => true, }, { // override existing rule label: '18 characters', key: 'minLength', validate: minLength, additionalArgs: [18], }, { // disable existing rule key: 'requireSpecialCharacter', disabled: true, }, ], }" @update:model-value="updateModelValue" @input:valid="inputValidAction" @input:error="inputErrorAction" /> </template> <script setup lang="ts"> import { BentoInputFieldPassword, minLength } from '@adyen/bento-vue2' import { reactive } from 'vue'; const errors = reactive({ password: '', }); const updateModelValue = () => { // do something when the input value changes } const inputValidAction = () => { // do something when password is valid } const inputErrorAction = () => { errors.password = 'Password field has an error'; } </script> `; export const CustomValidation: Story = { render: (_args, { argTypes }) => ({ components: { BentoInputFieldPassword }, props: Object.keys(argTypes), template: ` <bento-input-field-password v-bind="args" @update:model-value="updateModelValue" @input:valid="inputValidAction" @input:error="inputErrorAction" /> `, setup(props) { return { // Values args: isVue2 ? props : _args, // Events updateModelValue: (value: string) => action('update:model-value')(value), inputErrorAction: (value: string) => action('input:error')(value), inputValidAction: action('input:valid'), }; }, }), args: { ...DEFAULT_PROPS, validation: CUSTOM_VALIDATION, }, parameters: storybookDocsParameter(customValidationCode), };
1
+ import { action } from '@storybook/addon-actions'; import { isVue2 } from 'vue-demi'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import BentoInputFieldPassword from './input-field-password.vue'; import type { Meta, StoryObj } from '@storybook/vue'; import { minLength } from '@/components/input-field-password/utilities/input-field-password.validation'; import { type BentoInputFieldPasswordValidation } from './input-field-password.types'; const meta: Meta = { title: 'Input Field Password', component: BentoInputFieldPassword, argTypes: { condensed: { table: { type: { summary: 'boolean' }, }, }, disabled: { table: { type: { summary: 'boolean' }, }, }, errorMessage: { table: { type: { summary: 'string' }, }, }, placeholder: { table: { type: { summary: 'string' }, }, }, readonly: { table: { type: { summary: 'boolean' }, }, }, description: { name: 'description', description: 'If set, displays a description text for the input.', table: { category: 'props', type: { summary: 'string' }, }, control: { type: 'text', }, }, 'slot:description': { name: 'description', defaultValue: '', description: 'If set, displays a description text for the input. Overrides the `description` prop when provided.', table: { category: 'slots', type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, modelValue: { control: { type: 'text' }, table: { type: { summary: 'string | number' }, }, }, label: { table: { type: { summary: 'string' }, }, }, // Events 'input:valid': { table: { type: { summary: '() => void' }, }, control: { disable: true }, }, // Deprecated input: { description: 'Deprecated since version 2.0. Use `v-model` or `update:model-value instead', table: { category: 'Deprecated' }, control: { disable: true }, }, value: { control: { type: 'text' }, table: { category: 'Deprecated' }, description: 'Deprecated for usage with properties since version 2.0. Use `v-model` or `model-value` property instead', }, }, }; export default meta; type Story = StoryObj<typeof BentoInputFieldPassword>; const DEFAULT_PROPS = { label: 'Password', withHint: true, condensed: false, disabled: false, readonly: false, description: 'Enter your password', }; const CUSTOM_VALIDATION: BentoInputFieldPasswordValidation = { extendDefaultValidation: true, list: [ { label: 'Always true', key: 'alwaysTrue', validate: () => true, }, { label: '18 characters', key: 'minLength', validate: minLength, additionalArgs: [18], }, { key: 'requireSpecialCharacter', disabled: true, }, ], }; const defaultCode = ` <template> <bento-input-field-password label="Label" :error-message="errors.password" @update:model-value="updateModelValue" @input:valid="inputValidAction" @input:error="inputErrorAction" /> </template> <script setup lang="ts"> import { BentoInputFieldPassword } from '@adyen/bento-vue2' import { reactive } from 'vue'; const errors = reactive({ password: '', }); const updateModelValue = () => { // do something when the input value changes } const inputValidAction = () => { // do something when password is valid } const inputErrorAction = () => { errors.password = 'Password field has an error'; } </script> `; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoInputFieldPassword }, props: Object.keys(argTypes), template: ` <bento-input-field-password v-bind="args" @update:model-value="updateModelValue" @input:valid="inputValidAction" @input:error="inputErrorAction" > <template #description v-if="args['slot:description']">{{ args['slot:description'] }}</template> </bento-input-field-password> `, setup(props) { return { // Values args: isVue2 ? props : _args, // Events updateModelValue: (value: string) => action('update:model-value')(value), inputErrorAction: (value: string) => action('input:error')(value), inputValidAction: action('input:valid'), }; }, }), args: DEFAULT_PROPS, parameters: storybookDocsParameter(defaultCode), }; const customValidationCode = ` <template> <bento-input-field-password label="Label" :error-message="errors.password" :validation="{ extendDefaultValidation: true, list: [ { // custom rule label: 'Always true', key: 'alwaysTrue', validate: () => true, }, { // override existing rule label: '18 characters', key: 'minLength', validate: minLength, additionalArgs: [18], }, { // disable existing rule key: 'requireSpecialCharacter', disabled: true, }, ], }" @update:model-value="updateModelValue" @input:valid="inputValidAction" @input:error="inputErrorAction" /> </template> <script setup lang="ts"> import { BentoInputFieldPassword, minLength } from '@adyen/bento-vue2' import { reactive } from 'vue'; const errors = reactive({ password: '', }); const updateModelValue = () => { // do something when the input value changes } const inputValidAction = () => { // do something when password is valid } const inputErrorAction = () => { errors.password = 'Password field has an error'; } </script> `; export const CustomValidation: Story = { render: (_args, { argTypes }) => ({ components: { BentoInputFieldPassword }, props: Object.keys(argTypes), template: ` <bento-input-field-password v-bind="args" @update:model-value="updateModelValue" @input:valid="inputValidAction" @input:error="inputErrorAction" > <template #description v-if="args['slot:description']">{{ args['slot:description'] }}</template> </bento-input-field-password> `, setup(props) { return { // Values args: isVue2 ? props : _args, // Events updateModelValue: (value: string) => action('update:model-value')(value), inputErrorAction: (value: string) => action('input:error')(value), inputValidAction: action('input:valid'), }; }, }), args: { ...DEFAULT_PROPS, validation: CUSTOM_VALIDATION, }, parameters: storybookDocsParameter(customValidationCode), };
@@ -0,0 +1 @@
1
+ import type { BentoInputFieldProps, BentoInputFieldValue } from '@/components/input-field/input-field.types'; import { type FormField } from '../../types/form-field'; /** * Public */ export interface BentoInputFieldPasswordValidationListItem { label?: string; key?: BentoInputFieldPasswordDefaultRuleKeys | string; // eslint-disable-next-line @typescript-eslint/no-explicit-any validate?: (value: BentoInputFieldValue, ...args: Array<any>) => boolean; // eslint-disable-next-line @typescript-eslint/no-explicit-any additionalArgs?: Array<any>; disabled?: boolean; } export type BentoInputFieldPasswordDefaultRuleKeys = | 'minLength' | 'requireLowercase' | 'requireNumeric' | 'requireSpecialCharacter' | 'requireUppercase'; export type BentoInputFieldPasswordErrorsList = Record<BentoInputFieldPasswordDefaultRuleKeys | string, string>; export interface BentoInputFieldPasswordValidation { title?: string; suggestion?: string; extendDefaultValidation?: boolean; list: Array<BentoInputFieldPasswordValidationListItem>; } export interface BentoInputFieldPasswordProps extends FormField { /** * Reduces height of the input */ condensed?: BentoInputFieldProps['condensed']; /** * The debounce time in milliseconds for running validation and emitting the `input` event after the user has stopped typing. * This helps to avoid excessive validation checks on every keystroke. Defaults to `500`. */ debounceTime?: number; /** * Performs real-time validations over the input value. Default: `false`. * Disabling the option (set to `true`) will not run pre-defined validations or custom validations defined in the `validation` field. */ disableValidation?: boolean; /** * Text displayed as the value of the input-field * @deprecated for usage with properties since version 2.0. Use `v-model` or `model-value` instead. */ value?: BentoInputFieldProps['value']; /** * Text displayed as the value of the input-field */ modelValue?: BentoInputFieldProps['modelValue']; /** * Configuration object for password field validation. * * This object defines the validation criteria and associated messages for a password field. * It includes the following properties: * * - `title`: The title displayed at the top of the validation hint. * - `suggestion`: The message displayed at the bottom of the validation hint, providing additional guidance. * - `extendDefaultValidation`: Set to true if you want to add your custom rules to the default validation instead of overriding the list. * - `list`: An array of callback functions to be executed on the value after each user input, validating the password against the specified rules. * * By default, the validation checks that: * * - The value has a minimum length of 12 characters. * - The value contains at least one lowercase letter. * - The value contains at least one uppercase letter. * - The value contains at least one numeric digit. * - The value contains at least one special character. * * */ validation?: BentoInputFieldPasswordValidation; /** * Whether the password validation hint is displayed when the input field is activated via focus or input */ withHint?: boolean; } /** * Private */ export enum BentoInputFieldPasswordType { TEXT = 'text', PASSWORD = 'password', } export enum BentoInputFieldPasswordDefaultRule { MIN_LENGTH = 'minLength', REQUIRE_LOWERCASE = 'requireLowercase', REQUIRE_NUMERIC = 'requireNumeric', REQUIRE_SPECIAL_CHARACTER = 'requireSpecialCharacter', REQUIRE_UPPERCASE = 'requireUppercase', }
@@ -1 +1 @@
1
- import { isVue2 } from 'vue-demi'; import { action } from '@storybook/addon-actions'; import { nextTick, onMounted, ref } from 'vue'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import BentoInputFieldPhoneNumber from './input-field-phone-number.vue'; import type { Meta, StoryObj } from '@storybook/vue'; import type { BentoInputFieldPhoneNumberDropdownProps } from './input-field-phone-number.types'; import InputFieldPhoneNumberDefaultExample from './__tests__/input-field-phone-number-default-example.vue?raw'; const meta: Meta = { title: 'Input field phone number', component: BentoInputFieldPhoneNumber, argTypes: { input: { description: 'Deprecated since version 2.0. Use `v-model` or `update:model-value instead', table: { category: 'Deprecated' }, control: { disable: true }, }, value: { control: { type: 'text' }, table: { category: 'Deprecated' }, description: 'Deprecated for usage with properties since version 2.0. Use `v-model` or `model-value` property instead', }, }, }; export default meta; type Story = StoryObj<typeof BentoInputFieldPhoneNumber>; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoInputFieldPhoneNumber }, props: Object.keys(argTypes), template: ` <bento-input-field-phone-number v-bind="args" :model-value="value" :selected-country="country" :error-message="errorMessage" @update:model-value="updateModelValue" @update:selected-country="onSelectedCountry" @blur="onBlur" @input:valid="validate" > <template #default v-if='args.default'> {{ args.default }} </template> <template #description v-if='args.description'> {{ args.description }} </template> </bento-input-field-phone-number> `, setup(props) { const value = ref('+12025550123'); const country = ref('US'); const errorMessage = ref(''); const isValid = ref(false); const updateErrorMessage = () => { if (!isValid.value && value.value) { errorMessage.value = 'This number is not valid.'; } else { errorMessage.value = ''; } }; const onSelectedCountry = async updatedCountry => { country.value = updatedCountry; action('update:selected-country')(updatedCountry); await nextTick(); updateErrorMessage(); }; const updateModelValue = input => { value.value = input; action('update:model-value')(input); }; const validate = (validity: boolean) => { isValid.value = validity; if (validity) { updateErrorMessage(); } action('input:valid')(validity); }; const onBlur = () => { updateErrorMessage(); action('blur')(); }; onMounted(() => { updateErrorMessage(); }); return { // Values args: isVue2 ? props : _args, value, country, errorMessage, // Methods onSelectedCountry, updateModelValue, onBlur, validate, }; }, }), args: { label: 'Phone number', description: 'Select your country and input the phone number', dropdown: { readonly: false, } satisfies BentoInputFieldPhoneNumberDropdownProps, }, parameters: storybookDocsParameter(InputFieldPhoneNumberDefaultExample), };
1
+ import { isVue2 } from 'vue-demi'; import { action } from '@storybook/addon-actions'; import { nextTick, onMounted, ref } from 'vue'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import BentoInputFieldPhoneNumber from './input-field-phone-number.vue'; import type { Meta, StoryObj } from '@storybook/vue'; import type { BentoInputFieldPhoneNumberDropdownProps } from './input-field-phone-number.types'; import InputFieldPhoneNumberDefaultExample from './__tests__/input-field-phone-number-default-example.vue?raw'; const meta: Meta = { title: 'Input field phone number', component: BentoInputFieldPhoneNumber, argTypes: { description: { name: 'description', description: 'If set, displays a description text for the input.', table: { category: 'props', type: { summary: 'string' }, }, control: { type: 'text', }, }, 'slot:description': { name: 'description', defaultValue: '', description: 'If set, displays a description text for the input. Overrides the `description` prop when provided.', table: { category: 'slots', type: { summary: 'VNode[]' }, }, control: { type: 'text', }, }, input: { description: 'Deprecated since version 2.0. Use `v-model` or `update:model-value instead', table: { category: 'Deprecated' }, control: { disable: true }, }, value: { control: { type: 'text' }, table: { category: 'Deprecated' }, description: 'Deprecated for usage with properties since version 2.0. Use `v-model` or `model-value` property instead', }, }, }; export default meta; type Story = StoryObj<typeof BentoInputFieldPhoneNumber>; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoInputFieldPhoneNumber }, props: Object.keys(argTypes), template: ` <bento-input-field-phone-number v-bind="args" :model-value="value" :selected-country="country" :error-message="errorMessage" @update:model-value="updateModelValue" @update:selected-country="onSelectedCountry" @blur="onBlur" @input:valid="validate" > <template #default v-if='args.default'> {{ args.default }} </template> <template #description v-if="args['slot:description']"> {{ args['slot:description'] }} </template> </bento-input-field-phone-number> `, setup(props) { const value = ref('+12025550123'); const country = ref('US'); const errorMessage = ref(''); const isValid = ref(false); const updateErrorMessage = () => { if (!isValid.value && value.value) { errorMessage.value = 'This number is not valid.'; } else { errorMessage.value = ''; } }; const onSelectedCountry = async updatedCountry => { country.value = updatedCountry; action('update:selected-country')(updatedCountry); await nextTick(); updateErrorMessage(); }; const updateModelValue = input => { value.value = input; action('update:model-value')(input); }; const validate = (validity: boolean) => { isValid.value = validity; if (validity) { updateErrorMessage(); } action('input:valid')(validity); }; const onBlur = () => { updateErrorMessage(); action('blur')(); }; onMounted(() => { updateErrorMessage(); }); return { // Values args: isVue2 ? props : _args, value, country, errorMessage, // Methods onSelectedCountry, updateModelValue, onBlur, validate, }; }, }), args: { label: 'Phone number', description: 'Select your country and input the phone number', dropdown: { readonly: false, } satisfies BentoInputFieldPhoneNumberDropdownProps, }, parameters: storybookDocsParameter(InputFieldPhoneNumberDefaultExample), };
@@ -0,0 +1 @@
1
+ import { type CountryCode } from 'libphonenumber-js'; import { type FormField } from '../../types/form-field'; import { type BentoInputDropdownProps } from '@/components/input-field/input-field.types'; export type BentoInputFieldPhoneNumberDropdownProps = Pick<BentoInputDropdownProps, 'readonly'>; /** * String literal with all the available country codes. */ export type BentoInputFieldPhoneNumberCountryCode = CountryCode | any; export interface BentoInputFieldPhoneNumberProps extends FormField { /** * Array of country codes to show on the dropdown */ countries?: Array<BentoInputFieldPhoneNumberCountryCode>; /** * Dropdown props for the small selectable dropdown menu. * Properties supported: * * - `readonly`: Sets the dropdown in read-only mode */ dropdown?: BentoInputFieldPhoneNumberDropdownProps; /** * If set, allows filtering on the countries dropdown */ dynamicFiltering?: boolean; /** * If true, applies error styling to the field. * @deprecated Use `errorMessage` prop instead. */ error?: boolean; /** * Selected country code */ selectedCountry?: BentoInputFieldPhoneNumberCountryCode; /** * The current value of the field. * @deprecated for usage with properties since version 2.0. Use `v-model` or `model-value` instead. */ value?: string | number; /** * The current value of the field. */ modelValue?: string | number; }
@@ -0,0 +1 @@
1
+ export const BentoInspectorSizeOptions = ['small', 'large'] as const; export type BentoInspectorRelativeLayout = 'push-content' | 'overlay-content'; export type BentoInspectorSize = (typeof BentoInspectorSizeOptions)[number]; export interface BentoInspectorProps { /** * ID of the current active inspector page */ activePage?: string; /** * Shows the Expand icon in the inspector */ expandable?: boolean; /** * Opens and closes the inspector */ isOpen?: boolean; /** * Shows loading indicator for the content */ loading?: boolean; /** * Determines the size of the inspector */ size?: BentoInspectorSize; /** * The title of the component */ title: string; /** * The appearance of the inspector relative to the main content. Defaults to `push-content`. * * - `push-content`: The inspector pushes the main content to the side, resizing it to fit. * - `overlay-content`: The inspector opens on top of the main content, without affecting its layout. */ relativeLayout?: BentoInspectorRelativeLayout; /** * An optional HTMLElement to focus on when returning focus from the inspector * to the main page content (e.g. via the `Ctrl+Shift+S` keyboard shortcut). * * By default, the inspector attempts to return focus to the element that was active before it opened. * However, if that trigger element is removed from the DOM (e.g., via a `v-if`), focus cannot be returned. * * Providing a `pageFocusAnchor` (e.g. role="gridcell") ensures that the * focus context is preserved for accessibility. */ pageFocusAnchor?: HTMLElement; }
@@ -0,0 +1 @@
1
+ export enum BentoBaseButtonPropClass { DESTRUCTIVE = 'critical', ICON_ONLY = 'icon-only', } export enum BentoBaseButtonEvent { BLUR = 'blur', CLICK = 'click', FOCUS = 'focus', KEYDOWN_ESC = 'keydown.esc', } export enum BaseButtonType { BUTTON = 'button', RESET = 'reset', SUBMIT = 'submit', }
@@ -0,0 +1 @@
1
+ import type { BentoPopoverPositions } from '@/components/popover/popover.types'; import type { BentoButtonActionsList } from '@/components/button/components/button-actions/button-actions.types'; export interface ButtonActionsWithMenuProps { /** * List of actions that will be used to render the buttons. * First element in the list will be rendered as "primary". * All elements after the first will be rendered as "secondary". * * Each object in the list should have a `title`, an `event` and * (optional) a Vue `icon` from the library `@adyen/ui-assets-icons-16`. * * `title`: Button's text. * * `event`: Event triggered when clicking the Button. * * `icon` (optional): Vue Icon from the library `@adyen/ui-assets-icons-16`. * * @see BentoButton for a list of all the other props supported by each button action. * * ``` * [{ * title: 'Primary', * event: () => { ... }, * icon: FourPeopleIcon, * link: { variant: 'default', external: true, to: 'https://www.adyen.com/' }, * }, { * title: 'Secondary', * event: () => { ... } * disabled: true, * variant: 'primary', * critical: true * }]" * ``` */ actions: BentoButtonActionsList; /** * Defines the layout in which the button actions is presented. * * */ actionsLayout?: string; /** * The number of actions to be displayed. The rest of the actions will be collapsed in a menu component. */ disableResponsiveBehavior?: boolean; /** * The number of actions to be displayed. The rest of the actions will be collapsed in a menu component. */ displayedActions?: number; /** * Set inverse color scheme to buttons and menu */ inverse?: boolean; /** * The min-width breakpoint to hide the button actions. * * For example, a value of 200 means that buttons will be hidden at <= 200px. * * Defaults to 0 i.e. it shows all buttons. */ hideDisplayedActionsBreakpoint?: number; /** * The position of where the menu should open. */ menuPosition?: BentoPopoverPositions | `${BentoPopoverPositions}`; }
@@ -0,0 +1 @@
1
+ import { type Ref, type UnwrapNestedRefs } from 'vue'; import type { Day } from 'date-fns'; export { CalendarMonthFirstDayOfWeek as CalendarFirstDayOfWeek } from './components/calendar-month/calendar-month.types'; export type { CalendarMonthIsDateDisabled as CalendarIsDateDisabled } from './components/calendar-month/calendar-month.types'; export { CalendarYearPosition as CalendarPosition } from './components/calendar-year/calendar-year.types'; export type CalendarGranularityType = 'daily' | 'weekly' | 'monthly' | 'quarterly'; export interface CalendarGranularityConfig<T extends CalendarGranularityType = CalendarGranularityType> { type: T; earliest?: Date; latest?: Date; disabled?: boolean; } export interface CalendarRangeDateValue { startDate: Date; endDate: Date; granularity?: CalendarGranularityType; range?: string; } export type CalendarSingleDateValue = Date; export type CalendarValue = CalendarSingleDateValue | CalendarRangeDateValue; interface UseCalendarPaneProps { isDateDisabled?: (date: Date) => boolean; maxRange?: Ref<number>; selectedDate: Ref<CalendarValue>; granularity?: Ref<CalendarGranularityConfig>; firstDayOfWeek: Day; min?: Ref<Date>; max?: Ref<Date>; } export type UseCalendarPane = ( propRefs: UseCalendarPaneProps, emit ) => { internalValue: UnwrapNestedRefs<CalendarRangeDateValue>; onDateInput: (date: Date) => void; onMouseOver: (date: Date) => void; }; export enum CalendarEvent { INPUT = 'input', START_DATE_SELECTED = 'start-date-selected', END_DATE_SELECTED = 'end-date-selected', } /** * Private types */ export enum CalendarVariant { DAY = 'day', MONTH = 'month', }
@@ -0,0 +1 @@
1
+ export enum CalendarMonthEvent { INPUT = 'input', MOUSE_OVER = 'mouseover', CHANGE_DAY = 'changeDay', NEXT_MONTH = 'nextMonth', PREVIOUS_MONTH = 'previousMonth', } export enum CalendarMonthFirstDayOfWeek { MONDAY = 1, SATURDAY = 6, SUNDAY = 0, } export type CalendarMonthIsDateDisabled = (date: Date) => boolean;
@@ -0,0 +1 @@
1
+ export enum CalendarMonthDayVariant { SINGLE = 'single', MIDDLE = 'middle', BEGINNING = 'beginning', END = 'end', } export enum CalendarMonthDayClass { // Variant SINGLE = CalendarMonthDayVariant.SINGLE, MIDDLE = CalendarMonthDayVariant.MIDDLE, BEGINNING = CalendarMonthDayVariant.BEGINNING, END = CalendarMonthDayVariant.END, // Selected SELECTED = 'selected', UNSELECTED = 'unselected', // Current day CURRENT_DAY = 'current-day', // Disabled DISABLED = 'disabled', } export enum CalendarMonthDayEvent { CLICK = 'click', MOUSE_OVER = 'mouseover', }
@@ -0,0 +1 @@
1
+ import type { CalendarGranularityConfig } from '../../../calendar.types'; import type { CalendarMonthFirstDayOfWeek } from '../calendar-month.types'; export interface UseMinMaxDateProps { firstDayOfWeek: CalendarMonthFirstDayOfWeek; min: Date; max: Date; } export type UseGranularMinMaxDate = (props: UseMinMaxDateProps) => { getGranularCalendarLimits: (granularity: CalendarGranularityConfig) => { min: Date; max: Date }; };
@@ -0,0 +1 @@
1
+ export enum CalendarYearPosition { FIRST = 'first', LAST = 'last', MIDDLE = 'middle', UNIQUE = 'unique', } /** * Private types */ export interface CalendarYearProps { /** * end of the selected range */ endDate?: Date; /** * Indicate if a date should be disabled or not */ isDateDisabled?: (date: Date) => boolean; /** * Indicates if the calendar is part of a range date picker or a single date picker */ isRange?: boolean; /** * Sets a minimum limit for selectable dates - dates before `min` will not be selectable */ min?: Date; /** * Sets a maximum limit for selectable dates - dates after `max` will not be selectable */ max?: Date; /** * When rendering multiple calendars, this property allows to render the * Next and Previous calendar buttons to the right, left or not at all * depending on the position: Unique (only 1), First, Middle or Last */ position?: `${CalendarYearPosition}`; /** * start of the selected range */ startDate?: Date; /** * Year to be displayed in the calendar */ year: Date; }
@@ -0,0 +1 @@
1
+ export interface CalendarYearMonthProps { /** * Date to be displayed as the calendar month. From 1st to 12th. */ month: Date; /** * Indicate if a date should be disabled or not */ disabled?: boolean; /** * Changes the state of the calendar month to selected. */ selected?: boolean; /** * When the month is selected, this indicates if the selection is a single month or part of a range. * If it's a range it can be at the beginning, middle or end of the selection. */ variant?: `${CalendarYearMonthVariant}`; } /** * Private types */ export enum CalendarYearMonthVariant { SINGLE = 'single', MIDDLE = 'middle', BEGINNING = 'beginning', END = 'end', } export enum CalendarYearMonthClass { // Variant SINGLE = CalendarYearMonthVariant.SINGLE, MIDDLE = CalendarYearMonthVariant.MIDDLE, BEGINNING = CalendarYearMonthVariant.BEGINNING, END = CalendarYearMonthVariant.END, // Selected SELECTED = 'selected', UNSELECTED = 'unselected', // Current month CURRENT_MONTH = 'current-month', // Disabled DISABLED = 'disabled', } export enum CalendarYearMonthEvent { CLICK = 'click', MOUSE_OVER = 'mouseover', }
@@ -0,0 +1 @@
1
+ import { type Day } from 'date-fns'; export type UseGranularityAdjustments = (firstDayOfWeek: Day) => { adjustDateForWeekly: (date: Date, endDate?: Date, min?: Date, max?: Date) => { startDate: Date; endDate: Date }; adjustDateForMonthly: (date: Date, endDate?: Date, min?: Date, max?: Date) => { startDate: Date; endDate: Date }; adjustDateForQuarterly: (date: Date, endDate?: Date, min?: Date, max?: Date) => { startDate: Date; endDate: Date }; adjustStartDateInputForWeekly: ( date: string, formatDate: (dateToFormat?: Date) => string, min?: Date, max?: Date ) => string; adjustEndDateInputForWeekly: ( date: string, formatDate: (dateToFormat?: Date) => string, min?: Date, max?: Date ) => string; adjustStartDateInputForMonthly: ( date: string, formatDate: (dateToFormat?: Date) => string, min?: Date, max?: Date ) => string; adjustEndDateInputForMonthly: ( date: string, formatDate: (dateToFormat?: Date) => string, min?: Date, max?: Date ) => string; adjustStartDateInputForQuarterly: ( date: string, formatDate: (dateToFormat?: Date) => string, min?: Date, max?: Date ) => string; adjustEndDateInputForQuarterly: ( date: string, formatDate: (dateToFormat?: Date) => string, min?: Date, max?: Date ) => string; };
@@ -0,0 +1 @@
1
+ export type MultiCheckboxInputType = Array<string | number>; export type CheckboxInputType = boolean | MultiCheckboxInputType; export enum CheckboxInputState { UNCHECKED = 'unchecked', CHECKED = 'checked', DISABLED = 'disabled', ERROR = 'error', READONLY = 'readonly', INDETERMINATE = 'indeterminate', } export enum CheckboxInputEvent { UPDATE = 'update:model-value', } interface CheckboxInputGroupItem { value: string | number; disabled?: boolean; hasError?: boolean; errorMessage?: string; readonly?: boolean; } export type CheckboxInputGroupItems = Array<CheckboxInputGroupItem>;
@@ -0,0 +1 @@
1
+ import { type PopperContainerPosition } from '@/components/popper-container'; import type { BentoButton } from '@/components/button'; export enum CopyTooltipState { DEFAULT = 'default', COPYING = 'copying', ERROR = 'error', } type ButtonProps = InstanceType<typeof BentoButton>['$props']; export interface BentoCopyButtonProps { variant?: ButtonProps['variant']; condensed?: ButtonProps['condensed']; disabled?: ButtonProps['disabled']; } export interface BentoCopyProps { /** * Object containing props to change the menu button appearance. Accepts the same props present in BentoButton. */ button?: BentoCopyButtonProps; /** * Sets the button text of the copy button. */ buttonText?: string; /** * Defines the string that will get copied to the clipboard */ text: string; /** * Position the tooltip should take if space is available. Defaults to 'top' */ tooltipPosition?: PopperContainerPosition; }
@@ -0,0 +1 @@
1
+ import { type Ref } from 'vue'; export enum BentoDialogPageAnimation { TRANSITION_LEVEL_DEEPER = 'b-dialog-page__animation--level-deeper', TRANSITION_LEVEL_UPPER = 'b-dialog-page__animation--level-upper', } export interface BentoDialogPageConfigData { activePage: Ref<string>; animation: Ref<string>; isAnimationActive?: Ref<boolean>; isOpen: Ref<boolean>; pages: Ref<Array<string>>; previousPages: Ref<Array<string>>; updatePage: (page: string) => void; } export type BentoDialogPageRegisterPage = (pageId: string) => { unregisterPage: () => void };
@@ -0,0 +1 @@
1
+ export enum GridLayoutContainerType { INLINE = 'inline-size', SIZE = 'size', NORMAL = 'normal', } export interface GridLayoutColumnWidth { small: number | string; medium: number | string; large: number | string; } export type GridLayoutColumnWidths = Array<'auto' | GridLayoutColumnWidth>;
@@ -0,0 +1 @@
1
+ import { type BentoHeaderReloadButton } from '../../header/header.types'; export interface HeaderMetaProps { /** * Meta description for the header component */ description?: string; /** * JavaScript "Date" object for when the content was last updated */ lastUpdated?: Date | number; /** * Reload button which shows next to the header's timestamp * @see BentoHeaderReloadButton */ reloadButton?: BentoHeaderReloadButton; }
@@ -0,0 +1 @@
1
+ export enum ListboxMultiSelectCategoryClass { DISABLED = 'disabled', STATIC_CATEGORY = 'static-category', } export enum ListboxMultiSelectCategoryEvent { SELECT_CATEGORY = 'select-category', UNSELECT_CATEGORY = 'unselect-category', TOGGLE_CATEGORY_VISIBILITY = 'toggle-category-visibility', }
@@ -0,0 +1 @@
1
+ export enum ListboxMultiSelectOptionsEvent { SELECT_CATEGORY = 'select-category', TOGGLE_CHECKBOX_SELECTION = 'toggle-checkbox-selection', UNSELECT_CATEGORY = 'unselect-category', TOGGLE_CATEGORY_VISIBILITY = 'toggle-category-visibility', }
@@ -0,0 +1 @@
1
+ import { type BentoListboxIsOptionDisabled, type BentoListboxLazyLoadType, type BentoListboxOptions } from '@/types/listbox'; export interface ListboxMultiSelectProps { /** * Indicates whether there are more items to load */ hasMoreItems?: boolean; /** * Function that allows the options to be disabled * * @type {BentoListboxIsOptionDisabled} * @param {BentoListboxOptionItem} option - listbox option object * @param {string} option.label - Option's label text * @param {string|number} option.value - Option's value * @param {unknown} option.data - Option's extra data to be passed to the default slot */ isOptionDisabled?: BentoListboxIsOptionDisabled; /** * The option elements to populate the listbox with. * It must be an array of {@see BentoListboxOptionItem }. * * @property {string} value.label - Text to be displayed in the option * @property {string,number} value.value - Value of the option */ items: BentoListboxOptions; /** * The type of `Lazy Load`. * Type "automatic" will enable infinite scrolling * Type "button" will enable lazy loading with "Show more" button */ lazyLoadType?: BentoListboxLazyLoadType | `${BentoListboxLazyLoadType}`; /** * Flag that indicates that an external search it's being made * to filter out the items inside the the multi-select listbox * * If enabled, hides the "Select all" checkbox in "multiple" mode. */ searching?: boolean; /** * The `input` value. * Providing an empty array will select no options. */ selectedValues: BentoListboxOptions; /** * If enabled, dropdown will display non-selectable, static categories */ staticCategories?: boolean; }
@@ -0,0 +1 @@
1
+ // Types for this components should be in @/types/listbox.ts
@@ -0,0 +1 @@
1
+ export type RadioInputValue = string | number; export enum RadioInputStateClass { DISABLED = 'disabled', READONLY = 'readonly', ERROR = 'error', }
@@ -1 +1 @@
1
- <template> <input :id="id" ref="inputRef" :aria-checked="isChecked" :aria-label="ariaLabel" :aria-invalid="ariaInvalid" :aria-describedby="ariaDescribedby" :checked="isChecked" :disabled="disabled" :value="value" :name="name" type="radio" class="b-radio-input" :class="conditionalClasses" role="radio" @click="onClick" @change="onChange" /> </template> <script setup lang="ts"> import { computed, type ComputedRef, type PropType, ref, toRefs } from 'vue'; import { RadioInputStateClass, type RadioInputValue } from './radio-input.types'; import type { HTMLAttributes } from 'vue/types/jsx.d.ts'; const props = defineProps({ /** * The aria label associated to the input checkbox. */ ariaLabel: { type: String, default: '' }, /** * An additional string that serves as description for the input checkbox (useful if the component shows a description). */ ariaDescribedby: { type: String, default: '' }, /** * Disable the radio button (optional) */ disabled: { type: Boolean, default: false }, /** * Shows bento-radio-button in error state (optional) */ hasError: { type: Boolean, default: false }, /** * Sets the id of the radio input. Required for accessibility purposes */ id: { type: String, default: null }, /** * This property should not be used directly. * It will be used by v-model directive on radio component. */ modelValue: { type: [String, Number] as PropType<RadioInputValue>, default: null, }, /** * Sets the radio button to readonly (optional) */ readonly: { type: Boolean, default: false }, /** * Indicates the value of the input that will be returned when it's checked */ value: { type: [String, Number] as PropType<RadioInputValue>, required: true, }, /** * Sets the name of the radio input. * Used for differentiating radio groups or accessing input via form submission. */ name: { type: String, default: null }, }); const emit = defineEmits<{ /** * Emit that emits the input value */ (e: 'update:model-value', value: RadioInputValue): void; }>(); const { value } = toRefs(props); const inputRef = ref(null); const conditionalClasses = computed(() => ({ [`b-radio-input--${RadioInputStateClass.DISABLED}`]: props.disabled, [`b-radio-input--${RadioInputStateClass.ERROR}`]: props.hasError, [`b-radio-input--${RadioInputStateClass.READONLY}`]: props.readonly, })); const ariaInvalid = computed<HTMLAttributes['aria-invalid']>(() => props.hasError); const isChecked: ComputedRef<boolean> = computed(() => props.value === props.modelValue); const onChange = () => { if (!props.disabled && !props.readonly) { emit('update:model-value', props.value); } }; // readonly attr doesn't work with radio button, so we need to manually ignore the click instead const onClick = event => { if (props.readonly) { event.preventDefault(); } }; const focus = () => { inputRef.value.focus(); }; defineExpose({ focus, }); </script> <script lang="ts"> /** * Internal component that renders a radio input (without label) * * @example * import { RadioInput } from '@/internal/radio-input'; * * export default { * components: { BentoCheckboxInput }, * template: ` * <label for="checkbox-id">Your label</label> * <span id="description-id">Description</span> * <radio-input id="checkbox-id" aria=label="Your label" aria-describedby="description-id" /> * ` * } */ export default { name: 'radio-input', inheritAttrs: false, }; </script> <style lang="scss" scoped src="./radio-input.scss" />
1
+ <template> <div class="b-radio-input"> <input :id="id" ref="inputRef" :aria-checked="isChecked" :aria-label="ariaLabel" :aria-invalid="ariaInvalid" :aria-describedby="ariaDescribedby" :checked="isChecked" :disabled="disabled" :value="value" :name="name" type="radio" class="b-radio-input__input" :class="conditionalClasses" role="radio" @click="onClick" @change="onChange" /> </div> </template> <script setup lang="ts"> import { computed, type ComputedRef, type PropType, ref, toRefs } from 'vue'; import { RadioInputStateClass, type RadioInputValue } from './radio-input.types'; import type { HTMLAttributes } from 'vue/types/jsx.d.ts'; const props = defineProps({ /** * The aria label associated to the input checkbox. */ ariaLabel: { type: String, default: '' }, /** * An additional string that serves as description for the input checkbox (useful if the component shows a description). */ ariaDescribedby: { type: String, default: '' }, /** * Disable the radio button (optional) */ disabled: { type: Boolean, default: false }, /** * Shows bento-radio-button in error state (optional) */ hasError: { type: Boolean, default: false }, /** * Sets the id of the radio input. Required for accessibility purposes */ id: { type: String, default: null }, /** * This property should not be used directly. * It will be used by v-model directive on radio component. */ modelValue: { type: [String, Number] as PropType<RadioInputValue>, default: null, }, /** * Sets the radio button to readonly (optional) */ readonly: { type: Boolean, default: false }, /** * Indicates the value of the input that will be returned when it's checked */ value: { type: [String, Number] as PropType<RadioInputValue>, required: true, }, /** * Sets the name of the radio input. * Used for differentiating radio groups or accessing input via form submission. */ name: { type: String, default: null }, }); const emit = defineEmits<{ /** * Emit that emits the input value */ (e: 'update:model-value', value: RadioInputValue): void; }>(); const { value } = toRefs(props); const inputRef = ref(null); const conditionalClasses = computed(() => ({ [`b-radio-input__input--${RadioInputStateClass.DISABLED}`]: props.disabled, [`b-radio-input__input--${RadioInputStateClass.ERROR}`]: props.hasError, [`b-radio-input__input--${RadioInputStateClass.READONLY}`]: props.readonly, })); const ariaInvalid = computed<HTMLAttributes['aria-invalid']>(() => props.hasError); const isChecked: ComputedRef<boolean> = computed(() => props.value === props.modelValue); const onChange = () => { if (!props.disabled && !props.readonly) { emit('update:model-value', props.value); } }; // readonly attr doesn't work with radio button, so we need to manually ignore the click instead const onClick = event => { if (props.readonly) { event.preventDefault(); } }; const focus = () => { inputRef.value.focus(); }; defineExpose({ focus, }); </script> <script lang="ts"> /** * Internal component that renders a radio input (without label) * * @example * import { RadioInput } from '@/internal/radio-input'; * * export default { * components: { BentoCheckboxInput }, * template: ` * <label for="checkbox-id">Your label</label> * <span id="description-id">Description</span> * <radio-input id="checkbox-id" aria=label="Your label" aria-describedby="description-id" /> * ` * } */ export default { name: 'radio-input', inheritAttrs: false, }; </script> <style lang="scss" scoped src="./radio-input.scss" />
@@ -0,0 +1 @@
1
+ export interface BentoTeleportProps { /** * Disables the teleport. It will prevent the slotted element to be * teleported outside of the initial parent element * @default false */ disabled: boolean; /** * Indicates the parent container in which the slotted element will be * teleported to. */ to?: string; // NOTE: "where" is not added as it doesn't exist in Vue3 }
@@ -0,0 +1 @@
1
+ import { PopperContainerPositionBasic } from '../../popper-container/popper-container.types'; export const BentoTooltipPosition = { ...PopperContainerPositionBasic }; export type BentoTooltipPosition = PopperContainerPositionBasic; export enum BentoTooltipState { HIDDEN = 'hidden', }
@@ -0,0 +1 @@
1
+ /** * @private */ export const BentoLayoutVariantOptions = ['page', 'component'] as const; export const BentoLayoutSizeOptions = ['full-width', 'narrow', 'half-width'] as const; export const BentoLayoutRowColumnLayoutOptions = ['3-9', '9-3', '4-8', '8-4', '6-6'] as const; // Public export type BentoLayoutVariant = (typeof BentoLayoutVariantOptions)[number]; export type BentoLayoutSize = (typeof BentoLayoutSizeOptions)[number]; export type BentoLayoutRowColumnLayout = (typeof BentoLayoutRowColumnLayoutOptions)[number]; export interface BentoLayoutProps { /** Defines if the layout is used in a page or only a section */ variant?: BentoLayoutVariant; /** Defines the size of the page */ size?: BentoLayoutSize; } export interface BentoLayoutRowProps { /** Sets the layout of the columns when multiple columns are used */ columnsLayout?: BentoLayoutRowColumnLayout; }
@@ -0,0 +1 @@
1
+ import type { Location } from 'vue-router/types/router.d.ts'; // TODO: revert to import once fully migrated to Vue 3 // import type { RouterLinkProps } from 'vue-router/types/router.d.ts'; /** * Manually defined RouterLinkProps to ensure compatibility * with Vue Macros and Vue 2.7 / 3 monorepos. */ export interface RouterLinkProps { /** * Denotes the target route of the link. When clicked, the value of the `to` prop will be passed to * `router.push()` internally, so the value can be either a string or a location descriptor object. */ to: string | Location; /** * Setting `replace` prop will call `router.replace()` instead of `router.push()` when clicked, so the navigation will * not create a new history record. * * @default false */ replace?: boolean; /** * Setting `append` prop always appends the relative path to the current path. For example, assuming we are navigating * from `/a` to a relative link `b`, without `append` we will end up at `/b`, but with append we will end up at * `/a/b`. * * @default false */ append?: boolean; /** * Sometimes we want <RouterLink> to render as another tag, e.g <li>. Then we can use tag prop to specify which tag to * render to, and it will still listen to click events for navigation. * * @default "a" */ tag?: string; /** * Configure the active CSS class applied when the link is active. Note the default value can also be configured * globally via the `linkActiveClass` router constructor option. * * @default "router-link-active" */ activeClass?: string; /** * The default active class matching behavior is **inclusive match**. For example, `<RouterLink to="/a">` will get * this class applied as long as the current path starts with `/a/` or is `/a`. * * @default false */ exact?: boolean; /** * Allows matching only using the `path` section of the url, effectively ignoring the `query` and the `hash` sections. * * @default false */ exactPath?: boolean; /** * Configure the active CSS class applied when the link is active with exact path match. Note the default value can * also be configured globally via the `linkExactPathActiveClass` router constructor option. * * @default "router-link-exact-path-active" */ exactPathActiveClass?: string; /** * Specify the event(s) that can trigger the link navigation. * * @default 'click' */ event?: string | ReadonlyArray<string>; /** * Configure the active CSS class applied when the link is active with exact match. Note the default value can also be * configured globally via the `linkExactActiveClass` router constructor option. * * @default "router-link-exact-active" */ exactActiveClass?: string; /** * Configure the value of `aria-current` when the link is active with exact match. It must be one of the allowed * values for [aria-current](https://www.w3.org/TR/wai-aria-1.2/#aria-current) in the ARIA spec. In most cases, the * default of page should be the best fit. * * @default "page" */ ariaCurrentValue?: 'page' | 'step' | 'location' | 'date' | 'time' | 'true' | 'false'; } /** * @deprecated for usage with properties since version 2.0. Use the string literal instead. */ export enum BentoLinkVariant { DEFAULT = 'default', QUIET = 'quiet', } export type BentoLinkProps = RouterLinkProps & { /** * Disable the default typography for the component. Only use this when the component is inside another typography component. */ disableTypography?: boolean; /** * Set the rendered link to a regular external anchor link and renders an external link icon. */ external?: boolean; /** * Set to true if used inside a `BentoButton` component. */ isButton?: boolean; /** * Set the rendered link to a regular external anchor link. */ isNotRouting?: boolean; /** * Sets the target of the rendered link. */ target?: string; /** * Set to true to truncate link. Doesn't work with disableTypography. */ truncate?: boolean; /** * Link variant type affecting visual style. * @values default, quiet */ variant?: BentoLinkVariant | `${BentoLinkVariant}`; };