@adyen/bento-mcp 0.1.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +55 -0
- package/README.md +50 -5
- package/SKILL.md +188 -0
- package/bin/add-skill.js +46 -0
- package/dist/assets/components/accordion/accordion.types.ts +1 -0
- package/dist/assets/components/action-bar/action-bar.types.ts +1 -0
- package/dist/assets/components/ai-tag/ai-tag.types.ts +1 -0
- package/dist/assets/components/alert/alert.types.ts +1 -0
- package/dist/assets/components/anchor-scroller/anchor-scroller.types.ts +1 -0
- package/dist/assets/components/anchor-scroller/components/anchor-scroller-list/anchor-scroller-list.types.ts +1 -0
- package/dist/assets/components/avatar/components/avatar-image/avatar-image.types.ts +1 -0
- package/dist/assets/components/button/button.types.ts +1 -0
- package/dist/assets/components/button/components/ai-button/ai-button.types.ts +1 -0
- package/dist/assets/components/button/components/button-actions/button-actions.types.ts +1 -0
- package/dist/assets/components/button/components/loading-button/loading-button.types.ts +1 -0
- package/dist/assets/components/button/components/toggle-button/toggle.types.ts +1 -0
- package/dist/assets/components/card/card.types.ts +1 -0
- package/dist/assets/components/checkbox/checkbox.types.ts +1 -0
- package/dist/assets/components/checkbox/components/checkbox-group/checkbox-group.types.ts +1 -0
- package/dist/assets/components/chip/chip.types.ts +1 -0
- package/dist/assets/components/code-snippet/code-snippet.types.ts +1 -0
- package/dist/assets/components/country/country.types.ts +1 -0
- package/dist/assets/components/currency/currency.types.ts +1 -0
- package/dist/assets/components/dashed-underline/dashed-underline.types.ts +1 -0
- package/dist/assets/components/data-grid/components/data-grid-cell/data-grid-cell.types.ts +1 -0
- package/dist/assets/components/data-grid/components/data-grid-cell/data-grid-cell.vue +1 -1
- package/dist/assets/components/data-grid/components/data-grid-cell-actions/data-grid-cell-actions.types.ts +1 -0
- package/dist/assets/components/data-grid/components/data-grid-columns/data-grid-columns.types.ts +1 -0
- package/dist/assets/components/data-grid/components/data-grid-columns/data-grid-columns.vue +1 -1
- package/dist/assets/components/data-grid/components/data-grid-config-settings/data-grid-config-settings.types.ts +1 -0
- package/dist/assets/components/data-grid/components/data-grid-row/data-grid-row.types.ts +1 -0
- package/dist/assets/components/data-grid/components/data-grid-row/data-grid-row.vue +1 -1
- package/dist/assets/components/data-grid/components/data-grid-static-icon/data-grid-static-icon.types.ts +1 -0
- package/dist/assets/components/data-grid/components/data-grid-summary-cell/data-grid-summary-cell.types.ts +1 -0
- package/dist/assets/components/data-grid/components/data-grid-tag-with-text-cell/data-grid-tag-with-text-cell.types.ts +1 -0
- package/dist/assets/components/data-grid/components/data-grid-trend-cell/data-grid-trend-cell.types.ts +1 -0
- package/dist/assets/components/data-grid/composables/use-calculate-column-width/use-calculate-column-width.types.ts +1 -0
- package/dist/assets/components/data-grid/composables/use-column-hovering/use-column-hovering.types.ts +1 -0
- package/dist/assets/components/data-grid/composables/use-config-settings/use-config.settings.types.ts +1 -0
- package/dist/assets/components/data-grid/composables/use-keyboard-navigator/use-keyboard-navigator.types.ts +1 -0
- package/dist/assets/components/data-grid/data-grid.types.ts +1 -0
- package/dist/assets/components/data-grid/data-grid.vue +1 -1
- package/dist/assets/components/date/date.types.ts +1 -0
- package/dist/assets/components/date-picker/composables/use-date-picker-single-calendar-text.types.ts +1 -0
- package/dist/assets/components/date-picker/date-picker.types.ts +1 -0
- package/dist/assets/components/date-range-picker/components/date-range-picker-calendar/date-range-picker-calendar.types.ts +1 -0
- package/dist/assets/components/date-range-picker/components/date-range-picker-calendar/date-range-picker-calendar.vue +1 -1
- package/dist/assets/components/date-range-picker/composables/use-date-range-picker-calendar-text.types.ts +1 -0
- package/dist/assets/components/date-range-picker/composables/use-granularity-memory.types.ts +1 -0
- package/dist/assets/components/date-range-picker/date-range-picker.types.ts +1 -0
- package/dist/assets/components/divider/divider.types.ts +1 -0
- package/dist/assets/components/draggable-handle/draggable-handle.types.ts +1 -0
- package/dist/assets/components/dropdown/components/dropdown-base-textbox/dropdown-base-textbox.types.ts +1 -0
- package/dist/assets/components/dropdown/components/variants/dropdown-avatar/dropdown-avatar.types.ts +1 -0
- package/dist/assets/components/dropdown/components/variants/dropdown-country/dropdown-country.types.ts +1 -0
- package/dist/assets/components/dropdown/components/variants/dropdown-currency/dropdown-currency.types.ts +1 -0
- package/dist/assets/components/dropdown/components/variants/dropdown-payment-method/dropdown-payment-method.types.ts +1 -0
- package/dist/assets/components/dropdown/components/variants/dropdown-tag/dropdown-tag.types.ts +1 -0
- package/dist/assets/components/dropdown/composables/use-display-value.types.ts +1 -0
- package/dist/assets/components/dropdown/composables/use-keyboard-navigation.types.ts +1 -0
- package/dist/assets/components/dropdown/dropdown.types.ts +1 -0
- package/dist/assets/components/empty-state/empty-state.types.ts +1 -0
- package/dist/assets/components/file-uploader/components/file-uploader-file-card/file-uploader-file-card.types.ts +1 -0
- package/dist/assets/components/file-uploader/components/file-uploader-restrictions/file-uploader-restrictions.types.ts +1 -0
- package/dist/assets/components/file-uploader/composables/use-drag-drop-state/use-drag-drop-state.types.ts +1 -0
- package/dist/assets/components/file-uploader/file-uploader.types.ts +1 -0
- package/dist/assets/components/filter-bar/components/all-filters-modal/all-filters-modal.types.ts +1 -0
- package/dist/assets/components/filter-bar/components/all-filters-modal/all-filters-modal.vue +1 -1
- package/dist/assets/components/filter-bar/components/base-filter/base-filter.types.ts +1 -0
- package/dist/assets/components/filter-bar/components/checkbox-group-filter/checkbox-group-filter.types.ts +1 -0
- package/dist/assets/components/filter-bar/components/filter-bar-button-group/filter-bar-button-group.types.ts +1 -0
- package/dist/assets/components/filter-bar/components/input-filter/input-filter.types.ts +1 -0
- package/dist/assets/components/filter-bar/components/radio-group-filter/radio-group-filter.types.ts +1 -0
- package/dist/assets/components/filter-bar/components/toggle-filter/toggle-filter.types.ts +1 -0
- package/dist/assets/components/filter-bar/filter-bar.types.ts +1 -0
- package/dist/assets/components/focus-trap/focus-trap.types.ts +1 -0
- package/dist/assets/components/form-layout/components/form-layout-field-tip/form-layout-tip.types.ts +1 -0
- package/dist/assets/components/form-layout/components/form-layout-group/form-layout-group.types.ts +1 -0
- package/dist/assets/components/form-layout/form-layout.types.ts +1 -0
- package/dist/assets/components/header/header.types.ts +1 -0
- package/dist/assets/components/header-with-views/components/header-with-views-all-views/header-with-views-all-views.types.ts +1 -0
- package/dist/assets/components/header-with-views/components/header-with-views-item-edit-form/header-with-views-edit-form.types.ts +1 -0
- package/dist/assets/components/header-with-views/header-with-views.types.ts +1 -0
- package/dist/assets/components/image/image.types.ts +1 -0
- package/dist/assets/components/info-icon/info-icon.types.ts +1 -0
- package/dist/assets/components/input-field/input-field.types.ts +1 -0
- package/dist/assets/components/input-field-password/input-field-password.types.ts +1 -0
- package/dist/assets/components/input-field-phone-number/input-field-phone-number.types.ts +1 -0
- package/dist/assets/components/input-time/input-time.docs.mdx +52 -0
- package/dist/assets/components/input-time/input-time.stories.ts +1 -0
- package/dist/assets/components/input-time/input-time.types.ts +1 -0
- package/dist/assets/components/input-time/input-time.vue +1 -0
- package/dist/assets/components/inspector/inspector.types.ts +1 -0
- package/dist/assets/components/internal/base-button/base-button.types.ts +1 -0
- package/dist/assets/components/internal/button-actions-with-menu/button-actions-with-menu.types.ts +1 -0
- package/dist/assets/components/internal/calendar/calendar.types.ts +1 -0
- package/dist/assets/components/internal/calendar/components/calendar-month/calendar-month.types.ts +1 -0
- package/dist/assets/components/internal/calendar/components/calendar-month/components/calendar-month-day/calendar-month-day.types.ts +1 -0
- package/dist/assets/components/internal/calendar/components/calendar-month/composables/granular-min-max-date.types.ts +1 -0
- package/dist/assets/components/internal/calendar/components/calendar-year/calendar-year.types.ts +1 -0
- package/dist/assets/components/internal/calendar/components/calendar-year/components/calendar-year-month/calendar-year-month.types.ts +1 -0
- package/dist/assets/components/internal/calendar/composables/use-granularity-adjustments.types.ts +1 -0
- package/dist/assets/components/internal/checkbox-input/checkbox-input.types.ts +1 -0
- package/dist/assets/components/internal/copy/copy.types.ts +1 -0
- package/dist/assets/components/internal/dialog-page/dialog-page.types.ts +1 -0
- package/dist/assets/components/internal/grid-layout/grid-layout.types.ts +1 -0
- package/dist/assets/components/internal/header-meta/header-meta.types.ts +1 -0
- package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/components/listbox-multi-select-category/listbox-multi-select-category.types.ts +1 -0
- package/dist/assets/components/internal/listbox/components/listbox-multi-select/components/listbox-multi-select-options/listbox-multi-select-options.types.ts +1 -0
- package/dist/assets/components/internal/listbox/components/listbox-multi-select/listbox-multi-select.types.ts +1 -0
- package/dist/assets/components/internal/listbox/listbox.types.ts +1 -0
- package/dist/assets/components/internal/radio-input/radio-input.types.ts +1 -0
- package/dist/assets/components/internal/teleport/teleport.types.ts +1 -0
- package/dist/assets/components/internal/tooltip/tooltip.types.ts +1 -0
- package/dist/assets/components/layout/layout.types.ts +1 -0
- package/dist/assets/components/link/link.types.ts +1 -0
- package/dist/assets/components/list/components/list-item/list-item.stories.ts +1 -0
- package/dist/assets/components/list/components/list-item/list-item.types.ts +1 -0
- package/dist/assets/components/list/components/list-item/list-item.vue +1 -0
- package/dist/assets/components/list/list.docs.mdx +97 -0
- package/dist/assets/components/list/list.stories.ts +1 -0
- package/dist/assets/components/list/list.types.ts +1 -0
- package/dist/assets/components/list/list.vue +1 -0
- package/dist/assets/components/loading-indicator/loading-indicator.types.ts +1 -0
- package/dist/assets/components/menu/components/menu-item/menu-item.types.ts +1 -0
- package/dist/assets/components/menu/menu.types.ts +1 -0
- package/dist/assets/components/modal/components/modal-page/modal-page.types.ts +1 -0
- package/dist/assets/components/modal/modal.types.ts +1 -0
- package/dist/assets/components/pagination/pagination.types.ts +1 -0
- package/dist/assets/components/payment-method/payment-method.types.ts +1 -0
- package/dist/assets/components/popover/popover.types.ts +1 -0
- package/dist/assets/components/popper-container/popper-container.types.ts +1 -0
- package/dist/assets/components/promo-banner/promo-banner.types.ts +1 -0
- package/dist/assets/components/radio-group/components/radio-button/radio-button.types.ts +1 -0
- package/dist/assets/components/radio-group/radio-group.types.ts +1 -0
- package/dist/assets/components/rich-text-editor/components/rich-text-editor-content-area/rich-text-editor-content-area.types.ts +1 -0
- package/dist/assets/components/rich-text-editor/components/rich-text-editor-renderer/components/rich-text-editor-code-block/rich-text-editor-code-block.types.ts +1 -0
- package/dist/assets/components/rich-text-editor/components/rich-text-editor-renderer/components/rich-text-editor-inline-code/rich-text-editor-inline-code.types.ts +1 -0
- 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
- 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
- package/dist/assets/components/rich-text-editor/components/rich-text-editor-renderer/rich-text-editor-renderer.types.ts +1 -0
- package/dist/assets/components/rich-text-editor/rich-text-editor.types.ts +1 -0
- package/dist/assets/components/search-bar/search-bar.types.ts +1 -0
- package/dist/assets/components/secondary-nav/components/secondary-nav-category/secondary-nav-category.vue +1 -1
- package/dist/assets/components/secondary-nav/components/secondary-nav-item/secondary-nav-item.vue +1 -1
- package/dist/assets/components/secondary-nav/secondary-nav.docs.mdx +32 -2
- package/dist/assets/components/secondary-nav/secondary-nav.stories.ts +1 -1
- package/dist/assets/components/secondary-nav/secondary-nav.types.ts +1 -0
- package/dist/assets/components/secondary-nav/secondary-nav.vue +1 -1
- package/dist/assets/components/segmented-control/segmented-control.types.ts +1 -0
- package/dist/assets/components/selection-card/components/selection-card-group/selection-card-group.types.ts +1 -0
- package/dist/assets/components/selection-card/selection-card.types.ts +1 -0
- package/dist/assets/components/sidepanel/sidepanel.types.ts +1 -0
- package/dist/assets/components/status/status.types.ts +1 -0
- package/dist/assets/components/stepper/stepper.types.ts +1 -0
- package/dist/assets/components/structured-list/structured-list.types.ts +1 -0
- package/dist/assets/components/summary-grid/components/summary-grid-item/summary-grid-item.types.ts +1 -0
- package/dist/assets/components/summary-grid/components/summary-grid-item-amount/summary-grid-item-amount.types.ts +1 -0
- package/dist/assets/components/summary-grid/components/summary-grid-item-custom/summary-grid-item-custom.types.ts +1 -0
- package/dist/assets/components/summary-grid/components/summary-grid-item-numeric/summary-grid-item-numeric.types.ts +1 -0
- package/dist/assets/components/summary-grid/components/summary-grid-item-percentage/summary-grid-item-percentage.types.ts +1 -0
- package/dist/assets/components/summary-grid/components/summary-grid-item-text/summary-grid-item-text.types.ts +1 -0
- package/dist/assets/components/summary-grid/summary-grid.types.ts +1 -0
- package/dist/assets/components/tabs/components/tab.types.ts +1 -0
- package/dist/assets/components/tabs/tabs.types.ts +1 -0
- package/dist/assets/components/tag/tag.types.ts +1 -0
- package/dist/assets/components/textarea/textarea.types.ts +1 -0
- package/dist/assets/components/timeline/components/timeline-item/timeline-item.vue +1 -1
- package/dist/assets/components/timeline/timeline.stories.ts +1 -1
- package/dist/assets/components/timeline/timeline.types.ts +1 -0
- package/dist/assets/components/toast/components/toast-shadow-stack/toast-shadow-stack.types.ts +1 -0
- package/dist/assets/components/toggle/toggle.types.ts +1 -0
- package/dist/assets/components/tutorial/tutorial.types.ts +1 -0
- package/dist/assets/components/typography/typography.types.ts +1 -0
- package/dist/assets/components.json +102 -0
- package/dist/assets/composables/use-bento-theme/install.ts +1 -0
- package/dist/assets/composables/use-bento-theme/install.types.ts +1 -0
- package/dist/assets/composables/use-bento-theme/use-bento-theme.types.ts +1 -0
- package/dist/assets/composables/use-bento-toast-controller/install.ts +1 -0
- package/dist/assets/composables/use-bento-toast-controller/use-bento-toast-controller.types.ts +1 -0
- package/dist/assets/composables/use-form-validate/use-form.types.ts +1 -0
- package/dist/assets/composables/use-form-validate-zod-4/use-form.types.ts +1 -0
- package/dist/assets/composables/use-virtual-list/use-virtual-list.types.ts +1 -0
- package/dist/assets/deprecations.md +330 -0
- package/dist/assets/directives/keyboard-navigation/keyboard-navigation.types.ts +1 -0
- package/dist/assets/directives/tooltip/tooltip.types.ts +1 -0
- package/dist/assets/icons.json +415 -0
- package/dist/assets/index.ts +1 -1
- package/dist/assets/install.ts +1 -0
- package/dist/assets/tailwind/README.md +89 -0
- package/dist/assets/templates/dashboard-template/dashboard-template.types.ts +1 -0
- package/dist/assets/templates/data-grid-template/data-grid-template.stories.ts +1 -1
- package/dist/assets/templates/data-grid-template/data-grid-template.types.ts +1 -0
- package/dist/assets/utility-classes.md +92 -0
- package/dist/assets/utils/ts/currency/currency.types.ts +1 -0
- package/dist/assets/variables.css +309 -0
- package/dist/main.js +395 -29
- package/package.json +15 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,60 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0 (2026-04-08)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- amended writing bento comps skill to batch `get_component` mcp tool calls when needed ([5b9100929](https://github.com/Adyen/bento/commit/5b9100929))
|
|
8
|
+
|
|
9
|
+
### ❤️ Thank You
|
|
10
|
+
|
|
11
|
+
- gerald
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## 0.2.1 (2026-04-01)
|
|
15
|
+
|
|
16
|
+
This was a version bump only for mcp to align it with other projects, there were no code changes.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
## 0.2.0 (2026-04-01)
|
|
20
|
+
|
|
21
|
+
### Features
|
|
22
|
+
|
|
23
|
+
- updated `get_components` tool to also add the Types of each component with the payload ([12c4b6c53](https://github.com/Adyen/bento/commit/12c4b6c53))
|
|
24
|
+
|
|
25
|
+
Co-authored-by: Gerald Campbell <gerald.campbell@adyen.com>
|
|
26
|
+
- added `get_utility_classes` tool to provide information about deprecated Bento utility classes ([59783fc88](https://github.com/Adyen/bento/commit/59783fc88))
|
|
27
|
+
|
|
28
|
+
Co-authored-by: Gerald Campbell <gerald.campbell@adyen.com>
|
|
29
|
+
- added `get_deprecations` tool to provide information about Bento deprecations ([1c74ed2c0](https://github.com/Adyen/bento/commit/1c74ed2c0))
|
|
30
|
+
|
|
31
|
+
Co-authored-by: Gerald Campbell <gerald.campbell@adyen.com>
|
|
32
|
+
- added `get_design_tokens` to provide information about Design System tokens ([a9d8ebbf0](https://github.com/Adyen/bento/commit/a9d8ebbf0))
|
|
33
|
+
|
|
34
|
+
Co-authored-by: Gerald Campbell <gerald.campbell@adyen.com>
|
|
35
|
+
- added `get_icons` tool to list all the available 16x16 icons ([c8347def7](https://github.com/Adyen/bento/commit/c8347def7))
|
|
36
|
+
|
|
37
|
+
Co-authored-by: Gerald Campbell <gerald.campbell@adyen.com>
|
|
38
|
+
- added `get_docs` tool to provide more docs to the LLM ([bac254ffd](https://github.com/Adyen/bento/commit/bac254ffd))
|
|
39
|
+
|
|
40
|
+
Co-authored-by: Gerald Campbell <gerald.campbell@adyen.com>
|
|
41
|
+
- updated `get_all_components` tool to return a more accurate list of all available components ([beb2a5ea7](https://github.com/Adyen/bento/commit/beb2a5ea7))
|
|
42
|
+
|
|
43
|
+
Co-authored-by: Gerald Campbell <gerald.campbell@adyen.com>
|
|
44
|
+
- added AI SKILL and command to install it through `@adyen/bento-mcp` cli command ([85f8f3c77](https://github.com/Adyen/bento/commit/85f8f3c77))
|
|
45
|
+
|
|
46
|
+
Co-authored-by: Gerald Campbell <gerald.campbell@adyen.com>
|
|
47
|
+
|
|
48
|
+
### Miscellaneous Chores
|
|
49
|
+
|
|
50
|
+
- updated `@adyen/bento-mcp` deps ([7681bc265](https://github.com/Adyen/bento/commit/7681bc265))
|
|
51
|
+
|
|
52
|
+
### ❤️ Thank You
|
|
53
|
+
|
|
54
|
+
- daver
|
|
55
|
+
- Gerald Campbell
|
|
56
|
+
|
|
57
|
+
|
|
3
58
|
## 0.1.4 (2026-03-25)
|
|
4
59
|
|
|
5
60
|
This was a version bump only for mcp to align it with other projects, there were no code changes.
|
package/README.md
CHANGED
|
@@ -6,11 +6,15 @@ models (LLMs) to interact with Bento's codebase, documentation, and components.
|
|
|
6
6
|
## Features
|
|
7
7
|
|
|
8
8
|
- **Component Context**: Provide component definitions and usage guidelines to LLMs.
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
9
|
+
- **Improved Discovery**: Comprehensive component mapping including sub-components.
|
|
10
|
+
- **Documentation Access**: Easy access to Tailwind and Getting Started guides.
|
|
11
|
+
- **Deprecation Registry**: Query deprecated props and their alternatives.
|
|
12
|
+
- **Bento AI Skill**: A strict implementation protocol for AI agents.
|
|
11
13
|
|
|
12
14
|
## Usage
|
|
13
15
|
|
|
16
|
+
### 1. Register the MCP Server
|
|
17
|
+
|
|
14
18
|
You can use this server as a tool with various AI assistant clients that support the Model Context Protocol.
|
|
15
19
|
|
|
16
20
|
To configure the MCP server, add the following to your client's settings file:
|
|
@@ -38,6 +42,32 @@ can typically use:
|
|
|
38
42
|
|
|
39
43
|
Once configured, you can invoke the tool by its name (`bento`).
|
|
40
44
|
|
|
45
|
+
### 2. Add the Bento AI Skill
|
|
46
|
+
|
|
47
|
+
The Bento AI Skill provides a "Verify & Interpret" implementation workflow. To add it to your agent:
|
|
48
|
+
|
|
49
|
+
#### For Gemini CLI
|
|
50
|
+
|
|
51
|
+
Run the following command in your project root:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npx @adyen/bento-mcp add-skill
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
#### For Other Agents (Claude, Cursor, etc.)
|
|
58
|
+
|
|
59
|
+
We recommend using [@codemcp/agentskills](https://github.com/codemcp/agentskills):
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Install the CLI if you haven't already
|
|
63
|
+
npm install -g @codemcp/agentskills-cli
|
|
64
|
+
|
|
65
|
+
# Install the skill for your preferred agent
|
|
66
|
+
npx @codemcp/agentskills-cli install --agent claude
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
41
71
|
## Available Tools
|
|
42
72
|
|
|
43
73
|
The server exposes the following tools to the language model:
|
|
@@ -52,7 +82,22 @@ Retrieves the documentation, stories, and Vue implementation for a list of compo
|
|
|
52
82
|
|
|
53
83
|
### `get_all_components`
|
|
54
84
|
|
|
55
|
-
Retrieves the
|
|
56
|
-
available in the library.
|
|
85
|
+
Retrieves the global component type definitions file that lists all available Bento components (including children). Use
|
|
86
|
+
this to understand which components are available in the library.
|
|
87
|
+
|
|
88
|
+
- **Returns:** The list of components available in Bento
|
|
89
|
+
|
|
90
|
+
### `get_deprecations`
|
|
91
|
+
|
|
92
|
+
Retrieves the Bento Deprecations Registry. Use this to find out which components, properties, or features are deprecated
|
|
93
|
+
and what are the recommended alternatives.
|
|
94
|
+
|
|
95
|
+
- **Returns:** A Markdown formatted string containing the registry of all deprecated features extracted from the source
|
|
96
|
+
code.
|
|
97
|
+
|
|
98
|
+
### `get_docs`
|
|
99
|
+
|
|
100
|
+
Retrieves specific documentation files for Bento.
|
|
57
101
|
|
|
58
|
-
- **
|
|
102
|
+
- **Arguments:** `docType` ('tailwind' | 'getting-started'): The type of documentation to retrieve.
|
|
103
|
+
- **Returns:** The content of the requested documentation file.
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: writing-bento-components
|
|
3
|
+
description:
|
|
4
|
+
Strict implementation protocol for using Bento UI components correctly, with mandatory MCP analysis, setup guidance,
|
|
5
|
+
and explicit prohibition of manual discovery.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Writing Bento Components (Refined Protocol)
|
|
9
|
+
|
|
10
|
+
This skill provides a **"Verify & Interpret"** implementation workflow for Adyen's Bento design system. It establishes
|
|
11
|
+
the Bento MCP as the **exclusive** discovery mechanism and strictly forbids manual inspection of `node_modules`.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 🛠️ 1. The Bento MCP Protocol (Mandatory Workflow)
|
|
16
|
+
|
|
17
|
+
### Step 0: Installation Guidance
|
|
18
|
+
|
|
19
|
+
If you need to install or configure Bento in a project:
|
|
20
|
+
|
|
21
|
+
- Execute `get_docs({ docType: 'getting-started' })` for the core Bento installation guide.
|
|
22
|
+
- Execute `get_docs({ docType: 'tailwind' })` if Tailwind integration is required.
|
|
23
|
+
|
|
24
|
+
### Step 1: Discovery (Check Existence)
|
|
25
|
+
|
|
26
|
+
If you are unsure if a Bento component exists or what it is called:
|
|
27
|
+
|
|
28
|
+
- **DO NOT** use `ls`, `grep`, or `read_file` on `node_modules`.
|
|
29
|
+
- **DO** execute `get_all_components()` to retrieve the official registry of components.
|
|
30
|
+
|
|
31
|
+
### Step 2: Inspection (Fetch Truth)
|
|
32
|
+
|
|
33
|
+
Once the component name is known:
|
|
34
|
+
|
|
35
|
+
- Execute `get_component(['component-name'])`.
|
|
36
|
+
- **If tools are missing:** Provide the user with the setup instructions in Section 2.
|
|
37
|
+
|
|
38
|
+
#### ⚠️ CRITICAL: Truncation & Completeness Rules
|
|
39
|
+
|
|
40
|
+
1. **One-at-a-Time Rule:** If requesting 3+ components, call `get_component` for **each component individually**. Batch
|
|
41
|
+
requests for many components often exceed output limits and result in truncated/incomplete documentation.
|
|
42
|
+
|
|
43
|
+
2. **Truncation = Failure:** If `get_component` output is truncated or shows "Output too large", treat it as a **failed
|
|
44
|
+
fetch**. You MUST re-run the tool for each missing component individually.
|
|
45
|
+
|
|
46
|
+
3. **Completeness Gate:** You are **STRICTLY PROHIBITED** from writing any Bento component code until you have
|
|
47
|
+
successfully fetched and read the full documentation (`.docs.mdx`, `.stories.ts`, `.vue`, `.types.ts`) for **EVERY**
|
|
48
|
+
Bento component you intend to use in that file.
|
|
49
|
+
|
|
50
|
+
4. **Pre-Write Checklist:** Before any `write_file` or code edit, mentally verify: _"Have I called `get_component` for
|
|
51
|
+
every Bento component in this file?"_ If the answer is no, **STOP** and fetch the missing components.
|
|
52
|
+
|
|
53
|
+
### Step 3: Constraints First (Read `.docs.mdx`)
|
|
54
|
+
|
|
55
|
+
- **DO NOT SKIM.** Look specifically for **"Do not use"** and **"Guidelines"** sections.
|
|
56
|
+
- **Rule:** If the docs say "text only," you MUST NOT use custom HTML in that slot.
|
|
57
|
+
- **Rule:** If the docs say "max 2 buttons," you MUST NOT include 3.
|
|
58
|
+
|
|
59
|
+
### Step 4: Syntax & Logic Validation
|
|
60
|
+
|
|
61
|
+
- Check `.stories.ts` for correct icon imports from `@adyen/ui-assets-icons-16`.
|
|
62
|
+
- Check `.vue` implementation for event names (e.g., `update:model-value`) and prop types.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 🚫 2. ANTI-PATTERNS (Forbidden Actions)
|
|
67
|
+
|
|
68
|
+
To prevent token waste and errors, the following actions are **STRICTLY FORBIDDEN**:
|
|
69
|
+
|
|
70
|
+
- ❌ **Manual Discovery:** Running `ls -R node_modules/@adyen/bento-*` to find components.
|
|
71
|
+
- ❌ **Type Inspection:** Trying to read `.d.ts` or `.js` files inside `node_modules`.
|
|
72
|
+
- ❌ **Icon Guessing:** Searching the filesystem for icons instead of checking `.stories.ts`.
|
|
73
|
+
- ❌ **Grep-Discovery:** Running `grep` on `node_modules` to find component exports.
|
|
74
|
+
- ❌ **Partial Implementation:** Writing code that uses Bento components you haven't fetched via `get_component`.
|
|
75
|
+
- ❌ **Scavenging Truncated Output:** Using partial information from a truncated `get_component` response instead of
|
|
76
|
+
re-fetching individually.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 🎨 3. Figma MCP Integration (Name Authority)
|
|
81
|
+
|
|
82
|
+
When using Figma MCP alongside Bento MCP:
|
|
83
|
+
|
|
84
|
+
### ⚠️ Component Name Sovereignty
|
|
85
|
+
|
|
86
|
+
Design-to-code tools (like Figma MCP) often provide **legacy or internal names** that do not match the public API:
|
|
87
|
+
|
|
88
|
+
| Figma MCP Output | Correct Bento Export |
|
|
89
|
+
| :--------------- | :------------------- |
|
|
90
|
+
| `BHeader` | `BentoHeader` |
|
|
91
|
+
| `BModal` | `BentoModal` |
|
|
92
|
+
| `BButton` | `BentoButton` |
|
|
93
|
+
| `BInput` | `BentoInputField` |
|
|
94
|
+
|
|
95
|
+
**Rule:** You MUST **ignore** component names from Figma MCP and use **ONLY** the names discovered via `get_component`
|
|
96
|
+
or `get_all_components`. The Bento MCP is the **sole authority** on component names and exports.
|
|
97
|
+
|
|
98
|
+
### Figma + Bento Workflow
|
|
99
|
+
|
|
100
|
+
1. **Figma MCP** identifies visual components in the design (e.g., header, modal, button).
|
|
101
|
+
2. **Bento MCP** `get_all_components()` to find the correct Bento component names.
|
|
102
|
+
3. **Bento MCP** `get_component(['component-name'])` for each component individually (following the **One-at-a-Time
|
|
103
|
+
Rule**).
|
|
104
|
+
4. **Implementation:** Use the names, props, and patterns from Bento MCP, not Figma MCP.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## ⚙️ 4. Bento MCP Setup
|
|
109
|
+
|
|
110
|
+
If the Bento MCP tools are not available in your environment, add the following configuration to your client:
|
|
111
|
+
|
|
112
|
+
### Configuration JSON
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"mcpServers": {
|
|
117
|
+
"bento": {
|
|
118
|
+
"type": "stdio",
|
|
119
|
+
"command": "npx",
|
|
120
|
+
"args": ["@adyen/bento-mcp@latest"]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Client Configuration Paths
|
|
127
|
+
|
|
128
|
+
- **Gemini:** `.gemini/settings.json` (Local) or `~/.gemini/settings.json` (Global)
|
|
129
|
+
- **Windsurf:** `~/.codeium/windsurf/mcp_config.json`
|
|
130
|
+
- **Claude Desktop:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
131
|
+
- **Factory Droid:** Run `droid mcp add bento -- npx @adyen/bento-mcp@latest`
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 📚 5. Immutable Documentation (Tailwind & Tokens)
|
|
136
|
+
|
|
137
|
+
The following rules are NOT available via the MCP and must be followed strictly:
|
|
138
|
+
|
|
139
|
+
### Tailwind 4 "Golden Standard" Setup
|
|
140
|
+
|
|
141
|
+
The `global.css` MUST follow this exact `@layer` order:
|
|
142
|
+
|
|
143
|
+
```css
|
|
144
|
+
@layer theme, base, components, utilities;
|
|
145
|
+
@import 'tailwindcss/theme' layer(theme);
|
|
146
|
+
@import 'tailwindcss/utilities' layer(utilities);
|
|
147
|
+
@import '@adyen/bento-tailwind';
|
|
148
|
+
@import '@adyen/bento-vue3/fonts.css';
|
|
149
|
+
@import '@adyen/bento-vue3/styles/bento';
|
|
150
|
+
@import '@adyen/bento-vue3/styles/utility';
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Design Token Semanticism
|
|
154
|
+
|
|
155
|
+
- **Alias Tokens:** (e.g., `b-color-label-critical`) **USE THESE.** Accessible via CSS variables (e.g.,
|
|
156
|
+
`var(--b-color-label-critical)`).
|
|
157
|
+
- **Definition Tokens:** (e.g., `b-color-red-600`) **DO NOT USE.**
|
|
158
|
+
- **Utility Class Pattern:** `b-{cssProp}-{direction}-{spacerAlias}` (e.g., `b-margin-top-050`).
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## 🎯 6. Tool Prioritization
|
|
163
|
+
|
|
164
|
+
1. **Primary Tool:** **Bento MCP** (`get_all_components`, `get_component`).
|
|
165
|
+
2. **Verification Tool:** **Production Code** (e.g., `wrapper.ts`).
|
|
166
|
+
3. **Last Resort Tool:** **Netlify Storybook** via Playwright. Use ONLY for complex **Templates** (Dashboard/DataGrid).
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 🩺 7. Bento Doctor (Troubleshooting)
|
|
171
|
+
|
|
172
|
+
| Issue | Resolution |
|
|
173
|
+
| :---------------------- | :------------------------------------------------------------------------------------------- |
|
|
174
|
+
| **Missing Tools** | Follow setup instructions in **Section 2**. **DO NOT** use `ls` or `grep` on `node_modules`. |
|
|
175
|
+
| **Invisible Component** | Check package match (Vue 2 vs 3) and `index.ts` initialization. |
|
|
176
|
+
| **Broken Layout** | Verify `@layer` order and check for custom HTML in strict slots. |
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## ✅ 8. Final Review Checklist
|
|
181
|
+
|
|
182
|
+
- [ ] **Discovery Check:** Did I use `get_all_components()` instead of `ls node_modules`?
|
|
183
|
+
- [ ] **Completeness Check:** Did I call `get_component` for **EVERY** Bento component I'm using?
|
|
184
|
+
- [ ] **Truncation Check:** Was any `get_component` output truncated? If yes, did I re-fetch individually?
|
|
185
|
+
- [ ] **Name Authority Check:** Am I using component names from Bento MCP (not Figma MCP)?
|
|
186
|
+
- [ ] **Constraint Check:** Did I verify the "Do not use" section in the `.docs.mdx`?
|
|
187
|
+
- [ ] **Literal Check:** Are all props using **string literals**?
|
|
188
|
+
- [ ] **Layer Check:** Is my `global.css` using the correct Tailwind 4 `@layer` order?
|
package/bin/add-skill.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { copyFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
4
|
+
import { join, dirname } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { execSync } from 'node:child_process';
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
|
|
10
|
+
// In the installed package, SKILL.md will be in the same directory as the package.json
|
|
11
|
+
// which is usually the parent of 'bin'
|
|
12
|
+
const skillSource = join(__dirname, '../SKILL.md');
|
|
13
|
+
|
|
14
|
+
if (!existsSync(skillSource)) {
|
|
15
|
+
console.error(`Error: Could not find skill file at ${skillSource}`);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
console.log('🤖 Bento AI Skill Onboarding');
|
|
20
|
+
console.log('----------------------------');
|
|
21
|
+
|
|
22
|
+
// 1. Install for Gemini CLI (Local)
|
|
23
|
+
const geminiPath = join(process.cwd(), '.gemini/skills/writing-bento-components/SKILL.md');
|
|
24
|
+
try {
|
|
25
|
+
mkdirSync(dirname(geminiPath), { recursive: true });
|
|
26
|
+
copyFileSync(skillSource, geminiPath);
|
|
27
|
+
console.log(`✅ Gemini CLI: Added to ${geminiPath}`);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
// Silently continue if Gemini install fails (e.g. not in a project root)
|
|
30
|
+
console.log(`ℹ️ Gemini CLI: Skipping local installation (ensure you are in your project root)`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 2. Support for other agents via @codemcp/agentskills
|
|
34
|
+
console.log('\n🌟 Multi-Agent Support (Claude, Cursor, etc.)');
|
|
35
|
+
try {
|
|
36
|
+
// Check if agentskills is available
|
|
37
|
+
execSync('npx @codemcp/agentskills-cli --version', { stdio: 'ignore' });
|
|
38
|
+
console.log('You can use @codemcp/agentskills-cli to install this skill for other agents.');
|
|
39
|
+
console.log(`Run: npx @codemcp/agentskills-cli install --agent claude`);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.log('To use this skill with Claude, Cursor, or other agents, we recommend @codemcp/agentskills.');
|
|
42
|
+
console.log('1. Install: npm install -g @codemcp/agentskills-cli');
|
|
43
|
+
console.log('2. Configure: agentskills install --agent claude');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log('\nFor more information, see: https://github.com/adyen/bento/blob/main/packages/mcp/README.md');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const BentoAccordionTitleSizeOptions = ['default', 'small'] as const; export type BentoAccordionTitleSize = (typeof BentoAccordionTitleSizeOptions)[number];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const BentoActionBarVariantOptions = ['default', 'confirmation'] as const; export const BentoActionBarStateOptions = ['start', 'loading', 'success', 'fail'] as const; export type BentoActionBarVariant = (typeof BentoActionBarVariantOptions)[number]; export type BentoActionBarState = (typeof BentoActionBarStateOptions)[number];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import type { BentoButtonActionObject } from '@/components/button'; export interface BentoAiTagProps { /** * The team-provided headline describing the specific AI action. */ title: string; /** * The team-provided, plain-language explanation of what the AI did, why, or its limitations. */ description: string; /** * AI influenced value shown for context. */ influencedValue?: string; /** * Whether the AI tag popover is open. */ toggled?: boolean; /** * A call-to-action link or button for users to learn more, manage settings, or provide feedback. * The `title` property in the `BentoButtonActionObject` will be used as the button text. */ action?: BentoButtonActionObject; }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/** * @deprecated for usage with properties since version 2.0. Use the string literal instead. */ export enum BentoAlertVariant { DEFAULT = 'default', TIP = 'tip', } /** * @deprecated for usage with properties since version 2.0. Use the string literal instead. */ export enum BentoAlertTypeOption { WARNING = 'warning', CRITICAL = 'critical', HIGHLIGHT = 'highlight', SUCCESS = 'success', } /** * @deprecated from version 2.0.0. Use "@close-alert" instead. */ export enum BentoAlertEvent { CLOSE_ALERT = 'close-alert', }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { type AnchorScrollerListItem, type AnchorScrollerListProps, } from './components/anchor-scroller-list/anchor-scroller-list.types'; export type BentoAnchorScrollerItem = AnchorScrollerListItem; export interface BentoAnchorScrollerProps { /** * The index of the currently active item. Can be used to programmatically set the * active item. * @default undefined */ activeIndex?: AnchorScrollerListProps['activeIndex']; /** * An array of objects to define the navigation links. Each object must have a * `label` (string), an `elementRef` (Vue ref to an element), and an optional * `disabled` (boolean) property. */ items: AnchorScrollerListProps['items']; }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { type VNodeRef } from 'vue/types/vnode'; export interface AnchorScrollerListItem { disabled?: boolean; elementRef: Exclude<VNodeRef, 'string'>; title: string; } export interface AnchorScrollerListProps { activeIndex?: number; items: Array<AnchorScrollerListItem>; scrollOffset?: number; }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export enum BentoAvatarImageVariant { LARGE = 'large', SMALL = 'small', } export enum BentoAvatarImageColor { BLUE = 'blue', GREEN = 'green', RED = 'red', YELLOW = 'yellow', }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/** * @deprecated for usage with properties since version 2.0. Use the string literal instead. */ export enum BentoButtonVariant { PRIMARY = 'primary', SECONDARY = 'secondary', TERTIARY = 'tertiary', TERTIARY_WITH_BACKGROUND = 'tertiary-with-background', } export enum BentoButtonPropClass { CONDENSED = 'condensed', DESTRUCTIVE = 'critical', DISABLED = 'disabled', ICON_ONLY = 'icon-only', INVERSE = 'inverse', } export interface BentoButtonProps { condensed?: boolean; critical?: boolean; disabled?: boolean; inverse?: boolean; variant?: BentoButtonVariant | `${BentoButtonVariant}`; type?: string; link?: object; }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { type BentoButtonProps } from '../../button.types'; export interface BentoAiButtonProps { /** * Reduces size of the button */ condensed?: BentoButtonProps['condensed']; /** * Disables button functionality */ disabled?: BentoButtonProps['disabled']; /** * Sets color set to inverse */ inverse?: BentoButtonProps['inverse']; /** * Object containing props passed on to the BentoLink component. * * @see BentoLink documentation for which properties you can pass. */ link?: BentoButtonProps['link']; /** * The default behavior of the button. * Possible values are: 'button', 'reset', 'submit' */ type?: BentoButtonProps['type']; }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import type { BentoButtonProps } from '../../button.types'; import type { BentoMenuProps } from '@/components/menu/menu.types'; import type { BentoLoadingButtonState } from '../loading-button/loading-button.types'; import type { VueNodeElement } from '@/types/elements'; import type { OmitStrict } from '@/types/omit-strict'; import type { VNodeRef } from 'vue/types/vnode'; export type BentoButtonActionObject = BentoActionButton; // TODO: Update to Array<BentoButtonActionButton | BentoButtonActionMenuObject> in v2.0.0 export type BentoButtonActionsList = Array<BentoActionButton & BentoActionMenu>; export enum BentoButtonActionsLayoutBasic { BUTTONS_END = 'buttons-end', FILL_CONTAINER = 'fill-container', SPACE_BETWEEN = 'space-between', VERTICAL_STACK = 'vertical-stack', } export enum BentoButtonActionsLayoutExtended { BUTTONS_START = 'buttons-start', } /** * @deprecated for usage with properties since version 2.0. Use the string literal instead. */ export const BentoButtonActionsLayout = { ...BentoButtonActionsLayoutBasic, ...BentoButtonActionsLayoutExtended }; export type BentoButtonActionsLayout = BentoButtonActionsLayoutBasic | BentoButtonActionsLayoutExtended; export interface BentoButtonActionsProps { /** * 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: 'secondary', * critical: true * }] * ``` */ actions: BentoButtonActionsList; /** * Sets the Button Actions to color scheme inverse */ inverse?: boolean; /** * Defines the layout in which the button actions is presented. * It can be one of: * * @values BUTTONS_START * @values BUTTONS_END * @values FILL_CONTAINER * @values SPACE_BETWEEN * @values VERTICAL_STACK */ layout?: string; } /** * Private */ /** * Base interface for the Button and Menu objects */ export interface BentoButtonActionBase { title: string; icon?: VueNodeElement; iconLeft?: VueNodeElement; iconRight?: VueNodeElement; /** * Provides a template ref to the underlying component instance. */ elementRef?: Exclude<VNodeRef, string>; } /** * Type for the Buttons passed as objects to Button Actions */ export interface BentoActionButton extends BentoButtonActionBase, BentoButtonProps { event?: (event: Event) => void; state?: BentoLoadingButtonState | `${BentoLoadingButtonState}`; iconOnly?: boolean; } /** * Type for the Menus passed as objects to Button Actions */ export type BentoActionMenu = BentoButtonActionBase & OmitStrict<BentoMenuProps, 'button' | 'data'> & Partial<Pick<BentoMenuProps, 'data'>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export enum BentoLoadingButtonState { START = 'start', LOADING = 'loading', SUCCESS = 'success', FAIL = 'fail', } export type BentoLoadingButtonIconState = Partial<{ [key in BentoLoadingButtonState]: string }>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type BentoToggleState = 'default' | 'toggled';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/** * @deprecated for usage with properties since version 2.0. Use the string literal instead. */ export enum BentoCardBackground { PRIMARY = 'primary', SECONDARY = 'secondary', } /** * @deprecated for usage with properties since version 2.0. Use the string literal instead. */ export enum BentoCardTitleSize { DEFAULT = 'default', SMALL = 'small', }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import type { BentoTagProps } from '../tag/tag.types'; import { CheckboxInputState as BentoCheckboxState, type CheckboxInputType as BentoCheckboxType, type MultiCheckboxInputType as BentoMultiCheckboxType, } from '@/internal/checkbox-input/checkbox-input.types'; export { BentoCheckboxState, BentoCheckboxType, BentoMultiCheckboxType }; export enum BentoCheckboxEvent { UPDATE = 'update:model-value', INPUT = 'input', } export type BentoCheckboxTag = BentoTagProps;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { type FormFieldEmits } from '../../../../types/form-field'; import type { BentoCheckboxTag } from '../../checkbox.types'; /** * @deprecated for usage with properties since version 2.0. Use the string literal instead. */ export enum BentoCheckboxGroupVariant { HORIZONTAL = 'horizontal', VERTICAL = 'vertical', } export interface BentoCheckboxGroupItem { value: string | number; label: string; description?: string; disabled?: boolean; hasError?: boolean; errorMessage?: string; readonly?: boolean; tag?: BentoCheckboxTag; } export type BentoCheckboxGroupItems = Array<BentoCheckboxGroupItem>; export type BentoCheckboxGroupEmits = FormFieldEmits<any>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export interface BentoChipProps { /** * The text content displayed within the chip. */ label: string; /** * If true, disables user interaction with the chip. */ disabled?: boolean; /** * If true, makes the chip's content readonly, preventing user modification. */ readonly?: boolean; /** * If true, displays the chip in an error state. */ error?: boolean; /** * If true, reduces the size of the chip. */ condensed?: boolean; /** * Limits the number of characters displayed in the chip. Additional characters will be truncated. */ characterLimit?: number; }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/** * @deprecated for usage with properties since version 2.0. Use the string literal instead. */ export enum BentoCodeSnippetVariant { INLINE = 'inline', SINGLELINE = 'singleline', MULTILINE = 'multiline', } /** * @deprecated for usage with properties since version 2.0. Use the string literal instead. */ export enum BentoCodeSnippetSupportedLanguage { JSON = 'json', XML = 'xml', JAVA = 'java', JAVASCRIPT = 'javascript', PYTHON = 'python', CSV = 'csv', } export enum BentoCodeSnippetEvent { ACTION = 'action', CHANGE = 'change', } export interface BentoCodeSnippetProps { /** * Displays a button that when clicked will emit an action event * Leaves to the parent component the logic of what to do with it */ actionable?: boolean; /** * Displays a button that when clicked will emit a run event * Leaves to the parent component the logic of what to do with it */ actionableText?: string; /** * The code content */ content?: string; /** * Displays a button that can expand the codeblock into a modal to easily * view large blocks of code. */ expandable?: boolean; /** * Allows editing of the code-snippet content by the user */ editable?: boolean; /** * Language name for syntax highlighting rules */ lang?: BentoCodeSnippetSupportedLanguage | `${BentoCodeSnippetSupportedLanguage}`; /** * Label to show in the action-bar, describing the language */ langLabel?: string; /** * Toggles the loading indicator within the action bar */ loading?: boolean; /** * Defines the variant of code-snippet */ variant?: BentoCodeSnippetVariant | `${BentoCodeSnippetVariant}`; }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/** * @deprecated for usage with properties since version 2.0. Use the string literal instead. */ export enum BentoCountryVariant { ISO = 'iso', NAME = 'name', PHONE_CODE = 'phone_code', CAPITAL = 'capital', /** deprecated Use any of the other BentoCountry variants instead OR BentoTypography component for custom text */ CUSTOM = 'custom', } export enum BentoCountryCode { BD = 'BD', BE = 'BE', BF = 'BF', BG = 'BG', BA = 'BA', BB = 'BB', WF = 'WF', BL = 'BL', BM = 'BM', BN = 'BN', BO = 'BO', BH = 'BH', BI = 'BI', BJ = 'BJ', BT = 'BT', JM = 'JM', BV = 'BV', BW = 'BW', WS = 'WS', BQ = 'BQ', BR = 'BR', BS = 'BS', JE = 'JE', BY = 'BY', BZ = 'BZ', RU = 'RU', RW = 'RW', RS = 'RS', TL = 'TL', RE = 'RE', TM = 'TM', TJ = 'TJ', RO = 'RO', TK = 'TK', GW = 'GW', GU = 'GU', GT = 'GT', GS = 'GS', GR = 'GR', GQ = 'GQ', GP = 'GP', JP = 'JP', GY = 'GY', GG = 'GG', GF = 'GF', GE = 'GE', GD = 'GD', GB = 'GB', GA = 'GA', SV = 'SV', GN = 'GN', GM = 'GM', GL = 'GL', GI = 'GI', GH = 'GH', OM = 'OM', TN = 'TN', JO = 'JO', HR = 'HR', HT = 'HT', HU = 'HU', HK = 'HK', HN = 'HN', HM = 'HM', VE = 'VE', PR = 'PR', PS = 'PS', PW = 'PW', PT = 'PT', SJ = 'SJ', PY = 'PY', IQ = 'IQ', PA = 'PA', PF = 'PF', PG = 'PG', PE = 'PE', PK = 'PK', PH = 'PH', PN = 'PN', PL = 'PL', PM = 'PM', ZM = 'ZM', EH = 'EH', EE = 'EE', EG = 'EG', ZA = 'ZA', EC = 'EC', IT = 'IT', VN = 'VN', SB = 'SB', ET = 'ET', SO = 'SO', ZW = 'ZW', SA = 'SA', ES = 'ES', ER = 'ER', ME = 'ME', MD = 'MD', MG = 'MG', MF = 'MF', MA = 'MA', MC = 'MC', UZ = 'UZ', MM = 'MM', ML = 'ML', MO = 'MO', MN = 'MN', MH = 'MH', MK = 'MK', MU = 'MU', MT = 'MT', MW = 'MW', MV = 'MV', MQ = 'MQ', MP = 'MP', MS = 'MS', MR = 'MR', IM = 'IM', UG = 'UG', TZ = 'TZ', MY = 'MY', MX = 'MX', IL = 'IL', FR = 'FR', IO = 'IO', SH = 'SH', FI = 'FI', FJ = 'FJ', FK = 'FK', FM = 'FM', FO = 'FO', NI = 'NI', NL = 'NL', NO = 'NO', NA = 'NA', VU = 'VU', NC = 'NC', NE = 'NE', NF = 'NF', NG = 'NG', NZ = 'NZ', NP = 'NP', NR = 'NR', NU = 'NU', CK = 'CK', XK = 'XK', CI = 'CI', CH = 'CH', CO = 'CO', CN = 'CN', CM = 'CM', CL = 'CL', CC = 'CC', CA = 'CA', CG = 'CG', CF = 'CF', CD = 'CD', CZ = 'CZ', CY = 'CY', CX = 'CX', CR = 'CR', CW = 'CW', CV = 'CV', CU = 'CU', SZ = 'SZ', SY = 'SY', SX = 'SX', KG = 'KG', KE = 'KE', SS = 'SS', SR = 'SR', KI = 'KI', KH = 'KH', KN = 'KN', KM = 'KM', ST = 'ST', SK = 'SK', KR = 'KR', SI = 'SI', KP = 'KP', KW = 'KW', SN = 'SN', SM = 'SM', SL = 'SL', SC = 'SC', KZ = 'KZ', KY = 'KY', SG = 'SG', SE = 'SE', SD = 'SD', DO = 'DO', DM = 'DM', DJ = 'DJ', DK = 'DK', VG = 'VG', DE = 'DE', YE = 'YE', DZ = 'DZ', US = 'US', UY = 'UY', YT = 'YT', UM = 'UM', LB = 'LB', LC = 'LC', LA = 'LA', TV = 'TV', TW = 'TW', TT = 'TT', TR = 'TR', LK = 'LK', LI = 'LI', LV = 'LV', TO = 'TO', LT = 'LT', LU = 'LU', LR = 'LR', LS = 'LS', TH = 'TH', TF = 'TF', TG = 'TG', TD = 'TD', TC = 'TC', LY = 'LY', VA = 'VA', VC = 'VC', AE = 'AE', AD = 'AD', AG = 'AG', AF = 'AF', AI = 'AI', VI = 'VI', IS = 'IS', IR = 'IR', AM = 'AM', AL = 'AL', AO = 'AO', AQ = 'AQ', AS = 'AS', AR = 'AR', AU = 'AU', AT = 'AT', AW = 'AW', IN = 'IN', AX = 'AX', AZ = 'AZ', IE = 'IE', ID = 'ID', UA = 'UA', QA = 'QA', MZ = 'MZ', UNKNOWN = 'ZZ', } export interface BentoCountryProps { /** * Two character country code ([ISO 3166-1 alpha-2 format](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)). */ code?: BentoCountryCode | `${BentoCountryCode}`; /** * Custom label text. */ label?: string; /** * Which label variant to display. * @values iso, name, phone_code, capital */ variant?: BentoCountryVariant | `${BentoCountryVariant}`; }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export interface BentoCurrencyProps { /** * Currency code based on the ISO 4217 standard */ currency?: BentoCurrencyISOCode | `${BentoCurrencyISOCode}`; /** * Disable the default typography for the component. Only use this when the component is inside another typography component. */ disableTypography?: boolean; /** * Accepts currency value in major units instead of minor ones */ majorUnits?: boolean; /** * Currency value to be formatted */ value?: number; /** * Determines how the currency symbol and negative values are displayed. * This is only applicable to certain countries such as `en-US`. * * - `'standard'`: Default format (e.g., `-1,234.56 USD`). * - `'accounting'`: Uses accounting conventions, such as wrapping negative numbers in parentheses (e.g., `(1,234.56) USD`). * * @default 'standard' */ currencySign?: Intl.NumberFormatOptions['currencySign']; } export enum BentoCurrencyISOCode { AED = 'AED', AFA = 'AFA', ALL = 'ALL', AMD = 'AMD', ANG = 'ANG', AOA = 'AOA', ARS = 'ARS', AUD = 'AUD', AWG = 'AWG', AZN = 'AZN', BAM = 'BAM', BBD = 'BBD', BDT = 'BDT', BEF = 'BEF', BGN = 'BGN', BHD = 'BHD', BIF = 'BIF', BMD = 'BMD', BND = 'BND', BOB = 'BOB', BRL = 'BRL', BSD = 'BSD', BTC = 'BTC', BTN = 'BTN', BWP = 'BWP', BYR = 'BYR', BZD = 'BZD', CAD = 'CAD', CDF = 'CDF', CHF = 'CHF', CLF = 'CLF', CLP = 'CLP', CNY = 'CNY', COP = 'COP', CRC = 'CRC', CUC = 'CUC', CVE = 'CVE', CZK = 'CZK', DEM = 'DEM', DJF = 'DJF', DKK = 'DKK', DOP = 'DOP', DZD = 'DZD', EEK = 'EEK', EGP = 'EGP', ERN = 'ERN', ETB = 'ETB', EUR = 'EUR', FJD = 'FJD', FKP = 'FKP', GBP = 'GBP', GEL = 'GEL', GHS = 'GHS', GIP = 'GIP', GMD = 'GMD', GNF = 'GNF', GRD = 'GRD', GTQ = 'GTQ', GYD = 'GYD', HKD = 'HKD', HNL = 'HNL', HRK = 'HRK', HTG = 'HTG', HUF = 'HUF', IDR = 'IDR', ILS = 'ILS', INR = 'INR', IQD = 'IQD', IRR = 'IRR', ISK = 'ISK', ITL = 'ITL', JMD = 'JMD', JOD = 'JOD', JPY = 'JPY', KES = 'KES', KGS = 'KGS', KHR = 'KHR', KMF = 'KMF', KPW = 'KPW', KRW = 'KRW', KWD = 'KWD', KYD = 'KYD', KZT = 'KZT', LAK = 'LAK', LBP = 'LBP', LKR = 'LKR', LRD = 'LRD', LSL = 'LSL', LTC = 'LTC', LTL = 'LTL', LVL = 'LVL', LYD = 'LYD', MAD = 'MAD', MDL = 'MDL', MGA = 'MGA', MKD = 'MKD', MMK = 'MMK', MNT = 'MNT', MOP = 'MOP', MRO = 'MRO', MRU = 'MRU', MUR = 'MUR', MVR = 'MVR', MWK = 'MWK', MXN = 'MXN', MYR = 'MYR', MZM = 'MZM', NAD = 'NAD', NGN = 'NGN', NIO = 'NIO', NOK = 'NOK', NPR = 'NPR', NZD = 'NZD', OMR = 'OMR', PAB = 'PAB', PEN = 'PEN', PGK = 'PGK', PHP = 'PHP', PKR = 'PKR', PLN = 'PLN', PYG = 'PYG', QAR = 'QAR', RON = 'RON', RSD = 'RSD', RUB = 'RUB', RWF = 'RWF', SAR = 'SAR', SBD = 'SBD', SCR = 'SCR', SDG = 'SDG', SEK = 'SEK', SGD = 'SGD', SHP = 'SHP', SKK = 'SKK', SLL = 'SLL', SOS = 'SOS', SRD = 'SRD', SSP = 'SSP', STD = 'STD', SVC = 'SVC', SYP = 'SYP', SZL = 'SZL', THB = 'THB', TJS = 'TJS', TMT = 'TMT', TND = 'TND', TOP = 'TOP', TRY = 'TRY', TTD = 'TTD', TWD = 'TWD', TZS = 'TZS', UAH = 'UAH', UGX = 'UGX', USD = 'USD', UYU = 'UYU', UZS = 'UZS', VEF = 'VEF', VND = 'VND', VUV = 'VUV', WST = 'WST', XAF = 'XAF', XCD = 'XCD', XDR = 'XDR', XOF = 'XOF', XPF = 'XPF', YER = 'YER', ZAR = 'ZAR', ZMK = 'ZMK', ZWL = 'ZWL', }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import type { BentoTooltipPosition } from '../internal/tooltip/tooltip.types'; import type { BentoPopoverPositions } from '@/components/popover/popover.types'; import type { BentoTeleportProps } from '../internal/teleport/teleport.types'; export type BentoDashedUnderlineTeleport = BentoTeleportProps; export interface BentoDashedUnderlineProps { /** * Text showed in the popover on hover */ popoverText?: string; /** * Title showed in the popover on hover */ popoverTitle?: string; /** * Position the popover should take if space is available */ popoverPosition?: BentoPopoverPositions | `${BentoPopoverPositions}`; /** * The size of the popover */ popoverSize?: 'default' | 'fit-content' | 'large' | 'small'; /** * Teleports the component outside of the parent container into * the target "to" element */ teleport?: BentoDashedUnderlineTeleport; /** * 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}`; }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { type BentoColumn } from '../data-grid-columns/data-grid-columns.types'; export enum DataGridCellPropClass { ACTION_COL_NESTED_CONTENT_AND_SELECTION_ENABLED = 'action-col-nested-content-and-selection-enabled', ACTION_COL_NESTED_CONTENT_ENABLED = 'action-col-nested-content-enabled', ACTION_COL_SELECTION_ENABLED = 'action-col-selection-enabled', COLUMN_HOVERED = 'column-hovered', COLUMN_HOVERED_NO_BORDER_LEFT = 'column-hovered-no-border-left', COLUMN_HOVERED_NO_BORDER_RIGHT = 'column-hovered-no-border-right', CONDENSED = 'condensed', FROZEN = 'frozen', IS_COLUMN_REORDERING = 'is-column-re-ordering', IS_COLUMN_REORDERING_TARGET_LEFT = 'is-column-re-order-target-left', IS_COLUMN_REORDERING_TARGET_RIGHT = 'is-column-re-order-target-right', LAST_FROZEN_COLUMN_CELL = 'last-frozen-column-cell', NESTED_CONTENT_ENABLED = 'nested-content-toggle-enabled', NUMERIC = 'numeric', OVERFLOW_ELLIPSIS = 'overflow-ellipsis', PADDING_LEFT_UNSET = 'padding-left-unset', PADDING_RIGHT_UNSET = 'padding-right-unset', SLASHED_ZERO = 'slashed-zero', } export interface DataGridCellDragEvents { dragenter?: (e: DragEvent) => void; drop?: () => void; dragover?: (e: DragEvent) => void; } export type DataGridCellDragEventsForColumn = (column: BentoColumn) => { dragenter?: (e: DragEvent) => void; drop?: () => void; dragover?: (e: DragEvent) => void; }; export interface DataGridCellColumnSet { columnSet: Array<BentoColumn>; id: string; isFrozenColumns?: boolean; } export interface DataGridCellEvents extends DataGridCellDragEvents { keyup?: (event: KeyboardEvent) => void; keydown?: (event: KeyboardEvent) => void; mouseenter?: () => void; mouseleave?: (e: MouseEvent) => void; focus?: (e: FocusEvent) => void; focusout?: (e: FocusEvent) => void; } export type DataGridCellEventsForColumn = (column: BentoColumn) => DataGridCellEvents;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<template> <div :key="`cell-${column.field}`" ref="gridcellRef" :aria-hidden="ariaHidden" :data-testid="`cell-${column.field}`" :data-cellindex="getCellIndex(rowIndex, colIndex, columnSetIndex)" class="b-data-grid-cell" :class="conditionalRowCellClasses(column)" role="gridcell" :tabindex="tabIndex" :aria-colindex="getColIndex(colIndex, columnSetIndex) + 1" :style="{ width: column.autoWidth && isMeasuringColumnWidths ? 'auto' : `${column.width}px`, }" v-on="getGridcellEvents(column)" > <template v-if="column.field === DATAGRID_ACTIONS_COLUMN_FIELD_NAME"> <template v-if="selectable"> <bento-checkbox class="b-data-grid-cell__select-cell" :aria-label="t('selectRow')" :disabled="isDataItemDisabled(rowData)" :indeterminate="selectionIsIndeterminate" :model-value="selectedItems" :value="getDataItemId(rowData)" :tabindex="isFocused ? 0 : -1" @update:model-value="$emit('select-row', $event)" /> </template> <template v-if="nestedContent"> <bento-toggle-button ref="menuButtonRef" aria-haspopup="true" :aria-controls="controlledNestedRowElementIds" condensed variant="tertiary" :toggled="isNestedContentExpanded" @click="toggleNestedContent" > <template #iconLeft> <chevron-up-icon v-if="isNestedContentExpanded" class="b-accordion-item__icon" :svg-title="t('collapseNestedContent')" /> <chevron-down-icon v-else class="b-accordion-item__icon" :svg-title="t('expandNestedContent')" /> </template> </bento-toggle-button> </template> </template> <template v-else> <bento-typography el="div" class="b-data-grid-cell__cell-content" :class="computedCellContentClasses" data-testid="cell-content" > <slot :item="rowData" :row-index="rowIndex" :name="`item-${column.field}`"> <span :title="conditionalTitleAttribute(column, rowData[column.field])">{{ getRowData(rowData[column.field]) }}</span> </slot> </bento-typography> <div v-if="column.cellActions?.length > 0" class="b-data-grid-cell__cell-actions"> <data-grid-cell-actions v-if="(shouldShowCellActions || isTouchDevice) && (hasRowData || hasSlot(`item-${column.field}`))" ref="cellActionsRef" :cell-actions="column.cellActions" :column-key="column.field" :row-data-item="rowData" :has-zebra-background="hasZebraBackground" :is-highlighted="isHighlighted" :is-selected="isSelected" teleport-menu @menu-item-click="onMenuClose" /> </div> </template> </div> </template> <script setup lang="ts"> import { computed, type ComputedRef, inject, nextTick, onMounted, type PropType, provide, type Ref, ref, type UnwrapRef, useSlots, watch, } from 'vue'; import { focusOnInteractiveChild, makeAllInteractiveChildrenFocusable, makeAllInteractiveChildrenUnFocusable, } from '../../utils'; import { DATAGRID_ACTIONS_COLUMN_FIELD_NAME } from '../../composables/use-calculate-column-width'; import { BentoCheckbox } from '@/components/checkbox'; import { BentoTypography } from '@/components/typography'; import { BentoToggleButton } from '@/components/button'; import DataGridCellActions from '../data-grid-cell-actions/data-grid-cell-actions.vue'; import { DATA_GRID_SLASHED_ZERO, DATA_GRID_SMALL_CONTAINER, DATA_GRID_TOUCH_DEVICE } from '../../data-grid.keys'; import ChevronDownIcon from '@adyen/ui-assets-icons-16/vue/chevron-down'; import ChevronUpIcon from '@adyen/ui-assets-icons-16/vue/chevron-up'; import { DATA_GRID_CELL_MENU_REGISTERING_INJECTION_KEY } from '@/components/data-grid/components/data-grid-cell/data-grid-cell.keys'; // Types and enums import { type BentoColumn, BentoColumnOverflow, type BentoDatagridDataItem, type BentoDatagridDataItemId, type BentoDatagridGetDataItemIdFn, type BentoDatagridIsDataItemDisabledFn, } from '@/components/data-grid/data-grid.types'; import { type DataGridCellColumnSet, type DataGridCellDragEventsForColumn, type DataGridCellEvents, type DataGridCellEventsForColumn, DataGridCellPropClass, } from './data-grid-cell.types'; import type { BentoDatagridDraggingColumnState } from '../data-grid-columns/data-grid-columns.types'; import type { DatagridColumnHoveringState } from '@/components/data-grid/composables/use-column-hovering/use-column-hovering.types'; // Utils import { useHasSlot } from '@/composables'; import { useI18n } from '@/utils/ts/i18n'; import { isFocusVisible } from '@/utils/ts/focus-visible'; import { EventKey } from '@/types/utils-events'; // Translations import messages from './messages.json'; const slots = useSlots(); const hasSlot = useHasSlot(slots); type MessageSchema = (typeof messages)['en-US']; const { t } = useI18n<{ message: MessageSchema }>({ messages }); const props = defineProps({ draggingEventsForRowCell: { type: Function as PropType<DataGridCellDragEventsForColumn>, required: true, }, /** * The columns sets including */ columnSets: { type: Array as PropType<Array<DataGridCellColumnSet>>, required: true, }, /** * The columns set we are iterating over */ column: { type: Object as PropType<BentoColumn>, required: true, }, colIndex: { type: Number, required: true, }, columnSetIndex: { type: Number, required: true, }, /** * Sets the row cells to the condensed padding state. */ condensed: { type: Boolean, default: false, }, /** * Columns being dragged, contains dragging column and a target column */ draggingColumns: { type: Object as PropType<BentoDatagridDraggingColumnState>, default: undefined, }, /** * A customisable method to retrieve a unique identifier for a data item in the array of data supplied. * This is used selecting and performance reasons and must exist in each data item. */ getDataItemId: { type: Function as PropType<BentoDatagridGetDataItemIdFn>, default: (item: BentoDatagridDataItem) => item.id, }, /** * Set to true if the cell has a darker background when zebra rows is enabled. */ hasZebraBackground: { type: Boolean, default: false, }, /** * Set to true if the row is selected. */ isSelected: { type: Boolean, default: false, }, /** * Set to true if the row is highlighted. */ isHighlighted: { type: Boolean, default: false, }, /** * The column hovered over state and whether the hovered over column should show a border right or left. */ hoveredOverColumnState: { type: Object as PropType<DatagridColumnHoveringState>, required: true, }, /** * A customisable method to determine if a row is not selectable. * The default is that every row is selectable. */ isDataItemDisabled: { type: Function as PropType<BentoDatagridIsDataItemDisabledFn>, default: () => false, }, isMeasuringColumnWidths: { type: Boolean, default: false, }, /** * Determines if the nested content is visible. */ isNestedContentExpanded: { type: Boolean, default: false, }, /** * Determines if the nest content slot is enabled for this data row. */ nestedContent: { type: Boolean, default: false, }, /** * The IDs of the rows this cell controls to show / hide them. */ nestedRowsElementIds: { type: Array as PropType<Array<string>>, default: () => [], }, /** * The row data object */ rowData: { type: Object as PropType<BentoDatagridDataItem>, required: true, }, rowIndex: { type: Number, required: true, }, /** * The row selection checkbox indeterminate state. */ selectionIsIndeterminate: { type: Boolean, default: false, }, /** * Determines if the row selection is enabled. */ selectable: { type: Boolean, default: false, }, selectedItems: { type: Array as PropType<Array<BentoDatagridDataItemId>>, required: true, }, }); const emit = defineEmits<{ /** * Emitted when an a frozen column cell fires a key up or down event. */ (e: 'on-frozen-columns-key-press', event: Event); /** * Emitted when a row has been selected. */ (e: 'select-row', value: Array<BentoDatagridDataItemId>); /** * Emitted when a row has been selected. */ (e: 'register-row-cell-element', el: Element, field: string, rowIndex: number); /** * Emitted when a cell has been hovered over. This is used to keep the row in a hovered state when hovering over a menu. */ (e: 'cell-hovered', value: number); /** * Emitted when nested content is being toggled. */ (e: 'nested-content-toggled'); /** * Emitted when a cell gains focus. */ ( e: 'cell-focus', value: { rowData: BentoDatagridDataItem; column: BentoColumn; rowIndex: number; colIndex: number } ); }>(); // References const gridcellRef = ref<HTMLDivElement | null>(null); const cellActionsRef = ref<InstanceType<typeof DataGridCellActions>>(null); const shouldShowCellActions = ref(false); const childrenMenuContainerElements = ref<Array<Ref<UnwrapRef<HTMLDivElement>>>>([]); const isFocused = ref(false); const focusableItems = ref<Array<{ node: HTMLElement }>>(); const hasEverBeenFocused = ref(false); // Computed const hasRowData = computed(() => !!props.rowData?.[props.column.field]); const controlledNestedRowElementIds = computed(() => props.column.field === DATAGRID_ACTIONS_COLUMN_FIELD_NAME && props.nestedRowsElementIds?.length > 0 ? props.nestedRowsElementIds.join(' ') : undefined ); const ariaHidden = computed( () => props.column.field === DATAGRID_ACTIONS_COLUMN_FIELD_NAME && !props.selectable && !props.nestedContent ); const tabIndex = computed(() => { if (!ariaHidden.value) { // The first cell of the grid should be tabbable on initial render to allow keyboard navigation into the grid. if (getCellIndex(props.rowIndex, props.colIndex, props.columnSetIndex) === 0 && !hasEverBeenFocused.value) { return '0'; } // A cell becomes part of the tab order only when it is focused. if (isFocused.value) { return '0'; } } // Action cells are not directly tabbable; they are accessed via cell navigation. if (props.column.field === DATAGRID_ACTIONS_COLUMN_FIELD_NAME) { return '-1'; } // By default, cells are not in the tab order. return '-1'; }); // Row data retrieval methods const conditionalTitleAttribute = (column: BentoColumn, content: unknown) => column?.overflow === BentoColumnOverflow.ELLIPSIS ? `${content}` : undefined; const getRowData = (rowData: unknown) => rowData ?? '-'; // Cell and Columns index calculation const sumColumnAmountsInColumnSets = (limitIndex?: number) => props.columnSets.slice(0, limitIndex).reduce((total, { columnSet }) => total + columnSet.length, 0); // Sums the amount of columns on every previous column set to find // the absolute column index (useful for frozen columns use case) const getColIndex = (colIndex: number, colSetIndex: number) => colIndex + sumColumnAmountsInColumnSets(colSetIndex); const getCellIndex = (rowIndex: number, colIndex: number, colSetIndex: number) => sumColumnAmountsInColumnSets() * rowIndex + getColIndex(colIndex, colSetIndex); /** * We check here if we are leaving the cell but mouse into a child menu * If this is the case we don't want to hide the cell actions. * @param relatedTarget */ const isLeavingCellFocus = (relatedTarget: EventTarget) => { if ( relatedTarget === null || (!gridcellRef.value.contains(relatedTarget as Node) && !childrenMenuContainerElements.value ?.map(registeredMenuRef => registeredMenuRef.value) .some(menuElement => menuElement === relatedTarget || menuElement?.contains(relatedTarget as Node))) ) { shouldShowCellActions.value = false; } }; /** * Hides the cell actions when a menu item is clicked. This is necessary as relying solely on * focus-out events is not reliable, especially when the menu is teleported or an action * causes focus to leave the window. */ const onMenuClose = () => { shouldShowCellActions.value = false; }; // Events const hasInteractiveElFocusedInside = ref(false); const getGridcellEvents: DataGridCellEventsForColumn = (column: BentoColumn) => { const defaultEvents: DataGridCellEvents = { ...props.draggingEventsForRowCell(column), // Focus on the first interactive child in the grid cell if one exists focus: async () => { if (!isFocusVisible()) { return; } isFocused.value = true; hasEverBeenFocused.value = true; emit('cell-focus', { rowData: props.rowData, column: props.column, rowIndex: props.rowIndex, colIndex: getColIndex(props.colIndex, props.columnSetIndex), }); makeAllInteractiveChildrenFocusable(focusableItems.value); await nextTick(); const hasFocusedOnInteractiveChild = focusOnInteractiveChild(gridcellRef.value); if (hasFocusedOnInteractiveChild) { hasInteractiveElFocusedInside.value = true; } }, focusout: () => { if (!isFocusVisible()) { return; } hasInteractiveElFocusedInside.value = false; }, keydown: (event: KeyboardEvent) => { if (event.key !== EventKey.TAB) { hasInteractiveElFocusedInside.value = false; isFocused.value = false; makeAllInteractiveChildrenUnFocusable(gridcellRef.value); } }, }; const gridCellEvents: DataGridCellEvents = { ...defaultEvents }; if (column.frozen) { gridCellEvents.keyup = (event: Event) => emit('on-frozen-columns-key-press', event); gridCellEvents.keydown = (event: KeyboardEvent) => { defaultEvents.keydown(event); emit('on-frozen-columns-key-press', event); }; } if (column.cellActions) { gridCellEvents.mouseenter = () => { shouldShowCellActions.value = true; }; gridCellEvents.mouseleave = (e: MouseEvent) => { isLeavingCellFocus(e?.relatedTarget); }; gridCellEvents.focus = async (e: FocusEvent) => { defaultEvents.focus(e); await nextTick(); shouldShowCellActions.value = true; }; gridCellEvents.focusout = (e: FocusEvent) => { defaultEvents.focusout(e); isLeavingCellFocus(e?.relatedTarget); }; } return gridCellEvents; }; onMounted(() => { focusableItems.value = makeAllInteractiveChildrenUnFocusable(gridcellRef.value); }); const toggleNestedContent = () => { emit('nested-content-toggled'); }; // Each cell knows it's on hover state but this state needs to be emitted up // in order for the DataGrid to know which row to set the hovered state on. watch( () => shouldShowCellActions.value, () => { if (shouldShowCellActions.value === true) { emit('cell-hovered', props.rowIndex); } else { emit('cell-hovered', -1); } } ); const registerMenuContainerElement = (menuContainerElement: Ref<UnwrapRef<HTMLDivElement>>) => { childrenMenuContainerElements.value.push(menuContainerElement); }; const menuMouseLeave = (e: MouseEvent) => { if (!gridcellRef.value.contains(e?.relatedTarget as Node)) { shouldShowCellActions.value = false; } }; provide<{ registerMenuContainerElement: (menuContainerElement: Ref<UnwrapRef<HTMLDivElement>>) => void; menuMouseLeave: (e: MouseEvent) => void; }>(DATA_GRID_CELL_MENU_REGISTERING_INJECTION_KEY, { registerMenuContainerElement, menuMouseLeave, }); const hasSlashedZero = inject(DATA_GRID_SLASHED_ZERO, ref(false)); const isSmallContainer: ComputedRef<boolean> = inject( DATA_GRID_SMALL_CONTAINER, computed(() => false) ); const isTouchDevice: Ref<boolean> = inject(DATA_GRID_TOUCH_DEVICE, ref(false)); // Styling const conditionalRowCellClasses = (column: BentoColumn) => ({ [`b-data-grid-cell--${DataGridCellPropClass.COLUMN_HOVERED}`]: column?.field === props.hoveredOverColumnState.hoveredOverColumnField, [`b-data-grid-cell--${DataGridCellPropClass.COLUMN_HOVERED_NO_BORDER_LEFT}`]: column?.field === props.hoveredOverColumnState.hoveredOverColumnField && props.hoveredOverColumnState.noBorderLeft, [`b-data-grid-cell--${DataGridCellPropClass.COLUMN_HOVERED_NO_BORDER_RIGHT}`]: column?.field === props.hoveredOverColumnState.hoveredOverColumnField && props.hoveredOverColumnState.noBorderRight, [`b-data-grid-cell--${DataGridCellPropClass.PADDING_LEFT_UNSET}`]: column?.padding?.left === false, [`b-data-grid-cell--${DataGridCellPropClass.PADDING_RIGHT_UNSET}`]: column?.padding?.right === false, [`b-data-grid-cell--${DataGridCellPropClass.NUMERIC}`]: column?.numeric, [`b-data-grid-cell--${DataGridCellPropClass.CONDENSED}`]: props.condensed, [`b-data-grid-cell--${DataGridCellPropClass.OVERFLOW_ELLIPSIS}`]: column?.overflow === BentoColumnOverflow.ELLIPSIS, [`b-data-grid-cell--${DataGridCellPropClass.IS_COLUMN_REORDERING}`]: props.draggingColumns.dragging?.field === column.field, [`b-data-grid-cell--${DataGridCellPropClass.IS_COLUMN_REORDERING_TARGET_LEFT}`]: props.draggingColumns.target?.field === column.field && props.draggingColumns?.dragToLeft, [`b-data-grid-cell--${DataGridCellPropClass.IS_COLUMN_REORDERING_TARGET_RIGHT}`]: props.draggingColumns.target?.field === column.field && !props.draggingColumns?.dragToLeft, [`b-data-grid-cell--${DataGridCellPropClass.FROZEN}`]: column?.frozen, [`b-data-grid-cell--${DataGridCellPropClass.NESTED_CONTENT_ENABLED}`]: props.nestedContent, [`b-data-grid-cell--${DataGridCellPropClass.ACTION_COL_NESTED_CONTENT_ENABLED}`]: props.nestedContent && !props.selectable && column.field === DATAGRID_ACTIONS_COLUMN_FIELD_NAME, [`b-data-grid-cell--${DataGridCellPropClass.ACTION_COL_NESTED_CONTENT_AND_SELECTION_ENABLED}`]: props.nestedContent && props.selectable && column.field === DATAGRID_ACTIONS_COLUMN_FIELD_NAME, [`b-data-grid-cell--${DataGridCellPropClass.ACTION_COL_SELECTION_ENABLED}`]: column.field === DATAGRID_ACTIONS_COLUMN_FIELD_NAME && props.selectable, [`b-data-grid-cell--${DataGridCellPropClass.SLASHED_ZERO}`]: hasSlashedZero.value, 'b-data-grid-cell--small-container': isSmallContainer.value, }); const computedCellContentClasses = computed(() => ({ 'b-data-grid-cell__cell-content--is-focused-on-inside-interactive-element': hasInteractiveElFocusedInside.value, })); // Exposed refs defineExpose({ gridcellRef, }); </script> <script lang="ts"> /** * Internal component to display the BentoDataGrid cells. * * The component can also render the selecting row checkbox as well as cell actions. * * @example * <data-grid-cell * * /> */ export default { i18n: { messages }, name: 'data-grid-cell', }; </script> <style lang="scss" scoped src="./data-grid-cell.scss" />
|
|
1
|
+
<template> <div :key="`cell-${column.field}`" ref="gridcellRef" :aria-hidden="ariaHidden" :data-testid="`cell-${column.field}`" :data-cellindex="getCellIndex(rowIndex, colIndex, columnSetIndex)" class="b-data-grid-cell" :class="conditionalRowCellClasses(column)" role="gridcell" :tabindex="tabIndex" :aria-colindex="getColIndex(colIndex, columnSetIndex) + 1" :style="{ width: column.autoWidth && isMeasuringColumnWidths ? 'auto' : `${column.width}px`, }" v-on="getGridcellEvents(column)" > <template v-if="column.field === DATAGRID_ACTIONS_COLUMN_FIELD_NAME"> <template v-if="selectable"> <bento-checkbox class="b-data-grid-cell__select-cell" :aria-label="t('selectRow')" :disabled="isDataItemDisabled(rowData)" :indeterminate="selectionIsIndeterminate" :model-value="selectedItems" :value="getDataItemId(rowData)" :tabindex="isFocused ? 0 : -1" @update:model-value="$emit('select-row', $event)" /> </template> <template v-if="nestedContent"> <bento-toggle-button ref="menuButtonRef" aria-haspopup="true" :aria-controls="controlledNestedRowElementIds" condensed variant="tertiary" :toggled="isNestedContentExpanded" @click="toggleNestedContent" > <template #iconLeft> <chevron-up-icon v-if="isNestedContentExpanded" class="b-accordion-item__icon" :svg-title="t('collapseNestedContent')" /> <chevron-down-icon v-else class="b-accordion-item__icon" :svg-title="t('expandNestedContent')" /> </template> </bento-toggle-button> </template> </template> <template v-else> <bento-typography el="div" class="b-data-grid-cell__cell-content" :class="computedCellContentClasses" data-testid="cell-content" > <slot :item="rowData" :row-index="rowIndex" :name="`item-${column.field}`"> <span :title="conditionalTitleAttribute(column, rowData[column.field])">{{ getRowData(rowData[column.field]) }}</span> </slot> </bento-typography> <div v-if="column.cellActions?.length > 0" class="b-data-grid-cell__cell-actions"> <data-grid-cell-actions v-if="(shouldShowCellActions || isTouchDevice) && (hasRowData || hasSlot(`item-${column.field}`))" ref="cellActionsRef" :cell-actions="column.cellActions" :column-key="column.field" :row-data-item="rowData" :has-zebra-background="hasZebraBackground" :is-highlighted="isHighlighted" :is-selected="isSelected" teleport-menu @menu-item-click="onMenuClose" /> </div> </template> </div> </template> <script setup lang="ts"> import { computed, type ComputedRef, inject, nextTick, onMounted, type PropType, provide, type Ref, ref, type UnwrapRef, useSlots, watch, } from 'vue'; import { makeAllInteractiveChildrenFocusable, makeAllInteractiveChildrenUnFocusable } from '../../utils'; import { useCellKeyboardNavigation } from './composables/use-cell-keyboard-navigation'; import { DATAGRID_ACTIONS_COLUMN_FIELD_NAME } from '../../composables/use-calculate-column-width'; import { BentoCheckbox } from '@/components/checkbox'; import { BentoTypography } from '@/components/typography'; import { BentoToggleButton } from '@/components/button'; import DataGridCellActions from '../data-grid-cell-actions/data-grid-cell-actions.vue'; import { DATA_GRID_SLASHED_ZERO, DATA_GRID_SMALL_CONTAINER, DATA_GRID_TOUCH_DEVICE } from '../../data-grid.keys'; import ChevronDownIcon from '@adyen/ui-assets-icons-16/vue/chevron-down'; import ChevronUpIcon from '@adyen/ui-assets-icons-16/vue/chevron-up'; import { DATA_GRID_CELL_MENU_REGISTERING_INJECTION_KEY } from '@/components/data-grid/components/data-grid-cell/data-grid-cell.keys'; // Types and enums import { type BentoColumn, BentoColumnOverflow, type BentoDatagridDataItem, type BentoDatagridDataItemId, type BentoDatagridGetDataItemIdFn, type BentoDatagridIsDataItemDisabledFn, } from '@/components/data-grid/data-grid.types'; import { type DataGridCellColumnSet, type DataGridCellDragEventsForColumn, type DataGridCellEvents, type DataGridCellEventsForColumn, DataGridCellPropClass, } from './data-grid-cell.types'; import type { BentoDatagridDraggingColumnState } from '../data-grid-columns/data-grid-columns.types'; import type { DatagridColumnHoveringState } from '@/components/data-grid/composables/use-column-hovering/use-column-hovering.types'; // Utils import { useHasSlot } from '@/composables'; import { useI18n } from '@/utils/ts/i18n'; // Translations import messages from './messages.json'; const slots = useSlots(); const hasSlot = useHasSlot(slots); type MessageSchema = (typeof messages)['en-US']; const { t } = useI18n<{ message: MessageSchema }>({ messages }); const props = defineProps({ draggingEventsForRowCell: { type: Function as PropType<DataGridCellDragEventsForColumn>, required: true, }, /** * The columns sets including */ columnSets: { type: Array as PropType<Array<DataGridCellColumnSet>>, required: true, }, /** * The columns set we are iterating over */ column: { type: Object as PropType<BentoColumn>, required: true, }, colIndex: { type: Number, required: true, }, columnSetIndex: { type: Number, required: true, }, /** * Sets the row cells to the condensed padding state. */ condensed: { type: Boolean, default: false, }, /** * Columns being dragged, contains dragging column and a target column */ draggingColumns: { type: Object as PropType<BentoDatagridDraggingColumnState>, default: undefined, }, /** * A customisable method to retrieve a unique identifier for a data item in the array of data supplied. * This is used selecting and performance reasons and must exist in each data item. */ getDataItemId: { type: Function as PropType<BentoDatagridGetDataItemIdFn>, default: (item: BentoDatagridDataItem) => item.id, }, /** * Set to true if the cell has a darker background when zebra rows is enabled. */ hasZebraBackground: { type: Boolean, default: false, }, /** * Set to true if the row is selected. */ isSelected: { type: Boolean, default: false, }, /** * Set to true if the row is highlighted. */ isHighlighted: { type: Boolean, default: false, }, /** * The column hovered over state and whether the hovered over column should show a border right or left. */ hoveredOverColumnState: { type: Object as PropType<DatagridColumnHoveringState>, required: true, }, /** * A customisable method to determine if a row is not selectable. * The default is that every row is selectable. */ isDataItemDisabled: { type: Function as PropType<BentoDatagridIsDataItemDisabledFn>, default: () => false, }, isMeasuringColumnWidths: { type: Boolean, default: false, }, /** * Determines if the nested content is visible. */ isNestedContentExpanded: { type: Boolean, default: false, }, /** * Determines if the nest content slot is enabled for this data row. */ nestedContent: { type: Boolean, default: false, }, /** * The IDs of the rows this cell controls to show / hide them. */ nestedRowsElementIds: { type: Array as PropType<Array<string>>, default: () => [], }, /** * The row data object */ rowData: { type: Object as PropType<BentoDatagridDataItem>, required: true, }, rowIndex: { type: Number, required: true, }, /** * The row selection checkbox indeterminate state. */ selectionIsIndeterminate: { type: Boolean, default: false, }, /** * Determines if the row selection is enabled. */ selectable: { type: Boolean, default: false, }, selectedItems: { type: Array as PropType<Array<BentoDatagridDataItemId>>, required: true, }, }); const emit = defineEmits<{ /** * Emitted when an a frozen column cell fires a key up or down event. */ (e: 'on-frozen-columns-key-press', event: Event); /** * Emitted when a row has been selected. */ (e: 'select-row', value: Array<BentoDatagridDataItemId>); /** * Emitted when a row has been selected. */ (e: 'register-row-cell-element', el: Element, field: string, rowIndex: number); /** * Emitted when a cell has been hovered over. This is used to keep the row in a hovered state when hovering over a menu. */ (e: 'cell-hovered', value: number); /** * Emitted when nested content is being toggled. */ (e: 'nested-content-toggled'); /** * Emitted when a cell gains focus. */ ( e: 'cell-focus', value: { rowData: BentoDatagridDataItem; column: BentoColumn; rowIndex: number; colIndex: number } ); }>(); // References const gridcellRef = ref<HTMLDivElement | null>(null); const cellActionsRef = ref<InstanceType<typeof DataGridCellActions>>(null); const hasEverBeenFocused = ref(false); const { shouldShowCellActions, isFocused, focusableItems, childrenMenuContainerElements, hasInteractiveElFocusedInside, onMenuClose, hideCellActionsIfLeft, handleFocus, handleFocusout, handleKeydown, handleCellActionsFocus, handleCellActionsFocusout, } = useCellKeyboardNavigation({ gridcellRef }); // Computed const hasRowData = computed(() => !!props.rowData?.[props.column.field]); const controlledNestedRowElementIds = computed(() => props.column.field === DATAGRID_ACTIONS_COLUMN_FIELD_NAME && props.nestedRowsElementIds?.length > 0 ? props.nestedRowsElementIds.join(' ') : undefined ); const ariaHidden = computed( () => props.column.field === DATAGRID_ACTIONS_COLUMN_FIELD_NAME && !props.selectable && !props.nestedContent ); const tabIndex = computed(() => { if (!ariaHidden.value) { // The first cell of the grid should be tabbable on initial render to allow keyboard navigation into the grid. if (getCellIndex(props.rowIndex, props.colIndex, props.columnSetIndex) === 0 && !hasEverBeenFocused.value) { return '0'; } // A cell becomes part of the tab order only when it is focused. if (isFocused.value) { return '0'; } } // Action cells are not directly tabbable; they are accessed via cell navigation. if (props.column.field === DATAGRID_ACTIONS_COLUMN_FIELD_NAME) { return '-1'; } // By default, cells are not in the tab order. return '-1'; }); // Row data retrieval methods const conditionalTitleAttribute = (column: BentoColumn, content: unknown) => column?.overflow === BentoColumnOverflow.ELLIPSIS ? `${content}` : undefined; const getRowData = (rowData: unknown) => rowData ?? '-'; // Cell and Columns index calculation const sumColumnAmountsInColumnSets = (limitIndex?: number) => props.columnSets.slice(0, limitIndex).reduce((total, { columnSet }) => total + columnSet.length, 0); // Sums the amount of columns on every previous column set to find // the absolute column index (useful for frozen columns use case) const getColIndex = (colIndex: number, colSetIndex: number) => colIndex + sumColumnAmountsInColumnSets(colSetIndex); const getCellIndex = (rowIndex: number, colIndex: number, colSetIndex: number) => sumColumnAmountsInColumnSets() * rowIndex + getColIndex(colIndex, colSetIndex); // Events const getGridcellEvents: DataGridCellEventsForColumn = (column: BentoColumn) => { const defaultEvents: DataGridCellEvents = { ...props.draggingEventsForRowCell(column), focus: async () => { hasEverBeenFocused.value = true; await handleFocus(() => { emit('cell-focus', { rowData: props.rowData, column: props.column, rowIndex: props.rowIndex, colIndex: getColIndex(props.colIndex, props.columnSetIndex), }); }); }, focusout: handleFocusout, keydown: handleKeydown, }; const gridCellEvents: DataGridCellEvents = { ...defaultEvents }; if (column.frozen) { gridCellEvents.keyup = (event: Event) => emit('on-frozen-columns-key-press', event); gridCellEvents.keydown = (event: KeyboardEvent) => { defaultEvents.keydown(event); emit('on-frozen-columns-key-press', event); }; } if (column.cellActions) { gridCellEvents.mouseenter = () => { shouldShowCellActions.value = true; }; gridCellEvents.mouseleave = (e: MouseEvent) => { hideCellActionsIfLeft(e?.relatedTarget); }; gridCellEvents.focus = async (e: FocusEvent) => { await handleCellActionsFocus(defaultEvents.focus, e); }; gridCellEvents.focusout = (e: FocusEvent) => { handleCellActionsFocusout(defaultEvents.focusout, e); }; } return gridCellEvents; }; onMounted(() => { focusableItems.value = makeAllInteractiveChildrenUnFocusable(gridcellRef.value); }); const toggleNestedContent = () => { emit('nested-content-toggled'); }; // Each cell knows it's on hover state but this state needs to be emitted up // in order for the DataGrid to know which row to set the hovered state on. watch( () => shouldShowCellActions.value, async () => { if (shouldShowCellActions.value === true) { emit('cell-hovered', props.rowIndex); // Re-scan for focusable items after cell-actions render into the DOM await nextTick(); focusableItems.value = makeAllInteractiveChildrenUnFocusable(gridcellRef.value); // When the cell has keyboard focus, make children tabbable so Tab // can reach cell-action buttons that just appeared. if (isFocused.value) { makeAllInteractiveChildrenFocusable(focusableItems.value); } } else { emit('cell-hovered', -1); } } ); const registerMenuContainerElement = (menuContainerElement: Ref<UnwrapRef<HTMLDivElement>>) => { childrenMenuContainerElements.value.push(menuContainerElement); }; const menuMouseLeave = (e: MouseEvent) => { if (!gridcellRef.value.contains(e?.relatedTarget as Node)) { shouldShowCellActions.value = false; } }; provide<{ registerMenuContainerElement: (menuContainerElement: Ref<UnwrapRef<HTMLDivElement>>) => void; menuMouseLeave: (e: MouseEvent) => void; }>(DATA_GRID_CELL_MENU_REGISTERING_INJECTION_KEY, { registerMenuContainerElement, menuMouseLeave, }); const hasSlashedZero = inject(DATA_GRID_SLASHED_ZERO, ref(false)); const isSmallContainer: ComputedRef<boolean> = inject( DATA_GRID_SMALL_CONTAINER, computed(() => false) ); const isTouchDevice: Ref<boolean> = inject(DATA_GRID_TOUCH_DEVICE, ref(false)); // Styling const conditionalRowCellClasses = (column: BentoColumn) => ({ [`b-data-grid-cell--${DataGridCellPropClass.COLUMN_HOVERED}`]: column?.field === props.hoveredOverColumnState.hoveredOverColumnField, [`b-data-grid-cell--${DataGridCellPropClass.COLUMN_HOVERED_NO_BORDER_LEFT}`]: column?.field === props.hoveredOverColumnState.hoveredOverColumnField && props.hoveredOverColumnState.noBorderLeft, [`b-data-grid-cell--${DataGridCellPropClass.COLUMN_HOVERED_NO_BORDER_RIGHT}`]: column?.field === props.hoveredOverColumnState.hoveredOverColumnField && props.hoveredOverColumnState.noBorderRight, [`b-data-grid-cell--${DataGridCellPropClass.PADDING_LEFT_UNSET}`]: column?.padding?.left === false, [`b-data-grid-cell--${DataGridCellPropClass.PADDING_RIGHT_UNSET}`]: column?.padding?.right === false, [`b-data-grid-cell--${DataGridCellPropClass.NUMERIC}`]: column?.numeric, [`b-data-grid-cell--${DataGridCellPropClass.CONDENSED}`]: props.condensed, [`b-data-grid-cell--${DataGridCellPropClass.OVERFLOW_ELLIPSIS}`]: column?.overflow === BentoColumnOverflow.ELLIPSIS, [`b-data-grid-cell--${DataGridCellPropClass.IS_COLUMN_REORDERING}`]: props.draggingColumns.dragging?.field === column.field, [`b-data-grid-cell--${DataGridCellPropClass.IS_COLUMN_REORDERING_TARGET_LEFT}`]: props.draggingColumns.target?.field === column.field && props.draggingColumns?.dragToLeft, [`b-data-grid-cell--${DataGridCellPropClass.IS_COLUMN_REORDERING_TARGET_RIGHT}`]: props.draggingColumns.target?.field === column.field && !props.draggingColumns?.dragToLeft, [`b-data-grid-cell--${DataGridCellPropClass.FROZEN}`]: column?.frozen, [`b-data-grid-cell--${DataGridCellPropClass.NESTED_CONTENT_ENABLED}`]: props.nestedContent, [`b-data-grid-cell--${DataGridCellPropClass.ACTION_COL_NESTED_CONTENT_ENABLED}`]: props.nestedContent && !props.selectable && column.field === DATAGRID_ACTIONS_COLUMN_FIELD_NAME, [`b-data-grid-cell--${DataGridCellPropClass.ACTION_COL_NESTED_CONTENT_AND_SELECTION_ENABLED}`]: props.nestedContent && props.selectable && column.field === DATAGRID_ACTIONS_COLUMN_FIELD_NAME, [`b-data-grid-cell--${DataGridCellPropClass.ACTION_COL_SELECTION_ENABLED}`]: column.field === DATAGRID_ACTIONS_COLUMN_FIELD_NAME && props.selectable, [`b-data-grid-cell--${DataGridCellPropClass.SLASHED_ZERO}`]: hasSlashedZero.value, 'b-data-grid-cell--small-container': isSmallContainer.value, }); const computedCellContentClasses = computed(() => ({ 'b-data-grid-cell__cell-content--is-focused-on-inside-interactive-element': hasInteractiveElFocusedInside.value, })); // Exposed refs defineExpose({ gridcellRef, }); </script> <script lang="ts"> /** * Internal component to display the BentoDataGrid cells. * * The component can also render the selecting row checkbox as well as cell actions. * * @example * <data-grid-cell * * /> */ export default { i18n: { messages }, name: 'data-grid-cell', }; </script> <style lang="scss" scoped src="./data-grid-cell.scss" />
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import type { BentoButtonActionObject } from '@/components/button/components/button-actions/button-actions.types'; import type { BentoMenuItem } from '@/components/menu/components/menu-item/menu-item.types'; import type { BentoDatagridDataItem } from '@/components/data-grid/components/data-grid-row/data-grid-row.types'; import type { OmitStrict } from '@/types/omit-strict'; import { type BentoTooltipPosition } from '@/directives/tooltip/tooltip.types'; export type BentoColumnCellActionVariant = 'copy' | 'edit' | 'open' | 'more'; export type BentoColumnCellActionEvent = (rowDataItem: BentoDatagridDataItem, columnKey: string) => void; export type BentoColumnCellActionMenuItem = { /** * @deprecated This property will be removed in version 2.0, please use `event` instead. */ handler?: BentoMenuItem['handler']; event?: BentoColumnCellActionEvent; } & OmitStrict<BentoMenuItem, 'handler'>; export type BentoColumnCellAction = OmitStrict< BentoButtonActionObject, 'variant' | 'event' | 'title' | 'icon' | 'state' > & { title?: string; event?: BentoColumnCellActionEvent; tooltipText?: string; tooltipPosition?: BentoTooltipPosition | `${BentoTooltipPosition}`; // Variant button properties isShort?: true; variant?: BentoColumnCellActionVariant; // Menu button properties menuData?: Array<BentoColumnCellActionMenuItem>; // Copy button properties getCopyData?: (rowDataItem: BentoDatagridDataItem, columnKey: string) => string; }; export type BentoColumnCellActions = Array<BentoColumnCellAction>; export type BentoColumnCellActionsByCellDataFn = ( rowDataItem: BentoDatagridDataItem, columnKey: string ) => BentoColumnCellActions; export type BentoColumnCellActionsProp = BentoColumnCellActions | BentoColumnCellActionsByCellDataFn; export type BentoDataGridRowActionsFn = (rowDataItem: BentoDatagridDataItem) => BentoColumnCellActions; export type BentoDataGridRowActionsProp = BentoColumnCellActions | BentoDataGridRowActionsFn;
|
package/dist/assets/components/data-grid/components/data-grid-columns/data-grid-columns.types.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { type BentoColumnCellActionsProp } from '../data-grid-cell-actions/data-grid-cell-actions.types'; export enum BentoColumnOverflow { WRAP = 'wrap', ELLIPSIS = 'ellipsis', } export interface BentoColumn { field: string; label: string; width?: number; autoWidth?: boolean; minWidth?: number; flex?: number; sortable?: boolean; numeric?: boolean; infoIconTooltip?: string; padding?: { left?: boolean; right?: boolean; }; overflow?: BentoColumnOverflow; visible?: boolean; mandatory?: boolean; frozen?: boolean; cellActions?: BentoColumnCellActionsProp; } /** * All the emit events provided by the DatagridColumns component */ export enum DatagridColumnsEvent { COLUMN_RESIZE = 'column-resize', COLUMN_RESIZING = 'column-resizing', SELECT_ALL_ROWS = 'select-all-rows', SELECT_ALL_ACROSS_PAGES = 'select-all-across-pages', SELECT_ALL_CURRENT_RESULTS = 'select-all-current-results', DESELECT_ALL = 'deselect-all', DESELECT_ALL_CURRENT_RESULTS = 'deselect-all-current-results', COLUMN_MOVE = 'column-move', COLUMN_UPDATE = 'column-update', COLUMN_MENU_OPEN = 'column-menu-open', COLUMN_MENU_CLOSE = 'column-menu-close', COLUMN_HOVER = 'column-hover', // Dragging events COLUMN_DRAG_START = 'column-dragstart', COLUMN_DRAG_ENTER = 'column-dragenter', COLUMN_DRAG_END = 'column-dragend', COLUMN_DROP = 'column-drop', } export interface DatagridColumnsHeaderReferences { [key: string]: HTMLDivElement | null; } /** * The Datagrid column dragging state. * @interface BentoDatagridDraggingColumnState * @field dragging - The column currently being dragged. * @field target - The column being dragged over during dragging another column. */ export interface BentoDatagridDraggingColumnState { dragging?: BentoColumn; dragToLeft?: boolean; target?: BentoColumn; } export type BentoDatagridColumnSelectionState = 'all' | 'page' | 'single' | 'unselected-page' | 'none';
|