primitives
Resizable
Resizable — базовый примитив RevueUI (Reka UI + shadcn-совместимый API).
Загрузка превью…
src/ui/resizable/ResizableHandle.vue
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { computed } from "vue"
import { SplitterResizeHandle, type SplitterResizeHandleEmits, type SplitterResizeHandleProps, useForwardPropsEmits } from "reka-ui"
import { cn } from "@/lib/utils"
const props = defineProps<
SplitterResizeHandleProps & {
class?: HTMLAttributes["class"]
withHandle?: boolean
}
>()
const emits = defineEmits<SplitterResizeHandleEmits>()
const delegatedProps = computed(() => {
const { class: _class, withHandle: _withHandle, ...rest } = props
return rest
})
const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>
<template>
<SplitterResizeHandle
data-slot="resizable-handle"
v-bind="forwarded"
:class="
cn(
'cn-resizable-handle relative flex w-px items-center justify-center bg-border ring-offset-background after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-hidden aria-[orientation=horizontal]:h-px aria-[orientation=horizontal]:w-full aria-[orientation=horizontal]:after:left-0 aria-[orientation=horizontal]:after:h-1 aria-[orientation=horizontal]:after:w-full aria-[orientation=horizontal]:after:translate-x-0 aria-[orientation=horizontal]:after:-translate-y-1/2 [&[aria-orientation=horizontal]>div]:rotate-90',
props.class
)
"
>
<div v-if="withHandle" class="cn-resizable-handle-icon z-10 flex shrink-0" />
</SplitterResizeHandle>
</template>
src/ui/resizable/ResizablePanel.vue
<script setup lang="ts">
import { SplitterPanel, type SplitterPanelProps } from "reka-ui"
defineProps<SplitterPanelProps>()
</script>
<template>
<SplitterPanel data-slot="resizable-panel" v-bind="$props">
<slot />
</SplitterPanel>
</template>
src/ui/resizable/ResizablePanelGroup.vue
<script setup lang="ts">
/**
* Апстрим (registry/bases/radix/ui/resizable.tsx) построен на
* `react-resizable-panels@4` (Group/Panel/Separator, проп `orientation`,
* `aria-orientation` на DOM). Прямого Vue-порта именно этого пакета нет.
* У reka-ui есть `Splitter*` (SplitterGroup/SplitterPanel/
* SplitterResizeHandle) — тот же смысл (resizable-панели), но собственный
* API старшего поколения react-resizable-panels (`direction`, проценты
* `defaultSize`/`minSize`/`maxSize`, `autoSaveId`) — так же, как это
* делает shadcn-vue. Порт использует нативные имена пропов reka-ui
* (`direction`, а не `orientation`) вместо попытки эмулировать API v4,
* которого сам движок не реализует — см. docs/PORTING.md.
*
* reka-ui выставляет `data-orientation`, апстрим целится в
* `aria-orientation` (см. `aria-[orientation=vertical]:flex-col` ниже) —
* `react-resizable-panels@4` реально ставит атрибут `aria-orientation` на
* DOM (проверено по исходнику пакета). Чтобы Tailwind-селектор из cva
* реально сработал на обеих реализациях, а не только "случайно совпадал
* по умолчанию", `aria-orientation` проброшен явно.
*/
import type { HTMLAttributes } from "vue"
import { computed } from "vue"
import { SplitterGroup, type SplitterGroupEmits, type SplitterGroupProps, useForwardPropsEmits } from "reka-ui"
import { cn } from "@/lib/utils"
const props = defineProps<SplitterGroupProps & { class?: HTMLAttributes["class"] }>()
const emits = defineEmits<SplitterGroupEmits>()
const delegatedProps = computed(() => {
const { class: _class, ...rest } = props
return rest
})
const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>
<template>
<SplitterGroup
data-slot="resizable-panel-group"
v-bind="forwarded"
:aria-orientation="props.direction"
:class="cn('cn-resizable-panel-group flex h-full w-full aria-[orientation=vertical]:flex-col', props.class)"
>
<slot />
</SplitterGroup>
</template>
src/ui/resizable/index.ts
export { default as ResizableHandle } from "./ResizableHandle.vue"
export { default as ResizablePanel } from "./ResizablePanel.vue"
export { default as ResizablePanelGroup } from "./ResizablePanelGroup.vue"
Установка
npx shadcn-vue@latest add https://revueui.rootapi.dev/r/resizable.jsonЗависимости реестра
npm-зависимости
- reka-ui
Источник: порт из ReUI (Keenthemes, MIT)