diff --git a/packages/builder/src/components/userInterface/Colorpicker/ButtonGroup.svelte b/packages/builder/src/components/userInterface/Colorpicker/ButtonGroup.svelte
new file mode 100644
index 0000000000..f9c402ac81
--- /dev/null
+++ b/packages/builder/src/components/userInterface/Colorpicker/ButtonGroup.svelte
@@ -0,0 +1,27 @@
+
+
+
+
+
handleClick(event.clientX)}
+ class="color-format-slider"
+ class:hue={type === 'hue'}
+ class:alpha={type === 'alpha'}>
+
handleClick(e.detail)}
+ class="slider-thumb"
+ {style} />
+
diff --git a/packages/builder/src/components/userInterface/Colorpicker/drag.js b/packages/builder/src/components/userInterface/Colorpicker/drag.js
new file mode 100644
index 0000000000..0d7a9c2481
--- /dev/null
+++ b/packages/builder/src/components/userInterface/Colorpicker/drag.js
@@ -0,0 +1,22 @@
+export default function(node) {
+ function handleMouseDown() {
+ window.addEventListener("mousemove", handleMouseMove)
+ window.addEventListener("mouseup", handleMouseUp)
+ }
+
+ function handleMouseMove(event) {
+ let mouseX = event.clientX
+ node.dispatchEvent(
+ new CustomEvent("drag", {
+ detail: mouseX,
+ })
+ )
+ }
+
+ function handleMouseUp() {
+ window.removeEventListener("mousedown", handleMouseDown)
+ window.removeEventListener("mousemove", handleMouseMove)
+ }
+
+ node.addEventListener("mousedown", handleMouseDown)
+}
diff --git a/packages/builder/src/components/userInterface/Colorpicker/helpers.js b/packages/builder/src/components/userInterface/Colorpicker/helpers.js
new file mode 100644
index 0000000000..5d9ff750af
--- /dev/null
+++ b/packages/builder/src/components/userInterface/Colorpicker/helpers.js
@@ -0,0 +1,14 @@
+export const buildStyle = styles => {
+ let str = ""
+ for (let s in styles) {
+ if (styles[s]) {
+ let key = convertCamel(s)
+ str += `${key}: ${styles[s]}; `
+ }
+ }
+ return str
+}
+
+export const convertCamel = str => {
+ return str.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`)
+}
diff --git a/packages/builder/src/components/userInterface/Colorpicker/index.js b/packages/builder/src/components/userInterface/Colorpicker/index.js
new file mode 100644
index 0000000000..21e19acc9b
--- /dev/null
+++ b/packages/builder/src/components/userInterface/Colorpicker/index.js
@@ -0,0 +1,2 @@
+import Colorpreview from "./Colorpreview.svelte"
+export default Colorpreview
diff --git a/packages/builder/src/components/userInterface/Colorpicker/utils.js b/packages/builder/src/components/userInterface/Colorpicker/utils.js
new file mode 100644
index 0000000000..e14c8711ab
--- /dev/null
+++ b/packages/builder/src/components/userInterface/Colorpicker/utils.js
@@ -0,0 +1,279 @@
+export const isValidHex = str =>
+ /^#(?:[A-F0-9]{3}$|[A-F0-9]{4}$|[A-F0-9]{6}$|[A-F0-9]{8})$/gi.test(str)
+
+const getHexaValues = hexString => {
+ if (hexString.length <= 5) {
+ let hexArr = hexString.match(/[A-F0-9]/gi)
+ let t = hexArr.map(c => (c += c))
+ return t
+ } else {
+ return hexString.match(/[A-F0-9]{2}/gi)
+ }
+}
+
+export const isValidRgb = str => {
+ const hasValidStructure = /^(?:rgba\(|rgb\()(?:[0-9,\s]|\.(?=\d))*\)$/gi.test(
+ str
+ )
+ if (hasValidStructure) {
+ return testRgbaValues(str.toLowerCase())
+ }
+}
+
+const findNonNumericChars = /[a-z()\s]/gi
+
+export const getNumericValues = str =>
+ str
+ .replace(findNonNumericChars, "")
+ .split(",")
+ .map(v => (v !== "" ? v : undefined))
+
+export const testRgbaValues = str => {
+ const rgba = getNumericValues(str)
+ const [r, g, b, a] = rgba
+
+ let isValidLengthRange =
+ (str.startsWith("rgb(") && rgba.length === 3) ||
+ (str.startsWith("rgba(") && rgba.length === 4)
+ let isValidColorRange = [r, g, b].every(v => v >= 0 && v <= 255)
+ let isValidAlphaRange = str.startsWith("rgba(")
+ ? `${a}`.length <= 4 && a >= 0 && a <= 1
+ : true
+
+ return isValidLengthRange && isValidColorRange && isValidAlphaRange
+}
+
+export const isValidHsl = str => {
+ const hasValidStructure = /^(?:hsl\(|hsla\()(?:[0-9,%\s]|\.(?=\d))*\)$/gi.test(
+ str
+ )
+ if (hasValidStructure) {
+ return testHslaValues(str.toLowerCase())
+ }
+}
+
+export const testHslaValues = str => {
+ const hsla = getNumericValues(str)
+ const [h, s, l, a] = hsla
+ const isUndefined = [h, s, l].some(v => v === undefined)
+
+ if (isUndefined) return false
+
+ let isValidLengthRange =
+ (str.startsWith("hsl(") && hsla.length === 3) ||
+ (str.startsWith("hsla(") && hsla.length === 4)
+ let isValidHue = h >= 0 && h <= 360
+ let isValidSatLum = [s, l].every(
+ v => v.endsWith("%") && parseInt(v) >= 0 && parseInt(v) <= 100
+ )
+ let isValidAlphaRange = str.startsWith("hsla(")
+ ? `${a}`.length <= 4 && a >= 0 && a <= 1
+ : true
+
+ return isValidLengthRange && isValidHue && isValidSatLum && isValidAlphaRange
+}
+
+export const getColorFormat = color => {
+ if (typeof color === "string") {
+ if (isValidHex(color)) {
+ return "hex"
+ } else if (isValidRgb(color)) {
+ return "rgb"
+ } else if (isValidHsl(color)) {
+ return "hsl"
+ }
+ }
+}
+
+export const convertToHSVA = (value, format) => {
+ switch (format) {
+ case "hex":
+ return getAndConvertHexa(value)
+ case "rgb":
+ return getAndConvertRgba(value)
+ case "hsl":
+ return getAndConvertHsla(value)
+ }
+}
+
+export const convertHsvaToFormat = (hsva, format) => {
+ switch (format) {
+ case "hex":
+ return hsvaToHexa(hsva, true)
+ case "rgb":
+ return hsvaToRgba(hsva, true)
+ case "hsl":
+ return hsvaToHsla(hsva)
+ }
+}
+
+export const getAndConvertHexa = color => {
+ let [rHex, gHex, bHex, aHex] = getHexaValues(color)
+ return hexaToHSVA([rHex, gHex, bHex], aHex)
+}
+
+export const getAndConvertRgba = color => {
+ let rgba = getNumericValues(color)
+ return rgbaToHSVA(rgba)
+}
+
+export const getAndConvertHsla = color => {
+ let hsla = getNumericValues(color)
+ return hslaToHSVA(hsla)
+}
+
+export const hexaToHSVA = (hex, alpha = "FF") => {
+ const rgba = hex
+ .map(v => parseInt(v, 16))
+ .concat(Number((parseInt(alpha, 16) / 255).toFixed(2)))
+ return rgbaToHSVA(rgba)
+}
+
+export const rgbaToHSVA = rgba => {
+ const [r, g, b, a = 1] = rgba
+ let hsv = _rgbToHSV([r, g, b])
+ return [...hsv, a].map(x => parseFloat(x))
+}
+
+export const hslaToHSVA = ([h, s, l, a = 1]) => {
+ let sat = s.replace(/%/, "")
+ let lum = l.replace(/%/, "")
+ let hsv = _hslToHSV([h, sat, lum])
+ return [...hsv, a].map(x => parseFloat(x))
+}
+
+export const hsvaToHexa = (hsva, asString = false) => {
+ const [r, g, b, a] = hsvaToRgba(hsva)
+
+ const hexa = [r, g, b]
+ .map(v => {
+ let hex = Math.round(v).toString(16)
+ return hex.length === 1 ? `0${hex}` : hex
+ })
+ .concat(Math.round(a * 255).toString(16))
+ return asString ? `#${hexa.join("")}` : hexa
+}
+
+export const hsvaToRgba = ([h, s, v, a = 1], asString = false) => {
+ let rgb = _hsvToRgb([h, s, v]).map(x => Math.round(x))
+ let rgba = [...rgb, a < 1 ? _fixNum(a, 2) : a]
+ return asString ? `rgba(${rgba.join(",")})` : rgba
+}
+
+export const hsvaToHsla = ([h, s, v, a = 1]) => {
+ let [hue, sat, lum] = _hsvToHSL([h, s, v])
+ let hsla = [hue, sat + "%", lum + "%", a < 1 ? _fixNum(a, 2) : a]
+ return `hsla(${hsla.join(",")})`
+}
+
+export const _hslToHSV = hsl => {
+ const h = hsl[0]
+ let s = hsl[1] / 100
+ let l = hsl[2] / 100
+ let smin = s
+ const lmin = Math.max(l, 0.01)
+
+ l *= 2
+ s *= l <= 1 ? l : 2 - l
+ smin *= lmin <= 1 ? lmin : 2 - lmin
+ const v = (l + s) / 2
+ const sv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s)
+
+ return [h, sv * 100, v * 100]
+}
+
+//Credit : https://github.com/Qix-/color-convert
+export const _rgbToHSV = rgb => {
+ let rdif
+ let gdif
+ let bdif
+ let h
+ let s
+
+ const r = rgb[0] / 255
+ const g = rgb[1] / 255
+ const b = rgb[2] / 255
+ const v = Math.max(r, g, b)
+ const diff = v - Math.min(r, g, b)
+ const diffc = function(c) {
+ return (v - c) / 6 / diff + 1 / 2
+ }
+
+ if (diff === 0) {
+ h = 0
+ s = 0
+ } else {
+ s = diff / v
+ rdif = diffc(r)
+ gdif = diffc(g)
+ bdif = diffc(b)
+
+ if (r === v) {
+ h = bdif - gdif
+ } else if (g === v) {
+ h = 1 / 3 + rdif - bdif
+ } else if (b === v) {
+ h = 2 / 3 + gdif - rdif
+ }
+
+ if (h < 0) {
+ h += 1
+ } else if (h > 1) {
+ h -= 1
+ }
+ }
+
+ const hsvResult = [h * 360, s * 100, v * 100].map(v => Math.round(v))
+ return hsvResult
+}
+
+//Credit : https://github.com/Qix-/color-convert
+export const _hsvToRgb = hsv => {
+ const h = hsv[0] / 60
+ const s = hsv[1] / 100
+ let v = hsv[2] / 100
+ const hi = Math.floor(h) % 6
+
+ const f = h - Math.floor(h)
+ const p = 255 * v * (1 - s)
+ const q = 255 * v * (1 - s * f)
+ const t = 255 * v * (1 - s * (1 - f))
+ v *= 255
+
+ switch (hi) {
+ case 0:
+ return [v, t, p]
+ case 1:
+ return [q, v, p]
+ case 2:
+ return [p, v, t]
+ case 3:
+ return [p, q, v]
+ case 4:
+ return [t, p, v]
+ case 5:
+ return [v, p, q]
+ }
+}
+
+//Credit : https://github.com/Qix-/color-convert
+export const _hsvToHSL = hsv => {
+ const h = hsv[0]
+ const s = hsv[1] / 100
+ const v = hsv[2] / 100
+ const vmin = Math.max(v, 0.01)
+ let sl
+ let l
+
+ l = (2 - s) * v
+ const lmin = (2 - s) * vmin
+ sl = s * vmin
+ sl /= lmin <= 1 ? lmin : 2 - lmin
+ sl = sl || 0
+ l /= 2
+
+ return [_fixNum(h, 0), _fixNum(sl * 100, 0), _fixNum(l * 100, 0)]
+}
+
+export const _fixNum = (value, decimalPlaces) =>
+ Number(parseFloat(value).toFixed(decimalPlaces))
diff --git a/packages/builder/src/components/userInterface/Colorpicker/utils.test.js b/packages/builder/src/components/userInterface/Colorpicker/utils.test.js
new file mode 100644
index 0000000000..c47d54ed1b
--- /dev/null
+++ b/packages/builder/src/components/userInterface/Colorpicker/utils.test.js
@@ -0,0 +1,106 @@
+import { getColorFormat, convertToHSVA, convertHsvaToFormat } from "./utils"
+
+describe("convertToHSVA - convert to hsva from format", () => {
+ test("convert from hexa", () => {
+ expect(convertToHSVA("#f222d382", "hex")).toEqual([309, 86, 95, 0.51])
+ })
+
+ test("convert from hex", () => {
+ expect(convertToHSVA("#f222d3", "hex")).toEqual([309, 86, 95, 1])
+ })
+
+ test("convert from rgba", () => {
+ expect(convertToHSVA("rgba(242, 34, 211, 1)", "rgb")).toEqual([
+ 309,
+ 86,
+ 95,
+ 1,
+ ])
+ })
+
+ test("convert from rgb", () => {
+ expect(convertToHSVA("rgb(150, 80, 255)", "rgb")).toEqual([264, 69, 100, 1])
+ })
+
+ test("convert from from hsl", () => {
+ expect(convertToHSVA("hsl(264, 100%, 65.7%)", "hsl")).toEqual([
+ 264,
+ 68.6,
+ 100,
+ 1,
+ ])
+ })
+
+ test("convert from from hsla", () => {
+ expect(convertToHSVA("hsla(264, 100%, 65.7%, 0.51)", "hsl")).toEqual([
+ 264,
+ 68.6,
+ 100,
+ 0.51,
+ ])
+ })
+})
+
+describe("convertHsvaToFormat - convert from hsva to format", () => {
+ test("Convert to hexa", () => {
+ expect(convertHsvaToFormat([264, 68.63, 100, 0.5], "hex")).toBe("#9650ff80")
+ })
+
+ test("Convert to rgba", () => {
+ expect(convertHsvaToFormat([264, 68.63, 100, 0.75], "rgb")).toBe(
+ "rgba(150,80,255,0.75)"
+ )
+ })
+
+ test("Convert to hsla", () => {
+ expect(convertHsvaToFormat([264, 68.63, 100, 1], "hsl")).toBe(
+ "hsla(264,100%,66%,1)"
+ )
+ })
+})
+
+describe("Get Color Format", () => {
+ test("Testing valid hex string", () => {
+ expect(getColorFormat("#FFF")).toBe("hex")
+ })
+
+ test("Testing invalid hex string", () => {
+ expect(getColorFormat("#FFZ")).toBeUndefined()
+ })
+
+ test("Testing valid hex with alpha", () => {
+ expect(getColorFormat("#FF00BB80")).toBe("hex")
+ })
+
+ test("Test valid rgb value", () => {
+ expect(getColorFormat("RGB(255, 20, 50)")).toBe("rgb")
+ })
+
+ test("Testing invalid rgb value", () => {
+ expect(getColorFormat("rgb(255, 0)")).toBeUndefined()
+ })
+
+ test("Testing rgb value with alpha", () => {
+ expect(getColorFormat("rgba(255, 0, 50, 0.5)")).toBe("rgb")
+ })
+
+ test("Testing rgb value with incorrectly provided alpha", () => {
+ expect(getColorFormat("rgb(255, 0, 50, 0.5)")).toBeUndefined()
+ })
+
+ test("Testing invalid hsl value", () => {
+ expect(getColorFormat("hsla(255, 0)")).toBeUndefined()
+ })
+
+ test("Testing hsla value with alpha", () => {
+ expect(getColorFormat("hsla(150, 60%, 50%, 0.5)")).toBe("hsl")
+ })
+
+ test("Testing hsl value with incorrectly provided alpha", () => {
+ expect(getColorFormat("hsl(150, 0, 50, 0.5)")).toBeUndefined()
+ })
+
+ test("Testing out of bounds hsl", () => {
+ expect(getColorFormat("hsl(375, 0, 50)")).toBeUndefined()
+ })
+})
diff --git a/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte b/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte
index e0a5de3fdb..88ce4edca9 100644
--- a/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte
+++ b/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte
@@ -103,8 +103,6 @@
height: 100%;
display: flex;
flex-direction: column;
- overflow-x: hidden;
- overflow-y: hidden;
padding: 20px;
box-sizing: border-box;
}
@@ -122,6 +120,5 @@
margin-top: 20px;
flex: 1 1 auto;
min-height: 0;
- overflow-y: auto;
}
diff --git a/packages/builder/src/components/userInterface/DesignView.svelte b/packages/builder/src/components/userInterface/DesignView.svelte
index 070ba502e3..6826bddc5c 100644
--- a/packages/builder/src/components/userInterface/DesignView.svelte
+++ b/packages/builder/src/components/userInterface/DesignView.svelte
@@ -31,6 +31,7 @@
+