feat: context menu
This commit is contained in:
parent
b34e1dbc62
commit
9d43d0b6e7
66
apps/www/src/content/docs/components/context-menu.md
Normal file
66
apps/www/src/content/docs/components/context-menu.md
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
---
|
||||||
|
title: Context Menu
|
||||||
|
description: Displays a menu to the user — such as a set of actions or functions — triggered by a button.
|
||||||
|
source: https://github.com/radix-vue/shadcn-vue/tree/main/apps/www/src/lib/registry/default/ui/context-menu
|
||||||
|
primitive: https://www.radix-vue.com/components/context-menu.html
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
<ComponentPreview name="ContextMenuDemo" >
|
||||||
|
|
||||||
|
<<< ../../../lib/registry/default/examples/ContextMenuDemo.vue
|
||||||
|
|
||||||
|
</ComponentPreview>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx shadcn-vue@latest add context-menu
|
||||||
|
```
|
||||||
|
|
||||||
|
<ManualInstall>
|
||||||
|
|
||||||
|
1. Install `radix-vue`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install radix-vue
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||||
|
</ManualInstall>
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {
|
||||||
|
ContextMenu,
|
||||||
|
ContextMenuCheckboxItem,
|
||||||
|
ContextMenuContent,
|
||||||
|
ContextMenuItem,
|
||||||
|
ContextMenuLabel,
|
||||||
|
ContextMenuRadioGroup,
|
||||||
|
ContextMenuRadioItem,
|
||||||
|
ContextMenuSeparator,
|
||||||
|
ContextMenuShortcut,
|
||||||
|
ContextMenuSub,
|
||||||
|
ContextMenuSubContent,
|
||||||
|
ContextMenuSubTrigger,
|
||||||
|
ContextMenuTrigger,
|
||||||
|
} from '@/lib/registry/default/ui/context-menu'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ContextMenu>
|
||||||
|
<ContextMenuTrigger>Right click</ContextMenuTrigger>
|
||||||
|
<ContextMenuContent>
|
||||||
|
<ContextMenuItem>Profile</ContextMenuItem>
|
||||||
|
<ContextMenuItem>Billing</ContextMenuItem>
|
||||||
|
<ContextMenuItem>Team</ContextMenuItem>
|
||||||
|
<ContextMenuItem>Subscription</ContextMenuItem>
|
||||||
|
</ContextMenuContent>
|
||||||
|
</ContextMenu>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {
|
||||||
|
ContextMenu,
|
||||||
|
ContextMenuCheckboxItem,
|
||||||
|
ContextMenuContent,
|
||||||
|
ContextMenuItem,
|
||||||
|
ContextMenuLabel,
|
||||||
|
ContextMenuRadioGroup,
|
||||||
|
ContextMenuRadioItem,
|
||||||
|
ContextMenuSeparator,
|
||||||
|
ContextMenuShortcut,
|
||||||
|
ContextMenuSub,
|
||||||
|
ContextMenuSubContent,
|
||||||
|
ContextMenuSubTrigger,
|
||||||
|
ContextMenuTrigger,
|
||||||
|
} from '@/lib/registry/default/ui/context-menu'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ContextMenu>
|
||||||
|
<ContextMenuTrigger class="flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed text-sm">
|
||||||
|
Right click here
|
||||||
|
</ContextMenuTrigger>
|
||||||
|
<ContextMenuContent class="w-64">
|
||||||
|
<ContextMenuItem inset>
|
||||||
|
Back
|
||||||
|
<ContextMenuShortcut>⌘[</ContextMenuShortcut>
|
||||||
|
</ContextMenuItem>
|
||||||
|
<ContextMenuItem inset disabled>
|
||||||
|
Forward
|
||||||
|
<ContextMenuShortcut>⌘]</ContextMenuShortcut>
|
||||||
|
</ContextMenuItem>
|
||||||
|
<ContextMenuItem inset>
|
||||||
|
Reload
|
||||||
|
<ContextMenuShortcut>⌘R</ContextMenuShortcut>
|
||||||
|
</ContextMenuItem>
|
||||||
|
<ContextMenuSub>
|
||||||
|
<ContextMenuSubTrigger inset>
|
||||||
|
More Tools
|
||||||
|
</ContextMenuSubTrigger>
|
||||||
|
<ContextMenuSubContent class="w-48">
|
||||||
|
<ContextMenuItem>
|
||||||
|
Save Page As...
|
||||||
|
<ContextMenuShortcut>⇧⌘S</ContextMenuShortcut>
|
||||||
|
</ContextMenuItem>
|
||||||
|
<ContextMenuItem>Create Shortcut...</ContextMenuItem>
|
||||||
|
<ContextMenuItem>Name Window...</ContextMenuItem>
|
||||||
|
<ContextMenuSeparator />
|
||||||
|
<ContextMenuItem>Developer Tools</ContextMenuItem>
|
||||||
|
</ContextMenuSubContent>
|
||||||
|
</ContextMenuSub>
|
||||||
|
<ContextMenuSeparator />
|
||||||
|
<ContextMenuCheckboxItem checked>
|
||||||
|
Show Bookmarks Bar
|
||||||
|
<ContextMenuShortcut>⌘⇧B</ContextMenuShortcut>
|
||||||
|
</ContextMenuCheckboxItem>
|
||||||
|
<ContextMenuCheckboxItem>Show Full URLs</ContextMenuCheckboxItem>
|
||||||
|
<ContextMenuSeparator />
|
||||||
|
<ContextMenuRadioGroup value="pedro">
|
||||||
|
<ContextMenuLabel inset>
|
||||||
|
People
|
||||||
|
</ContextMenuLabel>
|
||||||
|
<ContextMenuSeparator />
|
||||||
|
<ContextMenuRadioItem value="pedro">
|
||||||
|
Pedro Duarte
|
||||||
|
</ContextMenuRadioItem>
|
||||||
|
<ContextMenuRadioItem value="colm">
|
||||||
|
Colm Tuite
|
||||||
|
</ContextMenuRadioItem>
|
||||||
|
</ContextMenuRadioGroup>
|
||||||
|
</ContextMenuContent>
|
||||||
|
</ContextMenu>
|
||||||
|
</template>
|
||||||
|
|
@ -5,12 +5,10 @@ import { useEmitAsProps } from '@/lib/utils'
|
||||||
|
|
||||||
const props = defineProps<CollapsibleRootProps>()
|
const props = defineProps<CollapsibleRootProps>()
|
||||||
const emits = defineEmits<CollapsibleRootEmits>()
|
const emits = defineEmits<CollapsibleRootEmits>()
|
||||||
|
|
||||||
const emitsAsProps = useEmitAsProps(emits)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<CollapsibleRoot v-slot="{ open }" v-bind="{ ...props, ...emitsAsProps }">
|
<CollapsibleRoot v-slot="{ open }" v-bind="{ ...props, ...useEmitAsProps(emits) }">
|
||||||
<slot :open="open" />
|
<slot :open="open" />
|
||||||
</CollapsibleRoot>
|
</CollapsibleRoot>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ContextMenuRoot, type ContextMenuRootProps } from 'radix-vue'
|
import { ContextMenuRoot } from 'radix-vue'
|
||||||
|
import type { ContextMenuRootEmits, ContextMenuRootProps } from 'radix-vue'
|
||||||
|
import { useEmitAsProps } from '@/lib/utils'
|
||||||
|
|
||||||
const props = defineProps<ContextMenuRootProps>()
|
const props = defineProps<ContextMenuRootProps>()
|
||||||
|
const emits = defineEmits<ContextMenuRootEmits>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ContextMenuRoot v-bind="props">
|
<ContextMenuRoot v-bind="{ ...props, ...useEmitAsProps(emits) }">
|
||||||
<slot />
|
<slot />
|
||||||
</ContextMenuRoot>
|
</ContextMenuRoot>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -5,30 +5,30 @@ import {
|
||||||
type ContextMenuCheckboxItemProps,
|
type ContextMenuCheckboxItemProps,
|
||||||
ContextMenuItemIndicator,
|
ContextMenuItemIndicator,
|
||||||
} from 'radix-vue'
|
} from 'radix-vue'
|
||||||
import { cn } from '@/lib/utils'
|
import { Check } from 'lucide-vue-next'
|
||||||
import RadixIconsCheck from '~icons/radix-icons/check'
|
import { cn, useEmitAsProps } from '@/lib/utils'
|
||||||
|
|
||||||
const props = defineProps<ContextMenuCheckboxItemProps & { class?: string }>()
|
const props = defineProps<ContextMenuCheckboxItemProps & { class?: string }>()
|
||||||
|
|
||||||
const emits = defineEmits<ContextMenuCheckboxItemEmits>()
|
const emits = defineEmits<ContextMenuCheckboxItemEmits>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ContextMenuCheckboxItem
|
<ContextMenuCheckboxItem
|
||||||
v-bind="props"
|
v-bind="{ ...props, ...useEmitAsProps(emits) }"
|
||||||
:class="[
|
:class="[
|
||||||
cn(
|
cn(
|
||||||
'flex relative items-center rounded-md transition-colors data-[disabled]:opacity-50 data-[disabled]:pointer-events-none data-[highlighted]:bg-outline-hover pl-7 py-1.5 text-sm outline-none select-none cursor-default',
|
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||||
props.class,
|
props.class,
|
||||||
),
|
),
|
||||||
]"
|
]"
|
||||||
@update:checked="emits('update:checked', $event)"
|
|
||||||
>
|
>
|
||||||
<ContextMenuItemIndicator
|
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
class="absolute left-1.5 inline-flex w-4 h-4 items-center justify-center"
|
<ContextMenuItemIndicator
|
||||||
>
|
class="absolute left-1.5 inline-flex w-4 h-4 items-center justify-center"
|
||||||
<RadixIconsCheck />
|
>
|
||||||
</ContextMenuItemIndicator>
|
<Check class="h-4 h-w" />
|
||||||
|
</ContextMenuItemIndicator>
|
||||||
|
</span>
|
||||||
<slot />
|
<slot />
|
||||||
</ContextMenuCheckboxItem>
|
</ContextMenuCheckboxItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -5,25 +5,23 @@ import {
|
||||||
type ContextMenuContentProps,
|
type ContextMenuContentProps,
|
||||||
ContextMenuPortal,
|
ContextMenuPortal,
|
||||||
} from 'radix-vue'
|
} from 'radix-vue'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn, useEmitAsProps } from '@/lib/utils'
|
||||||
|
|
||||||
const props = defineProps<ContextMenuContentProps & { class?: string }>()
|
const props = defineProps<ContextMenuContentProps & { class?: string }>()
|
||||||
|
|
||||||
const emits = defineEmits<ContextMenuContentEmits>()
|
const emits = defineEmits<ContextMenuContentEmits>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ContextMenuPortal force-mount>
|
<ContextMenuPortal>
|
||||||
<ContextMenuContent
|
<ContextMenuContent
|
||||||
:loop="props.loop"
|
|
||||||
:align-offset="props.alignOffset"
|
:align-offset="props.alignOffset"
|
||||||
:as-child="props.asChild"
|
|
||||||
:class="[
|
:class="[
|
||||||
cn(
|
cn(
|
||||||
'bg-background focus:outline-none outline-none border border-border p-1 z-50 min-w-[8rem] rounded-md shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||||
props.class,
|
props.class,
|
||||||
),
|
),
|
||||||
]"
|
]"
|
||||||
|
v-bind="{ ...props, ...useEmitAsProps(emits) }"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</ContextMenuContent>
|
</ContextMenuContent>
|
||||||
|
|
|
||||||
|
|
@ -4,23 +4,22 @@ import {
|
||||||
type ContextMenuItemEmits,
|
type ContextMenuItemEmits,
|
||||||
type ContextMenuItemProps,
|
type ContextMenuItemProps,
|
||||||
} from 'radix-vue'
|
} from 'radix-vue'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn, useEmitAsProps } from '@/lib/utils'
|
||||||
|
|
||||||
const props = defineProps<ContextMenuItemProps & { class?: string }>()
|
|
||||||
|
|
||||||
|
const props = defineProps<ContextMenuItemProps & { class?: string; inset?: boolean }>()
|
||||||
const emits = defineEmits<ContextMenuItemEmits>()
|
const emits = defineEmits<ContextMenuItemEmits>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ContextMenuItem
|
<ContextMenuItem
|
||||||
v-bind="props"
|
v-bind="{ ...props, ...useEmitAsProps(emits) }"
|
||||||
:class="[
|
:class="[
|
||||||
cn(
|
cn(
|
||||||
'flex items-center rounded-md transition-colors data-[disabled]:opacity-50 data-[disabled]:pointer-events-none focus:bg-outline-hover px-2 py-1.5 text-sm outline-none select-none cursor-default',
|
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||||
|
inset && 'pl-8',
|
||||||
props.class,
|
props.class,
|
||||||
),
|
),
|
||||||
]"
|
]"
|
||||||
@select="emits('select', $event)"
|
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</ContextMenuItem>
|
</ContextMenuItem>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,18 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ContextMenuLabel, type ContextMenuLabelProps } from 'radix-vue'
|
import { ContextMenuLabel, type ContextMenuLabelProps } from 'radix-vue'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = defineProps<ContextMenuLabelProps>()
|
const props = defineProps<ContextMenuLabelProps & { class?: string; inset?: boolean }>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="px-2 py-1.5 text-sm font-semibold">
|
<ContextMenuLabel
|
||||||
<ContextMenuLabel v-bind="props">
|
v-bind="props"
|
||||||
<slot />
|
:class="
|
||||||
</ContextMenuLabel>
|
cn('px-2 py-1.5 text-sm font-semibold text-foreground',
|
||||||
</div>
|
inset && 'pl-8', props.class ?? '',
|
||||||
|
)"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</ContextMenuLabel>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ContextMenuPortal, type ContextMenuPortalProps } from 'radix-vue'
|
||||||
|
|
||||||
|
const props = defineProps<ContextMenuPortalProps>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ContextMenuPortal v-bind="props">
|
||||||
|
<slot />
|
||||||
|
</ContextMenuPortal>
|
||||||
|
</template>
|
||||||
|
|
@ -5,30 +5,28 @@ import {
|
||||||
type ContextMenuRadioItemEmits,
|
type ContextMenuRadioItemEmits,
|
||||||
type ContextMenuRadioItemProps,
|
type ContextMenuRadioItemProps,
|
||||||
} from 'radix-vue'
|
} from 'radix-vue'
|
||||||
import { cn } from '@/lib/utils'
|
import { Circle } from 'lucide-vue-next'
|
||||||
import RiCheckboxBlankCircleFill from '~icons/ri/checkbox-blank-circle-fill'
|
import { cn, useEmitAsProps } from '@/lib/utils'
|
||||||
|
|
||||||
const props = defineProps<ContextMenuRadioItemProps & { class?: string }>()
|
const props = defineProps<ContextMenuRadioItemProps & { class?: string }>()
|
||||||
|
|
||||||
const emits = defineEmits<ContextMenuRadioItemEmits>()
|
const emits = defineEmits<ContextMenuRadioItemEmits>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ContextMenuRadioItem
|
<ContextMenuRadioItem
|
||||||
v-bind="props"
|
v-bind="{ ...props, ...useEmitAsProps(emits) }"
|
||||||
:class="[
|
:class="[
|
||||||
cn(
|
cn(
|
||||||
'flex relative items-center rounded-md transition-colors data-[disabled]:opacity-50 data-[disabled]:pointer-events-none data-[highlighted]:bg-outline-hover pl-7 py-1.5 text-sm outline-none select-none cursor-default',
|
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||||
props.class,
|
props.class,
|
||||||
),
|
),
|
||||||
]"
|
]"
|
||||||
@select="emits('select', $event)"
|
|
||||||
>
|
>
|
||||||
<ContextMenuItemIndicator
|
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
class="absolute left-2 inline-flex w-2 h-2 items-center justify-center"
|
<ContextMenuItemIndicator>
|
||||||
>
|
<Circle class="h-2 w-2 fill-current" />
|
||||||
<RiCheckboxBlankCircleFill class="text-foreground" />
|
</ContextMenuItemIndicator>
|
||||||
</ContextMenuItemIndicator>
|
</span>
|
||||||
<slot />
|
<slot />
|
||||||
</ContextMenuRadioItem>
|
</ContextMenuRadioItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,11 @@ import {
|
||||||
ContextMenuSeparator,
|
ContextMenuSeparator,
|
||||||
type ContextMenuSeparatorProps,
|
type ContextMenuSeparatorProps,
|
||||||
} from 'radix-vue'
|
} from 'radix-vue'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = defineProps<ContextMenuSeparatorProps>()
|
const props = defineProps<ContextMenuSeparatorProps>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ContextMenuSeparator v-bind="props" class="-mx-1 my-1 h-px bg-secondary" />
|
<ContextMenuSeparator v-bind="props" :class="cn('-mx-1 my-1 h-px bg-border', $attrs.class ?? '')" />
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="text-xxs ml-auto tracking-widest opacity-50">
|
<span :class="cn('ml-auto text-xs tracking-widest text-muted-foreground', $attrs.class ?? '')">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,25 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {
|
import {
|
||||||
ContextMenuPortal,
|
|
||||||
ContextMenuSubContent,
|
ContextMenuSubContent,
|
||||||
type DropdownMenuSubContentEmits,
|
type DropdownMenuSubContentEmits,
|
||||||
type DropdownMenuSubContentProps,
|
type DropdownMenuSubContentProps,
|
||||||
} from 'radix-vue'
|
} from 'radix-vue'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn, useEmitAsProps } from '@/lib/utils'
|
||||||
|
|
||||||
const props = defineProps<DropdownMenuSubContentProps & { class?: string }>()
|
const props = defineProps<DropdownMenuSubContentProps & { class?: string }>()
|
||||||
|
|
||||||
const emits = defineEmits<DropdownMenuSubContentEmits>()
|
const emits = defineEmits<DropdownMenuSubContentEmits>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ContextMenuPortal force-mount>
|
<ContextMenuSubContent
|
||||||
<ContextMenuSubContent
|
v-bind="{ ...props, ...useEmitAsProps(emits) }"
|
||||||
:loop="props.loop"
|
:class="
|
||||||
:align-offset="props.alignOffset"
|
cn(
|
||||||
:side="props.side"
|
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||||
:side-offset="props.sideOffset"
|
props.class,
|
||||||
:as-child="props.asChild"
|
)
|
||||||
:class="
|
"
|
||||||
cn(
|
>
|
||||||
'bg-background focus:outline-none outline-none text-foreground border border-border p-1 z-50 min-w-[10rem] rounded-md shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
<slot />
|
||||||
props.class,
|
</ContextMenuSubContent>
|
||||||
)
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<slot />
|
|
||||||
</ContextMenuSubContent>
|
|
||||||
</ContextMenuPortal>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,10 @@ import {
|
||||||
ContextMenuSubTrigger,
|
ContextMenuSubTrigger,
|
||||||
type ContextMenuSubTriggerProps,
|
type ContextMenuSubTriggerProps,
|
||||||
} from 'radix-vue'
|
} from 'radix-vue'
|
||||||
|
import { ChevronRight } from 'lucide-vue-next'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = defineProps<ContextMenuSubTriggerProps & { class?: string }>()
|
const props = defineProps<ContextMenuSubTriggerProps & { class?: string; inset?: boolean }>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -13,11 +14,13 @@ const props = defineProps<ContextMenuSubTriggerProps & { class?: string }>()
|
||||||
v-bind="props"
|
v-bind="props"
|
||||||
:class="[
|
:class="[
|
||||||
cn(
|
cn(
|
||||||
'flex items-center rounded-md transition-colors data-[disabled]:opacity-50 data-[disabled]:pointer-events-none data-[highlighted]:bg-outline-hover px-2 py-1.5 text-sm outline-none select-none cursor-default',
|
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground',
|
||||||
|
inset && 'pl-8',
|
||||||
props.class,
|
props.class,
|
||||||
),
|
),
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
|
<ChevronRight class="ml-auto h-4 w-4" />
|
||||||
</ContextMenuSubTrigger>
|
</ContextMenuSubTrigger>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user