@adyen/bento-mcp 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +11 -66
- package/dist/assets/components/action-bar/action-bar.stories.ts +1 -1
- package/dist/assets/components/action-bar/action-bar.vue +1 -1
- package/dist/assets/components/ai-tag/ai-tag.docs.mdx +75 -0
- package/dist/assets/components/ai-tag/ai-tag.stories.ts +1 -0
- package/dist/assets/components/ai-tag/ai-tag.vue +1 -0
- package/dist/assets/components/card/card.docs.mdx +3 -3
- package/dist/assets/components/data-grid/components/data-grid-tag-with-text-cell/data-grid-tag-with-text-cell.docs.mdx +35 -0
- package/dist/assets/components/data-grid/components/data-grid-tag-with-text-cell/data-grid-tag-with-text-cell.stories.ts +1 -0
- package/dist/assets/components/data-grid/components/data-grid-tag-with-text-cell/data-grid-tag-with-text-cell.vue +1 -0
- package/dist/assets/components/data-grid/data-grid.docs.mdx +16 -4
- package/dist/assets/components/data-grid/data-grid.stories.ts +1 -1
- package/dist/assets/components/data-grid/data-grid.vue +1 -1
- 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/date-range-picker.vue +1 -1
- package/dist/assets/components/draggable-handle/draggable-handle.docs.mdx +61 -0
- package/dist/assets/components/draggable-handle/draggable-handle.stories.ts +1 -0
- package/dist/assets/components/draggable-handle/draggable-handle.vue +1 -0
- package/dist/assets/components/dropdown/dropdown.docs.mdx +3 -3
- package/dist/assets/components/file-uploader/components/file-uploader-file-card/file-uploader-file-card.vue +1 -1
- package/dist/assets/components/filter-bar/components/date-range-filter/date-range-filter.vue +1 -1
- package/dist/assets/components/filter-bar/filter-bar.docs.mdx +1 -1
- package/dist/assets/components/form-layout/components/form-layout-title/form-layout-title.vue +1 -1
- package/dist/assets/components/form-layout/form-layout.docs.mdx +2 -2
- package/dist/assets/components/inspector/inspector.docs.mdx +2 -2
- package/dist/assets/components/internal/copy/copy.docs.mdx +2 -2
- package/dist/assets/components/layout/layout.docs.mdx +8 -8
- package/dist/assets/components/layout/layout.vue +1 -1
- package/dist/assets/components/modal/modal.docs.mdx +4 -4
- package/dist/assets/components/modal-fullscreen/modal-fullscreen.docs.mdx +5 -5
- package/dist/assets/components/sidepanel/sidepanel.docs.mdx +27 -27
- package/dist/assets/components/summary-grid/summary-grid.docs.mdx +1 -1
- package/dist/assets/components/tabs/tabs.docs.mdx +1 -1
- package/dist/assets/components/toast/toast.docs.mdx +10 -10
- package/dist/assets/index.ts +1 -1
- package/dist/main.js +121 -101
- package/package.json +5 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.1 (2026-03-04)
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
- updated `@modelcontextprotocol/sdk` to fix `CVE-2026-25536`, `CVE-2026-25536` ([15f9b8fd1](https://github.com/Adyen/bento/commit/15f9b8fd1))
|
|
8
|
+
|
|
9
|
+
### Documentation
|
|
10
|
+
|
|
11
|
+
- updated MCP docs with standard config for models ([471b7fa80](https://github.com/Adyen/bento/commit/471b7fa80))
|
|
12
|
+
|
|
13
|
+
### ❤️ Thank You
|
|
14
|
+
|
|
15
|
+
- daver
|
|
16
|
+
|
|
17
|
+
|
|
3
18
|
## 0.1.0 (2026-02-25)
|
|
4
19
|
|
|
5
20
|
### Features
|
package/README.md
CHANGED
|
@@ -5,25 +5,15 @@ models (LLMs) to interact with Bento's codebase, documentation, and components.
|
|
|
5
5
|
|
|
6
6
|
## Features
|
|
7
7
|
|
|
8
|
-
- **Changelog Access**: Query and retrieve information from the Bento Vue2 changelog.
|
|
9
8
|
- **Component Context**: Provide component definitions and usage guidelines to LLMs.
|
|
9
|
+
- **Changelog Access**: (Planned) Query and retrieve information from the Bento changelog.
|
|
10
10
|
- **Design Tokens**: (Planned) Access design token values and documentation.
|
|
11
11
|
|
|
12
12
|
## Usage
|
|
13
13
|
|
|
14
|
-
You can use this server as a tool with various AI assistant clients that support the Model Context Protocol.
|
|
15
|
-
command to use is `bento-mcp`.
|
|
14
|
+
You can use this server as a tool with various AI assistant clients that support the Model Context Protocol.
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
You can use the `bento-mcp` server as a tool with the `gemini-cli` by passing the command in the `-t` flag.
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
gemini -t "bento-mcp" "What props does the button component have?"
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
Alternatively, you can configure the tool in a JSON file. For example, you can create a `.gemini-cli-config.json` file
|
|
26
|
-
in your home directory:
|
|
16
|
+
To configure the MCP server, add the following to your client's settings file:
|
|
27
17
|
|
|
28
18
|
```json
|
|
29
19
|
{
|
|
@@ -37,61 +27,16 @@ in your home directory:
|
|
|
37
27
|
}
|
|
38
28
|
```
|
|
39
29
|
|
|
40
|
-
|
|
30
|
+
The location of this file may vary depending on your client and setup. For project-level and global configuration, you
|
|
31
|
+
can typically use:
|
|
41
32
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
33
|
+
| Client | Local Path | Global Path |
|
|
34
|
+
| -------- | ----------------------------- | ------------------------------------- |
|
|
35
|
+
| Claude | `.claude/settings.local.json` | `~/.claude/settings.json` |
|
|
36
|
+
| Gemini | `.gemini/settings.json` | `~/.gemini/settings.json` |
|
|
37
|
+
| Windsurf | `-` | `~/.codeium/windsurf/mcp_config.json` |
|
|
45
38
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
To configure the `bento-mcp` tool for the Claude desktop client on macOS, you can edit the configuration file located at
|
|
49
|
-
`~/Library/Application Support/Claude/claude_desktop_config.json`.
|
|
50
|
-
|
|
51
|
-
Add a `bento` server entry that points to the `bento-mcp` command:
|
|
52
|
-
|
|
53
|
-
```json
|
|
54
|
-
{
|
|
55
|
-
"mcpServers": {
|
|
56
|
-
"bento": {
|
|
57
|
-
"type": "stdio",
|
|
58
|
-
"command": "npx",
|
|
59
|
-
"args": ["@adyen/bento-mcp@latest"]
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### With Windsurf
|
|
66
|
-
|
|
67
|
-
#### Installation
|
|
68
|
-
|
|
69
|
-
You can install the package globally using NPM:
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
npm install -g @adyen/bento-mcp
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
This will make the `bento-mcp` command available in your shell.
|
|
76
|
-
|
|
77
|
-
You can pass the tool command directly to the `windsurf` client:
|
|
78
|
-
|
|
79
|
-
```bash
|
|
80
|
-
windsurf --tool "bento-mcp" "What props does the button component have?"
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
You can also configure tools in a JSON file. For instance, create a `~/.windsurf/config.json` file:
|
|
84
|
-
|
|
85
|
-
```json
|
|
86
|
-
{
|
|
87
|
-
"tools": [
|
|
88
|
-
{
|
|
89
|
-
"alias": "bento",
|
|
90
|
-
"command": "bento-mcp"
|
|
91
|
-
}
|
|
92
|
-
]
|
|
93
|
-
}
|
|
94
|
-
```
|
|
39
|
+
Once configured, you can invoke the tool by its name (`bento`).
|
|
95
40
|
|
|
96
41
|
## Available Tools
|
|
97
42
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import { action } from '@storybook/addon-actions'; import { isVue2, ref } from 'vue-demi'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import BentoActionBar from './action-bar.vue'; import { BentoButton } from '@/components/button'; import type { Meta, StoryObj } from '@storybook/vue'; import BinIcon from '@adyen/ui-assets-icons-16/vue/bin'; import EditIcon from '@adyen/ui-assets-icons-16/vue/edit-1'; const meta: Meta = { title: 'Action bar', component: BentoActionBar, argTypes: { variant: { control: { type: 'select', }, }, },
|
|
1
|
+
import { action } from '@storybook/addon-actions'; import { isVue2, ref } from 'vue-demi'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import BentoActionBar from './action-bar.vue'; import { BentoButton } from '@/components/button'; import type { Meta, StoryObj } from '@storybook/vue'; import BinIcon from '@adyen/ui-assets-icons-16/vue/bin'; import EditIcon from '@adyen/ui-assets-icons-16/vue/edit-1'; const meta: Meta = { title: 'Action bar', component: BentoActionBar, argTypes: { variant: { options: ['default', 'confirmation'], control: { type: 'select', }, }, }, parameters: { layout: 'fullscreen', }, }; export default meta; type Story = StoryObj<typeof BentoActionBar>; const DEFAULT_ACTIONS = [ { title: 'Assign to...', disabled: true, event: () => true, }, { title: 'Snooze', event: () => true, }, { title: 'Edit', icon: EditIcon, event: () => true, }, { title: 'Delete', critical: true, icon: BinIcon, event: () => true, }, { title: 'Extra option', event: () => true, }, ]; const DEFAULT_PROPS = { actions: DEFAULT_ACTIONS, selectionLabel: 'selected', itemCounter: 3 }; const defaultCode = ` <template> <bento-action-bar :actions="[ { title: 'Assign to...', event: () => true, }, { title: 'Snooze', event: () => true, }, { title: 'Edit', icon: EditIcon, event: () => true, }, { title: 'Delete', critical: true, icon: BinIcon, event: () => true, }, { title: 'Extra option', event: () => true, } ]" @close="closeAction" :item-counter="3" /> <script setup> const closeAction = () => { // unselect selected items and reset itemCounter } </script> </template>`; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoActionBar, BentoButton }, props: Object.keys(argTypes), template: ` <div style="height:140px"> <bento-button @click='toggleActionBar = !toggleActionBar'>Toggle action bar</bento-button> <bento-action-bar v-if='toggleActionBar' v-bind="args" @close="closeAction" @cancel="cancelAction" @save="saveAction" /> </div> `, setup(props) { const closeAction = () => action('close')(); const cancelAction = () => action('cancel')(); const saveAction = () => action('save')(); const toggleActionBar = ref(true); return { // Values args: isVue2 ? props : _args, toggleActionBar, // Events closeAction, cancelAction, saveAction, }; }, }), args: { ...DEFAULT_PROPS, }, parameters: storybookDocsParameter(defaultCode), };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<template> <Transition name="b-action-bar__animation" appear> <section class="b-action-bar" :class="conditionalClasses" :aria-label="t('actionBar')"> <div ref="actionBar" class="b-action-bar__container"> <div v-if="!isConfirmationVariant" class="b-action-bar__close-button"> <bento-button variant="tertiary" inverse :aria-label="t('close')" @click="emit('close')"> <template #iconLeft><cross-icon :aria-hidden="true" /></template> </bento-button> </div> <bento-typography el="span" stronger class="b-action-bar__selection"> {{ n(itemCounter) }} {{ isConfirmationVariant ? tc('unsavedChanges', itemCounter) : label }} </bento-typography> <bento-button-actions v-if="isConfirmationVariant" :actions="confirmationActions" class="b-action-bar__actions" inverse /> <button-actions-with-menu v-else :actions="actionsInternal" class="b-action-bar__actions" :displayed-actions="internalDisplayedActions" menu-position="top-end" disable-responsive-behavior inverse /> </div> </section> </Transition> </template> <script setup lang="ts"> import { computed, nextTick, type PropType, provide, ref, toRefs, watch } from 'vue'; import { BentoButton, BentoButtonActions, type BentoButtonActionsList } from '@/components/button'; import { BentoTypography } from '@/components/typography'; import { type BentoActionBarVariant } from '@/components/action-bar/action-bar.types'; import ButtonActionsWithMenu from '@/components/internal/button-actions-with-menu/button-actions-with-menu.vue'; import CrossIcon from '@adyen/ui-assets-icons-16/vue/cross'; import { useI18n } from '@/utils/ts/i18n'; import { useWindowSize } from '@vueuse/core'; import messages from './messages.json'; import { POPOVER_OFFSET_INJECTION_KEY } from '@/components/popover/popover.keys'; type MessageSchema = (typeof messages)['en-US']; // Constants const AVERAGE_BUTTON_SIZE = 100; const MENU_OFFSET = 7; const RESPONSIVE_BREAKPOINT = 500; const SPACING = 32; const props = defineProps({ /** * List of actions that will be used to render the buttons. * Required and used for the `default` variant. * * Each object in the list should have a `title`, an `event` and, * optionally, an `icon`. * * The component will display 4 actions and the hide the rest inside a menu. * * @see BentoButton for a list of all the other props supported by each button action. */ actions: { type: Array as PropType<BentoButtonActionsList>, default: () => [], }, /** * How many actions should be visible outside the menu, cannot be more than 4 */ visibleActions: { type: Number, default: 4, validator: (value: number) => value > 0 && value <= 4, }, /** * Use when there are sticky elements at the bottom, like sticky pagination */ extraBottomSpacing: { type: Boolean, default: false, }, /** * Show how many items are selected */ itemCounter: { type: Number,
|
|
1
|
+
<template> <Transition name="b-action-bar__animation" appear> <section class="b-action-bar" :class="conditionalClasses" :aria-label="t('actionBar')"> <div ref="actionBar" class="b-action-bar__container"> <div v-if="!isConfirmationVariant" class="b-action-bar__close-button"> <bento-button variant="tertiary" inverse :aria-label="t('close')" @click="emit('close')"> <template #iconLeft><cross-icon :aria-hidden="true" /></template> </bento-button> </div> <bento-typography el="span" stronger class="b-action-bar__selection"> <template v-if="isConfirmationVariant && noItemCounter"> {{ tc('unsavedChanges', 0) }} </template> <template v-else> {{ n(itemCounter) }} {{ isConfirmationVariant ? tc('unsavedChanges', itemCounter) : label }} </template> </bento-typography> <bento-button-actions v-if="isConfirmationVariant" :actions="confirmationActions" class="b-action-bar__actions" inverse /> <button-actions-with-menu v-else :actions="actionsInternal" class="b-action-bar__actions" :displayed-actions="internalDisplayedActions" menu-position="top-end" disable-responsive-behavior inverse /> </div> </section> </Transition> </template> <script setup lang="ts"> import { computed, nextTick, type PropType, provide, ref, toRefs, watch } from 'vue'; import { BentoButton, BentoButtonActions, type BentoButtonActionsList } from '@/components/button'; import { BentoTypography } from '@/components/typography'; import { type BentoActionBarVariant } from '@/components/action-bar/action-bar.types'; import ButtonActionsWithMenu from '@/components/internal/button-actions-with-menu/button-actions-with-menu.vue'; import CrossIcon from '@adyen/ui-assets-icons-16/vue/cross'; import { useI18n } from '@/utils/ts/i18n'; import { useWindowSize } from '@vueuse/core'; import messages from './messages.json'; import { POPOVER_OFFSET_INJECTION_KEY } from '@/components/popover/popover.keys'; type MessageSchema = (typeof messages)['en-US']; // Constants const AVERAGE_BUTTON_SIZE = 100; const MENU_OFFSET = 7; const RESPONSIVE_BREAKPOINT = 500; const SPACING = 32; const props = defineProps({ /** * List of actions that will be used to render the buttons. * Required and used for the `default` variant. * * Each object in the list should have a `title`, an `event` and, * optionally, an `icon`. * * The component will display 4 actions and the hide the rest inside a menu. * * @see BentoButton for a list of all the other props supported by each button action. */ actions: { type: Array as PropType<BentoButtonActionsList>, default: () => [], }, /** * How many actions should be visible outside the menu, cannot be more than 4 */ visibleActions: { type: Number, default: 4, validator: (value: number) => value > 0 && value <= 4, }, /** * Use when there are sticky elements at the bottom, like sticky pagination */ extraBottomSpacing: { type: Boolean, default: false, }, /** * Show how many items are selected. * When omitted in the `confirmation` variant, a generic "Unsaved changes" label is displayed. */ itemCounter: { type: Number, default: null, }, /** * Label for the selection, e.g. 'selected'/'changed' */ selectionLabel: { type: String, default: null, }, /** * Variant for the action bar * @values default, confirmation */ variant: { type: String as PropType<BentoActionBarVariant>, default: 'default', }, }); const emit = defineEmits<{ /** * Event emitted when the user click the close button */ (e: 'close'): void; (e: 'cancel'): void; (e: 'save'): void; }>(); const { t, tc, n } = useI18n<{ message: MessageSchema }>({ messages }); const label = computed(() => (props.selectionLabel ? props.selectionLabel : t('selected'))); // Refs const actionBar = ref<HTMLDivElement>(null); const { extraBottomSpacing, visibleActions } = toRefs(props); const { width } = useWindowSize(); const internalDisplayedActions = ref(null); const internalVisibleActions = ref(null); const isConfirmationVariant = computed(() => props.variant === 'confirmation'); watch( () => visibleActions.value, value => { internalVisibleActions.value = value <= 4 ? value : 4; internalDisplayedActions.value = internalVisibleActions.value; }, { immediate: true } ); // Styling const conditionalClasses = computed(() => ({ 'b-action-bar--extra-spacing': extraBottomSpacing.value, 'b-action-bar--confirmation': isConfirmationVariant.value, })); // Provide POPOVER_OFFSET_INJECTION_KEY to change the value of the popover offset provide(POPOVER_OFFSET_INJECTION_KEY, MENU_OFFSET); // Manipulate actions array to display as intended const actionsInternal = computed(() => { // All buttons should be of type secondary in the action bar const actions = props.actions.map(action => ({ ...action, variant: 'secondary', })) as BentoButtonActionsList; // Shown actions should display from left to right in action bar, instead of right to left which is the button actions default const shownActions = actions.slice(0, internalDisplayedActions.value).reverse(); const hiddenActions = actions.slice(internalDisplayedActions.value); return [...shownActions, ...hiddenActions]; }); const confirmationActions = computed<BentoButtonActionsList>(() => [ { title: t('save'), event: () => emit('save'), }, { title: t('cancel'), variant: 'secondary', event: () => emit('cancel'), }, ]); const noItemCounter = computed(() => { return props.itemCounter == null || props.itemCounter < 1; }); // Recursive functions to determine how many actions should be visible/hidden based on the screens width const showActions = async () => { await nextTick(); if ( width.value > actionBar.value.clientWidth + SPACING + AVERAGE_BUTTON_SIZE && internalDisplayedActions.value < internalVisibleActions.value ) { internalDisplayedActions.value += 1; showActions(); } }; const hideActions = async () => { await nextTick(); if (width.value < actionBar.value.clientWidth + SPACING && internalDisplayedActions.value > 0) { internalDisplayedActions.value -= 1; hideActions(); } }; // Screen width watcher to toggle hidden/visible actions watch( () => width.value, async (newValue, oldValue) => { await nextTick(); if (!actionBar.value) { return; } const isIncreasing = newValue > oldValue; if (width.value < RESPONSIVE_BREAKPOINT) { internalDisplayedActions.value = 0; } else if (isIncreasing) { showActions(); } else { hideActions(); } }, { immediate: true } ); </script> <script lang="ts"> /** * Action bar is a floating bar that provides users with quick access to key actions that can be applied to one or multiple items. * * @example * import { BentoActionBar } from '@adyen/bento-vue2'; * * export default { * components: { BentoActionBar }, * template: ` * <bento-action-bar * :actions='[ * { * title: 'Delete', * critical: true, * icon: BinIcon, * event: () => true, * }, * { * title: 'Edit', * icon: EditIcon, * event: () => true, * } * ]' * @close="closeAction" * :item-counter="5" * /> * ` * } */ export default { i18n: { messages }, }; </script> <style lang="scss" scoped src="./action-bar.scss" />
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Canvas, Meta } from '@storybook/blocks';
|
|
2
|
+
import * as AiTagStories from './ai-tag.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={AiTagStories} />
|
|
5
|
+
|
|
6
|
+
# AI tag
|
|
7
|
+
|
|
8
|
+
The AI tag is a component used to transparently identify content, data, or experiences that have been generated or
|
|
9
|
+
enhanced by artificial intelligence. Its primary purpose is to build user trust by clearly attributing AI's role.
|
|
10
|
+
|
|
11
|
+
It can be used standalone—placed next to the affected value—or embedded within other Bento components (e.g.,
|
|
12
|
+
b-input-field, b-card) via their designated slots. Clicking the tag opens an Explainability Popover with a short,
|
|
13
|
+
contextual summary of what the AI did.
|
|
14
|
+
|
|
15
|
+
<Canvas of={AiTagStories.Default} />
|
|
16
|
+
|
|
17
|
+
## Use Cases
|
|
18
|
+
|
|
19
|
+
- **To label AI-generated content:** Use it next to text, images, or data that was fully created by an AI model (e.g., a
|
|
20
|
+
generated summary, a generated data prediction).
|
|
21
|
+
- **To label AI-enhanced content:** Use it when AI has modified or significantly assisted in creating content (e.g., "AI
|
|
22
|
+
suggested these edits," "AI prefilled this input fields").
|
|
23
|
+
- **To identify AI-powered features:** Use it when a specific feature is an AI-driven system (e.g., “AI assistant chat”)
|
|
24
|
+
- **To identify AI-generated pages:** Use it when an entire page is generated by AI
|
|
25
|
+
|
|
26
|
+
### Do not use
|
|
27
|
+
|
|
28
|
+
- **For non-AI automation:** Do not use it for simple rules-based logic or standard algorithms (e.g., sorting a list
|
|
29
|
+
alphabetically).
|
|
30
|
+
- **For values that are not influenced by AI**, or where the AI role is irrelevant to the user’s decision.
|
|
31
|
+
- **As a decorative label** without an attached Explainability Popover.
|
|
32
|
+
|
|
33
|
+
### Best practices
|
|
34
|
+
|
|
35
|
+
- Place the AI tag on the right side of the AI-influenced value or in the component’s designated meta/info slot (also
|
|
36
|
+
usually on the right side).
|
|
37
|
+
- Keep Explainability Popover content concise and plain-language
|
|
38
|
+
- Prefer actionable transparency: include a “Learn more” action when deeper context or policy details exist.
|
|
39
|
+
|
|
40
|
+
## Placement
|
|
41
|
+
|
|
42
|
+
There are two primary ways to place the AI Tag:
|
|
43
|
+
|
|
44
|
+
- **Standalone**: AI tag is a standalone element placed directly on the right side of the AI-generated or enhanced
|
|
45
|
+
label/content/feature/page. Use this for freeform content.
|
|
46
|
+
- **Embedded**: AI tag is placed inside of an existing component, typically on the right side. This shows that the AI is
|
|
47
|
+
acting within or upon that specific component (e.t., an AI suggestion inside a input field, dropdown, etc).
|
|
48
|
+
|
|
49
|
+
## Accessibility
|
|
50
|
+
|
|
51
|
+
### Keyboard interaction
|
|
52
|
+
|
|
53
|
+
| Keyboard interaction | Action |
|
|
54
|
+
| ---------------------- | ---------------------------------------------------------------------------------------- |
|
|
55
|
+
| `Tab` | Moves focus to the AI tag trigger or away from it. |
|
|
56
|
+
| `Space` / `Enter` | Activates the trigger and toggles the visibility of the Explainability Popover. |
|
|
57
|
+
| `Esc` | Closes the Popover and returns focus to the trigger button. |
|
|
58
|
+
| `Tab` (inside Popover) | Cycles focus through the interactive elements within the Popover (e.g., action buttons). |
|
|
59
|
+
|
|
60
|
+
### Roles, states and properties
|
|
61
|
+
|
|
62
|
+
The AI tag follows the [disclosure pattern](https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/) for the trigger and
|
|
63
|
+
the [dialog pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/) for the popover content.
|
|
64
|
+
|
|
65
|
+
| ARIA attribute | Is automatic? | Description |
|
|
66
|
+
| --------------- | ------------- | ---------------------------------------------------------------------------------------- |
|
|
67
|
+
| `role="button"` | Yes | The trigger is a semantic button. |
|
|
68
|
+
| `aria-expanded` | Yes | Set to `true` when the popover is visible, `false` otherwise. |
|
|
69
|
+
| `aria-controls` | Yes | Points to the `id` of the popover content. |
|
|
70
|
+
| `role="dialog"` | Yes | The popover container has the dialog role. |
|
|
71
|
+
| `aria-label` | Yes | The popover uses "AI explained" as its accessible label (derived from the header title). |
|
|
72
|
+
|
|
73
|
+
## Resources
|
|
74
|
+
|
|
75
|
+
- [Figma link](https://www.figma.com/design/uLabwF3243jdMDsNSP7U9I/Bento---Components?node-id=49373-138087&m=dev)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import BentoAiTag from './ai-tag.vue'; import AiTagDefault from './__tests__/ai-tag-default.vue?raw'; import { action } from '@storybook/addon-actions'; import { isVue2 } from 'vue-demi'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import type { Meta, StoryObj } from '@storybook/vue'; const meta: Meta = { title: 'AI tag', component: BentoAiTag, }; export default meta; type Story = StoryObj<typeof BentoAiTag>; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoAiTag }, props: Object.keys(argTypes), template: ` <bento-ai-tag v-bind="args" @update:toggled="onToggleAction"/> `, setup(props) { const onToggleAction = (value: boolean) => action('update:toggled')(value); return { // Values args: isVue2 ? props : _args, // Events onToggleAction, }; }, }), args: { title: 'Input fields auto-filled by AI', description: 'Based on your documents uploaded, AI has auto-filled some information for you. You can change that information any time.', influencedValue: '30%', action: { title: 'Learn more', event: () => action('action-click')('Learn more clicked'), }, }, parameters: storybookDocsParameter(AiTagDefault), };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<template> <div ref="aiTagRef" class="b-ai-tag" @keydown.esc="closePopover"> <bento-toggle-button ref="targetElement" :toggled="toggled" :aria-controls="popoverId" variant="secondary" condensed class="b-ai-tag__trigger" @update:toggled="onToggle" > <template #iconLeft> <artificial-intelligence-ai-icon class="b-ai-tag__trigger-icon" :aria-hidden="true" /> </template> {{ t('ai') }} </bento-toggle-button> <bento-popover v-if="targetElement" :id="popoverId" :open="toggled" :target-element="targetElement" :actions="popoverActions" actions-layout="fill-container" :title="t('aiExplained')" trap-all :trap-all-options="{ onDeactivate: closePopover, allowOutsideClick: true }" fixed-positioning overflow-visible @dismiss="closePopover" > <template #headerIcon> <artificial-intelligence-ai-icon class="b-ai-tag__popover-header-icon" :aria-hidden="true" /> </template> <div class="b-ai-tag__popover-content"> <bento-typography v-if="influencedValue" variant="title" medium class="b-ai-tag__influenced-value"> {{ influencedValue }} </bento-typography> <bento-typography variant="title"> {{ title }} </bento-typography> <bento-typography> {{ description }} </bento-typography> </div> </bento-popover> </div> </template> <script setup lang="ts"> import { computed, ref, watch } from 'vue'; import { BentoPopover } from '@/components/popover'; import { BentoToggleButton } from '@/components/button'; import { BentoTypography } from '@/components/typography'; import { useClickOutside } from '@/composables'; import { useI18n } from '@/utils/ts/i18n'; import { generateUid } from '@/core/utils/ts'; import type { BentoButtonActionsList } from '@/components/button/components/button-actions/button-actions.types'; import ArtificialIntelligenceAiIcon from '@adyen/ui-assets-icons-16/vue/artificial-intelligence-ai-filled'; import type { BentoAiTagProps } from './ai-tag.types'; import messages from './messages.json'; type MessageSchema = (typeof messages)['en-US']; const props = withDefaults(defineProps<BentoAiTagProps>(), { influencedValue: undefined, toggled: false, action: undefined, }); const { t } = useI18n<{ message: MessageSchema }>({ messages }); const toggled = ref(props.toggled); const aiTagRef = ref<HTMLElement | null>(null); const targetElement = ref<InstanceType<typeof BentoToggleButton> | null>(null); const popoverId = generateUid('b-ai-tag-popover'); watch( () => props.toggled, value => { toggled.value = value; } ); useClickOutside(aiTagRef, () => { closePopover(); }); const popoverActions = computed<BentoButtonActionsList>(() => props.action ? [ { ...props.action, variant: 'secondary', }, ] : undefined ); const emit = defineEmits<{ /** * Triggered when the popover is toggled */ (e: 'update:toggled', toggled: boolean): void; }>(); const onToggle = (value: boolean) => { toggled.value = value; emit('update:toggled', value); }; const closePopover = () => { if (toggled.value) { onToggle(false); } }; </script> <script lang="ts"> /** * The AI tag is a component used to transparently identify content, data, or experiences that have been generated or * enhanced by artificial intelligence. * * @example * import { BentoAiTag } from '@adyen/bento-vue2'; * * export default { * components: { BentoAiTag }, * template: ` * <bento-ai-tag * title="Input fields auto-filled by AI" * description="Based on your documents uploaded, AI has auto-filled some information for you." * /> * ` * } */ export default { i18n: { messages }, }; </script> <style lang="scss" scoped src="./ai-tag.scss" />
|
|
@@ -65,7 +65,7 @@ This creates a confusing and inaccessible experience for users of assistive tech
|
|
|
65
65
|
|
|
66
66
|
When expandable `bento-card` is used, then it's rendered by default with opened state.
|
|
67
67
|
|
|
68
|
-
You can control the opened/closed
|
|
68
|
+
You can control the opened/closed behavior of expandable `bento-card` with 'closed' property.
|
|
69
69
|
|
|
70
70
|
<Canvas of={CardStories.ExpandableClosed} />
|
|
71
71
|
|
|
@@ -135,9 +135,9 @@ const cardButtonActions = [{
|
|
|
135
135
|
`}
|
|
136
136
|
/>
|
|
137
137
|
|
|
138
|
-
> **Important note:** Actions as links will still be rendered as buttons meaning that native link
|
|
138
|
+
> **Important note:** Actions as links will still be rendered as buttons meaning that native link behavior like right
|
|
139
139
|
> clicking to open in new tab won't work. The Bento team is currently working on a solution to provide native link
|
|
140
|
-
>
|
|
140
|
+
> behavior to the actions.
|
|
141
141
|
|
|
142
142
|
## Accessibility
|
|
143
143
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Canvas, Meta, Controls, Source } from '@storybook/blocks';
|
|
2
|
+
import * as DataGridTagWithTextCellStories from './data-grid-tag-with-text-cell.stories';
|
|
3
|
+
import DataGridTagWithTextCellExample from '../../__tests__/data-grid-tag-with-text-cell-example.vue?raw';
|
|
4
|
+
|
|
5
|
+
<Meta of={DataGridTagWithTextCellStories} />
|
|
6
|
+
|
|
7
|
+
# Data Grid Tag With Text Cell
|
|
8
|
+
|
|
9
|
+
The `bento-data-grid-tag-with-text-cell` is a component designed to be used within cells of the `bento-data-grid`. It
|
|
10
|
+
displays a tag alongside a text value.
|
|
11
|
+
|
|
12
|
+
<Canvas of={DataGridTagWithTextCellStories.Default} />
|
|
13
|
+
|
|
14
|
+
## Use Cases
|
|
15
|
+
|
|
16
|
+
Use a `bento-data-grid-tag-with-text-cell` to display categorized data with labels, such as:
|
|
17
|
+
|
|
18
|
+
- HTTP method indicators (GET, POST, PUT, DELETE)
|
|
19
|
+
- Status labels with descriptions
|
|
20
|
+
- Category tags with associated values
|
|
21
|
+
|
|
22
|
+
### Do not use
|
|
23
|
+
|
|
24
|
+
Don't use the `bento-data-grid-tag-with-text-cell` component outside of a data grid. For standalone tags, use
|
|
25
|
+
`bento-tag`.
|
|
26
|
+
|
|
27
|
+
## How to use
|
|
28
|
+
|
|
29
|
+
The component is intended to be used within a `bento-data-grid`'s item slot.
|
|
30
|
+
|
|
31
|
+
<Source dark language="html" code={DataGridTagWithTextCellExample} />
|
|
32
|
+
|
|
33
|
+
## Props
|
|
34
|
+
|
|
35
|
+
<Controls />
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import BentoDataGridTagWithTextCell from './data-grid-tag-with-text-cell.vue'; import DataGridTagWithTextCellDefaultExample from './__tests__/data-grid-tag-with-text-cell-default-example.vue?raw'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import type { Meta, StoryObj } from '@storybook/vue'; import { isVue2 } from 'vue-demi'; const meta: Meta = { title: 'Data Grid/Components/Data Grid Tag With Text Cell', component: BentoDataGridTagWithTextCell, argTypes: { tag: { control: { type: 'object' }, }, value: { control: { type: 'text' }, }, }, }; export default meta; type Story = StoryObj<typeof BentoDataGridTagWithTextCell>; export const Default: Story = { render: (_args, { argTypes }) => ({ components: { BentoDataGridTagWithTextCell }, props: Object.keys(argTypes), template: ` <bento-data-grid-tag-with-text-cell v-bind="args" /> `, setup(props) { return { // Values args: isVue2 ? props : _args, }; }, }), args: { tag: { label: 'POST', variant: 'blue' }, value: 'Sample text', condensed: false, }, parameters: storybookDocsParameter(DataGridTagWithTextCellDefaultExample), };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<template> <div class="b-data-grid-tag-with-text-cell"> <bento-tag v-bind="tag" /> <bento-typography el="span">{{ value }}</bento-typography> </div> </template> <script setup lang="ts"> import BentoTag from '@/components/tag/tag.vue'; import BentoTypography from '@/components/typography/typography.vue'; import { type BentoDataGridTagWithTextCellProps } from './data-grid-tag-with-text-cell.types'; defineProps<BentoDataGridTagWithTextCellProps>(); </script> <script lang="ts"> /** * The bento-data-grid-tag-with-text-cell is a component for `bento-data-grid` that displays a tag alongside a text value. * * @example * import { BentoDataGridTagWithTextCell } from '@adyen/bento-vue2'; * * export default { * components: { BentoDataGridTagWithTextCell }, * template: ` * <bento-data-grid-tag-with-text-cell :tag="{ label: 'POST', variant: 'blue' }" value="Sample text" /> * ` * } */ export default {}; </script> <style lang="scss" scoped src="./data-grid-tag-with-text-cell.scss" />
|
|
@@ -66,6 +66,7 @@ filter and sort the information.
|
|
|
66
66
|
- [Action types](#action-types)
|
|
67
67
|
- [Components](#components)
|
|
68
68
|
- [Summary Cell](#summary-cell)
|
|
69
|
+
- [Tag with Text Cell](#tag-with-text-cell)
|
|
69
70
|
- [Trend Cell](#trend-cell)
|
|
70
71
|
- [Everything Bagel Example](#everything-bagel-example)
|
|
71
72
|
- [Server side filtering and sorting](#server-side-filtering-and-sorting)
|
|
@@ -170,7 +171,7 @@ This can be done by using the `numeric` boolean property
|
|
|
170
171
|
|
|
171
172
|
<Canvas of={ComponentStories.EverythingBagelExample} />
|
|
172
173
|
|
|
173
|
-
It is possible to
|
|
174
|
+
It is possible to customize the text overflow for columns - note that this will affect on all row cells for that column.
|
|
174
175
|
|
|
175
176
|
This can be done by using the properties:
|
|
176
177
|
|
|
@@ -346,7 +347,7 @@ UX rules to decide which one to set:
|
|
|
346
347
|
#### Sticky filters
|
|
347
348
|
|
|
348
349
|
By default, filters will be sticky, showing always on top of the page as the user scrolls, along with the column
|
|
349
|
-
headers. This
|
|
350
|
+
headers. This behavior can be disabled by setting `stickyFilters` to false.
|
|
350
351
|
|
|
351
352
|
### Pagination
|
|
352
353
|
|
|
@@ -583,7 +584,7 @@ Enabling this boolean property will add the Column wiew settings functionality.
|
|
|
583
584
|
|
|
584
585
|
It's possible to nest content inside of each data row in the Datagrid. In order to do this you have to set the
|
|
585
586
|
`hasNestedContent` to true and then use the `nested-slot` slot to render elements in the slot. This slot passes on the
|
|
586
|
-
`BentoDatagridDataItem` object which you can use to
|
|
587
|
+
`BentoDatagridDataItem` object which you can use to customize the slot.
|
|
587
588
|
|
|
588
589
|
You can also use the `shouldShowNestedContent` property to filter which rows should show the nested content slot. This
|
|
589
590
|
property accepts a function of type `BentoDatagridShouldShowNestedContentFn`. i.e.
|
|
@@ -653,7 +654,7 @@ Note: For `rowActions`, the columnKey parameter is not applicable and will not b
|
|
|
653
654
|
| ------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
654
655
|
| `variant` | `string` | Must be set to 'copy'. |
|
|
655
656
|
| `isShort` | `boolean` | If set to true, will only show icon. |
|
|
656
|
-
| `getCopyData` | `(rowDataItem: BentoDatagridDataItem, columnKey: string) => string` | A function that can be used to
|
|
657
|
+
| `getCopyData` | `(rowDataItem: BentoDatagridDataItem, columnKey: string) => string` | A function that can be used to customize what data is copied upon the user clicking the button. |
|
|
657
658
|
|
|
658
659
|
##### Edit action
|
|
659
660
|
|
|
@@ -718,6 +719,17 @@ Passing a `searchTerm` (from the filter bar or global search) to the summary cel
|
|
|
718
719
|
You can also use the `tooltipText` property to override the default tooltip text. By default, the tooltip displays
|
|
719
720
|
`"{numberOfResultsInItems} results"`.
|
|
720
721
|
|
|
722
|
+
### Tag With Text Cell
|
|
723
|
+
|
|
724
|
+
<Canvas of={ComponentStories.TagWithTextCell} />
|
|
725
|
+
|
|
726
|
+
The `bento-data-grid-tag-with-text-cell` is a specialized component for `bento-data-grid` that displays a tag alongside
|
|
727
|
+
a text value. This is useful for showing categorized data with labels, such as status indicators with descriptions.
|
|
728
|
+
|
|
729
|
+
To use it, place `bento-data-grid-tag-with-text-cell` inside a column's item slot (e.g., `#item-endpoint`). Pass a `tag`
|
|
730
|
+
object with [BentoTag properties](../?path=/docs/components-tag--docs#properties) and a `value` string for the text
|
|
731
|
+
content.
|
|
732
|
+
|
|
721
733
|
### Trend Cell
|
|
722
734
|
|
|
723
735
|
<Canvas of={ComponentStories.TrendCell} />
|