Skip to content

Commit

Permalink
feat(VColorPicker): add eyedropper button when supported (#17952)
Browse files Browse the repository at this point in the history
closes #14790

Co-authored-by: Kael <kaelwd@gmail.com>
  • Loading branch information
prashantsinghb and KaelWD committed Aug 9, 2023
1 parent afeb6c0 commit 3559698
Show file tree
Hide file tree
Showing 10 changed files with 63 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,7 @@
align-items: center
display: flex
margin-bottom: $color-picker-preview-margin-bottom

.v-color-picker-preview__eye-dropper
position: relative
margin-right: $color-picker-preview-dropper-margin
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,27 @@
import './VColorPickerPreview.sass'

// Components
import { VBtn } from '@/components/VBtn'
import { VSlider } from '@/components/VSlider'

// Composables
import { makeComponentProps } from '@/composables/component'

// Utilities
import { onUnmounted } from 'vue'
import { nullColor } from './util'
import { defineComponent, HSVtoCSS, propsFactory, useRender } from '@/util'
import {
defineComponent,
HexToHSV,
HSVtoCSS,
propsFactory,
SUPPORTS_EYE_DROPPER,
useRender,
} from '@/util'

// Types
import type { PropType } from 'vue'
import type { HSV } from '@/util'
import type { Hex, HSV } from '@/util'

export const makeVColorPickerPreviewProps = propsFactory({
color: {
Expand All @@ -35,6 +44,21 @@ export const VColorPickerPreview = defineComponent({
},

setup (props, { emit }) {
const abortController = new AbortController()

onUnmounted(() => abortController.abort())

async function openEyeDropper () {
if (!SUPPORTS_EYE_DROPPER) return

const eyeDropper = new window.EyeDropper()
try {
const result = await eyeDropper.open({ signal: abortController.signal })
const colorHexValue = HexToHSV(result.sRGBHex as Hex)
emit('update:color', { ...(props.color ?? nullColor), ...colorHexValue })
} catch (e) {}
}

useRender(() => (
<div
class={[
Expand All @@ -46,6 +70,12 @@ export const VColorPickerPreview = defineComponent({
]}
style={ props.style }
>
{ SUPPORTS_EYE_DROPPER && (
<div class="v-color-picker-preview__eye-dropper" key="eyeDropper">
<VBtn onClick={ openEyeDropper } icon="$eyeDropper" variant="plain" density="comfortable" />
</div>
)}

<div class="v-color-picker-preview__dot">
<div style={{ background: HSVtoCSS(props.color ?? nullColor) }} />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ $color-picker-canvas-dot-size: 15px !default;
// VColorPickerPreview
$color-picker-preview-dot-size: 30px !default;
$color-picker-preview-dot-margin: 24px !default;
$color-picker-preview-dropper-margin: 12px !default;
20 changes: 20 additions & 0 deletions packages/vuetify/src/globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,26 @@ declare global {
sourceCapabilities?: { firesTouchEvents: boolean }
}

interface ColorSelectionOptions {
signal?: AbortSignal
}

interface ColorSelectionResult {
sRGBHex: string
}

interface EyeDropper {
open: (options?: ColorSelectionOptions) => Promise<ColorSelectionResult>
}

interface EyeDropperConstructor {
new (): EyeDropper
}

interface Window {
EyeDropper: EyeDropperConstructor
}

function parseInt(s: string | number, radix?: number): number
function parseFloat(string: string | number): number

Expand Down
1 change: 1 addition & 0 deletions packages/vuetify/src/iconsets/fa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const aliases: IconAliases = {
plus: 'fas fa-plus',
minus: 'fas fa-minus',
calendar: 'fas fa-calendar',
eyeDropper: 'fas fa-eye-dropper',
}

const fa: IconSet = {
Expand Down
1 change: 1 addition & 0 deletions packages/vuetify/src/iconsets/fa4.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const aliases: IconAliases = {
plus: 'fa-plus',
minus: 'fa-minus',
calendar: 'fa-calendar',
eyeDropper: 'fa-eye-dropper',
}

const fa: IconSet = {
Expand Down
1 change: 1 addition & 0 deletions packages/vuetify/src/iconsets/md.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const aliases: IconAliases = {
plus: 'add',
minus: 'remove',
calendar: 'event',
eyeDropper: 'colorize',
}

const md: IconSet = {
Expand Down
1 change: 1 addition & 0 deletions packages/vuetify/src/iconsets/mdi-svg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const aliases: IconAliases = {
plus: 'svg:M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z',
minus: 'svg:M19,13H5V11H19V13Z',
calendar: 'svg:M19,19H5V8H19M16,1V3H8V1H6V3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3H18V1M17,12H12V17H17V12Z',
eyeDropper: 'svg:M19.35,11.72L17.22,13.85L15.81,12.43L8.1,20.14L3.5,22L2,20.5L3.86,15.9L11.57,8.19L10.15,6.78L12.28,4.65L19.35,11.72M16.76,3C17.93,1.83 19.83,1.83 21,3C22.17,4.17 22.17,6.07 21,7.24L19.08,9.16L14.84,4.92L16.76,3M5.56,17.03L4.5,19.5L6.97,18.44L14.4,11L13,9.6L5.56,17.03Z',
}

const mdi: IconSet = {
Expand Down
1 change: 1 addition & 0 deletions packages/vuetify/src/iconsets/mdi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const aliases: IconAliases = {
plus: 'mdi-plus',
minus: 'mdi-minus',
calendar: 'mdi-calendar',
eyeDropper: 'mdi-eyedropper',
}

const mdi: IconSet = {
Expand Down
1 change: 1 addition & 0 deletions packages/vuetify/src/util/globals.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const IN_BROWSER = typeof window !== 'undefined'
export const SUPPORTS_INTERSECTION = IN_BROWSER && 'IntersectionObserver' in window
export const SUPPORTS_TOUCH = IN_BROWSER && ('ontouchstart' in window || window.navigator.maxTouchPoints > 0)
export const SUPPORTS_EYE_DROPPER = IN_BROWSER && 'EyeDropper' in window

0 comments on commit 3559698

Please sign in to comment.