@studiotoolkit/color-from-image 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/color-from-image.css +2 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +194 -214
- package/package.json +17 -14
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
.cfi-container{background-color:#fff;flex-direction:column;align-items:flex-start;gap:8px;display:flex}[data-theme=dark] .cfi-container{background-color:#1a1a1a!important}.cfi-canvas-wrapper{box-sizing:border-box;border-style:solid;line-height:0;display:inline-block;position:relative}[data-theme=dark] .cfi-canvas-wrapper{border-color:#444}.cfi-canvas{display:block}.cfi-canvas-overlay{pointer-events:none;background:#f8f8f8d9;flex-direction:column;justify-content:center;align-items:center;gap:4px;line-height:normal;display:flex;position:absolute;inset:0}[data-theme=dark] .cfi-canvas-overlay{background:#1a1a1ad9}.cfi-canvas-overlay span{color:#888;font-family:inherit;font-size:14px}[data-theme=dark] .cfi-canvas-overlay span{color:#aaa}.cfi-canvas-overlay span:first-child{color:#555;font-size:16px;font-weight:600}[data-theme=dark] .cfi-canvas-overlay span:first-child{color:#ccc}.cfi-actions-row{align-items:center;gap:8px;display:flex}.cfi-file-input{flex:1;font-family:inherit;font-size:13px}.cfi-clear-button{color:#fff;cursor:pointer;white-space:nowrap;background:#e74c3c;border:none;border-radius:4px;padding:5px 12px;font-family:inherit;font-size:13px}.cfi-clear-button:hover{background:#c0392b}.cfi-paste-button{color:#fff;cursor:pointer;white-space:nowrap;background:#2196f3;border:none;border-radius:4px;padding:5px 12px;font-family:inherit;font-size:13px}.cfi-paste-button:hover{background:#1976d2}.cfi-url-row{align-items:center;gap:6px;display:flex}.cfi-url-input{border:1px solid #ccc;border-radius:4px;padding:5px 8px;font-family:inherit;font-size:13px}.cfi-load-button{color:#fff;cursor:pointer;background:#3498db;border:none;border-radius:4px;padding:5px 12px;font-family:inherit;font-size:13px}.cfi-load-button:hover{background:#217dbb}.cfi-url-error{color:#c0392b;margin:0;font-size:12px}
|
|
2
|
+
/*$vite$:1*/
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,s)=>(s=n==null?{}:e(i(n)),o(r||!n||!n.__esModule||!a.call(n,`default`)?t(s,`default`,{value:n,enumerable:!0}):s,n));let c=require("react");c=s(c);let l=require("react/jsx-runtime");var u=e=>e<=.04045?e/12.92:((e+.055)/1.055)**2.4,d=e=>e<=.0031308?12.92*e:1.055*e**(1/2.4)-.055,f=e=>Math.max(0,Math.min(1,e)),p=({r:e,g:t,b:n})=>{let r=u(e),i=u(t),a=u(n),o=Math.cbrt(.4122214708*r+.5363325363*i+.0514459929*a),s=Math.cbrt(.2119034982*r+.6806995451*i+.1073969566*a),c=Math.cbrt(.0883024619*r+.2817188376*i+.6299787005*a);return{L:.2104542553*o+.793617785*s-.0040720468*c,a:1.9779984951*o-2.428592205*s+.4505937099*c,b:.0259040371*o+.7827717662*s-.808675766*c}},m=({L:e,a:t,b:n})=>{let r=e+.3963377774*t+.2158037573*n,i=e-.1055613458*t-.0638541728*n,a=e-.0894841775*t-1.291485548*n,o=r*r*r,s=i*i*i,c=a*a*a;return{r:f(d(4.0767416621*o-3.3077115913*s+.2309699292*c)),g:f(d(-1.2684380046*o+2.6097574011*s-.3413193965*c)),b:f(d(-.0041960863*o-.7034186147*s+1.707614701*c))}},h=(e,t)=>(e.L-t.L)**2+(e.a-t.a)**2+(e.b-t.b)**2,g=e=>Math.sqrt(e.a*e.a+e.b*e.b),_=({r:e,g:t,b:n})=>{let r=e=>Math.round(e*255).toString(16).padStart(2,`0`);return`#${r(e)}${r(t)}${r(n)}`},v=(e,t,n=20)=>{let r=[],i=Math.max(1,Math.floor(e.length/4/4e3));for(let t=0;t<e.length;t+=4*i){if(e[t+3]<128)continue;let n=p({r:e[t]/255,g:e[t+1]/255,b:e[t+2]/255}),i=g(n);Math.random()>(i<.05?.2:i<.15?.6:1)||r.push(n)}if(r.length===0)return[];let a=r.length,o=[];o.push(r[Math.floor(Math.random()*a)]);for(let e=1;e<t;e++){let e=r.map(e=>Math.min(...o.map(t=>h(e,t)))),t=e.reduce((e,t)=>e+t,0),n=Math.random()*t,i=0;for(let t=0;t<a;t++)if(n-=e[t],n<=0){i=t;break}o.push({...r[i]})}let s=new Int32Array(a);for(let e=0;e<n;e++){let e=!1;for(let n=0;n<a;n++){let i=0,a=1/0;for(let e=0;e<t;e++){let t=h(r[n],o[e]);t<a&&(a=t,i=e)}s[n]!==i&&(s[n]=i,e=!0)}if(!e)break;let n=Array.from({length:t},()=>({L:0,a:0,b:0,count:0}));for(let e=0;e<a;e++){let t=s[e];n[t].L+=r[e].L,n[t].a+=r[e].a,n[t].b+=r[e].b,n[t].count++}for(let e=0;e<t;e++)n[e].count>0&&(o[e]={L:n[e].L/n[e].count,a:n[e].a/n[e].count,b:n[e].b/n[e].count})}let c=Array(t).fill(0);for(let e=0;e<a;e++)c[s[e]]++;return o.map((e,t)=>({hex:_(m(e)),count:c[t],total:a,score:c[t]*(1+3*g(e))})).filter(e=>e.count>0).sort((e,t)=>t.score-e.score)},y=(e,t=16)=>{let n=e.naturalWidth,r=e.naturalHeight;if(!n||!r)return{palette:[]};let i=document.createElement(`canvas`);i.width=n,i.height=r;let a=i.getContext(`2d`);if(!a)return{palette:[]};a.drawImage(e,0,0);let o;try{o=a.getImageData(0,0,n,r).data}catch{return{palette:[]}}return{palette:v(o,t).map(({hex:e})=>e)}},b=({width:e=200,height:t=200,borderColor:n=`#cccccc`,borderThickness:r=1,onColorsExtracted:i,imageUrl:a,imageFile:o,clearTrigger:s})=>{let u=(0,c.useRef)(null),d=(0,c.useRef)(()=>{}),f=(0,c.useRef)(i),[p,m]=(0,c.useState)(null),[h,g]=(0,c.useState)(``),_=n=>{let r=u.current;if(!r)return;let i=r.getContext(`2d`);if(!i)return;i.clearRect(0,0,e,t);let a=Math.min(e/n.width,t/n.height),o=n.width*a,s=n.height*a;i.drawImage(n,(e-o)/2,(t-s)/2,o,s)};(0,c.useLayoutEffect)(()=>{d.current=_}),(0,c.useLayoutEffect)(()=>{f.current=i}),(0,c.useEffect)(()=>{p&&d.current(p)},[e,t,p]);let v=e=>{let t=new FileReader;t.onload=()=>{let e=new Image;e.onload=()=>{m(e),g(``),d.current(e);let t=y(e);t.palette.length>0&&f.current?.(t)},e.src=t.result},t.readAsDataURL(e)};return(0,c.useEffect)(()=>{if(!a)return;g(``);let e=new Image;e.crossOrigin=`anonymous`,e.src=a,e.onload=()=>{m(e),d.current(e);let t=y(e);t.palette.length>0?f.current?.(t):g(`Image loaded but color extraction failed.`)},e.onerror=()=>{let e=new Image;e.src=a,e.onload=()=>{m(e),d.current(e),g(`Displayed but CORS blocked color extraction. Upload the file directly.`)},e.onerror=()=>g(`Failed to load image. Check the URL and try again.`)}},[a]),(0,c.useEffect)(()=>{o&&(g(``),v(o))},[o]),(0,c.useEffect)(()=>{s&&((u.current?.getContext(`2d`))?.clearRect(0,0,e,t),m(null),g(``),f.current?.({palette:[]}))},[s,e,t]),(0,c.useEffect)(()=>{let e=e=>{let t=e.clipboardData?.items;if(t){for(let e=0;e<t.length;e++)if(t[e].type.startsWith(`image`)){let n=t[e].getAsFile();if(n){v(n);return}}}};return window.addEventListener(`paste`,e),()=>window.removeEventListener(`paste`,e)},[]),(0,l.jsxs)(`div`,{className:`cfi-container`,children:[(0,l.jsxs)(`div`,{className:`cfi-canvas-wrapper`,style:{borderColor:n,borderWidth:`${r}px`},onDragOver:e=>e.preventDefault(),onDrop:e=>{e.preventDefault();let t=e.dataTransfer.files?.[0];t?.type.startsWith(`image/`)&&v(t)},children:[(0,l.jsx)(`canvas`,{ref:u,width:e,height:t,className:`cfi-canvas`,style:{width:`${e}px`,height:`${t}px`}}),!p&&(0,l.jsxs)(`div`,{className:`cfi-canvas-overlay`,children:[(0,l.jsx)(`span`,{children:`Drag & Drop`}),(0,l.jsx)(`span`,{children:`or Ctrl+V / Paste`})]})]}),h&&(0,l.jsx)(`p`,{className:`cfi-url-error`,children:h})]})};exports.ColorFromImage=b;
|
package/dist/index.mjs
CHANGED
|
@@ -1,215 +1,195 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}) => {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
"canvas",
|
|
195
|
-
{
|
|
196
|
-
ref: b,
|
|
197
|
-
width: t,
|
|
198
|
-
height: r,
|
|
199
|
-
className: "cfi-canvas",
|
|
200
|
-
style: { width: `${t}px`, height: `${r}px` }
|
|
201
|
-
}
|
|
202
|
-
),
|
|
203
|
-
!f && /* @__PURE__ */ I("div", { className: "cfi-canvas-overlay", children: [
|
|
204
|
-
/* @__PURE__ */ L("span", { children: "Drag & Drop" }),
|
|
205
|
-
/* @__PURE__ */ L("span", { children: "or Ctrl+V / Paste" })
|
|
206
|
-
] })
|
|
207
|
-
]
|
|
208
|
-
}
|
|
209
|
-
),
|
|
210
|
-
g && /* @__PURE__ */ L("p", { className: "cfi-url-error", children: g })
|
|
211
|
-
] });
|
|
212
|
-
};
|
|
213
|
-
export {
|
|
214
|
-
B as ColorFromImage
|
|
1
|
+
import { useEffect as e, useLayoutEffect as t, useRef as n, useState as r } from "react";
|
|
2
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
3
|
+
// src/ColorFromImage.tsx
|
|
4
|
+
var o = (e) => e <= .04045 ? e / 12.92 : ((e + .055) / 1.055) ** 2.4, s = (e) => e <= .0031308 ? 12.92 * e : 1.055 * e ** (1 / 2.4) - .055, c = (e) => Math.max(0, Math.min(1, e)), l = ({ r: e, g: t, b: n }) => {
|
|
5
|
+
let r = o(e), i = o(t), a = o(n), s = Math.cbrt(.4122214708 * r + .5363325363 * i + .0514459929 * a), c = Math.cbrt(.2119034982 * r + .6806995451 * i + .1073969566 * a), l = Math.cbrt(.0883024619 * r + .2817188376 * i + .6299787005 * a);
|
|
6
|
+
return {
|
|
7
|
+
L: .2104542553 * s + .793617785 * c - .0040720468 * l,
|
|
8
|
+
a: 1.9779984951 * s - 2.428592205 * c + .4505937099 * l,
|
|
9
|
+
b: .0259040371 * s + .7827717662 * c - .808675766 * l
|
|
10
|
+
};
|
|
11
|
+
}, u = ({ L: e, a: t, b: n }) => {
|
|
12
|
+
let r = e + .3963377774 * t + .2158037573 * n, i = e - .1055613458 * t - .0638541728 * n, a = e - .0894841775 * t - 1.291485548 * n, o = r * r * r, l = i * i * i, u = a * a * a;
|
|
13
|
+
return {
|
|
14
|
+
r: c(s(4.0767416621 * o - 3.3077115913 * l + .2309699292 * u)),
|
|
15
|
+
g: c(s(-1.2684380046 * o + 2.6097574011 * l - .3413193965 * u)),
|
|
16
|
+
b: c(s(-.0041960863 * o - .7034186147 * l + 1.707614701 * u))
|
|
17
|
+
};
|
|
18
|
+
}, d = (e, t) => (e.L - t.L) ** 2 + (e.a - t.a) ** 2 + (e.b - t.b) ** 2, f = (e) => Math.sqrt(e.a * e.a + e.b * e.b), p = ({ r: e, g: t, b: n }) => {
|
|
19
|
+
let r = (e) => Math.round(e * 255).toString(16).padStart(2, "0");
|
|
20
|
+
return `#${r(e)}${r(t)}${r(n)}`;
|
|
21
|
+
}, m = (e, t, n = 20) => {
|
|
22
|
+
let r = [], i = Math.max(1, Math.floor(e.length / 4 / 4e3));
|
|
23
|
+
for (let t = 0; t < e.length; t += 4 * i) {
|
|
24
|
+
if (e[t + 3] < 128) continue;
|
|
25
|
+
let n = l({
|
|
26
|
+
r: e[t] / 255,
|
|
27
|
+
g: e[t + 1] / 255,
|
|
28
|
+
b: e[t + 2] / 255
|
|
29
|
+
}), i = f(n);
|
|
30
|
+
Math.random() > (i < .05 ? .2 : i < .15 ? .6 : 1) || r.push(n);
|
|
31
|
+
}
|
|
32
|
+
if (r.length === 0) return [];
|
|
33
|
+
let a = r.length, o = [];
|
|
34
|
+
o.push(r[Math.floor(Math.random() * a)]);
|
|
35
|
+
for (let e = 1; e < t; e++) {
|
|
36
|
+
let e = r.map((e) => Math.min(...o.map((t) => d(e, t)))), t = e.reduce((e, t) => e + t, 0), n = Math.random() * t, i = 0;
|
|
37
|
+
for (let t = 0; t < a; t++) if (n -= e[t], n <= 0) {
|
|
38
|
+
i = t;
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
o.push({ ...r[i] });
|
|
42
|
+
}
|
|
43
|
+
let s = new Int32Array(a);
|
|
44
|
+
for (let e = 0; e < n; e++) {
|
|
45
|
+
let e = !1;
|
|
46
|
+
for (let n = 0; n < a; n++) {
|
|
47
|
+
let i = 0, a = Infinity;
|
|
48
|
+
for (let e = 0; e < t; e++) {
|
|
49
|
+
let t = d(r[n], o[e]);
|
|
50
|
+
t < a && (a = t, i = e);
|
|
51
|
+
}
|
|
52
|
+
s[n] !== i && (s[n] = i, e = !0);
|
|
53
|
+
}
|
|
54
|
+
if (!e) break;
|
|
55
|
+
let n = Array.from({ length: t }, () => ({
|
|
56
|
+
L: 0,
|
|
57
|
+
a: 0,
|
|
58
|
+
b: 0,
|
|
59
|
+
count: 0
|
|
60
|
+
}));
|
|
61
|
+
for (let e = 0; e < a; e++) {
|
|
62
|
+
let t = s[e];
|
|
63
|
+
n[t].L += r[e].L, n[t].a += r[e].a, n[t].b += r[e].b, n[t].count++;
|
|
64
|
+
}
|
|
65
|
+
for (let e = 0; e < t; e++) n[e].count > 0 && (o[e] = {
|
|
66
|
+
L: n[e].L / n[e].count,
|
|
67
|
+
a: n[e].a / n[e].count,
|
|
68
|
+
b: n[e].b / n[e].count
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
let c = Array(t).fill(0);
|
|
72
|
+
for (let e = 0; e < a; e++) c[s[e]]++;
|
|
73
|
+
return o.map((e, t) => ({
|
|
74
|
+
hex: p(u(e)),
|
|
75
|
+
count: c[t],
|
|
76
|
+
total: a,
|
|
77
|
+
score: c[t] * (1 + 3 * f(e))
|
|
78
|
+
})).filter((e) => e.count > 0).sort((e, t) => t.score - e.score);
|
|
79
|
+
}, h = (e, t = 16) => {
|
|
80
|
+
let n = e.naturalWidth, r = e.naturalHeight;
|
|
81
|
+
if (!n || !r) return { palette: [] };
|
|
82
|
+
let i = document.createElement("canvas");
|
|
83
|
+
i.width = n, i.height = r;
|
|
84
|
+
let a = i.getContext("2d");
|
|
85
|
+
if (!a) return { palette: [] };
|
|
86
|
+
a.drawImage(e, 0, 0);
|
|
87
|
+
let o;
|
|
88
|
+
try {
|
|
89
|
+
o = a.getImageData(0, 0, n, r).data;
|
|
90
|
+
} catch {
|
|
91
|
+
return { palette: [] };
|
|
92
|
+
}
|
|
93
|
+
return { palette: m(o, t).map(({ hex: e }) => e) };
|
|
94
|
+
}, g = ({ width: o = 200, height: s = 200, borderColor: c = "#cccccc", borderThickness: l = 1, onColorsExtracted: u, imageUrl: d, imageFile: f, clearTrigger: p }) => {
|
|
95
|
+
let m = n(null), g = n(() => {}), _ = n(u), [v, y] = r(null), [b, x] = r(""), S = (e) => {
|
|
96
|
+
let t = m.current;
|
|
97
|
+
if (!t) return;
|
|
98
|
+
let n = t.getContext("2d");
|
|
99
|
+
if (!n) return;
|
|
100
|
+
n.clearRect(0, 0, o, s);
|
|
101
|
+
let r = Math.min(o / e.width, s / e.height), i = e.width * r, a = e.height * r;
|
|
102
|
+
n.drawImage(e, (o - i) / 2, (s - a) / 2, i, a);
|
|
103
|
+
};
|
|
104
|
+
t(() => {
|
|
105
|
+
g.current = S;
|
|
106
|
+
}), t(() => {
|
|
107
|
+
_.current = u;
|
|
108
|
+
}), e(() => {
|
|
109
|
+
v && g.current(v);
|
|
110
|
+
}, [
|
|
111
|
+
o,
|
|
112
|
+
s,
|
|
113
|
+
v
|
|
114
|
+
]);
|
|
115
|
+
let C = (e) => {
|
|
116
|
+
let t = new FileReader();
|
|
117
|
+
t.onload = () => {
|
|
118
|
+
let e = new Image();
|
|
119
|
+
e.onload = () => {
|
|
120
|
+
y(e), x(""), g.current(e);
|
|
121
|
+
let t = h(e);
|
|
122
|
+
t.palette.length > 0 && _.current?.(t);
|
|
123
|
+
}, e.src = t.result;
|
|
124
|
+
}, t.readAsDataURL(e);
|
|
125
|
+
};
|
|
126
|
+
return e(() => {
|
|
127
|
+
if (!d) return;
|
|
128
|
+
x("");
|
|
129
|
+
let e = new Image();
|
|
130
|
+
e.crossOrigin = "anonymous", e.src = d, e.onload = () => {
|
|
131
|
+
y(e), g.current(e);
|
|
132
|
+
let t = h(e);
|
|
133
|
+
t.palette.length > 0 ? _.current?.(t) : x("Image loaded but color extraction failed.");
|
|
134
|
+
}, e.onerror = () => {
|
|
135
|
+
let e = new Image();
|
|
136
|
+
e.src = d, e.onload = () => {
|
|
137
|
+
y(e), g.current(e), x("Displayed but CORS blocked color extraction. Upload the file directly.");
|
|
138
|
+
}, e.onerror = () => x("Failed to load image. Check the URL and try again.");
|
|
139
|
+
};
|
|
140
|
+
}, [d]), e(() => {
|
|
141
|
+
f && (x(""), C(f));
|
|
142
|
+
}, [f]), e(() => {
|
|
143
|
+
p && ((m.current?.getContext("2d"))?.clearRect(0, 0, o, s), y(null), x(""), _.current?.({ palette: [] }));
|
|
144
|
+
}, [
|
|
145
|
+
p,
|
|
146
|
+
o,
|
|
147
|
+
s
|
|
148
|
+
]), e(() => {
|
|
149
|
+
let e = (e) => {
|
|
150
|
+
let t = e.clipboardData?.items;
|
|
151
|
+
if (t) {
|
|
152
|
+
for (let e = 0; e < t.length; e++) if (t[e].type.startsWith("image")) {
|
|
153
|
+
let n = t[e].getAsFile();
|
|
154
|
+
if (n) {
|
|
155
|
+
C(n);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
return window.addEventListener("paste", e), () => window.removeEventListener("paste", e);
|
|
162
|
+
}, []), /* @__PURE__ */ a("div", {
|
|
163
|
+
className: "cfi-container",
|
|
164
|
+
children: [/* @__PURE__ */ a("div", {
|
|
165
|
+
className: "cfi-canvas-wrapper",
|
|
166
|
+
style: {
|
|
167
|
+
borderColor: c,
|
|
168
|
+
borderWidth: `${l}px`
|
|
169
|
+
},
|
|
170
|
+
onDragOver: (e) => e.preventDefault(),
|
|
171
|
+
onDrop: (e) => {
|
|
172
|
+
e.preventDefault();
|
|
173
|
+
let t = e.dataTransfer.files?.[0];
|
|
174
|
+
t?.type.startsWith("image/") && C(t);
|
|
175
|
+
},
|
|
176
|
+
children: [/* @__PURE__ */ i("canvas", {
|
|
177
|
+
ref: m,
|
|
178
|
+
width: o,
|
|
179
|
+
height: s,
|
|
180
|
+
className: "cfi-canvas",
|
|
181
|
+
style: {
|
|
182
|
+
width: `${o}px`,
|
|
183
|
+
height: `${s}px`
|
|
184
|
+
}
|
|
185
|
+
}), !v && /* @__PURE__ */ a("div", {
|
|
186
|
+
className: "cfi-canvas-overlay",
|
|
187
|
+
children: [/* @__PURE__ */ i("span", { children: "Drag & Drop" }), /* @__PURE__ */ i("span", { children: "or Ctrl+V / Paste" })]
|
|
188
|
+
})]
|
|
189
|
+
}), b && /* @__PURE__ */ i("p", {
|
|
190
|
+
className: "cfi-url-error",
|
|
191
|
+
children: b
|
|
192
|
+
})]
|
|
193
|
+
});
|
|
215
194
|
};
|
|
195
|
+
export { g as ColorFromImage };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@studiotoolkit/color-from-image",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "React component for extracting dominant colors from images using advanced color analysis algorithms",
|
|
6
6
|
"author": "StudioToolkit",
|
|
@@ -53,17 +53,6 @@
|
|
|
53
53
|
"engines": {
|
|
54
54
|
"node": ">=16.0.0"
|
|
55
55
|
},
|
|
56
|
-
"peerDependencies": {
|
|
57
|
-
"react": "^18.0.0 || ^19.0.0",
|
|
58
|
-
"react-dom": "^18.0.0 || ^19.0.0"
|
|
59
|
-
},
|
|
60
|
-
"devDependencies": {
|
|
61
|
-
"@types/react": "^18.2.0 || ^19.0.0",
|
|
62
|
-
"@types/react-dom": "^18.2.0 || ^19.0.0",
|
|
63
|
-
"@vitejs/plugin-react": "^4.2.0",
|
|
64
|
-
"typescript": "^5.3.3",
|
|
65
|
-
"vite": "^5.0.0"
|
|
66
|
-
},
|
|
67
56
|
"scripts": {
|
|
68
57
|
"build": "npx tsc --project tsconfig.json && vite build && cp src/ColorFromImage.css dist/style.css",
|
|
69
58
|
"dev": "vite build --watch",
|
|
@@ -72,6 +61,20 @@
|
|
|
72
61
|
"lint:fix": "eslint src --ext .ts,.tsx --fix",
|
|
73
62
|
"test": "vitest run",
|
|
74
63
|
"test:watch": "vitest",
|
|
75
|
-
"test:ui": "vitest --ui"
|
|
64
|
+
"test:ui": "vitest --ui",
|
|
65
|
+
"prepublishOnly": "pnpm run build && pnpm test"
|
|
66
|
+
},
|
|
67
|
+
"peerDependencies": {
|
|
68
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
69
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {
|
|
72
|
+
"@types/react": "^19.3.0",
|
|
73
|
+
"@types/react-dom": "^19.3.0",
|
|
74
|
+
"@vitejs/plugin-react": "^6.2.1",
|
|
75
|
+
"react": "^19.3.1",
|
|
76
|
+
"react-dom": "^19.3.1",
|
|
77
|
+
"typescript": "^6.0.3",
|
|
78
|
+
"vite": "^8.3.6"
|
|
76
79
|
}
|
|
77
|
-
}
|
|
80
|
+
}
|