This commit is contained in:
dap
2024-09-27 07:48:45 +08:00
37 changed files with 396 additions and 71 deletions

View File

@@ -82,11 +82,11 @@
@apply opacity-100;
}
input:-webkit-autofill {
/* input:-webkit-autofill {
@apply border-none;
box-shadow: 0 0 0 1000px transparent inset;
}
} */
input[type='number']::-webkit-inner-spin-button,
input[type='number']::-webkit-outer-spin-button {

View File

@@ -83,8 +83,8 @@ function escapeKeyDown(e: KeyboardEvent) {
// pointer-down-outside
function pointerDownOutside(e: Event) {
const target = e.target as HTMLElement;
const isDismissableModal = !!target?.dataset.dismissableModal;
if (!closeOnClickModal.value || !isDismissableModal) {
const dismissableDrawer = !!target?.dataset.dismissableDrawer;
if (!closeOnClickModal.value || !dismissableDrawer) {
e.preventDefault();
}
}

View File

@@ -40,7 +40,6 @@
}
},
"dependencies": {
"@radix-icons/vue": "catalog:",
"@vben-core/composables": "workspace:*",
"@vben-core/icons": "workspace:*",
"@vben-core/shared": "workspace:*",

View File

@@ -15,6 +15,7 @@ export * from './input-password';
export * from './link';
export * from './logo';
export * from './menu-badge';
export * from './pagination';
export * from './pin-input';
export * from './popover';
export * from './render-content';
@@ -39,6 +40,7 @@ export * from './ui/hover-card';
export * from './ui/input';
export * from './ui/label';
export * from './ui/number-field';
export * from './ui/pagination';
export * from './ui/pin-input';
export * from './ui/popover';
export * from './ui/radio-group';

View File

@@ -0,0 +1,2 @@
export type { PaginationProps as VbenPaginationProps } from './pagination';
export { default as VbenPagination } from './pagination.vue';

View File

@@ -0,0 +1,41 @@
export interface PaginationProps {
/**
* 是否禁用
*/
disabled?: boolean;
/**
* 每页记录数选项
*/
pageSizeOptions?: number[];
/**
* 当 时true始终显示第一页、最后一页和省略号
*/
showEdges?: boolean;
/**
* 显示当前页选择下拉框
*/
showRowsPerPage?: boolean;
/**
* 显示总条数文本
*/
showTotalText?: boolean;
/**
* 当前页面周围应显示的兄弟页面数量
*/
siblingCount?: number;
/**
* 组件尺寸
*/
size?: 'default' | 'large' | 'small';
/**
* 总条数
*/
total?: number;
}
export const SIZE_CLASS_MAP = {
default: 'size-8',
large: 'size-9',
small: 'size-7',
};

View File

@@ -0,0 +1,111 @@
<script setup lang="ts">
import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { Button } from '../ui/button';
import {
Pagination,
PaginationEllipsis,
PaginationFirst,
PaginationLast,
PaginationList,
PaginationListItem,
PaginationNext,
PaginationPrev,
} from '../ui/pagination';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '../ui/select';
import { type PaginationProps, SIZE_CLASS_MAP } from './pagination';
interface Props extends PaginationProps {}
const {
disabled = false,
pageSizeOptions = [10, 20, 30, 50, 100, 200],
showEdges = true,
showRowsPerPage = true,
showTotalText = true,
siblingCount = 1,
size = 'default',
total = 500,
} = defineProps<Props>();
const currentPage = defineModel<number>('currentPage', { default: 1 });
const itemPerPage = defineModel<number>('itemPerPage', { default: 20 });
const itemSize = computed(() => {
return SIZE_CLASS_MAP[size];
});
const options = computed(() => {
return pageSizeOptions.map((item) => ({
label: `${item} 条/页`,
value: `${item}`,
}));
});
function handleUpdateModelValue(value: string) {
itemPerPage.value = Number(value);
}
</script>
<template>
<Pagination
v-model:page="currentPage"
:disabled="disabled"
:items-per-page="itemPerPage"
:show-edges="showEdges"
:sibling-count="siblingCount"
:total="total"
>
<PaginationList
v-slot="{ items }"
class="flex w-full items-center justify-end gap-1"
>
<span v-if="showTotalText" class="mr-2"> {{ total }} </span>
<Select
v-if="showRowsPerPage"
:model-value="`${itemPerPage}`"
@update:model-value="handleUpdateModelValue"
>
<SelectTrigger class="w-30 mr-auto h-8">
<SelectValue />
</SelectTrigger>
<SelectContent>
<template v-for="item in options" :key="item.value">
<SelectItem :value="item.value"> {{ item.label }} </SelectItem>
</template>
</SelectContent>
</Select>
<PaginationFirst :class="cn('size-8', itemSize)" />
<PaginationPrev :class="cn('size-8', itemSize)" />
<template v-for="(item, index) in items">
<PaginationListItem
v-if="item.type === 'page'"
:key="index"
:value="item.value"
as-child
>
<Button
:class="cn('size-8 p-0 shadow-none', itemSize)"
:variant="item.value === currentPage ? 'default' : 'outline'"
>
{{ item.value }}
</Button>
</PaginationListItem>
<PaginationEllipsis v-else :key="item.type" :index="index" />
</template>
<PaginationNext :class="cn('size-8', itemSize)" />
<PaginationLast :class="cn('size-8', itemSize)" />
</PaginationList>
</Pagination>
</template>

View File

@@ -3,7 +3,7 @@ import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { ChevronDownIcon } from '@radix-icons/vue';
import { ChevronDown } from 'lucide-vue-next';
import {
AccordionHeader,
AccordionTrigger,
@@ -32,7 +32,7 @@ const delegatedProps = computed(() => {
>
<slot></slot>
<slot name="icon">
<ChevronDownIcon
<ChevronDown
class="text-muted-foreground h-4 w-4 shrink-0 transition-transform duration-200"
/>
</slot>

View File

@@ -1,7 +1,7 @@
<script lang="ts" setup>
import { cn } from '@vben-core/shared/utils';
import { DotsHorizontalIcon } from '@radix-icons/vue';
import { MoreHorizontal } from 'lucide-vue-next';
const props = defineProps<{
class?: any;
@@ -15,7 +15,7 @@ const props = defineProps<{
role="presentation"
>
<slot>
<DotsHorizontalIcon class="h-4 w-4" />
<MoreHorizontal class="h-4 w-4" />
</slot>
<span class="sr-only">More</span>
</span>

View File

@@ -1,7 +1,7 @@
<script lang="ts" setup>
import { cn } from '@vben-core/shared/utils';
import { ChevronRightIcon } from '@radix-icons/vue';
import { ChevronRight } from 'lucide-vue-next';
const props = defineProps<{
class?: any;
@@ -15,7 +15,7 @@ const props = defineProps<{
role="presentation"
>
<slot>
<ChevronRightIcon />
<ChevronRight />
</slot>
</li>
</template>

View File

@@ -10,7 +10,7 @@ import { buttonVariants } from './button';
interface Props extends PrimitiveProps {
class?: any;
size?: ButtonVariantSize;
variant?: 'heavy' & ButtonVariants;
variant?: ButtonVariants;
}
const props = withDefaults(defineProps<Props>(), {

View File

@@ -5,7 +5,7 @@ import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { CheckIcon } from '@radix-icons/vue';
import { Check } from 'lucide-vue-next';
import {
CheckboxIndicator,
CheckboxRoot,
@@ -38,7 +38,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
class="flex h-full w-full items-center justify-center text-current"
>
<slot>
<CheckIcon class="h-4 w-4" />
<Check class="h-4 w-4" />
</slot>
</CheckboxIndicator>
</CheckboxRoot>

View File

@@ -3,7 +3,7 @@ import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { CheckIcon } from '@radix-icons/vue';
import { Check } from 'lucide-vue-next';
import {
ContextMenuCheckboxItem,
type ContextMenuCheckboxItemEmits,
@@ -36,7 +36,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<ContextMenuItemIndicator>
<CheckIcon class="h-4 w-4" />
<Check class="h-4 w-4" />
</ContextMenuItemIndicator>
</span>
<slot></slot>

View File

@@ -3,7 +3,7 @@ import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { DotFilledIcon } from '@radix-icons/vue';
import { Circle } from 'lucide-vue-next';
import {
ContextMenuItemIndicator,
ContextMenuRadioItem,
@@ -36,7 +36,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<ContextMenuItemIndicator>
<DotFilledIcon class="h-4 w-4 fill-current" />
<Circle class="h-2 w-2 fill-current" />
</ContextMenuItemIndicator>
</span>
<slot></slot>

View File

@@ -3,7 +3,7 @@ import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { ChevronRightIcon } from '@radix-icons/vue';
import { ChevronRight } from 'lucide-vue-next';
import {
ContextMenuSubTrigger,
type ContextMenuSubTriggerProps,
@@ -38,6 +38,6 @@ const forwardedProps = useForwardProps(delegatedProps);
"
>
<slot></slot>
<ChevronRightIcon class="ml-auto h-4 w-4" />
<ChevronRight class="ml-auto h-4 w-4" />
</ContextMenuSubTrigger>
</template>

View File

@@ -3,7 +3,7 @@ import { computed, ref } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { Cross2Icon } from '@radix-icons/vue';
import { X } from 'lucide-vue-next';
import {
DialogClose,
DialogContent,
@@ -77,7 +77,7 @@ defineExpose({
"
@click="() => emits('close')"
>
<Cross2Icon class="h-4 w-4" />
<X class="h-4 w-4" />
</DialogClose>
</DialogContent>
</DialogPortal>

View File

@@ -3,6 +3,7 @@ import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { X } from 'lucide-vue-next';
import {
DialogClose,
DialogContent,
@@ -56,7 +57,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<DialogClose
class="hover:bg-secondary absolute right-4 top-4 rounded-md p-0.5 transition-colors"
>
<Cross2Icon class="h-4 w-4" />
<X class="h-4 w-4" />
<span class="sr-only">Close</span>
</DialogClose>
</DialogContent>

View File

@@ -3,7 +3,7 @@ import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { CheckIcon } from '@radix-icons/vue';
import { Check } from 'lucide-vue-next';
import {
DropdownMenuCheckboxItem,
type DropdownMenuCheckboxItemEmits,
@@ -36,7 +36,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuItemIndicator>
<CheckIcon class="h-4 w-4" />
<Check class="h-4 w-4" />
</DropdownMenuItemIndicator>
</span>
<slot></slot>

View File

@@ -3,7 +3,7 @@ import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { DotFilledIcon } from '@radix-icons/vue';
import { Circle } from 'lucide-vue-next';
import {
DropdownMenuItemIndicator,
DropdownMenuRadioItem,
@@ -37,7 +37,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuItemIndicator>
<DotFilledIcon class="h-4 w-4 fill-current" />
<Circle class="h-2 w-2 fill-current" />
</DropdownMenuItemIndicator>
</span>
<slot></slot>

View File

@@ -3,7 +3,7 @@ import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { ChevronRightIcon } from '@radix-icons/vue';
import { ChevronRight } from 'lucide-vue-next';
import {
DropdownMenuSubTrigger,
type DropdownMenuSubTriggerProps,
@@ -32,6 +32,6 @@ const forwardedProps = useForwardProps(delegatedProps);
"
>
<slot></slot>
<ChevronRightIcon class="ml-auto h-4 w-4" />
<ChevronRight class="ml-auto h-4 w-4" />
</DropdownMenuSubTrigger>
</template>

View File

@@ -0,0 +1,27 @@
<script setup lang="ts">
import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { MoreHorizontal } from 'lucide-vue-next';
import { PaginationEllipsis, type PaginationEllipsisProps } from 'radix-vue';
const props = defineProps<{ class?: any } & PaginationEllipsisProps>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>
<template>
<PaginationEllipsis
v-bind="delegatedProps"
:class="cn('flex size-8 items-center justify-center', props.class)"
>
<slot>
<MoreHorizontal class="size-4" />
</slot>
</PaginationEllipsis>
</template>

View File

@@ -0,0 +1,33 @@
<script setup lang="ts">
import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { ChevronsLeft } from 'lucide-vue-next';
import { PaginationFirst, type PaginationFirstProps } from 'radix-vue';
import { Button } from '../button';
const props = withDefaults(
defineProps<{ class?: any } & PaginationFirstProps>(),
{
asChild: true,
},
);
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>
<template>
<PaginationFirst v-bind="delegatedProps">
<Button :class="cn('size-8 p-0', props.class)" variant="outline">
<slot>
<ChevronsLeft class="size-4" />
</slot>
</Button>
</PaginationFirst>
</template>

View File

@@ -0,0 +1,33 @@
<script setup lang="ts">
import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { ChevronsRight } from 'lucide-vue-next';
import { PaginationLast, type PaginationLastProps } from 'radix-vue';
import { Button } from '../button';
const props = withDefaults(
defineProps<{ class?: any } & PaginationLastProps>(),
{
asChild: true,
},
);
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>
<template>
<PaginationLast v-bind="delegatedProps">
<Button :class="cn('size-8 p-0', props.class)" variant="outline">
<slot>
<ChevronsRight class="size-4" />
</slot>
</Button>
</PaginationLast>
</template>

View File

@@ -0,0 +1,33 @@
<script setup lang="ts">
import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { ChevronRight } from 'lucide-vue-next';
import { PaginationNext, type PaginationNextProps } from 'radix-vue';
import { Button } from '../button';
const props = withDefaults(
defineProps<{ class?: any } & PaginationNextProps>(),
{
asChild: true,
},
);
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>
<template>
<PaginationNext v-bind="delegatedProps">
<Button :class="cn('size-8 p-0', props.class)" variant="outline">
<slot>
<ChevronRight class="size-4" />
</slot>
</Button>
</PaginationNext>
</template>

View File

@@ -0,0 +1,33 @@
<script setup lang="ts">
import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { ChevronLeft } from 'lucide-vue-next';
import { PaginationPrev, type PaginationPrevProps } from 'radix-vue';
import { Button } from '../button';
const props = withDefaults(
defineProps<{ class?: any } & PaginationPrevProps>(),
{
asChild: true,
},
);
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>
<template>
<PaginationPrev v-bind="delegatedProps">
<Button :class="cn('size-8 p-0', props.class)" variant="outline">
<slot>
<ChevronLeft class="size-4" />
</slot>
</Button>
</PaginationPrev>
</template>

View File

@@ -0,0 +1,10 @@
export { default as PaginationEllipsis } from './PaginationEllipsis.vue';
export { default as PaginationFirst } from './PaginationFirst.vue';
export { default as PaginationLast } from './PaginationLast.vue';
export { default as PaginationNext } from './PaginationNext.vue';
export { default as PaginationPrev } from './PaginationPrev.vue';
export {
PaginationList,
PaginationListItem,
PaginationRoot as Pagination,
} from 'radix-vue';

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { DashIcon } from '@radix-icons/vue';
import { Dot } from 'lucide-vue-next';
import { Primitive, type PrimitiveProps, useForwardProps } from 'radix-vue';
const props = defineProps<PrimitiveProps>();
@@ -9,7 +9,7 @@ const forwardedProps = useForwardProps(props);
<template>
<Primitive v-bind="forwardedProps">
<slot>
<DashIcon />
<Dot />
</slot>
</Primitive>
</template>

View File

@@ -3,7 +3,7 @@ import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { CheckIcon } from '@radix-icons/vue';
import { Circle } from 'lucide-vue-next';
import {
RadioGroupIndicator,
RadioGroupItem,
@@ -33,7 +33,7 @@ const forwardedProps = useForwardProps(delegatedProps);
"
>
<RadioGroupIndicator class="flex items-center justify-center">
<CheckIcon class="fill-primary h-3.5 w-3.5" />
<Circle class="h-2.5 w-2.5 fill-current text-current" />
</RadioGroupIndicator>
</RadioGroupItem>
</template>

View File

@@ -3,7 +3,7 @@ import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { CheckIcon } from '@radix-icons/vue';
import { Check } from 'lucide-vue-next';
import {
SelectItem,
SelectItemIndicator,
@@ -35,7 +35,7 @@ const forwardedProps = useForwardProps(delegatedProps);
>
<span class="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectItemIndicator>
<CheckIcon class="h-4 w-4" />
<Check class="h-4 w-4" />
</SelectItemIndicator>
</span>

View File

@@ -3,7 +3,7 @@ import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { ChevronDownIcon } from '@radix-icons/vue';
import { ChevronDown } from 'lucide-vue-next';
import {
SelectScrollDownButton,
type SelectScrollDownButtonProps,
@@ -29,7 +29,7 @@ const forwardedProps = useForwardProps(delegatedProps);
"
>
<slot>
<ChevronDownIcon />
<ChevronDown class="h-4 w-4" />
</slot>
</SelectScrollDownButton>
</template>

View File

@@ -3,7 +3,7 @@ import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { ChevronUpIcon } from '@radix-icons/vue';
import { ChevronUp } from 'lucide-vue-next';
import {
SelectScrollUpButton,
type SelectScrollUpButtonProps,
@@ -29,7 +29,7 @@ const forwardedProps = useForwardProps(delegatedProps);
"
>
<slot>
<ChevronUpIcon />
<ChevronUp class="h-4 w-4" />
</slot>
</SelectScrollUpButton>
</template>

View File

@@ -3,7 +3,7 @@ import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { CaretSortIcon } from '@radix-icons/vue';
import { ChevronDown } from 'lucide-vue-next';
import {
SelectIcon,
SelectTrigger,
@@ -34,7 +34,7 @@ const forwardedProps = useForwardProps(delegatedProps);
>
<slot></slot>
<SelectIcon as-child>
<CaretSortIcon class="h-4 w-4 opacity-50" />
<ChevronDown class="h-4 w-4 opacity-50" />
</SelectIcon>
</SelectTrigger>
</template>

View File

@@ -6,6 +6,6 @@ useScrollLock();
<template>
<div
class="bg-overlay fixed inset-0 z-[1000]"
data-dismissable-modal="true"
data-dismissable-drawer="true"
></div>
</template>

View File

@@ -3,7 +3,7 @@ import { computed } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { Cross2Icon } from '@radix-icons/vue';
import { X } from 'lucide-vue-next';
import { ToastClose, type ToastCloseProps } from 'radix-vue';
const props = defineProps<
@@ -29,6 +29,6 @@ const delegatedProps = computed(() => {
)
"
>
<Cross2Icon class="h-4 w-4" />
<X class="size-4" />
</ToastClose>
</template>

View File

@@ -7,29 +7,38 @@
color: inherit;
}
.ant-btn {
.anticon {
display: inline-flex;
}
}
.ant-message-notice-content,
.ant-notification-notice {
@apply dark:border-border/60 dark:border;
}
/** select 选择器的样式 */
.form-valid-error .ant-select .ant-select-selector {
border-color: hsl(var(--destructive)) !important;
}
.form-valid-error {
/** select 选择器的样式 */
.form-valid-error .ant-select-focused .ant-select-selector {
box-shadow: 0 0 0 2px rgb(255 38 5 / 6%) !important;
}
.ant-select .ant-select-selector {
border-color: hsl(var(--destructive)) !important;
}
/** 数字输入框样式 */
.form-valid-error .ant-input-number-focused {
box-shadow: 0 0 0 2px rgb(255 38 5 / 6%);
}
.ant-select-focused .ant-select-selector {
box-shadow: 0 0 0 2px rgb(255 38 5 / 6%) !important;
}
/** 密码输入框样式 */
.form-valid-error .ant-input-affix-wrapper:hover {
border-color: hsl(var(--destructive));
box-shadow: 0 0 0 2px rgb(255 38 5 / 6%);
/** 数字输入框样式 */
.ant-input-number-focused {
box-shadow: 0 0 0 2px rgb(255 38 5 / 6%);
}
/** 密码输入框样式 */
.ant-input-affix-wrapper:hover {
border-color: hsl(var(--destructive));
box-shadow: 0 0 0 2px rgb(255 38 5 / 6%);
}
}
/** 区间选择器下面来回切换时的样式 */