添加拾色器组件
This commit is contained in:
parent
a9407b257d
commit
c308a83a1b
|
@ -0,0 +1,60 @@
|
|||
<script context="module">
|
||||
export async function preload() {
|
||||
const res = await this.fetch(`components/colorPicker.json`);
|
||||
const jsdoc = await res.json();
|
||||
|
||||
return { jsdoc };
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
import {
|
||||
ColorPicker
|
||||
} from 'svelma-pro'
|
||||
import DocHeader from '../../components/DocHeader.svelte'
|
||||
import Example from '../../components/Example.svelte'
|
||||
import JSDoc from '../../components/JSDoc.svelte'
|
||||
|
||||
export let jsdoc
|
||||
let color = "#1ec131";
|
||||
|
||||
function change(e) {
|
||||
console.log(e.detail)
|
||||
}
|
||||
</script>
|
||||
|
||||
<DocHeader title="ColorPicker" subtitle="拾色器" />
|
||||
|
||||
<Example code={`<script>
|
||||
import { ColorPicker } from 'svelma-pro'
|
||||
let color = "#1ec131";
|
||||
|
||||
|
||||
function change(e){
|
||||
console.log(e.detail)
|
||||
}
|
||||
</script>
|
||||
|
||||
<ColorPicker {color} on:change={change} />
|
||||
`}>
|
||||
<div slot="preview">
|
||||
<ColorPicker {color} on:change={change} />
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
<hr class="is-medium" />
|
||||
|
||||
<p class="title is-4">面板模式</p>
|
||||
|
||||
<Example code={`<script>
|
||||
import { ColorPicker } from 'svelma-pro'
|
||||
let color = "#1ec131";
|
||||
</script>
|
||||
|
||||
<ColorPicker {color} on:change={change} mode="2"/>
|
||||
`}>
|
||||
<div slot="preview">
|
||||
<ColorPicker {color} mode="2"/>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
<JSDoc {jsdoc} showEvent="true"></JSDoc>
|
|
@ -2330,5 +2330,45 @@
|
|||
"defaultvalue": "center",
|
||||
"name": "navPosition",
|
||||
"values": "center,start,end"
|
||||
}]
|
||||
}],
|
||||
"ColorPicker": [
|
||||
{
|
||||
"description": "初始化色值,支持hex,rgba,hsla格式色值",
|
||||
"type": [
|
||||
"String"
|
||||
],
|
||||
"defaultvalue":"#1ec131",
|
||||
"name": "color",
|
||||
"values": "hex,rgba,hsla"
|
||||
},{
|
||||
"description": "显示模式,模式1表示按钮模式,2表示面板模式",
|
||||
"type": [
|
||||
"Number"
|
||||
],
|
||||
"defaultvalue":"1",
|
||||
"name": "mode",
|
||||
"values": "1,2"
|
||||
},{
|
||||
"description": "按钮模式下宽度",
|
||||
"type": [
|
||||
"String"
|
||||
],
|
||||
"defaultvalue":"200px",
|
||||
"name": "width",
|
||||
"values": ""
|
||||
},{
|
||||
"description": "色值类别,0:hex,1:rgba,2:hsla",
|
||||
"type": [
|
||||
"Number"
|
||||
],
|
||||
"defaultvalue":"0",
|
||||
"name": "fieldsIndex",
|
||||
"values": "0,1,2"
|
||||
},{
|
||||
"isEvent": true,
|
||||
"description": "选择改变事件",
|
||||
"name": "change",
|
||||
"values": ""
|
||||
}
|
||||
]
|
||||
}
|
|
@ -99,6 +99,7 @@ module.export = {
|
|||
<!-- main.js或者client.js全局引入 -->
|
||||
<script>
|
||||
import 'bulma/css/bulma.css'
|
||||
import 'svelma-pro/svelma-pro.css'
|
||||
</script>
|
||||
`}>
|
||||
</Codeview>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "svelma-pro",
|
||||
"version": "1.0.6",
|
||||
"version": "1.1.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1953,14 +1953,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"dom7": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/dom7/-/dom7-2.1.3.tgz",
|
||||
"integrity": "sha512-QTxHHDox+M6ZFz1zHPAHZKI3JOHY5iY4i9BK2uctlggxKQwRhO3q3HHFq1BKsT25Bm/ySSj70K6Wk/G4bs9rMQ==",
|
||||
"requires": {
|
||||
"ssr-window": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"dot-prop": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz",
|
||||
|
@ -10385,11 +10377,6 @@
|
|||
"tweetnacl": "~0.14.0"
|
||||
}
|
||||
},
|
||||
"ssr-window": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-1.0.1.tgz",
|
||||
"integrity": "sha512-dgFqB+f00LJTEgb6UXhx0h+SrG50LJvti2yMKMqAgzfUmUXZrLSv2fjULF7AWGwK25EXu8+smLR3jYsJQChPsg=="
|
||||
},
|
||||
"standard-version": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/standard-version/-/standard-version-6.0.1.tgz",
|
||||
|
@ -10815,15 +10802,6 @@
|
|||
"strip-indent": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"swiper": {
|
||||
"version": "5.3.8",
|
||||
"resolved": "https://registry.npmjs.org/swiper/-/swiper-5.3.8.tgz",
|
||||
"integrity": "sha512-bCxrayTgzC2bZBRuFwAx7T4exWeHqMADBpcuTQ7PNCOIIzJRPqNh4ySIvW06LEEU3Q0KncaNre4hrn+jXcWivQ==",
|
||||
"requires": {
|
||||
"dom7": "^2.1.3",
|
||||
"ssr-window": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"tar": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz",
|
||||
|
@ -10893,6 +10871,11 @@
|
|||
"readable-stream": "2 || 3"
|
||||
}
|
||||
},
|
||||
"tinycolor2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz",
|
||||
"integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g="
|
||||
},
|
||||
"tinydate": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/tinydate/-/tinydate-1.0.1.tgz",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "svelma-pro",
|
||||
"svelte": "src/index.js",
|
||||
"description": "Based on svelma project extension and modification",
|
||||
"version": "1.0.9",
|
||||
"version": "1.1.0",
|
||||
"author": "KeiferJu",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
@ -27,7 +27,8 @@
|
|||
"src"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"bulma": "^0.8.0"
|
||||
"bulma": "^0.8.0",
|
||||
"tinycolor2": "^1.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^9.6.0",
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<style>
|
||||
.alpha{
|
||||
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAJUlEQVQoU2N88eLFfwY0ICEhwYguxjgUFKI7GsTH5m4M3w1ChQCnziae7MntdQAAAABJRU5ErkJggg==);
|
||||
background-repeat: repeat;
|
||||
}
|
||||
|
||||
.alpha-in{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.horizontal{
|
||||
background-size: auto 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.vertical{
|
||||
background-size: 100% auto;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import Slider from "./Slider.svelte";
|
||||
|
||||
let className = "";
|
||||
export {className as class};
|
||||
|
||||
export let a = 1;
|
||||
export let vertical = false;
|
||||
export let color = "#fff" // style like string
|
||||
|
||||
$: toGradient = vertical ? "bottom" : "right";
|
||||
//$: style = `background: linear-gradient(to ${vertical ? "bottom" : "right"}, transparent 0%, ${color} 100%)`;
|
||||
</script>
|
||||
|
||||
<div class="alpha {className}" class:vertical class:horizontal={!vertical}>
|
||||
<div class="alpha-in" style="background: linear-gradient(to {toGradient}, transparent 0%, {color} 100%)">
|
||||
<Slider bind:value={a} {vertical} on:input on:input={(event) => console.log(event.detail)} />
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,380 @@
|
|||
<svelte:options accessors={true} />
|
||||
|
||||
<style>
|
||||
.color-picker{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 14.5em;
|
||||
box-shadow: 0 0 2px rgba(0,0,0,.3), 0 4px 8px rgba(0,0,0,.3);
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.color-picker :global(.saturation-value){
|
||||
height: 9em; /* 14.5 / 1.618 */
|
||||
}
|
||||
|
||||
.sliders-and-square{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.square-wrap{
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
border-radius: 1.5em;
|
||||
margin: auto 1.25em auto 0.75em;
|
||||
flex: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sliders{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
margin: auto 1em auto 0;
|
||||
}
|
||||
|
||||
.alpha-wrap{
|
||||
margin-top: 0.75em;
|
||||
}
|
||||
|
||||
.inputs-and-changer{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 1em 0.5em;
|
||||
}
|
||||
|
||||
.changer-wrap{
|
||||
box-sizing: border-box;
|
||||
width: 2em;
|
||||
flex: none;
|
||||
margin: auto;
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
.changer-up, .changer-down{
|
||||
margin: auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.changer-up {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 0.5em solid transparent;
|
||||
border-right: 0.5em solid transparent;
|
||||
border-bottom: 0.5em solid #666;
|
||||
}
|
||||
|
||||
.changer-down {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 0.5em solid transparent;
|
||||
border-right: 0.5em solid transparent;
|
||||
border-top: 0.5em solid #666;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.inputs-wrap{
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
input{
|
||||
text-align: center;
|
||||
outline: 0;
|
||||
box-shadow: none;
|
||||
font-family: inherit;
|
||||
font-size: 0.7em;
|
||||
display: block;
|
||||
width: auto;
|
||||
border: #ddd 1px solid;
|
||||
border-radius: 0.1em;
|
||||
padding: 0.25em 0;
|
||||
}
|
||||
|
||||
.hex{
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.rgba-wrap, .hsla-wrap{
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.rgba-wrap > div:not(:first-child),
|
||||
.hsla-wrap > div:not(:first-child){
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
.rgba-wrap input,
|
||||
.hsla-wrap input{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.percent-input{
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.percent-input:after{
|
||||
content: "%";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translate(-50%);
|
||||
right: 0.25em;
|
||||
}
|
||||
|
||||
label{
|
||||
display: block;
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
margin-top: 0.5em;
|
||||
font-size: 0.8em;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import {createEventDispatcher} from "svelte";
|
||||
const dispatch = createEventDispatcher();
|
||||
// input
|
||||
|
||||
import tinycolor from "tinycolor2";
|
||||
import {getValidColor} from "./utils.js"
|
||||
|
||||
import SaturationValue from "./SaturationValue.svelte";
|
||||
import Alpha from "./Alpha.svelte"
|
||||
import Hue from "./Hue.svelte";
|
||||
import ColorSquare from "./ColorSquare.svelte";
|
||||
|
||||
// RED
|
||||
export let h = 0;
|
||||
export let s = 1;
|
||||
export let v = 1;
|
||||
export let l = 0.5;
|
||||
export let r = 255;
|
||||
export let g = 0;
|
||||
export let b = 0;
|
||||
export let hex = "#ff0000";
|
||||
export let a = 1;
|
||||
|
||||
export let color;
|
||||
$: color = {r, g, b, h, s, l, v, a, hex};
|
||||
|
||||
export let startColor = "#ff0000"; // all tinycolor colors
|
||||
export let disableAlpha = false;
|
||||
|
||||
export let fieldsIndex = 0;
|
||||
|
||||
export const setColor = (args) => update(args, false);
|
||||
|
||||
const update = (args, dispatch=true) => {
|
||||
|
||||
// is not enough with color.isValidColor
|
||||
const color = getValidColor(args);
|
||||
if(!color) return;
|
||||
|
||||
const format = color.getFormat();
|
||||
// we dont use hex8
|
||||
(format === "hex" || format === "hex8") && color.setAlpha(a);
|
||||
const _rgba = color.toRgb();
|
||||
const _hsla = color.toHsl();
|
||||
const _hsva = color.toHsv();
|
||||
const _hex = `#${color.toHex()}`;
|
||||
|
||||
r = args.r != null ? args.r : _rgba.r;
|
||||
g = args.g != null ? args.g : _rgba.g;
|
||||
b = args.b != null ? args.b : _rgba.b;
|
||||
h = args.h != null ? args.h : _hsla.h;
|
||||
s = args.s != null ? args.s : _hsla.s;
|
||||
l = args.l != null ? args.l : _hsla.l;
|
||||
v = args.v != null ? args.v : _hsva.v;
|
||||
a = args.a != null ? args.a : _rgba.a;
|
||||
hex = format === "hex" ? args : _hex;
|
||||
|
||||
dispatch && dispatchInput();
|
||||
}
|
||||
|
||||
const updateAlpha = (alpha) => {
|
||||
if(isNaN(alpha) || alpha < 0 || alpha > 1)
|
||||
return;
|
||||
|
||||
a = alpha;
|
||||
dispatchInput()
|
||||
}
|
||||
|
||||
const dispatchInput = () =>{
|
||||
const value = getcolorValue();
|
||||
dispatch("input", value)
|
||||
} ;
|
||||
|
||||
const onlyChars = (chars) => (event) => chars.indexOf(String.fromCharCode(event.charCode)) === -1 && event.preventDefault();
|
||||
const onlyNumbers = onlyChars("0123456789");
|
||||
const onlyNumbersAndDot = onlyChars("0123456789.");
|
||||
|
||||
update(startColor, false);
|
||||
|
||||
|
||||
function getcolorValue(){
|
||||
switch(fieldsIndex){
|
||||
case 1:
|
||||
const rgba = `rgba(${color.r},${color.g},${color.b},${color.a})`;
|
||||
return rgba;
|
||||
break;
|
||||
case 2:
|
||||
const hsla = `hsla(${Math.round(color.h) % 360},${Math.round(color.s * 100)}%,${Math.round(color.l * 100)}%,${Math.round(color.a * 100) / 100})`;
|
||||
return hsla;
|
||||
break;
|
||||
default:
|
||||
const hex = color.hex;
|
||||
return hex;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="color-picker">
|
||||
|
||||
<div class="saturation-value-wrap">
|
||||
<SaturationValue {h} {s} {v} on:input={(event) => update({h, s: event.detail.s, v: event.detail.v, a})} />
|
||||
</div>
|
||||
|
||||
<div class="sliders-and-square">
|
||||
|
||||
<div class="square-wrap">
|
||||
<ColorSquare color="rgba({r}, {g}, {b}, {a})"/>
|
||||
</div>
|
||||
|
||||
<div class="sliders">
|
||||
<div class="hue-wrap">
|
||||
<Hue {h} on:input={event => update({h: event.detail, s, v, a})} />
|
||||
</div>
|
||||
|
||||
{#if !disableAlpha}
|
||||
<div class="alpha-wrap">
|
||||
<Alpha bind:a color={hex} on:input={dispatchInput}/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inputs-and-changer">
|
||||
|
||||
<div class="inputs-wrap">
|
||||
{#if fieldsIndex === 0}
|
||||
<div class="input-wrap hex-wrap">
|
||||
<input
|
||||
class="hex"
|
||||
type="text"
|
||||
value={hex}
|
||||
maxlength={7}
|
||||
on:keypress={onlyChars("#0123456789abcdefABCFDEF")}
|
||||
on:input={event => update(event.target.value)}
|
||||
/>
|
||||
<label>hex</label>
|
||||
</div>
|
||||
{:else if fieldsIndex === 1}
|
||||
<div class="rgba-wrap">
|
||||
<div class="input-wrap">
|
||||
<input
|
||||
class="rgba"
|
||||
type="text"
|
||||
value={r}
|
||||
maxlength={3}
|
||||
on:keypress={onlyNumbers}
|
||||
on:input={event => update({r: parseInt(event.target.value), g, b, a})}
|
||||
/>
|
||||
<label>r</label>
|
||||
</div>
|
||||
<div class="input-wrap">
|
||||
<input
|
||||
class="rgba"
|
||||
type="text"
|
||||
value={g}
|
||||
maxlength={3}
|
||||
on:keypress={onlyNumbers}
|
||||
on:input={event => update({r, g: parseInt(event.target.value), b, a})}
|
||||
/>
|
||||
<label>g</label>
|
||||
</div>
|
||||
<div class="input-wrap">
|
||||
<input class="rgba"
|
||||
type="text"
|
||||
value={b}
|
||||
maxlength={3}
|
||||
on:keypress={onlyNumbers}
|
||||
on:input={event => update({r, g, b: parseInt(event.target.value), a})}
|
||||
/>
|
||||
<label>b</label>
|
||||
</div>
|
||||
{#if !disableAlpha}
|
||||
<div class="input-wrap">
|
||||
<input
|
||||
class="rgba"
|
||||
type="text"
|
||||
value={Math.round(a * 100) / 100}
|
||||
maxlength={4}
|
||||
on:keypress={onlyNumbersAndDot}
|
||||
on:input={event => updateAlpha(parseFloat(event.target.value))}
|
||||
/>
|
||||
<label>a</label>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if fieldsIndex === 2}
|
||||
<div class="hsla-wrap">
|
||||
<div class="input-wrap">
|
||||
<input class="hsla"
|
||||
value={Math.round(h) % 360}
|
||||
type="text"
|
||||
maxlength={3}
|
||||
on:keypress={onlyNumbers}
|
||||
on:input={event => update({h: parseInt(event.target.value), s, l, a})}
|
||||
/>
|
||||
<label>h</label>
|
||||
</div>
|
||||
<div class="input-wrap">
|
||||
<input
|
||||
class="hsla percent-input"
|
||||
value="{Math.round(s * 100)}%"
|
||||
type="text"
|
||||
maxlength={4}
|
||||
on:keypress={onlyNumbers}
|
||||
on:input={event => update({h, s: parseFloat(event.target.value) / 100, l, a})}
|
||||
/>
|
||||
<label>s</label>
|
||||
</div>
|
||||
<div class="input-wrap">
|
||||
<input
|
||||
class="hsla percent-input"
|
||||
value="{Math.round(l * 100)}%"
|
||||
type="text"
|
||||
maxlength={4}
|
||||
on:keypress={onlyNumbers}
|
||||
on:input={event => update({h, s, l: parseFloat(event.target.value) / 100, a})}
|
||||
/>
|
||||
<label>l</label>
|
||||
</div>
|
||||
{#if !disableAlpha}
|
||||
<div class="input-wrap">
|
||||
<input
|
||||
class="hsla"
|
||||
value={Math.round(a * 100) / 100}
|
||||
type="text"
|
||||
maxlength={4}
|
||||
on:keypress={onlyNumbersAndDot}
|
||||
on:input={event => updateAlpha(parseFloat(event.target.value))}
|
||||
/>
|
||||
<label>a</label>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="changer-wrap">
|
||||
<div class="changer-up" on:click={() => fieldsIndex = (fieldsIndex === 0 ? 2 : (fieldsIndex - 1) % 3)}></div>
|
||||
<div class="changer-down" on:click={() => fieldsIndex = (fieldsIndex + 1) % 3}></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
|
@ -0,0 +1,66 @@
|
|||
<script>
|
||||
import { onMount } from "svelte";
|
||||
import Chrome from "./Chrome.svelte";
|
||||
import {createEventDispatcher} from "svelte";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let color = "#1ec131";
|
||||
export let fieldsIndex = 0; // 0 hex 1 rgba 2 hsla
|
||||
export let mode = 1; // 1 input点击模式 2 直接显示
|
||||
export let width = "200px";
|
||||
|
||||
let active = false;
|
||||
onMount(() => {});
|
||||
|
||||
function openChrome(event) {
|
||||
if (!active) {
|
||||
active = true;
|
||||
}
|
||||
}
|
||||
|
||||
function closeChrome() {
|
||||
active = false;
|
||||
}
|
||||
|
||||
const handleInput = event => {
|
||||
color = event.detail;
|
||||
dispatch("change", event.detail);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.smx-color-picker {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.smx-color-picker input{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.smx-color-panel {
|
||||
position: absolute;
|
||||
top: -105px;
|
||||
right: -250px;
|
||||
}
|
||||
</style>
|
||||
<svelte:window on:click={closeChrome}/>
|
||||
{#if mode === 1}
|
||||
<div class="smx-color-picker" style="width: {width}">
|
||||
<input
|
||||
type="text"
|
||||
class="input"
|
||||
on:click|stopPropagation={openChrome}
|
||||
value={color}
|
||||
style="background: {color};"
|
||||
readonly />
|
||||
{#if active}
|
||||
<div class="smx-color-panel" on:click|stopPropagation>
|
||||
<Chrome startColor={color} on:input={handleInput} fieldsIndex={fieldsIndex}/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<Chrome startColor={color} on:input={handleInput} fieldsIndex={fieldsIndex}/>
|
||||
{/if}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<style>
|
||||
.color-square{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAJUlEQVQoU2N88eLFfwY0ICEhwYguxjgUFKI7GsTH5m4M3w1ChQCnziae7MntdQAAAABJRU5ErkJggg==);
|
||||
background-repeat: repeat;
|
||||
background-size: 50% auto;
|
||||
}
|
||||
|
||||
.color-square-in{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export let color;
|
||||
</script>
|
||||
|
||||
<div class="color-square">
|
||||
<div class="color-square-in" style="background: {color}"></div>
|
||||
</div>
|
|
@ -0,0 +1,40 @@
|
|||
<style>
|
||||
.horizontal{
|
||||
background: linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
|
||||
}
|
||||
|
||||
.vertical{
|
||||
background: linear-gradient(to bottom, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import {createEventDispatcher} from "svelte";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
import Slider from "./Slider.svelte";
|
||||
|
||||
let className = "";
|
||||
export {className as class};
|
||||
|
||||
export let h = 0;
|
||||
export let vertical = false;
|
||||
|
||||
export const set = (newValue) => {
|
||||
h = newValue;
|
||||
sliderValue = newValue / 360;
|
||||
}
|
||||
|
||||
let slider;
|
||||
|
||||
$: sliderValue = h / 360;
|
||||
|
||||
const handle = (event) => {
|
||||
h = Math.floor(sliderValue * 360);
|
||||
dispatch("input", h);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="hue {className}" class:vertical class:horizontal={!vertical}>
|
||||
<Slider bind:value={sliderValue} {vertical} on:input={handle}/>
|
||||
</div>
|
|
@ -0,0 +1,111 @@
|
|||
<style>
|
||||
.saturation-value{
|
||||
height: calc(100% / 1.618); /* NUMERO AUREO */
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.saturation, .value{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.saturation{
|
||||
background: linear-gradient(to right, #fff, rgba(255,255,255,0));
|
||||
}
|
||||
|
||||
.value{
|
||||
background: linear-gradient(to top, #000, rgba(0,0,0,0));
|
||||
}
|
||||
|
||||
.pointer{
|
||||
box-sizing: border-box;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
transform: translate(-50%, -50%);
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
border-radius: 10px;
|
||||
box-shadow: rgba(255,255,255,1) 0 0 2px 2px inset, rgba(0,0,0,0.2) 0 0 2px 2px;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import {createEventDispatcher} from "svelte";
|
||||
const dispatch = createEventDispatcher();
|
||||
// input, inputstart, inputend {s, v}
|
||||
|
||||
import {limitatePercent} from "./utils.js";
|
||||
|
||||
let className = "";
|
||||
export {className as class};
|
||||
|
||||
export let h = 180;
|
||||
export let s = 0;
|
||||
export let v = 0;
|
||||
|
||||
$: pureColor = `hsl(${h}, 100%, 50%)`
|
||||
|
||||
// DOM
|
||||
let square;
|
||||
let pointer;
|
||||
|
||||
$: pointerX = s;
|
||||
$: pointerY = -(v - 1); // v = 1 - x // x = -(v - 1)
|
||||
|
||||
let pointerOffsetX = 0;
|
||||
let pointerOffsetY = 0;
|
||||
|
||||
const handleMousemove = (event) => {
|
||||
const {x, y, width, height} = square.getBoundingClientRect();
|
||||
s = limitatePercent((event.x - x + pointerOffsetX) / width);
|
||||
v = 1 - limitatePercent((event.y - y + pointerOffsetY) / height);
|
||||
dispatch("input", {s, v});
|
||||
}
|
||||
|
||||
const startMove = () => {
|
||||
//dispatch("inputstart", {s, v})
|
||||
handleMousemove(event);
|
||||
self.addEventListener("mousemove", handleMousemove);
|
||||
self.addEventListener("mouseup", handleMouseup);
|
||||
}
|
||||
|
||||
const handleMouseup = () => {
|
||||
self.removeEventListener("mousemove", handleMousemove);
|
||||
self.removeEventListener("mouseup", handleMouseup);
|
||||
//dispatch("inputend", {s, v});
|
||||
}
|
||||
|
||||
const handlePointerMousedown = (event) => {
|
||||
const {x, y, width, height} = pointer.getBoundingClientRect();
|
||||
pointerOffsetX = (width / 2) - (event.x - x);
|
||||
pointerOffsetY = (height / 2) - (event.y - y);
|
||||
startMove(event);
|
||||
}
|
||||
|
||||
const handleSquareMousedown = (event) => {
|
||||
pointerOffsetX = pointerOffsetY = 0;
|
||||
startMove(event);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="saturation-value {className}"
|
||||
bind:this={square}
|
||||
style="background-color: {pureColor}"
|
||||
on:mousedown|preventDefault={handleSquareMousedown}
|
||||
>
|
||||
<div class="saturation"></div>
|
||||
<div class="value"></div>
|
||||
<div
|
||||
class="pointer"
|
||||
bind:this={pointer}
|
||||
on:mousedown|preventDefault|stopPropagation={handlePointerMousedown}
|
||||
style="left: {pointerX * 100}%; top: {pointerY * 100}%"
|
||||
></div>
|
||||
</div>
|
|
@ -0,0 +1,115 @@
|
|||
<style>
|
||||
.slider{
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.horizontal{
|
||||
width: 100%;
|
||||
height: var(--slider-height, 0.6em);
|
||||
--slider-size: var(--slider-height, 0.6em);
|
||||
}
|
||||
|
||||
.vertical{
|
||||
height: 100%;
|
||||
width: var(--slider-width, 0.6em);
|
||||
--slider-size: var(--slider-width, 0.6em);
|
||||
}
|
||||
|
||||
.pointer{
|
||||
width: calc(var(--slider-size) * 1.333);
|
||||
height: calc(var(--slider-size) * 1.333);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
border-radius: 100000px; /* circle */
|
||||
background:#f8f8f8;
|
||||
box-shadow: 0 1px 4px 0 rgba(0,0,0,0.37);
|
||||
}
|
||||
|
||||
.horizontal > .pointer{
|
||||
left: var(--value);
|
||||
transform: translateX(-50%);
|
||||
margin-top: calc(var(--slider-size) * -0.25);
|
||||
}
|
||||
|
||||
.vertical > .pointer{
|
||||
top: var(--value);
|
||||
transform: translateY(-50%);
|
||||
margin-left: calc(var(--slider-size) * -0.25);
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import {createEventDispatcher} from "svelte";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
import {limitatePercent} from "./utils.js";
|
||||
|
||||
let className = "";
|
||||
export {className as class};
|
||||
|
||||
export let value = 0;
|
||||
export let vertical = false;
|
||||
|
||||
export const set = (newValue) => value = newValue;
|
||||
|
||||
let pointerOffsetX = 0;
|
||||
let pointerOffsetY = 0;
|
||||
|
||||
let prevValue = value;
|
||||
|
||||
let slider;
|
||||
let pointer;
|
||||
|
||||
const handleMousemove = (event) => {
|
||||
const {x, y, width, height} = slider.getBoundingClientRect();
|
||||
if(vertical){
|
||||
value = limitatePercent((event.y - y + pointerOffsetY) / height);
|
||||
} else {
|
||||
value = limitatePercent((event.x - x + pointerOffsetX) / width);
|
||||
}
|
||||
|
||||
if(value !== prevValue){
|
||||
prevValue = value;
|
||||
dispatch("input", value);
|
||||
}
|
||||
}
|
||||
|
||||
const startMove = (event) => {
|
||||
handleMousemove(event);
|
||||
self.addEventListener("mousemove", handleMousemove);
|
||||
self.addEventListener("mouseup", handleMouseup);
|
||||
}
|
||||
|
||||
const handleMouseup = () => {
|
||||
self.removeEventListener("mousemove", handleMousemove);
|
||||
self.removeEventListener("mousedown", handleMouseup)
|
||||
}
|
||||
|
||||
const handleSliderMousemove = (event) => {
|
||||
pointerOffsetX = pointerOffsetY = 0;
|
||||
startMove(event);
|
||||
}
|
||||
|
||||
const handlePointerMousedown = (event) => {
|
||||
const {x, y, width, height} = pointer.getBoundingClientRect();
|
||||
pointerOffsetX = (width / 2) - (event.x - x);
|
||||
pointerOffsetY = (height / 2) - (event.y - y);
|
||||
startMove(event);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
bind:this={slider}
|
||||
class="slider {className}"
|
||||
class:vertical
|
||||
class:horizontal={!vertical}
|
||||
on:mousedown|preventDefault={handleSliderMousemove}
|
||||
>
|
||||
<div
|
||||
bind:this={pointer}
|
||||
class="pointer"
|
||||
on:mousedown|preventDefault|stopPropagation={handlePointerMousedown}
|
||||
style="--value: {value * 100}%"
|
||||
></div>
|
||||
</div>
|
|
@ -0,0 +1,31 @@
|
|||
import tinycolor from "tinycolor2";
|
||||
|
||||
export const limitatePercent = (num) => Math.max(0, Math.min(1, num));
|
||||
|
||||
export const getValidColor = (input) => {
|
||||
|
||||
if(typeof input !== "string"){
|
||||
|
||||
for(const key in input){
|
||||
if(isNaN(input[key])){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const {h, s, l, v, r, g, b, a} = input;
|
||||
|
||||
if(
|
||||
(h !== null && (h < 0 || h > 360)) ||
|
||||
(a !== null && (a < 0 || a > 1)) ||
|
||||
(s !== null && (s < 0 || s > 1)) ||
|
||||
(v !== null && (v < 0 || v > 1)) ||
|
||||
(l !== null && (l < 0 || l > 1)) ||
|
||||
(r !== null && (r < 0 || r > 255)) ||
|
||||
(g !== null && (g < 0 || g > 255)) ||
|
||||
(b !== null && (b < 0 || b > 255))
|
||||
) return false;
|
||||
}
|
||||
|
||||
const color = tinycolor(input);
|
||||
return color.isValid() && color;
|
||||
}
|
|
@ -32,6 +32,8 @@ import {
|
|||
NavItem,
|
||||
NavLayout
|
||||
} from './components/Nav'
|
||||
import ColorPicker from './components/ColorPicker/ColorPicker.svelte';
|
||||
|
||||
export {
|
||||
Button,
|
||||
Collapse,
|
||||
|
@ -59,7 +61,8 @@ export {
|
|||
Carousel,
|
||||
Nav,
|
||||
NavItem,
|
||||
NavLayout
|
||||
NavLayout,
|
||||
ColorPicker
|
||||
}
|
||||
|
||||
export const Svelma = {
|
||||
|
@ -89,5 +92,6 @@ export const Svelma = {
|
|||
Carousel,
|
||||
Nav,
|
||||
NavItem,
|
||||
NavLayout
|
||||
NavLayout,
|
||||
ColorPicker
|
||||
}
|
Loading…
Reference in New Issue