Select Component

A dropdown selection component based on radix-vue, used for selecting values from a list of options.

Select

A dropdown selection component for choosing from a list of options.

Selected: option1
<script setup lang="ts">
  import { Select } from '@pikaso/core'
  import { useHotkeyGlobalContext } from '@pikaso/core'
  import { ref } from 'vue'
  import { SelectItem, SelectItemText } from 'radix-vue'

  const selected = ref('option1')
  const options = [
    { value: 'option1', label: 'Option 1' },
    { value: 'option2', label: 'Option 2' },
    { value: 'option3', label: 'Option 3' },
  ]

  useHotkeyGlobalContext()
</script>

<template>
  <div class="w-64">
    <Select.Root v-model="selected">
      <Select.TriggerSimple placeholder="Select an option" class="w-full" />
      <Select.Content>
        <Select.ItemSimple 
          v-for="option in options" 
          :key="option.value"
          :value="option.value"
          :label="option.label"
        />
      </Select.Content>
    </Select.Root>
    <div class="mt-2 text-xs">Selected: {{ selected }}</div>
  </div>
</template>

With Custom Trigger

The trigger can be customized with additional content.

<script setup lang="ts">
  import { Select } from '@pikaso/core'
  import { useHotkeyGlobalContext } from '@pikaso/core'
  import { ref } from 'vue'

  const selected = ref('2k')
  const resolutions = ['2k', '4k', '8k']

  useHotkeyGlobalContext()
</script>

<template>
  <div class="w-64">
    <Select.Root 
      v-model="selected"
      class="w-full"
    >
      <Select.TriggerSimple class="w-full">
        <div class="flex items-center gap-2">
          <span class="text-sm font-medium">Resolution:</span>
          <span class="ml-auto font-semibold">{{ selected }}</span>
        </div>
      </Select.TriggerSimple>

      <Select.Content>
        <Select.ItemSimple 
          v-for="resolution in resolutions" 
          :key="resolution"
          :value="resolution"
          :label="resolution"
        />
      </Select.Content>
    </Select.Root>
  </div>
</template>

With Custom Styling

The Select component can be styled to match your design system.

Image Style
<script setup lang="ts">
  import { Select } from '@pikaso/core'
  import { useHotkeyGlobalContext } from '@pikaso/core'
  import { ref } from 'vue'

  const preset = ref('Standard')
  const presets: Record<string, string> = {
    Standard: 'Standard',
    SoftPortrait: 'Soft Portrait',
    HardPortrait: 'Hard Portrait',
    ArtAndIllustration: 'Art and Illustration',
  }

  useHotkeyGlobalContext()
</script>

<template>
  <div class="w-64">
    <div class="text-xs font-semibold mb-2">Image Style</div>
    <Select.Root 
      v-model="preset"
      class="w-full"
    >
      <Select.TriggerSimple 
        class="w-full bg-neutral-800 border-neutral-700 hover:bg-neutral-700 focus:border-neutral-600 text-neutral-200"
      >
        {{ presets[preset] }}
      </Select.TriggerSimple>

      <Select.Content 
        class="border-neutral-700 bg-neutral-800 "
      >
        <Select.ItemSimple 
          v-for="(label, key) in presets" 
          :key="key"
          :value="key"
          :label="label"
          class="data-[highlighted]:bg-neutral-700 data-[highlighted]:text-white hover:bg-neutral-700 hover:text-white text-neutral-400"
        />
      </Select.Content>
    </Select.Root>
  </div>
</template>

With Custom Row Item

Customize each row to include additional elements like owner indicators or actions.

Presets
<script setup lang="ts">
  import { Select } from '@pikaso/core'
  import { useHotkeyGlobalContext } from '@pikaso/core'
  import { ref } from 'vue'
  import { SelectItem } from 'radix-vue'

  const imagination = ref('subtle')
  const imaginationPresets = [
    { id: 1, name: 'subtle', label: 'Subtle', isOwner: false },
    { id: 2, name: 'medium', label: 'Medium', isOwner: false },
    { id: 3, name: 'extreme', label: 'Extreme', isOwner: false },
    { id: 4, name: 'custom-preset', label: 'My Preset', isOwner: true },
  ]

  useHotkeyGlobalContext()
</script>

<template>
  <div class="w-64">
    <div class="text-xs font-semibold mb-2">Presets</div>
    <Select.Root v-model="imagination">
      <Select.TriggerSimple class="w-full">
        {{ imagination.charAt(0).toUpperCase() + imagination.slice(1) }}
      </Select.TriggerSimple>

      <Select.Content>
        <Select.Row
          v-for="option in imaginationPresets"
          :key="option.id"
        >
          <SelectItem
            :value="option.name"
            class="flex w-full items-center justify-between"
          >
            <span class="flex items-center gap-2">
              <span v-if="option.isOwner" class="text-blue-400 text-xs">★</span>
              <span class="flex h-7 items-center text-xs">{{ option.label }}</span>
            </span>
          </SelectItem>
          <button
            v-if="option.isOwner"
            class="px-2 text-neutral-100 hover:text-red-400"
          >
            <span class="text-xs">đŸ—‘ī¸</span>
          </button>
        </Select.Row>
      </Select.Content>
    </Select.Root>
  </div>
</template>

Disabled Items

Individual options can be disabled with tooltips explaining why.

Resolution
<script setup lang="ts">
  import { Select } from '@pikaso/core'
  import { useHotkeyGlobalContext } from '@pikaso/core'
  import { ref } from 'vue'
  import { SelectItem, SelectItemText } from 'radix-vue'

  const resolution = ref('2k')
  const allowed4k = false
  const allowedResolutions = ['2x', '2k']
  const resolutionOptions = ['2x', '2k', '4k', '8k']
  const showSizeInfo = ref(-1)

  useHotkeyGlobalContext()
</script>

<template>
  <div class="w-64">
    <div class="text-xs font-semibold mb-2">Resolution</div>
    <Select.Root v-model="resolution">
      <Select.TriggerSimple class="w-full" />

      <Select.Content>
        <Select.Row
          v-for="(res, index) in resolutionOptions"
          :key="res"
        >
          <SelectItem
            :value="res"
            :disabled="!allowedResolutions.includes(res)"
            :class="{
              'opacity-50': !allowedResolutions.includes(res),
            }"
            class="flex w-full items-center justify-between"
          >
            <SelectItemText>
              {{ res }}
            </SelectItemText>

            <span
              v-if="!allowedResolutions.includes(res)"
              :id="`resolution-info-${index + 1}`"
              class="relative flex items-center"
              @mouseover="showSizeInfo = index"
              @mouseleave="showSizeInfo = -1"
            >
              <span class="size-3 text-xs">â„šī¸</span>
              <div 
                v-if="showSizeInfo === index"
                class="absolute right-0 bottom-0 z-50 mr-4 whitespace-nowrap rounded bg-neutral-800 px-2 py-1 text-xs text-white shadow-lg"
              >
                Size exceeds limit
              </div>
            </span>
          </SelectItem>
        </Select.Row>
      </Select.Content>
    </Select.Root>
  </div>
</template>