<!--
  - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
  - SPDX-License-Identifier: AGPL-3.0-or-later
-->

<!-- Accessibility guidelines:
https://www.w3.org/TR/wai-aria-practices/examples/menu-button/menu-button-actions.html -->

<docs>
### Single action

```vue
<template>
	<NcActions>
		<NcActionButton @click="actionDelete">
			<template #icon>
				<IconTrashCanOutline :size="20" />
			</template>
			Delete
		</NcActionButton>
	</NcActions>
</template>
<script>
import IconTrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'

export default {
	components: {
		IconTrashCanOutline,
	},
	methods: {
		actionDelete() {
			alert('Delete')
		},
	},
}
</script>
```

### Multiple actions

```vue
<template>
	<NcActions>
		<NcActionButton @click="showMessage('Edit')">
			<template #icon>
				<IconPencilOutline :size="20" />
			</template>
			Edit
		</NcActionButton>
		<NcActionButton @click="showMessage('Delete')">
			<template #icon>
				<IconTrashCanOutline :size="20" />
			</template>
			Delete
		</NcActionButton>
		<NcActionLink href="https://nextcloud.com">
			<template #icon>
				<IconOpenInNew :size="20" />
			</template>
			Link
		</NcActionLink>
	</NcActions>
</template>
<script>
import IconTrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'
import IconOpenInNew from 'vue-material-design-icons/OpenInNew.vue'
import IconPencilOutline from 'vue-material-design-icons/PencilOutline.vue'

export default {
	components: {
		IconTrashCanOutline,
		IconOpenInNew,
		IconPencilOutline,
	},
	methods: {
		showMessage(msg) {
			alert(msg)
		},
	},
}
</script>
```

### Multiple actions with 2 items inline

```vue
<template>
	<NcActions :inline="2">
		<NcActionButton @click="showMessage('Add')">
			<template #icon>
				<IconPlus :size="20" />
			</template>
			Add
		</NcActionButton>
		<NcActionButton @click="showMessage('Edit')">
			<template #icon>
				<IconPencilOutline :size="20" />
			</template>
			Edit
		</NcActionButton>
		<NcActionButton @click="showMessage('Delete')">
			<template #icon>
				<IconTrashCanOutline :size="20" />
			</template>
			Delete
		</NcActionButton>
		<NcActionLink href="https://nextcloud.com">
			<template #icon>
				<IconOpenInNew :size="20" />
			</template>
			Link
		</NcActionLink>
	</NcActions>
</template>
<script>
import IconPlus from 'vue-material-design-icons/Plus.vue'
import IconTrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'
import IconOpenInNew from 'vue-material-design-icons/OpenInNew.vue'
import IconPencilOutline from 'vue-material-design-icons/PencilOutline.vue'

export default {
	components: {
		IconTrashCanOutline,
		IconOpenInNew,
		IconPencilOutline,
		IconPlus,
	},
	methods: {
		showMessage(msg) {
			alert(msg)
		},
	},
}
</script>
```

### Multiple actions with 2 items inline AND forced names

```vue
<template>
	<NcActions :force-name="true" :inline="2">
		<NcActionButton @click="showMessage('Add')">
			<template #icon>
				<IconPlus :size="20" />
			</template>
			Add
		</NcActionButton>
		<NcActionButton @click="showMessage('Edit')">
			<template #icon>
				<IconPencilOutline :size="20" />
			</template>
			Edit
		</NcActionButton>
		<NcActionButton @click="showMessage('Delete')">
			<template #icon>
				<IconTrashCanOutline :size="20" />
			</template>
			Delete
		</NcActionButton>
		<NcActionLink href="https://nextcloud.com">
			<template #icon>
				<IconOpenInNew :size="20" />
			</template>
			Link
		</NcActionLink>
	</NcActions>
</template>
<script>
import IconPlus from 'vue-material-design-icons/Plus.vue'
import IconTrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'
import IconOpenInNew from 'vue-material-design-icons/OpenInNew.vue'
import IconPencilOutline from 'vue-material-design-icons/PencilOutline.vue'
export default {
	components: {
		IconTrashCanOutline,
		IconOpenInNew,
		IconPencilOutline,
		IconPlus,
	},
	methods: {
		showMessage(msg) {
			alert(msg)
		},
	},
}
</script>
```

### Multiple actions with custom icon

```vue
<template>
	<NcActions>
		<template #icon>
			<IconPencilOutline :size="20" />
		</template>
		<NcActionButton @click="showMessage('Edit')">
			<template #icon>
				<IconPencilOutline :size="20" />
			</template>
			Edit
		</NcActionButton>
		<NcActionButton @click="showMessage('Delete')">
			<template #icon>
				<IconTrashCanOutline :size="20" />
			</template>
			Delete
		</NcActionButton>
		<NcActionLink href="https://nextcloud.com">
			<template #icon>
				<IconOpenInNew :size="20" />
			</template>
			Link
		</NcActionLink>
	</NcActions>
</template>
<script>
import IconTrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'
import IconOpenInNew from 'vue-material-design-icons/OpenInNew.vue'
import IconPencilOutline from 'vue-material-design-icons/PencilOutline.vue'

export default {
	components: {
		IconTrashCanOutline,
		IconOpenInNew,
		IconPencilOutline,
	},
	methods: {
		showMessage(msg) {
			alert(msg)
		},
	},
}
</script>
```

### With menu name

```vue
<template>
	<NcActions menu-name="Object management">
		<template #icon>
			<IconPencilOutline :size="20" />
		</template>
		<NcActionButton>
			<template #icon>
				<IconPencilOutline :size="20" />
			</template>
			Rename
		</NcActionButton>
		<NcActionButton>
			<template #icon>
				<IconTrashCanOutline :size="20" />
			</template>
			Delete
		</NcActionButton>
		<NcActionButton>
			<template #icon>
				<IconArrowRight :size="20" />
			</template>
			Validate
		</NcActionButton>
		<NcActionButton>
			<template #icon>
				<IconTrayArrowDown :size="20" />
			</template>
			Download
		</NcActionButton>
	</NcActions>
</template>
<script>
import IconArrowRight from 'vue-material-design-icons/ArrowRight.vue'
import IconTrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'
import IconTrayArrowDown from 'vue-material-design-icons/TrayArrowDown.vue'
import IconPencilOutline from 'vue-material-design-icons/PencilOutline.vue'

export default {
	components: {
		IconArrowRight,
		IconTrashCanOutline,
		IconTrayArrowDown,
		IconPencilOutline,
	},
}
</script>
```

### Various icons styles
```vue
<template>
	<NcActions :primary="true">
		<NcActionButton>
			<template #icon>
				<IconPencilOutline :size="20" />
			</template>
			Edit
		</NcActionButton>
		<NcActionButton>
			<template #icon>
				<IconTrashCanOutline :size="20" />
			</template>
			Delete
		</NcActionButton>
	</NcActions>
</template>
<script>
import IconTrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'
import IconPencilOutline from 'vue-material-design-icons/PencilOutline.vue'

export default {
	components: {
		IconTrashCanOutline,
		IconPencilOutline,
	},
}
</script>
```

```vue
<template>
	<NcActions :primary="true" menu-name="Object management">
		<template #icon>
			<IconPlus :size="20" />
		</template>
		<NcActionButton>
			<template #icon>
				<IconPencilOutline :size="20" />
			</template>
			Rename
		</NcActionButton>
		<NcActionButton>
			<template #icon>
				<IconTrashCanOutline :size="20" />
			</template>
			Delete
		</NcActionButton>
		<NcActionButton>
			<template #icon>
				<IconArrowRight :size="20" />
			</template>
			Validate
		</NcActionButton>
		<NcActionButton>
			<template #icon>
				<IconTrayArrowDown :size="20" />
			</template>
			Download
		</NcActionButton>
	</NcActions>
</template>
<script>
import IconArrowRight from 'vue-material-design-icons/ArrowRight.vue'
import IconTrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'
import IconTrayArrowDown from 'vue-material-design-icons/TrayArrowDown.vue'
import IconPencilOutline from 'vue-material-design-icons/PencilOutline.vue'
import IconPlus from 'vue-material-design-icons/Plus.vue'

export default {
	components: {
		IconArrowRight,
		IconTrashCanOutline,
		IconTrayArrowDown,
		IconPencilOutline,
		IconPlus,
	},
}
</script>
```

### Custom icon slot
To be used with `vue-material-design-icons` only. For icon classes use the `default-icon` slot.
It can be used with one or multiple actions.
```vue
<template>
	<div style="display: flex;align-items: center;">
		<NcButton @click="toggled = !toggled">Toggle multiple action</NcButton>
		<NcActions>
			<template #icon>
				<IconDotsHorizontalCircleOutline :size="20" />
			</template>
			<NcActionButton>
				<template #icon>
					<IconMicrophoneOff :size="20" />
				</template>
				Mute
			</NcActionButton>
			<NcActionButton v-if="toggled">
				<template #icon>
					<IconTrashCanOutline :size="20" />
				</template>
				Delete
			</NcActionButton>
		</NcActions>
	</div>
</template>
<script>
import IconTrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'
import IconDotsHorizontalCircleOutline from 'vue-material-design-icons/DotsHorizontalCircleOutline.vue'
import IconMicrophoneOff from 'vue-material-design-icons/MicrophoneOff.vue'

export default {
	components: {
		IconTrashCanOutline,
		IconDotsHorizontalCircleOutline,
		IconMicrophoneOff,
	},
	data() {
		return {
			toggled: false
		}
	}
}
</script>
```

### Custom icon slot in child elements
```vue
<template>
	<NcActions :primary="true">
		<NcActionButton>
			<template #icon>
				<IconMagnify :size="20" />
			</template>
			Search
		</NcActionButton>
		<NcActionButton>
			<template #icon>
				<IconTrashCanOutline :size="20" />
			</template>
			Delete
		</NcActionButton>
	</NcActions>
</template>
<script>
import IconTrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'
import IconMagnify from 'vue-material-design-icons/Magnify.vue'

export default {
	components: {
		IconTrashCanOutline,
		IconMagnify,
	},
}
</script>
```

### Design variants

```vue
<template>
	<div>
		<NcActions :variant="current">
			<template #icon>
				<IconSelectColor :size="20" />
			</template>

			<NcActionButton v-if="current" close-after-click @click="define()">
				<template #icon>
					<IconTrashCanOutline :size="20" />
				</template>
				Remove
			</NcActionButton>

			<NcActionButton v-for="row in variants" close-after-click @click="define(row)" :key="`type-icon--${row}`">
				<template #icon>
					<IconCheckboxMarkedCircleOutline v-if="row === current" :size="20" />
					<IconSelectColor v-else :size="20" />
				</template>
				{{ row }}
			</NcActionButton>
		</NcActions>

		<NcActions :variant="current" menu-name="Choose a variant">
			<NcActionButton v-if="current" close-after-click @click="define()">
				<template #icon>
					<IconTrashCanOutline :size="20" />
				</template>
				Remove
			</NcActionButton>

			<NcActionButton v-for="row in variants" close-after-click @click="define(row)" :key="`type-text--${row}`">
				<template #icon>
					<IconCheckboxMarkedCircleOutline v-if="row === current" :size="20" />
					<IconSelectColor v-else :size="20" />
				</template>
				{{ row }}
			</NcActionButton>
		</NcActions>

		<NcActions :variant="current"  menu-name="Choose a variant">
			<template #icon>
				<IconSelectColor :size="20" />
			</template>

			<NcActionButton v-if="current" close-after-click @click="define()">
				<template #icon>
					<IconTrashCanOutline :size="20" />
				</template>
				Remove
			</NcActionButton>

			<NcActionButton v-for="row in variants" close-after-click @click="define(row)" :key="`type-icon-text--${row}`">
				<template #icon>
					<IconCheckboxMarkedCircleOutline v-if="row === current" :size="20" />
					<IconSelectColor v-else :size="20" />
				</template>
				{{ row }}
			</NcActionButton>
		</NcActions>
	</div>
</template>

<script>
import IconTrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'
import IconPaletteOutline from 'vue-material-design-icons/PaletteOutline.vue'
import IconSelectColor from 'vue-material-design-icons/SelectColor.vue'
import IconCheckboxMarkedCircleOutline from 'vue-material-design-icons/CheckboxMarkedCircleOutline.vue'

export default {
	components: {
		IconTrashCanOutline,
		IconPaletteOutline,
		IconSelectColor,
		IconCheckboxMarkedCircleOutline,
	},
	data() {
		return {
			current: 'primary',
			variants: [
				'primary',
				'secondary',
				'tertiary',
				'error',
				'warning',
				'success'
			]
		}
	},
	methods: {
		define(row = undefined) {
			this.current = row
		}
	}
}
</script>
```

### Wide buttons

```vue
<template>
	<NcActions menu-name="Object management" wide>
		<template #icon>
			<IconPencilOutline :size="20" />
		</template>
		<NcActionButton>
			<template #icon>
				<IconPencilOutline :size="20" />
			</template>
			Rename
		</NcActionButton>
		<NcActionButton>
			<template #icon>
				<IconTrashCanOutline :size="20" />
			</template>
			Delete
		</NcActionButton>
		<NcActionButton>
			<template #icon>
				<IconArrowRight :size="20" />
			</template>
			Validate
		</NcActionButton>
		<NcActionButton>
			<template #icon>
				<IconTrayArrowDown :size="20" />
			</template>
			Download
		</NcActionButton>
	</NcActions>
	<NcActions wide>
		<template #icon>
			<IconPencilOutline :size="20" />
		</template>
		<NcActionButton>
			<template #icon>
				<IconPencilOutline :size="20" />
			</template>
			Rename
		</NcActionButton>
		<NcActionButton>
			<template #icon>
				<IconTrashCanOutline :size="20" />
			</template>
			Delete
		</NcActionButton>
		<NcActionButton>
			<template #icon>
				<IconArrowRight :size="20" />
			</template>
			Validate
		</NcActionButton>
		<NcActionButton>
			<template #icon>
				<IconTrayArrowDown :size="20" />
			</template>
			Download
		</NcActionButton>
	</NcActions>
</template>
<script>
import IconArrowRight from 'vue-material-design-icons/ArrowRight.vue'
import IconTrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'
import IconTrayArrowDown from 'vue-material-design-icons/TrayArrowDown.vue'
import IconPencilOutline from 'vue-material-design-icons/PencilOutline.vue'

export default {
	components: {
		IconArrowRight,
		IconTrashCanOutline,
		IconTrayArrowDown,
		IconPencilOutline,
	},
}
</script>
```

### Use cases

```vue
<template>
	<div>
		<h2>Application menu</h2>
		<p>Has buttons, button groups, links and router links, separators, texts. May have checkboxes and radio buttons. Separator can be used to make groups of radio buttons as well.</p>
		<p><kbd>Arrows</kbd> are used to navigate between items, <kbd>Tab</kbd> is used to navigate to the next UI element on the page.</p>
		<p>
			<NcActions aria-label="Email menu" variant="tertiary">
				<NcActionButtonGroup>
					<NcActionButton>
						<template #icon>
							<IconStarOutline :size="20" />
						</template>
						Favorite
					</NcActionButton>
					<NcActionButton>
						<template #icon>
							<IconEmail :size="20" />
						</template>
						Unread
					</NcActionButton>
					<NcActionButton>
						<template #icon>
							<IconBookmarkOutline :size="20" />
						</template>
						Important
					</NcActionButton>
				</NcActionButtonGroup>
				<NcActionText>
					<template #icon>
						<IconClockOutline :size="20" />
					</template>
					{{ new Date().toLocaleDateString('en-US') }}
				</NcActionText>
				<NcActionSeparator />
				<NcActionButton>
					<template #icon>
						<IconAlertOctagonOutline :size="20" />
					</template>
					Mark as spam
				</NcActionButton>
				<NcActionCheckbox v-model="selected">
					Select
				</NcActionCheckbox>
				<NcActionButton>
					<template #icon>
						<IconOpenInNew :size="20" />
					</template>
					Move thread
				</NcActionButton>
				<NcActionLink href="#">
					<template #icon>
						<IconTrayArrowDown :size="20" />
					</template>
					Download message
				</NcActionLink>
			</NcActions>
		</p>
		<p>
			<NcActions aria-label="Text settings" variant="tertiary">
				<template #icon>
					<IconFormatTitle :size="20" />
				</template>
				<NcActionButtonGroup name="Alignment">
					<NcActionButton aria-label="Left">
						<template #icon>
							<IconFormatAlignLeft :size="20" />
						</template>
					</NcActionButton>
					<NcActionButton aria-label="Center">
						<template #icon>
							<IconFormatAlignCenter :size="20" />
						</template>
					</NcActionButton>
					<NcActionButton aria-label="Right">
						<template #icon>
							<IconFormatAlignRight :size="20" />
						</template>
					</NcActionButton>
				</NcActionButtonGroup>
				<NcActionSeparator />
				<NcActionCheckbox v-model="checked.bold" value="bold">
					<template #icon>
						<IconFormatBold :size="20" />
					</template>
					Bold
				</NcActionCheckbox>
				<NcActionCheckbox v-model="checked.italic" value="italic">
					<template #icon>
						<IconFormatItalic :size="20" />
					</template>
					Italic
				</NcActionCheckbox>
				<NcActionCheckbox v-model="checked.underline" value="underline">
					<template #icon>
						<IconFormatUnderline :size="20" />
					</template>
					Underline
				</NcActionCheckbox>
				<NcActionSeparator />
				<NcActionRadio name="color" v-model="color.black" value="Black">Black</NcActionRadio>
				<NcActionRadio name="color" v-model="color.blue" value="Blue">Blue</NcActionRadio>
				<NcActionRadio name="color" v-model="color.red" value="Red">Red</NcActionRadio>
				<NcActionRadio name="color" v-model="color.green" value="Green">Green</NcActionRadio>
			</NcActions>
		</p>

		<h2>Navigation</h2>
		<p>Has links or router links. May use text elements, captions and separators.</p>
		<p>Uses classic <kbd>Tab</kbd> navigation.</p>
		<p>
			<NcActions aria-label="Applications navigation" :inline="2" variant="tertiary">
				<NcActionLink href="/apps/dashboard" icon="icon-category-dashboard-white">
					Dashboard
				</NcActionLink>
				<NcActionLink href="/apps/files" icon="icon-files-white">
					Files
				</NcActionLink>
				<NcActionLink href="/apps/spreed" icon="icon-talk-white">
					Talk
				</NcActionLink>
				<NcActionLink href="/apps/contacts" icon="icon-contacts-white">
					Contacts
				</NcActionLink>
				<NcActionLink href="/apps/circles" icon="icon-circles-white">
					Circles
				</NcActionLink>
			</NcActions>
		</p>

		<h2>Dialog</h2>
		<p>Includes data input elements, forms.</p>
		<p>Uses <kbd>Tab</kbd> navigation with a focus trap.</p>
		<p>
			<NcActions aria-label="Group management">
				<NcActionInput trailing-button-label="Submit" label="Rename group">
					<template #icon>
						<IconPencilOutline :size="20" />
					</template>
				</NcActionInput>
				<NcActionButton>
					<template #icon>
						<IconTrashCanOutline :size="20" />
					</template>
					Remove group
				</NcActionButton>
			</NcActions>
		</p>

		<h2>Tooltip</h2>
		<p>Has only text and no interactive elements.</p>
		<p>
			<NcActions aria-label="Contact" :inline="1">
				<NcActionLink aria-label="View profile" href="/u/alice" icon="icon-user-white">
					View profile
				</NcActionLink>
				<NcActionText icon="icon-timezone-white">
					Local time: 10:12
				</NcActionText>
			</NcActions>
		</p>
	</div>
</template>

<script>
// Common icons
import IconPencilOutline from 'vue-material-design-icons/PencilOutline.vue'
import IconTrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'

// Email icons
import IconStarOutline from 'vue-material-design-icons/StarOutline.vue'
import IconEmail from 'vue-material-design-icons/Email.vue'
import IconBookmarkOutline from 'vue-material-design-icons/BookmarkOutline.vue'
import IconClockOutline from 'vue-material-design-icons/ClockOutline.vue'
import IconAlertOctagonOutline from 'vue-material-design-icons/AlertOctagonOutline.vue'
import IconCheck from 'vue-material-design-icons/Check.vue'
import IconOpenInNew from 'vue-material-design-icons/OpenInNew.vue'
import IconTrayArrowDown from 'vue-material-design-icons/TrayArrowDown.vue'

// Formatting icons
import IconFormatTitle from 'vue-material-design-icons/FormatTitle.vue'
import IconFormatAlignLeft from 'vue-material-design-icons/FormatAlignLeft.vue'
import IconFormatAlignCenter from 'vue-material-design-icons/FormatAlignCenter.vue'
import IconFormatAlignRight from 'vue-material-design-icons/FormatAlignRight.vue'
import IconFormatBold from 'vue-material-design-icons/FormatBold.vue'
import IconFormatItalic from 'vue-material-design-icons/FormatItalic.vue'
import IconFormatUnderline from 'vue-material-design-icons/FormatUnderline.vue'

export default {
	components: {
		// Common icons
		IconPencilOutline,
		IconTrashCanOutline,

		// Email icons
		IconStarOutline,
		IconEmail,
		IconBookmarkOutline,
		IconClockOutline,
		IconAlertOctagonOutline,
		IconCheck,
		IconOpenInNew,
		IconTrayArrowDown,

		// Formatting icons
		IconFormatTitle,
		IconFormatAlignLeft,
		IconFormatAlignCenter,
		IconFormatAlignRight,
		IconFormatBold,
		IconFormatItalic,
		IconFormatUnderline,
	},

	data() {
		return {
			selected: false,
			// Formatting
			checked: {
				bold: true,
				italic: false,
				underline: false,
			},
			color: {
				black: true,
				blue: false,
				red: false,
				green: false,
			},
		}
	},
}
</script>

<style scoped>
p {
	margin: 1rem 0;
}
</style>
```

## NcActions children limitations

`<NcActions>` is supposed to be used with direct `<NcAction*>` children.
Although it works when actions are not direct children but wrapped in custom components, it has limitations:
- No `inline` prop property, including a single action display;
- Accessibility issues, including changed keyboard behavior;
- Invalid HTML.

```
<template>
	<table class="actions-limitations-table">
		<tr>
			<th style="width: 50%">Non-direct children</th>
			<th style="width: 50%">Direct NcAction* children</th>
		</tr>

		<tr>
			<th colspan="2">This single button is supposed to be rendered as inline action but it is rendered as a menu:</th>
		</tr>
		<tr>
			<td>
				<NcActions>
					<MyUserActionButton />
				</NcActions>
			</td>
			<td>
				<NcActions>
					<NcActionButton>
						<template #icon>
							<IconAccountOutline :size="20" />
						</template>
						Button
					</NcActionButton>
				</NcActions>
			</td>
		</tr>
		<tr>
			<th colspan="2">This NcActions is supposed to have 2 inline buttons but it has none:</th>
		</tr>
		<tr>
			<td>
				<NcActions :inline="2">
					<MyUserActionButton v-for="i in 4" />
				</NcActions>
			</td>
			<td>
				<NcActions :inline="2">
					<NcActionButton v-for="i in 4">
						<template #icon>
							<IconAccountOutline :size="20" />
						</template>
						Button
					</NcActionButton>
				</NcActions>
			</td>
		</tr>
		<tr>
			<th colspan="2">This NcActions is supposed to have a11y role menu and keyboard navigation but it acts like a dialog:</th>
		</tr>
		<tr>
			<td>
				<NcActions>
					<MyActionsList />
				</NcActions>
			</td>
			<td>
				<NcActions>
					<NcActionButton v-for="i in 4">
						<template #icon>
							<IconAccountOutline :size="20" />
						</template>
						Button
					</NcActionButton>
				</NcActions>
			</td>
		</tr>
	</table>
</template>

<script>
import { h, resolveComponent } from 'vue'
import IconAccountOutline from 'vue-material-design-icons/AccountOutline.vue'

export default {
	components: {
		IconAccountOutline,

		MyUserActionButton: {
			name: 'MyUserActionButton',
			components: { IconAccountOutline },
			render: () => h(resolveComponent('NcActionButton'), null, { default: () => 'Button', icon: () => h(IconAccountOutline, { size: 20 }) }),
		},

		MyActionsList: {
			name: 'MyActionsList',
			components: { IconAccountOutline },
			render: () => h('div', null, {
				default: () => [
					h(resolveComponent('NcActionButton'), null, { default: () => 'Button', icon: () => h(IconAccountOutline, { size: 20 }) }),
					h(resolveComponent('NcActionButton'), null, { default: () => 'Button', icon: () => h(IconAccountOutline, { size: 20 }) }),
					h(resolveComponent('NcActionButton'), null, { default: () => 'Button', icon: () => h(IconAccountOutline, { size: 20 }) }),
					h(resolveComponent('NcActionButton'), null, { default: () => 'Button', icon: () => h(IconAccountOutline, { size: 20 }) }),
				],
			}),
		},
	},
}
</script>

<style>
.actions-limitations-table {
	border-collapse: collapse;
	width: 100%;
	th,
	td {
		border: 1px solid var(--color-border);
		padding: var(--default-grid-baseline);
		max-width: 50%;
	}

	th {
		text-align: center;
		text-wrap: wrap;
	}
}
</style>
```
</docs>

<script>
import { computed, Fragment, h, mergeProps, warn } from 'vue'
import IconDotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'
import { useTrapStackControl } from '../../composables/useTrapStackControl.ts'
import { t } from '../../l10n.ts'
import { createElementId } from '../../utils/createElementId.ts'
import { isSlotPopulated } from '../../utils/isSlotPopulated.ts'
import NcButton from '../NcButton/index.ts'
import NcPopover from '../NcPopover/index.js'
import { NC_ACTIONS_CLOSE_MENU, NC_ACTIONS_IS_SEMANTIC_MENU } from './useNcActions.ts'

const focusableSelector = '.focusable'

/**
 * The Actions component can be used to display one ore more actions.
 * If only a single action is provided, it will be rendered as an inline icon.
 * For more, a menu indicator will be shown and a popover menu containing the
 * actions will be opened on click.
 *
 * @since 0.10.0
 */
export default {
	name: 'NcActions',

	components: {
		NcButton,
		NcPopover,
	},

	provide() {
		return {
			/**
			 * NcActions can be used as:
			 * - Application menu (has menu role)
			 * - Navigation (has no specific role, should be used an element with navigation role)
			 * - Popover with plain text or text inputs (has no specific role)
			 * Depending on the usage (used items), the menu and its items should have different roles for a11y.
			 * Provide the role for NcAction* components in the NcActions content.
			 *
			 * @type {import('vue').ComputedRef<boolean>}
			 */
			[NC_ACTIONS_IS_SEMANTIC_MENU]: computed(() => this.actionsMenuSemanticType === 'menu'),
			[NC_ACTIONS_CLOSE_MENU]: this.closeMenu,
		}
	},

	props: {
		/**
		 * Specify the open state of the popover menu
		 */
		open: {
			type: Boolean,
			default: false,
		},

		/**
		 * This disables the internal open management,
		 * so the actions menu only respects the `open` prop.
		 * This is e.g. necessary for the NcAvatar component
		 * to only open the actions menu after loading it's entries has finished.
		 */
		manualOpen: {
			type: Boolean,
			default: false,
		},

		/**
		 * Force the actions to display in a three dot menu
		 */
		forceMenu: {
			type: Boolean,
			default: false,
		},

		/**
		 * Force the name to show for single actions
		 */
		forceName: {
			type: Boolean,
			default: false,
		},

		/**
		 * Specify the menu name
		 */
		menuName: {
			type: String,
			default: null,
		},

		/**
		 * Apply primary styling for this menu
		 */
		primary: {
			type: Boolean,
			default: false,
		},

		/**
		 * Icon to show for the toggle menu button
		 * when more than one action is inside the actions component.
		 * Only replace the default three-dot icon if really necessary.
		 */
		defaultIcon: {
			type: String,
			default: '',
		},

		/**
		 * Aria label for the actions menu.
		 *
		 * If `menuName` is defined this will not be used to prevent
		 * any accessible name conflicts. This ensures that the
		 * element can be activated via voice input.
		 */
		ariaLabel: {
			type: String,
			default: t('Actions'),
		},

		/**
		 * Wanted direction of the menu
		 */
		placement: {
			type: String,
			default: 'bottom',
		},

		/**
		 * DOM element for the actions' popover boundaries
		 */
		boundariesElement: {
			type: Element,
			default: () => document.getElementById('content-vue') ?? document.querySelector('body'),
		},

		/**
		 * Selector for the actions' popover container
		 */
		container: {
			type: [Boolean, String, Object, Element],
			default: 'body',
		},

		/**
		 * Disabled state of the main button (single action or menu toggle)
		 */
		disabled: {
			type: Boolean,
			default: false,
		},

		/**
		 * Display x items inline out of the dropdown menu
		 * Will be ignored if `forceMenu` is set
		 */
		inline: {
			type: Number,
			default: 0,
		},

		/**
		 * Specifies the button variant used for trigger and single actions buttons.
		 *
		 * If left empty, the default button style will be applied.
		 *
		 * @since 8.23.0
		 */
		variant: {
			type: String,
			validator(value) {
				return ['primary', 'secondary', 'tertiary', 'tertiary-no-background', 'tertiary-on-primary', 'error', 'warning', 'success'].includes(value)
			},

			default: null,
		},

		/**
		 * Specifies whether the button should span all the available width.
		 */
		wide: {
			type: Boolean,
			default: false,
		},

		/**
		 * Specify the size used for trigger and single actions buttons.
		 *
		 * If left empty, the default button size will be applied.
		 */
		size: {
			type: String,
			default: 'normal',
			validator(value) {
				return ['small', 'normal', 'large'].includes(value)
			},
		},
	},

	emits: [
		'click',
		'blur',
		'focus',

		'close',
		'closed',
		'open',
		'opened',
		'update:open',
	],

	setup() {
		const randomId = createElementId()

		return {
			randomId,
		}
	},

	data() {
		return {
			opened: this.open,
			focusIndex: 0,
			/**
			 * @type {'menu'|'navigation'|'dialog'|'tooltip'|'unknown'}
			 */
			actionsMenuSemanticType: 'unknown',
		}
	},

	computed: {
		triggerButtonVariant() {
			// If requested, we use a primary button
			return this.variant || (this.primary
				? 'primary'
				// If it has a name, we use a secondary button
				: this.menuName ? 'secondary' : 'tertiary')
		},

		/**
		 * A11y roles and keyboard navigation configuration depending on the semantic type
		 */
		config() {
			/**
			 * Accessibility notes:
			 *
			 * There is no valid popup role for navigation and tooltip in `aria-haspopup`.
			 * aria-haspopup="true" is equivalent to aria-haspopup="menu".
			 * They must not be treated as menus.
			 *
			 * Having both arrow and tab navigation is not allowed for a11y.
			 * Either menu is an atomic UI element, and arrows select menu items, Tab moves to the next UI element.
			 * Or the menu is an expanded list of UI elements.
			 *
			 * Navigation type is just an "expanded" block, similar to native <details> element.
			 */
			const configs = {
				menu: {
					popupRole: 'menu',
					withArrowNavigation: true,
					withTabNavigation: false,
					withFocusTrap: false,
				},

				navigation: {
					popupRole: undefined,
					withArrowNavigation: false,
					withTabNavigation: true,
					withFocusTrap: false,
				},

				dialog: {
					popupRole: 'dialog',
					withArrowNavigation: false,
					withTabNavigation: true,
					withFocusTrap: true,
				},

				tooltip: {
					popupRole: undefined,
					withArrowNavigation: false,
					withTabNavigation: false,
					withFocusTrap: false,
				},

				// Due to Vue limitations, we sometimes cannot determine the true type
				// As a fallback use both arrow navigation and focus trap
				unknown: {
					popupRole: undefined,
					role: undefined,
					withArrowNavigation: true,
					withTabNavigation: false,
					withFocusTrap: true,
				},
			}
			return configs[this.actionsMenuSemanticType]
		},

		withFocusTrap() {
			return this.config.withFocusTrap
		},
	},

	watch: {
		// Watch parent prop
		open(state) {
			if (state === this.opened) {
				return
			}

			this.opened = state
		},

		opened() {
			// Ensure that pressing escape will close the menu even if the menu is not hovered
			// and not currently active, e.g. because user opened the context menu
			if (this.opened) {
				document.body.addEventListener('keydown', this.handleEscapePressed)
			} else {
				document.body.removeEventListener('keydown', this.handleEscapePressed)
			}
		},
	},

	created() {
		// When component has its own custom focus management
		// The global focus trap stack should be paused
		useTrapStackControl(() => this.opened, {
			disabled: () => this.config.withFocusTrap,
		})

		if ('ariaHidden' in this.$attrs) {
			warn('[NcActions]: Do not set the ariaHidden attribute as the root element will inherit the incorrect aria-hidden.')
		}
	},

	methods: {
		/**
		 * Get the name of the action component
		 *
		 * @param {import('vue').VNode} action - a vnode with a NcAction* component instance
		 * @return {string} the name of the action component
		 */
		getActionName(action) {
			return action?.type?.name
		},

		/**
		 * Do we have exactly one Action and
		 * is it allowed as a standalone element?
		 *
		 * @param {import('vue').VNode} action The action to check
		 * @return {boolean}
		 */
		isValidSingleAction(action) {
			return ['NcActionButton', 'NcActionLink', 'NcActionRouter'].includes(this.getActionName(action))
		},

		isAction(action) {
			return this.getActionName(action)?.startsWith?.('NcAction')
		},

		/**
		 * Check whether a icon prop value is an URL or not
		 *
		 * @param {string} url The icon prop value
		 */
		isIconUrl(url) {
			try {
				return !!(new URL(url, url.startsWith('/') ? window.location.origin : undefined))
			} catch {
				return false
			}
		},

		// MENU STATE MANAGEMENT
		toggleMenu(state) {
			if (state) {
				this.openMenu()
			} else {
				this.closeMenu()
			}
		},

		openMenu() {
			if (this.opened) {
				return
			}

			this.opened = true

			/**
			 * Event emitted when the popover menu open state is changed
			 *
			 * @type {boolean}
			 */
			this.$emit('update:open', true)

			/**
			 * Event emitted when the popover menu is opened
			 */
			this.$emit('open')
		},

		async closeMenu(returnFocus = true) {
			if (!this.opened) {
				return
			}

			// Wait for the next tick to keep the menu in DOM, allowing other components to find what button in what menu was used,
			// for example, to implement auto set return focus.
			// NcPopover will actually remove the menu from DOM also on the next tick.
			await this.$nextTick()

			this.opened = false

			this.$refs.popover?.clearFocusTrap({ returnFocus })

			/**
			 * Event emitted when the popover menu open state is changed
			 *
			 * @type {boolean}
			 */
			this.$emit('update:open', false)

			/**
			 * Event emitted when the popover menu is closed
			 */
			this.$emit('close')

			// close everything
			this.focusIndex = 0

			if (returnFocus) {
				// Focus back the trigger button
				this.$refs.triggerButton?.$el.focus()
			}
		},

		/**
		 * Called when popover is shown after the show delay
		 */
		onOpened() {
			this.$nextTick(() => {
				this.focusFirstAction(null)

				/**
				 * Event emitted when the popover menu is opened.
				 *
				 * This event is emitted after `update:open` was emitted and the opening transition finished.
				 */
				this.$emit('opened')
			})
		},

		onClosed() {
			/**
			 * Event emitted when the popover menu is closed.
			 *
			 * This event is emitted after `update:open` was emitted and the closing transition finished.
			 */
			this.$emit('closed')
		},

		// MENU KEYS & FOCUS MANAGEMENT
		/**
		 * @return {HTMLElement|null}
		 */
		getCurrentActiveMenuItemElement() {
			return this.$refs.menu.querySelector('li.active')
		},

		/**
		 * @return {NodeList<HTMLElement>}
		 */
		getFocusableMenuItemElements() {
			return this.$refs.menu.querySelectorAll(focusableSelector)
		},

		/**
		 * Dispatches the keydown listener to different handlers
		 *
		 * @param {object} event The keydown event
		 */
		onKeydown(event) {
			if (event.key === 'Tab') {
				if (this.config.withFocusTrap) {
					// Focus is managed by focus-trap
					return
				}

				if (!this.config.withTabNavigation) {
					// Tab is not used for navigation - close the menu
					// Return focus to restore Tab sequence
					// So browser will correctly move focus to the next element
					this.closeMenu(true)
					return
				}

				// Tab is used for classic navigation but we implement it manually

				event.preventDefault()

				const focusList = this.getFocusableMenuItemElements()
				const focusIndex = [...focusList].indexOf(document.activeElement)
				if (focusIndex === -1) {
					// This is not supposed to happen
					// But if it does - do nothing and keep native behavior
					return
				}
				const newFocusIndex = event.shiftKey ? focusIndex - 1 : focusIndex + 1

				// There is no focus-trap, so going out of the menu closes it
				if (newFocusIndex < 0 || newFocusIndex === focusList.length) {
					this.closeMenu(true)
				}

				// Update current focused element
				this.focusIndex = newFocusIndex
				this.focusAction()
				return
			}

			if (this.config.withArrowNavigation) {
				if (event.key === 'ArrowUp') {
					this.focusPreviousAction(event)
				}

				if (event.key === 'ArrowDown') {
					this.focusNextAction(event)
				}

				if (event.key === 'PageUp') {
					this.focusFirstAction(event)
				}

				if (event.key === 'PageDown') {
					this.focusLastAction(event)
				}
			}

			this.handleEscapePressed(event)
		},

		onTriggerKeydown(event) {
			if (event.key === 'Escape') {
				// Tooltip has no focusable elements and the focus remains on the trigger button.
				// So keydown event on the menu cannot be handled to close Tooltip on Escape.
				// Handle on the trigger.
				if (this.actionsMenuSemanticType === 'tooltip') {
					this.closeMenu()
				}
			}
		},

		handleEscapePressed(event) {
			if (event.key === 'Escape') {
				this.closeMenu()
				event.preventDefault()
			}
		},

		removeCurrentActive() {
			const currentActiveElement = this.$refs.menu.querySelector('li.active')
			if (currentActiveElement) {
				currentActiveElement.classList.remove('active')
			}
		},

		focusAction() {
			// TODO: have a global disabled state for non input elements
			const focusElement = this.getFocusableMenuItemElements()[this.focusIndex]
			if (focusElement) {
				this.removeCurrentActive()
				const liMenuParent = focusElement.closest('li.action')
				focusElement.focus()
				if (liMenuParent) {
					liMenuParent.classList.add('active')
				}
			}
		},

		focusPreviousAction(event) {
			if (this.opened) {
				if (this.focusIndex === 0) {
					this.focusLastAction(event)
				} else {
					this.preventIfEvent(event)
					this.focusIndex = this.focusIndex - 1
				}
				this.focusAction()
			}
		},

		focusNextAction(event) {
			if (this.opened) {
				const indexLength = this.getFocusableMenuItemElements().length - 1
				if (this.focusIndex === indexLength) {
					this.focusFirstAction(event)
				} else {
					this.preventIfEvent(event)
					this.focusIndex = this.focusIndex + 1
				}
				this.focusAction()
			}
		},

		focusFirstAction(event) {
			if (this.opened) {
				this.preventIfEvent(event)
				// In case a NcActionButton is considered checked we will use this one as a initial focus
				// Having aria-checked is the simplest way to determine the checked state of a button
				// TODO: determine when we need to focus the first checked item and when we not, for example, if menu has many radio groups
				const firstCheckedIndex = [...this.getFocusableMenuItemElements()].findIndex((button) => {
					return button.getAttribute('aria-checked') === 'true' && button.getAttribute('role') === 'menuitemradio'
				})
				this.focusIndex = firstCheckedIndex > -1 ? firstCheckedIndex : 0
				this.focusAction()
			}
		},

		focusLastAction(event) {
			if (this.opened) {
				this.preventIfEvent(event)
				this.focusIndex = this.getFocusableMenuItemElements().length - 1
				this.focusAction()
			}
		},

		preventIfEvent(event) {
			if (event) {
				event.preventDefault()
				event.stopPropagation()
			}
		},

		onFocus(event) {
			this.$emit('focus', event)
		},

		onBlur(event) {
			this.$emit('blur', event)

			// When there is no focusable elements to handle Tab press from actions menu
			// It requires manual closing
			if (this.actionsMenuSemanticType === 'tooltip') {
				// Tooltip is supposed to have no focusable element.
				// However, if there is a custom focusable element, it will be auto-focused and cause the menu to be closed on open.
				if (this.$refs.menu && this.getFocusableMenuItemElements().length === 0) {
					this.closeMenu(false)
				}
			}
		},

		onClick(event) {
			/**
			 * Event emitted when the menu toggle button is clicked.
			 *
			 * This is e.g. necessary for the NcAvatar component
			 * which needs to fetch the menu items on click.
			 *
			 * @type {PointerEvent}
			 */
			this.$emit('click', event)
		},
	},

	/**
	 * The render function to display the component
	 *
	 * @return {object|undefined} The created VNode
	 */
	render() {
		const actions = []
		// We have to iterate over all slot elements
		const findActions = (vnodes, actions) => {
			vnodes.forEach((vnode) => {
				if (this.isAction(vnode)) {
					actions.push(vnode)
					return
				}
				// If we encounter a Fragment, we have to check its children too
				if (vnode.type === Fragment) {
					findActions(vnode.children, actions)
				}
			})
		}
		findActions(this.$slots.default?.(), actions)

		// Check that we have at least one action
		if (actions.length === 0) {
			return
		}

		/**
		 * Separate the actions into inline and menu actions
		 */

		/**
		 * @type {import('vue').VNode[]}
		 */
		let validInlineActions = actions.filter(this.isValidSingleAction)
		if (this.forceMenu && validInlineActions.length > 0 && this.inline > 0) {
			warn('Specifying forceMenu will ignore any inline actions rendering.')
			validInlineActions = []
		}
		/**
		 * @type {import('vue').VNode[]}
		 */
		const inlineActions = validInlineActions.slice(0, this.inline)
		/**
		 * @type {import('vue').VNode[]}
		 */
		const menuActions = actions.filter((action) => !inlineActions.includes(action))

		/**
		 * Determine what kind of menu we have.
		 * It defines keyboard navigation and a11y.
		 */

		const menuItemsActions = ['NcActionButton', 'NcActionButtonGroup', 'NcActionCheckbox', 'NcActionRadio']
		const textInputActions = ['NcActionInput', 'NcActionTextEditable']
		const linkActions = ['NcActionLink', 'NcActionRouter']

		const hasTextInputAction = menuActions.some((action) => textInputActions.includes(this.getActionName(action)))
		const hasMenuItemAction = menuActions.some((action) => menuItemsActions.includes(this.getActionName(action)))
		const hasLinkAction = menuActions.some((action) => linkActions.includes(this.getActionName(action)))

		if (hasTextInputAction) {
			this.actionsMenuSemanticType = 'dialog'
		} else if (hasMenuItemAction) {
			this.actionsMenuSemanticType = 'menu'
		} else if (hasLinkAction) {
			this.actionsMenuSemanticType = 'navigation'
		} else {
			// (!) Hotfix (!)
			// In Vue 2 it is not easy to search for NcAction* in sub-component of a slot.
			// When a menu is rendered, children are not mounted yet.
			// If we have NcActions > MyActionsList > NcActionButton, only MyActionsList's vnode is available.
			// So when NcActions has actions as non-direct children, here then we don't know about them.
			// Like this menu has no buttons/links/inputs.
			// It makes the menu incorrectly considered a tooltip.
			const ncActions = actions.filter((action) => this.getActionName(action).startsWith('NcAction'))
			if (ncActions.length === actions.length) {
				// True tooltip
				this.actionsMenuSemanticType = 'tooltip'
			} else {
				// Custom components are passed to the NcActions
				this.actionsMenuSemanticType = 'unknown'
			}
		}

		/**
		 * Render the provided action
		 *
		 * @param {import('vue').VNode} action the action to render
		 * @return {import('vue').VNode}
		 */
		const renderInlineAction = (action) => {
			const iconProp = action?.props?.icon
			const icon = action?.children?.icon?.()?.[0] ?? (
				this.isIconUrl(iconProp)
					? h('img', { class: 'action-item__menutoggle__icon', src: iconProp, alt: '' })
					: h('span', { class: ['icon', iconProp] })
			)
			const text = action?.children?.default?.()?.[0]?.children?.trim()
			const buttonText = this.forceName ? text : ''

			let title = action?.props?.title
			// Show a default title for single actions if none is present
			if (!(this.forceName || title)) {
				title = text
			}

			const propsToForward = { ...(action?.props ?? {}) }
			const type = ['submit', 'reset'].includes(propsToForward.type) ? propsToForward.modelValue : 'button'
			// not available on NcButton or with different meaning
			delete propsToForward.modelValue
			delete propsToForward.type

			return h(
				NcButton,
				mergeProps(
					propsToForward,
					{
						class: [
							'action-item action-item--single',
							{
								'action-item--wide': this.wide,
							},
						],
						'aria-label': action?.props?.['aria-label'] || text,
						title,
						disabled: this.disabled || action?.props?.disabled,
						pressed: action?.props?.modelValue,
						size: this.size,
						type,
						wide: this.wide,
						// If it has a menuName, we use a secondary button
						variant: this.variant || (buttonText ? 'secondary' : 'tertiary'),
						onFocus: this.onFocus,
						onBlur: this.onBlur,
						// forward any pressed state from NcButton just like NcActionButton does
						'onUpdate:pressed': action?.props?.['onUpdate:modelValue'] ?? (() => {}),
					},
				),
				{
					default: () => buttonText,
					icon: () => icon,
				},
			)
		}

		/**
		 * Render the actions popover
		 *
		 * @param {Array} actions the actions to render within
		 * @return {import('vue').VNode}
		 */
		const renderActionsPopover = (actions) => {
			const triggerIcon = isSlotPopulated(this.$slots.icon?.())
				? this.$slots.icon?.()
				: (this.defaultIcon
						? h('span', { class: ['icon', this.defaultIcon] })
						: h(IconDotsHorizontal, { size: 20 })
					)
			const triggerRandomId = `${this.randomId}-trigger`
			return h(
				NcPopover,
				{
					ref: 'popover',
					delay: 0,
					shown: this.opened,
					placement: this.placement,
					boundary: this.boundariesElement,
					autoBoundaryMaxSize: true,
					container: this.container,
					...this.manualOpen && {
						triggers: [],
					},
					noCloseOnClickOutside: this.manualOpen,
					popoverBaseClass: 'action-item__popper',
					popupRole: this.config.popupRole,
					setReturnFocus: this.config.withFocusTrap ? this.$refs.triggerButton?.$el : undefined,
					noFocusTrap: !this.config.withFocusTrap,
					'onUpdate:shown': this.toggleMenu,
					onAfterShow: this.onOpened,
					onAfterClose: this.onClosed,
				},
				{
					trigger: () => h(NcButton, {
						id: triggerRandomId,
						class: 'action-item__menutoggle',
						disabled: this.disabled,
						size: this.size,
						variant: this.triggerButtonVariant,
						wide: this.wide,
						ref: 'triggerButton',
						'aria-label': this.menuName ? null : this.ariaLabel,
						// 'aria-controls' should only present together with a valid aria-haspopup
						'aria-controls': this.opened && this.config.popupRole ? this.randomId : null,
						onFocus: this.onFocus,
						onBlur: this.onBlur,
						onClick: this.onClick,
						onKeydown: this.onTriggerKeydown,
					}, {
						icon: () => triggerIcon,
						default: () => this.menuName,
					}),
					default: () => h('div', {
						class: {
							open: this.opened,
						},
						tabindex: '-1',
						onKeydown: this.onKeydown,
						ref: 'menu',
					}, [
						h('ul', {
							id: this.randomId,
							tabindex: '-1',
							ref: 'menuList',
							role: this.config.popupRole,
							// For most roles a label is required (dialog, menu), but also in general nothing speaks against labelling a list.
							// It is even recommended to do so.
							'aria-labelledby': triggerRandomId,
							'aria-modal': this.actionsMenuSemanticType === 'dialog' ? 'true' : undefined,
						}, [
							actions,
						]),
					]),
				},
			)
		}

		/**
		 * If we have a single action only and didn't force a menu,
		 * we render the action as a standalone button
		 */
		if (actions.length === 1 && validInlineActions.length === 1 && !this.forceMenu) {
			return renderInlineAction(actions[0])
		}

		// If we completely re-render the children
		// we need to focus the first action again
		// Mostly used when clicking a menu item
		this.$nextTick(() => {
			if (this.opened && this.$refs.menu) {
				const isAnyActive = this.$refs.menu.querySelector('li.active') || []
				if (isAnyActive.length === 0) {
					this.focusFirstAction()
				}
			}
		})

		/**
		 * If we some inline actions to render, render them, then the menu
		 */
		if (inlineActions.length > 0 && this.inline > 0) {
			return h(
				'div',
				{
					class: [
						'action-items',
						`action-item--${this.triggerButtonVariant}`,
					],
				},
				[
					// Render inline actions
					...inlineActions.map(renderInlineAction),
					// render the rest within the popover menu
					menuActions.length > 0
						? h(
								'div',
								{
									class: [
										'action-item',
										{
											'action-item--open': this.opened,
										},
									],
								},
								[renderActionsPopover(menuActions)],
							)
						: null,
				],
			)
		}

		/**
		 * Otherwise, we render the actions in a popover
		 */
		return h(
			'div',
			{
				class: [
					'action-item action-item--default-popover',
					`action-item--${this.triggerButtonVariant}`,
					{
						'action-item--open': this.opened,
						'action-item--wide': this.wide,
					},
				],
			},
			[
				renderActionsPopover(actions),
			],
		)
	},
}
</script>

<style lang="scss" scoped>
// Inline buttons
.action-items {
	display: flex;
	align-items: center;
	gap: calc($icon-margin / 2);
}

.action-item {
	--open-background-color: var(--color-background-hover, $action-background-hover);
	position: relative;
	display: inline-block;

	&.action-item--primary {
		--open-background-color: var(--color-primary-element-hover);
	}

	&.action-item--secondary {
		--open-background-color: var(--color-primary-element-light-hover);
	}

	&.action-item--error {
		--open-background-color: var(--color-error-hover);
	}

	&.action-item--warning {
		--open-background-color: var(--color-warning-hover);
	}

	&.action-item--success {
		--open-background-color: var(--color-success-hover);
	}

	&.action-item--tertiary-no-background {
		--open-background-color: transparent;
	}

	&.action-item--open .action-item__menutoggle {
		background-color: var(--open-background-color);
	}

	&.action-item--wide {
		width: 100%;
	}

	&__menutoggle__icon {
		width: 20px;
		height: 20px;
		object-fit: contain;
	}
}
</style>

<style lang="scss">
// We overwrote the popover base class, so we can style
// the popover__inner for actions only.
.v-popper--theme-nc-popover-9.v-popper__popper.action-item__popper .v-popper__wrapper {
	border-radius: var(--border-radius-element);

	.v-popper__inner {
		border-radius: var(--border-radius-element);
		padding: 4px;
		max-height: calc(100vh - var(--header-height));
		overflow: auto;
	}
}
</style>
