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)