Skip to content

ColorPicker Max

#
%
ColorPickerWithTabs.vue
<script lang="ts" setup>
import { ref, computed, useTemplateRef } from 'vue'
import { useForwardPropsEmits } from 'reka-ui'
import { TabsRoot, TabsContent, TabsList, TabsTrigger } from 'reka-ui'
import {
  ColorPickerRoot,
  ColorPickerCanvas,
  ColorPickerEyeDropper,
  ColorPickerSliderHue,
  ColorPickerSliderAlpha,
  ColorPickerInputHex,
  ColorPickerInputHSL,
  ColorPickerInputRGB,
  ColorPickerInputHSB,
  ColorPickerSwatch,
  type ColorPickerRootProps,
  type ColorPickerRootEmits
} from '@vuelor/picker'

type ColorPickerProps = Omit<ColorPickerRootProps, 'styling' | 'ui'>

const props = defineProps<ColorPickerProps>()
const emits = defineEmits<ColorPickerRootEmits>()

const forwarded = useForwardPropsEmits(props, emits)

const format = ref<string>('hex')

const canvasType = computed<'HSL' | 'HSV'>(() => {
  return format.value === 'hsl' ? 'HSL' : 'HSV'
})

const swatches = ref<string[]>([
  '#00C3D0FF',
  '#00C8B3FF',
  '#34C759FF',
  '#FFCC00FF',
  '#FF383CFF',
  '#FF8D2825',
  '#FF383C40',
  '#FF8D2880',
  '#FFCC0080',
  '#34C759FF',
  '#00C8B3FF',
  '#00C3D0FF',
  '#0088FFFF',
  '#6155F5FF',
  '#CB30E0FF',
  '#FF2D55FF',
  '#FF2D5525',
  '#AC7F5EFF'
])

const colorPicker = useTemplateRef<typeof ColorPickerRoot>('colorPicker')
</script>

<template>
  <ColorPickerRoot
    ref="colorPicker"
    v-bind="forwarded"
  >
    <ColorPickerCanvas :type="canvasType" />
    <div class="flex items-center gap-3">
      <ColorPickerEyeDropper>
        <svg width="24" height="24" fill="none" viewBox="0 0 24 24">
          <path
            fill="currentColor"
            fill-rule="evenodd"
            clip-rule="evenodd"
            d="M17.52 6.471a1.62 1.62 0 0 0-2.295.003l-1.87 1.88-.354.355-.355-.354-.01-.01a.9.9 0 0 0-1.272 0l-.02.02a.9.9 0 0 0 0 1.273l.51.51 2 2 .51.51a.9.9 0 0 0 1.272 0l.02-.02a.9.9 0 0 0 0-1.273l-.01-.01-.352-.353.351-.353 1.879-1.888a1.62 1.62 0 0 0-.003-2.29m-3.004-.702a2.621 2.621 0 1 1 3.717 3.697l-1.57 1.579a1.9 1.9 0 0 1-.3 2.3l-.02.02a1.9 1.9 0 0 1-2.687 0l-.156-.157-5.647 5.642a.5.5 0 0 1-.353.147H5.504a.5.5 0 0 1-.5-.5L5 16.503a.5.5 0 0 1 .146-.354l5.647-5.647-.157-.156a1.9 1.9 0 0 1 0-2.687l.02-.02a1.9 1.9 0 0 1 2.299-.3zm-3.016 5.44 1.293 1.292-5.5 5.496h-1.29L6 16.707z"
          />
        </svg>
      </ColorPickerEyeDropper>
      <div class="flex flex-col flex-1 gap-2">
        <ColorPickerSliderHue />
        <ColorPickerSliderAlpha />
      </div>
    </div>
    <div class="flex items-center gap-2">
      <TabsRoot
        v-model="format"
        default-value="hex"
      >
        <TabsList class="w-full grid grid-cols-4 items-center justify-center rounded-[7px] bg-[#f5f5f5] p-0.5">
          <TabsTrigger class="h-6 inline-flex items-center justify-center whitespace-nowrap rounded-[5px] px-1 py-0.5 text-[10px] font-medium focus-within:outline-1 focus-within:outline-[#0d99ff] disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white data-[state=active]:shadow" value="hex">Hex</TabsTrigger>
          <TabsTrigger class="h-6 inline-flex items-center justify-center whitespace-nowrap rounded-[5px] px-1 py-0.5 text-[10px] font-medium focus-within:outline-1 focus-within:outline-[#0d99ff] disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white data-[state=active]:shadow" value="rgb">RGB</TabsTrigger>
          <TabsTrigger class="h-6 inline-flex items-center justify-center whitespace-nowrap rounded-[5px] px-1 py-0.5 text-[10px] font-medium focus-within:outline-1 focus-within:outline-[#0d99ff] disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white data-[state=active]:shadow" value="hsl">HSL</TabsTrigger>
          <TabsTrigger class="h-6 inline-flex items-center justify-center whitespace-nowrap rounded-[5px] px-1 py-0.5 text-[10px] font-medium focus-within:outline-1 focus-within:outline-[#0d99ff] disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white data-[state=active]:shadow" value="hsb">HSB</TabsTrigger>
        </TabsList>
        <TabsContent class="mt-2" value="hex">
          <ColorPickerInputHex />
        </TabsContent>
        <TabsContent class="mt-2" value="rgb">
          <ColorPickerInputRGB />
        </TabsContent>
        <TabsContent class="mt-2" value="hsl">
          <ColorPickerInputHSL />
        </TabsContent>
        <TabsContent class="mt-2" value="hsb">
          <ColorPickerInputHSB />
        </TabsContent>
      </TabsRoot>
    </div>
    <div class="border-t -mx-4 px-3 pt-2 grid grid-cols-9">
      <ColorPickerSwatch
        v-for="color in swatches"
        :value="color"
        class="m-1"
        @click="colorPicker && (colorPicker.color.hexa.value = color)"
      />
    </div>
  </ColorPickerRoot>
</template>
R
G
B
%
ColorPickerWithTabsVerticalSliders.vue
<script lang="ts" setup>
import { ref, computed, useTemplateRef } from 'vue'
import { useForwardPropsEmits } from 'reka-ui'
import { TabsRoot, TabsList, TabsTrigger } from 'reka-ui'
import {
  ColorPickerRoot,
  ColorPickerCanvas,
  ColorPickerEyeDropper,
  ColorPickerSliderHue,
  ColorPickerSliderAlpha,
  ColorPickerInputHex,
  ColorPickerInputHSL,
  ColorPickerInputRGB,
  ColorPickerInputHSB,
  ColorPickerSwatch,
  type ColorPickerRootProps,
  type ColorPickerRootEmits
} from '@vuelor/picker'

type ColorPickerProps = Omit<ColorPickerRootProps, 'styling' | 'ui'>

const props = defineProps<ColorPickerProps>()
const emits = defineEmits<ColorPickerRootEmits>()

const forwarded = useForwardPropsEmits(props, emits)

const INPUTS = {
  hex: ColorPickerInputHex,
  rgb: ColorPickerInputRGB,
  hsl: ColorPickerInputHSL,
  hsb: ColorPickerInputHSB
}

const format = ref<string>('rgb')

const canvasType = computed<'HSL' | 'HSV'>(() => {
  return format.value === 'hsl' ? 'HSL' : 'HSV'
})

const swatches = ref<string[]>([
  '#FF690050',
  '#FCB900FF',
  '#7BDCB5FF',
  '#00D084FF',
  '#8ED1FCFF',
  '#0693E3FF',
  '#ABB8C344',
  '#EB144CFF',
  '#F78DA7FF',
  '#9900EFFF',
  '#F6BD6044',
  '#84A59DBA',
])

const colorPicker = useTemplateRef<typeof ColorPickerRoot>('colorPicker')
</script>

<template>
  <ColorPickerRoot
    ref="colorPicker"
    class="w-[295px] p-0 gap-0"
    :ui="{
      input: {
        group: '!outline-none gap-2',
        item: '!rounded-[6px] hover:outline-1 outline-[#e6e6e6] focus-within:outline-1 focus-within:outline-[#0d99ff]'
      },
      shared: {
        thumb: 'border-[3px] w-3.5 h-3.5'
      },
      canvas: {
        area: 'rounded-lg'
      },
      slider: {
        track: 'w-4'
      }
    }"
    v-bind="forwarded"
  >
    <div class="pt-4 px-4 pb-3 flex flex-col gap-3">
      <div class="flex gap-3">
        <ColorPickerCanvas :type="canvasType" />
        <ColorPickerSliderHue orientation="vertical" />
        <ColorPickerSliderAlpha orientation="vertical" />
      </div>
      <TabsRoot
        v-model="format"
        default-value="hex"
      >
        <TabsList class="grid grid-cols-4 items-center justify-center rounded-[7px] bg-[#f5f5f5] p-0.5 w-full">
          <TabsTrigger class="h-6 inline-flex items-center justify-center rounded-[5px] px-1 py-0.5 text-[11px] font-medium focus-within:outline-1 focus-within:outline-[#0d99ff] disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white data-[state=active]:shadow" value="hex">Hex</TabsTrigger>
          <TabsTrigger class="h-6 inline-flex items-center justify-center rounded-[5px] px-1 py-0.5 text-[11px] font-medium focus-within:outline-1 focus-within:outline-[#0d99ff] disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white data-[state=active]:shadow" value="rgb">RGB</TabsTrigger>
          <TabsTrigger class="h-6 inline-flex items-center justify-center rounded-[5px] px-1 py-0.5 text-[11px] font-medium focus-within:outline-1 focus-within:outline-[#0d99ff] disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white data-[state=active]:shadow" value="hsl">HSL</TabsTrigger>
          <TabsTrigger class="h-6 inline-flex items-center justify-center rounded-[5px] px-1 py-0.5 text-[11px] font-medium focus-within:outline-1 focus-within:outline-[#0d99ff] disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white data-[state=active]:shadow" value="hsb">HSB</TabsTrigger>
        </TabsList>
      </TabsRoot>
      <div class="flex items-center gap-3">
        <ColorPickerEyeDropper class="p-0">
          <svg width="24" height="24" fill="none" viewBox="0 0 24 24">
            <path
              fill="currentColor"
              fill-rule="evenodd"
              clip-rule="evenodd"
              d="M17.52 6.471a1.62 1.62 0 0 0-2.295.003l-1.87 1.88-.354.355-.355-.354-.01-.01a.9.9 0 0 0-1.272 0l-.02.02a.9.9 0 0 0 0 1.273l.51.51 2 2 .51.51a.9.9 0 0 0 1.272 0l.02-.02a.9.9 0 0 0 0-1.273l-.01-.01-.352-.353.351-.353 1.879-1.888a1.62 1.62 0 0 0-.003-2.29m-3.004-.702a2.621 2.621 0 1 1 3.717 3.697l-1.57 1.579a1.9 1.9 0 0 1-.3 2.3l-.02.02a1.9 1.9 0 0 1-2.687 0l-.156-.157-5.647 5.642a.5.5 0 0 1-.353.147H5.504a.5.5 0 0 1-.5-.5L5 16.503a.5.5 0 0 1 .146-.354l5.647-5.647-.157-.156a1.9 1.9 0 0 1 0-2.687l.02-.02a1.9 1.9 0 0 1 2.299-.3zm-3.016 5.44 1.293 1.292-5.5 5.496h-1.29L6 16.707z"
            />
          </svg>
        </ColorPickerEyeDropper>
        <component :is="INPUTS[format]" />
      </div>
    </div>
    <div class="border-t p-4 grid grid-cols-12 gap-y-1.5">
      <ColorPickerSwatch
        v-for="color in swatches"
        :value="color"
        class="m-1"
        @click="colorPicker && (colorPicker.color.hexa.value = color)"
      />
    </div>
  </ColorPickerRoot>
</template>

Released under the MIT License.