jaames / iro.js

🎨 Modular color picker widget for JavaScript, with support for a bunch of color formats
https://iro.js.org
Mozilla Public License 2.0
1.32k stars 82 forks source link

Does iro.js v5.0 work with Vue 3.0 #200

Closed Nukron closed 2 years ago

Nukron commented 3 years ago

Hey jaames,

first of all a huge thank you for iro.js. It is such an amazing and useful tool.

I noticed that iro.js currently doesn't work with Vue 3.0 or at least i don't now how to correctly implement it. I noticed that you mentioned that you were going to work on a React and Vue component using the iro-core. Has there been any updates yet or is there already a way to implement iro.js in to Vue 3.0 by any chance?

niktsanov commented 2 years ago

Hi @Nukron,

In my current project (Vue 3 + TypeScript) I had to make a wrapper around iro. You can take a look at the component, it also has an input that shows the current HEX value.

<template>
    <div class="color-picker">
        <div ref="container"></div>
        <label>
            <input
                class="color-picker__input"
                :style="{ width: `${width}px` }"
                :value="color"
                @change="onInputChange"
                type="text"
            />
        </label>
    </div>
</template>

<script lang="ts">
import { computed, defineComponent, onBeforeUnmount, onMounted, PropType, ref, watch } from 'vue'
import iro from '@jaames/iro'
import { IroColor } from '@irojs/iro-core'
import { IroColorPicker } from '@jaames/iro/dist/ColorPicker'

export default defineComponent({
    name: 'ColorPicker',
    props: {
        modelValue: {
            type: String as PropType<string>,
            default: '#ffffff',
        },
        width: {
            type: Number as PropType<number>,
            default: 200,
        },
    },
    setup(props, { emit }) {
        const container = ref<null | HTMLElement>(null)
        const picker = ref<null | IroColorPicker>(null)
        const color = ref<string>(props.modelValue)

        onMounted(() => {
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore
            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
            picker.value = new iro.ColorPicker(container.value!, {
                width: props.width,
                color: props.modelValue,
                layoutDirection: 'horizontal',
                layout: [
                    {
                        component: iro.ui.Box,
                    },
                    {
                        component: iro.ui.Slider,
                        options: {
                            id: 'hue-slider',
                            sliderType: 'hue',
                        },
                    },
                ],
            })
            picker.value?.on('input:end', onPickerInputEnd)
            picker.value?.on('input:change', onPickerInputChange)
        })

        onBeforeUnmount(() => {
            picker.value?.off('input:end', onPickerInputEnd)
            picker.value?.off('input:change', onPickerInputChange)
        })

        const isHex = (hexString: string): boolean => {
            return /^#[0-9A-F]{6}$/i.test(hexString)
        }

        const onInputChange = (event: InputEvent) => {
            const target = event.target as HTMLInputElement
            const value = target.value
            if (isHex(value)) {
                emit('update:modelValue', value)
            } else {
                emit('update:modelValue', '#ffffff')
            }
        }

        const onPickerInputEnd = (color: IroColor) => {
            emit('update:modelValue', color.hexString)
        }

        const onPickerInputChange = (colorObject: IroColor) => {
            color.value = colorObject.hexString
        }

        watch(
            computed(() => props.modelValue),
            value => {
                color.value = value
                if (picker.value?.color) {
                    picker.value.color.hexString = value
                }
            },
        )

        return {
            container,
            color,
            onInputChange,
        }
    },
})
</script>

then you can use it as <ColorPicker v-model="color" />