svelte-chroma-picker
Version:
A color picker for Svelte using chroma-js to do the color manipulations
12 lines • 11.5 kB
Source Map (JSON)
{
"version": 3,
"file": "index.css",
"sources": [
"../Picker.svelte"
],
"sourcesContent": [
"<script>\n import { createEventDispatcher } from 'svelte';\n import { valid, setChannel, channels, hsvToRgb } from './colors';\n\n // The initial color which the consumer can pass in\n export let color = '#fff';\n\n // The picker needs a width and a height\n // The consumer can customize this\n export let width = 240;\n export let height = 160;\n\n const dispatch = createEventDispatcher();\n\n // Keep track of the position, size and background color of the color box picker\n const colorBox = {\n width,\n height,\n handle: {\n x: 0,\n y: 0\n },\n bg: {}\n };\n\n // The initial hue value\n let hue = 180;\n\n // Keep track of whether the user is dragging the handle around the color box\n let trackMove = false;\n\n // We'll need references to these DOM elements as well\n let handleEl;\n let colorBoxEl;\n\n // If the color is valid, we need to update the handle position\n $: if (valid(color)) {\n const { hsv } = channels(color);\n\n // Hue-less colors (black, white, and grays), the hue component will be NaN\n // So we need to make sure it doesn't blow up\n if (!isNaN(hsv.h)) {\n hue = hsv.h;\n }\n\n // Finally, we update the position of the handle\n colorBox.handle.x = hsv.s * 100;\n colorBox.handle.y = (1 - hsv.v) * 100;\n }\n\n // Adjust a single channel for the color\n const updateChannel = (channel, value) => {\n color = setChannel(color, channel, value);\n };\n\n // Make sure both the colorBox background and the actual color are updated\n // whenever the hue changes\n const updateHue = h => {\n const rgb = hsvToRgb(h, 1, 1);\n updateChannel('hsv.h', h);\n colorBox.bg = { r: rgb[0], g: rgb[1], b: rgb[2] };\n };\n\n $: updateHue(hue);\n\n // When the user moved the handle, we reposition it and update the color\n const updateColor = (x, y) => {\n handleEl.style.top = `${y}%`;\n handleEl.style.left = `${x}%`;\n\n updateChannel('hsv.h', hue);\n updateChannel('hsv.s', x / 100);\n updateChannel('hsv.v', 1 - y / 100);\n };\n\n const minmax = (n, min = 0, max = 100) => {\n let result = n;\n if (n > max) {\n result = max;\n }\n if (n < min) {\n result = min;\n }\n result = result.toFixed(2);\n\n return result;\n };\n\n // Based on the X and Y position of the client's mouse/touch\n // we calculate where the new position of the handle should be\n // and update the color\n const pick = (clientX, clientY) => {\n const { x, y } = colorBoxEl.getBoundingClientRect();\n let xPercentage = ((clientX - x) / colorBox.width) * 100;\n let yPercentage = ((clientY - y) / colorBox.height) * 100;\n\n yPercentage = minmax(yPercentage);\n xPercentage = minmax(xPercentage);\n\n updateColor(xPercentage, yPercentage);\n };\n\n // Whenever we have a valid color, we can let the consumer know of the current value\n $: valid(color) && dispatch('update', channels(color));\n\n /* Events */\n const stop = () => {\n trackMove = false;\n };\n\n const mousedown = event => {\n trackMove = true; // We need to start tracking\n const xPercentage = (((event.offsetX + 1) / colorBox.width) * 100).toFixed(\n 2\n );\n const yPercentage = (((event.offsetY + 1) / colorBox.height) * 100).toFixed(\n 2\n );\n updateColor(xPercentage, yPercentage);\n };\n\n const mousemove = event => {\n // We only perform this if the user has previously clicked on the colorBox\n // Otherwise, we might end up updating the color whenever the user moves his mouse around\n if (trackMove) {\n pick(event.clientX, event.clientY);\n }\n };\n\n const touchmove = event => {\n // We only perform this if the user has previously touched the colorBox\n // Otherwise, we might end up updating the color whenever the user moves drags the page around\n if (trackMove) {\n pick(event.touches[0].clientX, event.touches[0].clientY);\n }\n };\n</script>\n\n<div\n role=\"presentation\"\n style=\"--width: {colorBox.width}px; --height: {colorBox.height}px;\n --color-red: {colorBox.bg.r}; --color-green: {colorBox.bg.g}; --color-blue: {colorBox.bg.b}\"\n>\n <div data-picker=\"saturation\">\n <div data-picker=\"value\">\n <div\n data-picker=\"handle\"\n bind:this=\"{handleEl}\"\n style=\"--top: {colorBox.handle.y}%; --left: {colorBox.handle.y}%\"\n ></div>\n <div\n data-picker=\"colorBox\"\n on:mousedown=\"{mousedown}\"\n on:touchstart=\"{mousedown}\"\n on:mousemove=\"{mousemove}\"\n on:touchmove=\"{touchmove}\"\n on:mouseup=\"{stop}\"\n on:touchend=\"{stop}\"\n bind:this=\"{colorBoxEl}\"\n ></div>\n </div>\n </div>\n</div>\n<label style=\"--width: {colorBox.width}px; --height: {colorBox.height}px\">\n <span>Hue</span>\n <input type=\"range\" min=\"0\" max=\"360\" bind:value=\"{hue}\" />\n</label>\n\n<style>\n [role='presentation'] {\n background: rgb(var(--color-red), var(--color-green), var(--color-blue));\n box-shadow: rgba(0, 0, 0, 0.06) 0 0 0 1px;\n height: var(--height);\n width: var(--width);\n }\n\n [data-picker='saturation'] {\n background: linear-gradient(\n to right,\n rgb(255, 255, 255),\n rgba(255, 255, 255, 0)\n );\n height: var(--height);\n width: var(--width);\n }\n\n [data-picker='value'] {\n background: linear-gradient(to top, rgb(0, 0, 0), rgba(0, 0, 0, 0));\n height: var(--height);\n overflow: hidden;\n width: var(--width);\n }\n\n [data-picker='handle'] {\n background: transparent;\n border-radius: 50%;\n border: 2px solid #f2f2f2;\n box-shadow: 0 0.3px 1.4px rgba(0, 0, 0, 0.6),\n 0 0.9px 4.7px rgba(0, 0, 0, 0.032), 0 4px 21px rgba(0, 0, 0, 0.04);\n cursor: crosshair;\n height: 8px;\n left: 100%;\n margin: 0;\n padding: 0;\n position: relative;\n transform: translate(-9px, -9px);\n width: 8px;\n\n top: var(--top, 50%);\n left: var(--left, 50%);\n }\n\n [data-picker='colorBox'] {\n box-shadow: 0 0 1px rgba(0, 0, 0, 0.32) inset;\n cursor: crosshair;\n display: block;\n height: 100%;\n position: relative;\n transform: translate(0, -16px);\n touch-action: none;\n width: 100%;\n }\n\n label {\n display: block;\n margin: 0.8em 0;\n max-width: calc(var(--width) - 4px);\n width: calc(var(--width) - 4px);\n }\n\n label span {\n border: 0;\n clip: rect(0, 0, 0, 0);\n height: 1px;\n margin: -1px;\n overflow: hidden;\n padding: 0;\n position: absolute;\n width: 1px;\n }\n\n input {\n -webkit-appearance: none;\n -webkit-tap-highlight-color: rgba(255, 255, 255, 0);\n background: linear-gradient(\n to right,\n #ff0000 0%,\n #ffff00 17%,\n #00ff00 33%,\n #00ffff 50%,\n #0000ff 67%,\n #ff00ff 83%,\n #ff0000 100%\n );\n border-radius: 6px;\n border: none;\n box-shadow: rgba(0, 0, 0, 0.06) 0 0 0 1px inset;\n height: 12px;\n outline: none;\n padding: 1px 2px;\n width: 100%;\n }\n\n input::-moz-range-track {\n background: transparent;\n border: inherit;\n }\n\n input::-ms-track {\n background: transparent;\n border: inherit;\n color: transparent;\n }\n\n input::-ms-fill-lower,\n input::-ms-fill-upper {\n background: transparent;\n }\n\n input::-ms-tooltip {\n display: none;\n }\n\n input::-webkit-slider-thumb,\n input::-moz-range-thumb {\n -webkit-appearance: none;\n background: #fff;\n box-shadow: rgba(0, 0, 0, 0.12) 0 0 0 1px inset;\n border-radius: 10px;\n border: none;\n height: 10px;\n width: 10px;\n }\n</style>\n"
],
"names": [],
"mappings": "AAyKE,CAAC,IAAI,CAAC,cAAc,CAAC,8BAAC,CAAC,AACrB,UAAU,CAAE,IAAI,IAAI,WAAW,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC,CACxE,UAAU,CAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CACzC,MAAM,CAAE,IAAI,QAAQ,CAAC,CACrB,KAAK,CAAE,IAAI,OAAO,CAAC,AACrB,CAAC,AAED,CAAC,WAAW,CAAC,YAAY,CAAC,8BAAC,CAAC,AAC1B,UAAU,CAAE;MACV,EAAE,CAAC,KAAK,CAAC;MACT,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;MACnB,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;KACvB,CACD,MAAM,CAAE,IAAI,QAAQ,CAAC,CACrB,KAAK,CAAE,IAAI,OAAO,CAAC,AACrB,CAAC,AAED,CAAC,WAAW,CAAC,OAAO,CAAC,8BAAC,CAAC,AACrB,UAAU,CAAE,gBAAgB,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CACnE,MAAM,CAAE,IAAI,QAAQ,CAAC,CACrB,QAAQ,CAAE,MAAM,CAChB,KAAK,CAAE,IAAI,OAAO,CAAC,AACrB,CAAC,AAED,CAAC,WAAW,CAAC,QAAQ,CAAC,8BAAC,CAAC,AACtB,UAAU,CAAE,WAAW,CACvB,aAAa,CAAE,GAAG,CAClB,MAAM,CAAE,GAAG,CAAC,KAAK,CAAC,OAAO,CACzB,UAAU,CAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;MAC3C,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CACpE,MAAM,CAAE,SAAS,CACjB,MAAM,CAAE,GAAG,CACX,IAAI,CAAE,IAAI,CACV,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CACV,QAAQ,CAAE,QAAQ,CAClB,SAAS,CAAE,UAAU,IAAI,CAAC,CAAC,IAAI,CAAC,CAChC,KAAK,CAAE,GAAG,CAEV,GAAG,CAAE,IAAI,KAAK,CAAC,IAAI,CAAC,CACpB,IAAI,CAAE,IAAI,MAAM,CAAC,IAAI,CAAC,AACxB,CAAC,AAED,CAAC,WAAW,CAAC,UAAU,CAAC,8BAAC,CAAC,AACxB,UAAU,CAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAC7C,MAAM,CAAE,SAAS,CACjB,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,IAAI,CACZ,QAAQ,CAAE,QAAQ,CAClB,SAAS,CAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAC9B,YAAY,CAAE,IAAI,CAClB,KAAK,CAAE,IAAI,AACb,CAAC,AAED,KAAK,8BAAC,CAAC,AACL,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,KAAK,CAAC,CAAC,CACf,SAAS,CAAE,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CACnC,KAAK,CAAE,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,AACjC,CAAC,AAED,oBAAK,CAAC,IAAI,eAAC,CAAC,AACV,MAAM,CAAE,CAAC,CACT,IAAI,CAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CACtB,MAAM,CAAE,GAAG,CACX,MAAM,CAAE,IAAI,CACZ,QAAQ,CAAE,MAAM,CAChB,OAAO,CAAE,CAAC,CACV,QAAQ,CAAE,QAAQ,CAClB,KAAK,CAAE,GAAG,AACZ,CAAC,AAED,KAAK,8BAAC,CAAC,AACL,kBAAkB,CAAE,IAAI,CACxB,2BAA2B,CAAE,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CACnD,UAAU,CAAE;MACV,EAAE,CAAC,KAAK,CAAC;MACT,OAAO,CAAC,EAAE,CAAC;MACX,OAAO,CAAC,GAAG,CAAC;MACZ,OAAO,CAAC,GAAG,CAAC;MACZ,OAAO,CAAC,GAAG,CAAC;MACZ,OAAO,CAAC,GAAG,CAAC;MACZ,OAAO,CAAC,GAAG,CAAC;MACZ,OAAO,CAAC,IAAI;KACb,CACD,aAAa,CAAE,GAAG,CAClB,MAAM,CAAE,IAAI,CACZ,UAAU,CAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAC/C,MAAM,CAAE,IAAI,CACZ,OAAO,CAAE,IAAI,CACb,OAAO,CAAE,GAAG,CAAC,GAAG,CAChB,KAAK,CAAE,IAAI,AACb,CAAC,AAED,mCAAK,kBAAkB,AAAC,CAAC,AACvB,UAAU,CAAE,WAAW,CACvB,MAAM,CAAE,OAAO,AACjB,CAAC,AAED,mCAAK,WAAW,AAAC,CAAC,AAChB,UAAU,CAAE,WAAW,CACvB,MAAM,CAAE,OAAO,CACf,KAAK,CAAE,WAAW,AACpB,CAAC,AAED,mCAAK,gBAAgB,CACrB,mCAAK,gBAAgB,AAAC,CAAC,AACrB,UAAU,CAAE,WAAW,AACzB,CAAC,AAED,mCAAK,aAAa,AAAC,CAAC,AAClB,OAAO,CAAE,IAAI,AACf,CAAC,AAED,mCAAK,sBAAsB,CAC3B,mCAAK,kBAAkB,AAAC,CAAC,AACvB,kBAAkB,CAAE,IAAI,CACxB,UAAU,CAAE,IAAI,CAChB,UAAU,CAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAC/C,aAAa,CAAE,IAAI,CACnB,MAAM,CAAE,IAAI,CACZ,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,AACb,CAAC"
}