@rogieking/figui3 3.20.2 → 3.21.0
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/components.css +45 -14
- package/fig.js +315 -46
- package/package.json +1 -1
package/components.css
CHANGED
|
@@ -3146,6 +3146,7 @@ fig-input-fill {
|
|
|
3146
3146
|
}
|
|
3147
3147
|
fig-input-gradient {
|
|
3148
3148
|
--height: 1.5rem;
|
|
3149
|
+
--chit-height: var(--height);
|
|
3149
3150
|
position: relative;
|
|
3150
3151
|
height: var(--height);
|
|
3151
3152
|
width: 100%;
|
|
@@ -3157,12 +3158,34 @@ fig-input-gradient {
|
|
|
3157
3158
|
outline: 1px solid var(--figma-color-border-selected) !important;
|
|
3158
3159
|
outline-offset: -1px !important;
|
|
3159
3160
|
}
|
|
3160
|
-
|
|
3161
|
+
|
|
3162
|
+
&[edit="false"] {
|
|
3163
|
+
pointer-events: none;
|
|
3164
|
+
|
|
3165
|
+
&:focus,
|
|
3166
|
+
&:active,
|
|
3167
|
+
&:focus-within {
|
|
3168
|
+
outline: none !important;
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
3171
|
+
|
|
3172
|
+
&[edit="picker"] {
|
|
3173
|
+
& > fig-fill-picker {
|
|
3174
|
+
display: contents;
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
& > fig-chit,
|
|
3178
|
+
& > fig-fill-picker > fig-chit {
|
|
3161
3179
|
--padding: 0;
|
|
3162
3180
|
--width: 100%;
|
|
3181
|
+
--height: var(--chit-height);
|
|
3163
3182
|
flex: 1 1 auto;
|
|
3164
3183
|
width: 100% !important;
|
|
3165
3184
|
min-width: 0 !important;
|
|
3185
|
+
min-height: var(--chit-height) !important;
|
|
3186
|
+
}
|
|
3187
|
+
&[size="large"] {
|
|
3188
|
+
--height: 3rem;
|
|
3166
3189
|
}
|
|
3167
3190
|
|
|
3168
3191
|
.fig-input-gradient-track {
|
|
@@ -3194,7 +3217,7 @@ fig-input-palette {
|
|
|
3194
3217
|
display: flex;
|
|
3195
3218
|
flex-wrap: nowrap;
|
|
3196
3219
|
gap: 0;
|
|
3197
|
-
border-radius: var(--radius-
|
|
3220
|
+
border-radius: var(--radius-small);
|
|
3198
3221
|
overflow: hidden;
|
|
3199
3222
|
grid-area: inputs;
|
|
3200
3223
|
min-width: 0;
|
|
@@ -3211,9 +3234,15 @@ fig-input-palette {
|
|
|
3211
3234
|
border-radius: var(--radius-medium);
|
|
3212
3235
|
background-color: var(--figma-color-bg-secondary);
|
|
3213
3236
|
width: 100%;
|
|
3237
|
+
gap: var(--spacer-1);
|
|
3238
|
+
place-items: center;
|
|
3214
3239
|
|
|
3215
3240
|
.palette-colors {
|
|
3216
3241
|
display: flex;
|
|
3242
|
+
--palette-colors-height: calc(1.5rem - var(--spacer-1));
|
|
3243
|
+
height: var(--palette-colors-height);
|
|
3244
|
+
margin-left: var(--spacer-1);
|
|
3245
|
+
|
|
3217
3246
|
background-color: var(--figma-color-bg-secondary);
|
|
3218
3247
|
fig-input-color {
|
|
3219
3248
|
width: 100%;
|
|
@@ -3223,10 +3252,11 @@ fig-input-palette {
|
|
|
3223
3252
|
--padding: 0px;
|
|
3224
3253
|
--border-radius: 0px;
|
|
3225
3254
|
--width: 100%;
|
|
3255
|
+
--height: var(--palette-colors-height);
|
|
3256
|
+
--size: var(--palette-colors-height);
|
|
3226
3257
|
flex: 1;
|
|
3227
3258
|
min-width: 0;
|
|
3228
3259
|
width: 100% !important;
|
|
3229
|
-
height: var(--size);
|
|
3230
3260
|
border-radius: 0 !important;
|
|
3231
3261
|
input,
|
|
3232
3262
|
&::before,
|
|
@@ -3248,6 +3278,11 @@ fig-input-palette {
|
|
|
3248
3278
|
grid-template-areas: "inputs inputs";
|
|
3249
3279
|
}
|
|
3250
3280
|
}
|
|
3281
|
+
&[color-strip="false"] {
|
|
3282
|
+
.palette-colors-inline {
|
|
3283
|
+
display: none !important;
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3251
3286
|
.palette-colors-expanded {
|
|
3252
3287
|
display: none;
|
|
3253
3288
|
flex-direction: column;
|
|
@@ -4375,17 +4410,13 @@ fig-preview {
|
|
|
4375
4410
|
}
|
|
4376
4411
|
}
|
|
4377
4412
|
|
|
4378
|
-
.fig-fill-picker-gradient-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
left: 0;
|
|
4386
|
-
right: 0;
|
|
4387
|
-
bottom: 0;
|
|
4388
|
-
pointer-events: none;
|
|
4413
|
+
.fig-fill-picker-gradient-preview {
|
|
4414
|
+
display: block;
|
|
4415
|
+
.fig-fill-picker-gradient-bar-input {
|
|
4416
|
+
--width: 100%;
|
|
4417
|
+
--height: 100%;
|
|
4418
|
+
aspect-ratio: 1/1;
|
|
4419
|
+
}
|
|
4389
4420
|
}
|
|
4390
4421
|
|
|
4391
4422
|
.fig-fill-picker-gradient-stops {
|
package/fig.js
CHANGED
|
@@ -5053,6 +5053,136 @@ function gradientInterpolationClause(gradient) {
|
|
|
5053
5053
|
return `in ${normalized.interpolationSpace}`;
|
|
5054
5054
|
}
|
|
5055
5055
|
|
|
5056
|
+
function figHexToRGB(hex) {
|
|
5057
|
+
const h = hex.replace(/^#/, "");
|
|
5058
|
+
return {
|
|
5059
|
+
r: parseInt(h.substring(0, 2), 16),
|
|
5060
|
+
g: parseInt(h.substring(2, 4), 16),
|
|
5061
|
+
b: parseInt(h.substring(4, 6), 16),
|
|
5062
|
+
};
|
|
5063
|
+
}
|
|
5064
|
+
|
|
5065
|
+
function figRGBToLinear(c) {
|
|
5066
|
+
const s = c / 255;
|
|
5067
|
+
return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
|
|
5068
|
+
}
|
|
5069
|
+
|
|
5070
|
+
function figLinearToSRGB(c) {
|
|
5071
|
+
const v = c <= 0.0031308 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
|
|
5072
|
+
return Math.round(Math.max(0, Math.min(1, v)) * 255);
|
|
5073
|
+
}
|
|
5074
|
+
|
|
5075
|
+
function figRGBToOklab(r, g, b) {
|
|
5076
|
+
const lr = figRGBToLinear(r);
|
|
5077
|
+
const lg = figRGBToLinear(g);
|
|
5078
|
+
const lb = figRGBToLinear(b);
|
|
5079
|
+
const l_ = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb);
|
|
5080
|
+
const m_ = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb);
|
|
5081
|
+
const s_ = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb);
|
|
5082
|
+
return {
|
|
5083
|
+
l: 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_,
|
|
5084
|
+
a: 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_,
|
|
5085
|
+
b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_,
|
|
5086
|
+
};
|
|
5087
|
+
}
|
|
5088
|
+
|
|
5089
|
+
function figOklabToRGB(L, a, b) {
|
|
5090
|
+
const l_ = L + 0.3963377774 * a + 0.2158037573 * b;
|
|
5091
|
+
const m_ = L - 0.1055613458 * a - 0.0638541728 * b;
|
|
5092
|
+
const s_ = L - 0.0894841775 * a - 1.291485548 * b;
|
|
5093
|
+
const l = l_ * l_ * l_;
|
|
5094
|
+
const m = m_ * m_ * m_;
|
|
5095
|
+
const s = s_ * s_ * s_;
|
|
5096
|
+
return {
|
|
5097
|
+
r: figLinearToSRGB(+4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s),
|
|
5098
|
+
g: figLinearToSRGB(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s),
|
|
5099
|
+
b: figLinearToSRGB(-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s),
|
|
5100
|
+
};
|
|
5101
|
+
}
|
|
5102
|
+
|
|
5103
|
+
function figOklabToOklch(L, a, b) {
|
|
5104
|
+
return { l: L, c: Math.sqrt(a * a + b * b), h: (Math.atan2(b, a) * 180) / Math.PI };
|
|
5105
|
+
}
|
|
5106
|
+
|
|
5107
|
+
function figOklchToOklab(l, c, h) {
|
|
5108
|
+
const hRad = (h * Math.PI) / 180;
|
|
5109
|
+
return { l, a: c * Math.cos(hRad), b: c * Math.sin(hRad) };
|
|
5110
|
+
}
|
|
5111
|
+
|
|
5112
|
+
function figInterpolateHue(h1, h2, t, mode) {
|
|
5113
|
+
let a = ((h1 % 360) + 360) % 360;
|
|
5114
|
+
let b = ((h2 % 360) + 360) % 360;
|
|
5115
|
+
let diff = b - a;
|
|
5116
|
+
switch (mode) {
|
|
5117
|
+
case "longer":
|
|
5118
|
+
if (diff > 0 && diff < 180) diff -= 360;
|
|
5119
|
+
else if (diff < 0 && diff > -180) diff += 360;
|
|
5120
|
+
else if (diff === 0) diff = 0;
|
|
5121
|
+
break;
|
|
5122
|
+
case "increasing":
|
|
5123
|
+
if (diff < 0) diff += 360;
|
|
5124
|
+
break;
|
|
5125
|
+
case "decreasing":
|
|
5126
|
+
if (diff > 0) diff -= 360;
|
|
5127
|
+
break;
|
|
5128
|
+
default:
|
|
5129
|
+
if (diff > 180) diff -= 360;
|
|
5130
|
+
else if (diff < -180) diff += 360;
|
|
5131
|
+
break;
|
|
5132
|
+
}
|
|
5133
|
+
return ((a + diff * t) % 360 + 360) % 360;
|
|
5134
|
+
}
|
|
5135
|
+
|
|
5136
|
+
function figSampleGradientAt(stops, position, interpolationSpace, hueInterpolation) {
|
|
5137
|
+
const sorted = [...stops].sort((a, b) => a.position - b.position);
|
|
5138
|
+
const pos = position * 100;
|
|
5139
|
+
if (sorted.length === 0) return "#888888";
|
|
5140
|
+
if (pos <= sorted[0].position) return sorted[0].color;
|
|
5141
|
+
if (pos >= sorted[sorted.length - 1].position) return sorted[sorted.length - 1].color;
|
|
5142
|
+
|
|
5143
|
+
let i = 0;
|
|
5144
|
+
while (i < sorted.length - 1 && sorted[i + 1].position < pos) i++;
|
|
5145
|
+
const s1 = sorted[i];
|
|
5146
|
+
const s2 = sorted[i + 1];
|
|
5147
|
+
const range = s2.position - s1.position;
|
|
5148
|
+
const t = range > 0 ? (pos - s1.position) / range : 0;
|
|
5149
|
+
|
|
5150
|
+
const c1 = figHexToRGB(s1.color);
|
|
5151
|
+
const c2 = figHexToRGB(s2.color);
|
|
5152
|
+
|
|
5153
|
+
let r, g, b;
|
|
5154
|
+
const space = interpolationSpace || "oklab";
|
|
5155
|
+
|
|
5156
|
+
if (space === "srgb-linear") {
|
|
5157
|
+
const lr1 = figRGBToLinear(c1.r), lg1 = figRGBToLinear(c1.g), lb1 = figRGBToLinear(c1.b);
|
|
5158
|
+
const lr2 = figRGBToLinear(c2.r), lg2 = figRGBToLinear(c2.g), lb2 = figRGBToLinear(c2.b);
|
|
5159
|
+
r = figLinearToSRGB(lr1 + (lr2 - lr1) * t);
|
|
5160
|
+
g = figLinearToSRGB(lg1 + (lg2 - lg1) * t);
|
|
5161
|
+
b = figLinearToSRGB(lb1 + (lb2 - lb1) * t);
|
|
5162
|
+
} else if (space === "oklch") {
|
|
5163
|
+
const lab1 = figRGBToOklab(c1.r, c1.g, c1.b);
|
|
5164
|
+
const lab2 = figRGBToOklab(c2.r, c2.g, c2.b);
|
|
5165
|
+
const lch1 = figOklabToOklch(lab1.l, lab1.a, lab1.b);
|
|
5166
|
+
const lch2 = figOklabToOklch(lab2.l, lab2.a, lab2.b);
|
|
5167
|
+
const L = lch1.l + (lch2.l - lch1.l) * t;
|
|
5168
|
+
const C = lch1.c + (lch2.c - lch1.c) * t;
|
|
5169
|
+
const H = figInterpolateHue(lch1.h, lch2.h, t, hueInterpolation || "shorter");
|
|
5170
|
+
const lab = figOklchToOklab(L, C, H);
|
|
5171
|
+
const rgb = figOklabToRGB(lab.l, lab.a, lab.b);
|
|
5172
|
+
r = rgb.r; g = rgb.g; b = rgb.b;
|
|
5173
|
+
} else {
|
|
5174
|
+
const lab1 = figRGBToOklab(c1.r, c1.g, c1.b);
|
|
5175
|
+
const lab2 = figRGBToOklab(c2.r, c2.g, c2.b);
|
|
5176
|
+
const L = lab1.l + (lab2.l - lab1.l) * t;
|
|
5177
|
+
const a = lab1.a + (lab2.a - lab1.a) * t;
|
|
5178
|
+
const bv = lab1.b + (lab2.b - lab1.b) * t;
|
|
5179
|
+
const rgb = figOklabToRGB(L, a, bv);
|
|
5180
|
+
r = rgb.r; g = rgb.g; b = rgb.b;
|
|
5181
|
+
}
|
|
5182
|
+
|
|
5183
|
+
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`.toUpperCase();
|
|
5184
|
+
}
|
|
5185
|
+
|
|
5056
5186
|
function hslToP3(h, s, l) {
|
|
5057
5187
|
const sRGB = hslToSRGB(h, s, l);
|
|
5058
5188
|
return sRGB.map((c) => +(c / 255).toFixed(4));
|
|
@@ -6124,13 +6254,24 @@ class FigInputGradient extends HTMLElement {
|
|
|
6124
6254
|
}
|
|
6125
6255
|
|
|
6126
6256
|
static get observedAttributes() {
|
|
6127
|
-
return ["value", "disabled"];
|
|
6257
|
+
return ["value", "disabled", "edit"];
|
|
6258
|
+
}
|
|
6259
|
+
|
|
6260
|
+
get #editMode() {
|
|
6261
|
+
const attr = this.getAttribute("edit");
|
|
6262
|
+
if (attr === "false") return "false";
|
|
6263
|
+
if (attr === "picker") return "picker";
|
|
6264
|
+
return "true";
|
|
6265
|
+
}
|
|
6266
|
+
|
|
6267
|
+
get #isEditable() {
|
|
6268
|
+
return this.#editMode === "true";
|
|
6128
6269
|
}
|
|
6129
6270
|
|
|
6130
6271
|
connectedCallback() {
|
|
6131
6272
|
this.#parseValue();
|
|
6132
6273
|
this.#render();
|
|
6133
|
-
document.addEventListener("keydown", this.#onKeyDown);
|
|
6274
|
+
if (this.#isEditable) document.addEventListener("keydown", this.#onKeyDown);
|
|
6134
6275
|
}
|
|
6135
6276
|
|
|
6136
6277
|
disconnectedCallback() {
|
|
@@ -6252,7 +6393,8 @@ class FigInputGradient extends HTMLElement {
|
|
|
6252
6393
|
(a, b) => a.position - b.position,
|
|
6253
6394
|
);
|
|
6254
6395
|
const stops = sorted.map((s) => `${s.color} ${s.position}%`).join(", ");
|
|
6255
|
-
|
|
6396
|
+
const interp = gradientInterpolationClause(this.#gradient);
|
|
6397
|
+
return `linear-gradient(${this.#gradient.angle}deg ${interp}, ${stops})`;
|
|
6256
6398
|
}
|
|
6257
6399
|
|
|
6258
6400
|
#buildStopHandles() {
|
|
@@ -6260,40 +6402,79 @@ class FigInputGradient extends HTMLElement {
|
|
|
6260
6402
|
return this.#gradient.stops
|
|
6261
6403
|
.map(
|
|
6262
6404
|
(stop, i) =>
|
|
6263
|
-
`<fig-tooltip action="manual" text="${Math.round(stop.position)}%"><fig-handle drag drag-axes="x" drag-surface=".fig-input-gradient-track" type="color" color="${stop.color}" value="${stop.position}% 50%" data-stop-index="${i}"${disabled ? " disabled" : ""}></fig-handle></fig-tooltip>`,
|
|
6405
|
+
`<fig-tooltip action="manual" text="${Math.round(stop.position)}%"><fig-handle drag drag-axes="x" drag-surface=".fig-input-gradient-track" type="color" color="${stop.color}" value="${stop.position}% 50%" hit-area="4" data-stop-index="${i}"${disabled ? " disabled" : ""}></fig-handle></fig-tooltip>`,
|
|
6264
6406
|
)
|
|
6265
6407
|
.join("");
|
|
6266
6408
|
}
|
|
6267
6409
|
|
|
6268
6410
|
#ghostHandle = null;
|
|
6411
|
+
#addedOnPointerDown = false;
|
|
6269
6412
|
|
|
6270
6413
|
#render() {
|
|
6271
6414
|
const disabled = this.hasAttribute("disabled");
|
|
6415
|
+
const mode = this.#editMode;
|
|
6416
|
+
|
|
6417
|
+
if (mode === "picker") {
|
|
6418
|
+
const experimental = this.getAttribute("experimental");
|
|
6419
|
+
const expAttr = experimental ? ` experimental="${experimental}"` : "";
|
|
6420
|
+
const gradientValue = JSON.stringify(this.value);
|
|
6421
|
+
this.innerHTML = `
|
|
6422
|
+
<fig-fill-picker mode="gradient"${expAttr} value='${gradientValue}'${disabled ? " disabled" : ""}>
|
|
6423
|
+
<fig-chit size="medium" background="${this.#buildGradientCSS()}"${disabled ? " disabled" : ""}></fig-chit>
|
|
6424
|
+
</fig-fill-picker>`;
|
|
6425
|
+
this.#chit = this.querySelector("fig-chit");
|
|
6426
|
+
this.#track = null;
|
|
6427
|
+
this.#setupPickerEvents();
|
|
6428
|
+
return;
|
|
6429
|
+
}
|
|
6430
|
+
|
|
6272
6431
|
this.innerHTML = `
|
|
6273
6432
|
<fig-chit size="medium" background="${this.#buildGradientCSS()}"${disabled ? " disabled" : ""}></fig-chit>
|
|
6274
|
-
|
|
6433
|
+
${mode === "true" ? `<div class="fig-input-gradient-track">${this.#buildStopHandles()}</div>` : ""}`;
|
|
6275
6434
|
this.#chit = this.querySelector("fig-chit");
|
|
6276
6435
|
this.#track = this.querySelector(".fig-input-gradient-track");
|
|
6277
|
-
|
|
6278
|
-
|
|
6436
|
+
|
|
6437
|
+
if (mode === "true") {
|
|
6438
|
+
this.#setupGhostHandle();
|
|
6439
|
+
this.#setupEventListeners();
|
|
6440
|
+
requestAnimationFrame(() => this.#repositionHandles());
|
|
6441
|
+
}
|
|
6442
|
+
}
|
|
6443
|
+
|
|
6444
|
+
#setupPickerEvents() {
|
|
6445
|
+
const picker = this.querySelector("fig-fill-picker");
|
|
6446
|
+
if (!picker) return;
|
|
6447
|
+
picker.anchorElement = this;
|
|
6448
|
+
|
|
6449
|
+
const syncFromPicker = (e) => {
|
|
6450
|
+
e.stopPropagation();
|
|
6451
|
+
const detail = e.detail;
|
|
6452
|
+
if (!detail?.gradient) return;
|
|
6453
|
+
this.#gradient = normalizeGradientConfig({
|
|
6454
|
+
...this.#gradient,
|
|
6455
|
+
...detail.gradient,
|
|
6456
|
+
});
|
|
6457
|
+
this.#syncChit();
|
|
6458
|
+
};
|
|
6459
|
+
|
|
6460
|
+
picker.addEventListener("input", (e) => {
|
|
6461
|
+
syncFromPicker(e);
|
|
6462
|
+
this.#emitInput();
|
|
6463
|
+
});
|
|
6464
|
+
|
|
6465
|
+
picker.addEventListener("change", (e) => {
|
|
6466
|
+
syncFromPicker(e);
|
|
6467
|
+
this.#emitChange();
|
|
6468
|
+
});
|
|
6279
6469
|
}
|
|
6280
6470
|
|
|
6281
6471
|
#sampleGradientColor(position) {
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
} catch {
|
|
6289
|
-
/* skip invalid */
|
|
6290
|
-
}
|
|
6291
|
-
}
|
|
6292
|
-
ctx.fillStyle = grad;
|
|
6293
|
-
ctx.fillRect(0, 0, 256, 1);
|
|
6294
|
-
const px = Math.round(Math.max(0, Math.min(255, position * 255)));
|
|
6295
|
-
const [r, g, b] = ctx.getImageData(px, 0, 1, 1).data;
|
|
6296
|
-
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`.toUpperCase();
|
|
6472
|
+
return figSampleGradientAt(
|
|
6473
|
+
this.#gradient.stops,
|
|
6474
|
+
position,
|
|
6475
|
+
this.#gradient.interpolationSpace,
|
|
6476
|
+
this.#gradient.hueInterpolation,
|
|
6477
|
+
);
|
|
6297
6478
|
}
|
|
6298
6479
|
|
|
6299
6480
|
#setupGhostHandle() {
|
|
@@ -6301,22 +6482,14 @@ class FigInputGradient extends HTMLElement {
|
|
|
6301
6482
|
|
|
6302
6483
|
const ghost = document.createElement("fig-handle");
|
|
6303
6484
|
ghost.classList.add("fig-input-gradient-ghost");
|
|
6485
|
+
ghost.setAttribute("type", "color");
|
|
6486
|
+
ghost.setAttribute("control", "add");
|
|
6304
6487
|
ghost.style.position = "absolute";
|
|
6305
6488
|
ghost.style.top = "50%";
|
|
6306
6489
|
ghost.style.transform = "translate(-50%, -50%)";
|
|
6307
6490
|
ghost.style.pointerEvents = "none";
|
|
6308
6491
|
ghost.style.opacity = "0";
|
|
6309
6492
|
ghost.style.transition = "opacity 0.15s";
|
|
6310
|
-
ghost.style.overflow = "visible";
|
|
6311
|
-
|
|
6312
|
-
const tip = document.createElement("fig-color-tip");
|
|
6313
|
-
tip.setAttribute("control", "add");
|
|
6314
|
-
tip.style.position = "absolute";
|
|
6315
|
-
tip.style.bottom = "calc(100% + 6px)";
|
|
6316
|
-
tip.style.left = "50%";
|
|
6317
|
-
tip.style.transform = "translateX(-50%)";
|
|
6318
|
-
tip.style.zIndex = "10";
|
|
6319
|
-
ghost.appendChild(tip);
|
|
6320
6493
|
|
|
6321
6494
|
this.#track.appendChild(ghost);
|
|
6322
6495
|
this.#ghostHandle = ghost;
|
|
@@ -6392,6 +6565,10 @@ class FigInputGradient extends HTMLElement {
|
|
|
6392
6565
|
#onTrackClick = (e) => {
|
|
6393
6566
|
if (!this.#track) return;
|
|
6394
6567
|
if (this.#handleDragging) return;
|
|
6568
|
+
if (this.#addedOnPointerDown) {
|
|
6569
|
+
this.#addedOnPointerDown = false;
|
|
6570
|
+
return;
|
|
6571
|
+
}
|
|
6395
6572
|
if (e.target.closest("fig-handle:not(.fig-input-gradient-ghost)")) {
|
|
6396
6573
|
if (e.shiftKey) {
|
|
6397
6574
|
const clickedHandle = e.target.closest("fig-handle");
|
|
@@ -6433,6 +6610,18 @@ class FigInputGradient extends HTMLElement {
|
|
|
6433
6610
|
});
|
|
6434
6611
|
};
|
|
6435
6612
|
|
|
6613
|
+
#repositionHandles() {
|
|
6614
|
+
if (!this.#track) return;
|
|
6615
|
+
const stops = this.#gradient.stops;
|
|
6616
|
+
this.#track
|
|
6617
|
+
.querySelectorAll("fig-handle:not(.fig-input-gradient-ghost)")
|
|
6618
|
+
.forEach((h, i) => {
|
|
6619
|
+
if (i >= stops.length) return;
|
|
6620
|
+
h.removeAttribute("value");
|
|
6621
|
+
h.setAttribute("value", `${stops[i].position}% 50%`);
|
|
6622
|
+
});
|
|
6623
|
+
}
|
|
6624
|
+
|
|
6436
6625
|
#syncHandles() {
|
|
6437
6626
|
if (!this.#track) return;
|
|
6438
6627
|
const handles = this.#track.querySelectorAll(
|
|
@@ -6445,6 +6634,7 @@ class FigInputGradient extends HTMLElement {
|
|
|
6445
6634
|
this.#track.innerHTML = this.#buildStopHandles();
|
|
6446
6635
|
if (ghost) this.#track.appendChild(ghost);
|
|
6447
6636
|
this.#reobserveHandleColors();
|
|
6637
|
+
requestAnimationFrame(() => this.#repositionHandles());
|
|
6448
6638
|
return;
|
|
6449
6639
|
}
|
|
6450
6640
|
|
|
@@ -6524,6 +6714,7 @@ class FigInputGradient extends HTMLElement {
|
|
|
6524
6714
|
if (e.target.closest("fig-handle:not(.fig-input-gradient-ghost)")) return;
|
|
6525
6715
|
if (e.button !== 0) return;
|
|
6526
6716
|
e.preventDefault();
|
|
6717
|
+
e.stopPropagation();
|
|
6527
6718
|
|
|
6528
6719
|
const trackRect = this.#track.getBoundingClientRect();
|
|
6529
6720
|
const pct = Math.max(0, Math.min(1, (e.clientX - trackRect.left) / trackRect.width));
|
|
@@ -6534,6 +6725,7 @@ class FigInputGradient extends HTMLElement {
|
|
|
6534
6725
|
const newIndex = this.#gradient.stops.findIndex(
|
|
6535
6726
|
(s) => s.position === position && s.color === color,
|
|
6536
6727
|
);
|
|
6728
|
+
this.#addedOnPointerDown = true;
|
|
6537
6729
|
this.#syncHandles();
|
|
6538
6730
|
this.#syncChit();
|
|
6539
6731
|
this.#emitInput();
|
|
@@ -6544,6 +6736,9 @@ class FigInputGradient extends HTMLElement {
|
|
|
6544
6736
|
);
|
|
6545
6737
|
const newHandle = handles[newIndex];
|
|
6546
6738
|
if (newHandle) {
|
|
6739
|
+
this.#track.querySelectorAll("fig-handle:not(.fig-input-gradient-ghost)").forEach((h) => {
|
|
6740
|
+
if (h !== newHandle) h.deselect();
|
|
6741
|
+
});
|
|
6547
6742
|
newHandle.select();
|
|
6548
6743
|
newHandle.dispatchEvent(new PointerEvent("pointerdown", {
|
|
6549
6744
|
bubbles: true,
|
|
@@ -6561,6 +6756,15 @@ class FigInputGradient extends HTMLElement {
|
|
|
6561
6756
|
const handle = e.target.closest("fig-handle");
|
|
6562
6757
|
if (!handle) return;
|
|
6563
6758
|
e.stopPropagation();
|
|
6759
|
+
if (e.detail?.color) {
|
|
6760
|
+
const idx = parseInt(handle.dataset.stopIndex, 10);
|
|
6761
|
+
if (!isNaN(idx) && this.#gradient.stops[idx]) {
|
|
6762
|
+
this.#gradient.stops[idx].color = e.detail.color;
|
|
6763
|
+
this.#syncChit();
|
|
6764
|
+
this.#emitInput();
|
|
6765
|
+
}
|
|
6766
|
+
return;
|
|
6767
|
+
}
|
|
6564
6768
|
if (!this.#handleDragging) handle.style.zIndex = "5";
|
|
6565
6769
|
this.#handleDragging = true;
|
|
6566
6770
|
const idx = parseInt(handle.dataset.stopIndex, 10);
|
|
@@ -6603,6 +6807,15 @@ class FigInputGradient extends HTMLElement {
|
|
|
6603
6807
|
const handle = e.target.closest("fig-handle");
|
|
6604
6808
|
if (!handle) return;
|
|
6605
6809
|
e.stopPropagation();
|
|
6810
|
+
if (e.detail?.color) {
|
|
6811
|
+
const idx = parseInt(handle.dataset.stopIndex, 10);
|
|
6812
|
+
if (!isNaN(idx) && this.#gradient.stops[idx]) {
|
|
6813
|
+
this.#gradient.stops[idx].color = e.detail.color;
|
|
6814
|
+
this.#syncChit();
|
|
6815
|
+
this.#emitChange();
|
|
6816
|
+
}
|
|
6817
|
+
return;
|
|
6818
|
+
}
|
|
6606
6819
|
handle.style.zIndex = "";
|
|
6607
6820
|
const tooltip = handle.closest("fig-tooltip");
|
|
6608
6821
|
if (tooltip) tooltip.removeAttribute("show");
|
|
@@ -6700,6 +6913,14 @@ class FigInputGradient extends HTMLElement {
|
|
|
6700
6913
|
case "disabled":
|
|
6701
6914
|
this.#syncDisabled();
|
|
6702
6915
|
break;
|
|
6916
|
+
case "edit":
|
|
6917
|
+
this.#render();
|
|
6918
|
+
if (this.#isEditable) {
|
|
6919
|
+
document.addEventListener("keydown", this.#onKeyDown);
|
|
6920
|
+
} else {
|
|
6921
|
+
document.removeEventListener("keydown", this.#onKeyDown);
|
|
6922
|
+
}
|
|
6923
|
+
break;
|
|
6703
6924
|
}
|
|
6704
6925
|
}
|
|
6705
6926
|
|
|
@@ -11502,8 +11723,7 @@ class FigFillPicker extends HTMLElement {
|
|
|
11502
11723
|
</fig-tooltip>
|
|
11503
11724
|
</fig-field>
|
|
11504
11725
|
<fig-preview class="fig-fill-picker-gradient-preview">
|
|
11505
|
-
<
|
|
11506
|
-
<div class="fig-fill-picker-gradient-stops-handles"></div>
|
|
11726
|
+
<fig-input-gradient class="fig-fill-picker-gradient-bar-input" edit="true" size="large" value='${JSON.stringify({ type: "gradient", gradient: gradientToValueShape(this.#gradient) })}'></fig-input-gradient>
|
|
11507
11727
|
</fig-preview>
|
|
11508
11728
|
<fig-field class="fig-fill-picker-gradient-interpolation" direction="horizontal">
|
|
11509
11729
|
<label>Mixing</label>
|
|
@@ -11634,6 +11854,30 @@ class FigFillPicker extends HTMLElement {
|
|
|
11634
11854
|
this.#updateGradientUI();
|
|
11635
11855
|
this.#emitInput();
|
|
11636
11856
|
});
|
|
11857
|
+
|
|
11858
|
+
// Embedded gradient bar input
|
|
11859
|
+
const gradientBarInput = container.querySelector(".fig-fill-picker-gradient-bar-input");
|
|
11860
|
+
if (gradientBarInput) {
|
|
11861
|
+
const syncFromBarInput = (e) => {
|
|
11862
|
+
e.stopPropagation();
|
|
11863
|
+
const detail = e.detail;
|
|
11864
|
+
if (!detail?.gradient) return;
|
|
11865
|
+
this.#gradient = normalizeGradientConfig({
|
|
11866
|
+
...this.#gradient,
|
|
11867
|
+
...detail.gradient,
|
|
11868
|
+
});
|
|
11869
|
+
this.#updateChit();
|
|
11870
|
+
this.#updateGradientStopsList();
|
|
11871
|
+
};
|
|
11872
|
+
gradientBarInput.addEventListener("input", (e) => {
|
|
11873
|
+
syncFromBarInput(e);
|
|
11874
|
+
this.#emitInput();
|
|
11875
|
+
});
|
|
11876
|
+
gradientBarInput.addEventListener("change", (e) => {
|
|
11877
|
+
syncFromBarInput(e);
|
|
11878
|
+
this.#emitChange();
|
|
11879
|
+
});
|
|
11880
|
+
}
|
|
11637
11881
|
}
|
|
11638
11882
|
|
|
11639
11883
|
#updateGradientUI() {
|
|
@@ -11679,14 +11923,14 @@ class FigFillPicker extends HTMLElement {
|
|
|
11679
11923
|
#updateGradientPreview() {
|
|
11680
11924
|
if (!this.#dialog) return;
|
|
11681
11925
|
|
|
11682
|
-
const
|
|
11683
|
-
".fig-fill-picker-gradient-
|
|
11926
|
+
const barInput = this.#dialog.querySelector(
|
|
11927
|
+
".fig-fill-picker-gradient-bar-input",
|
|
11684
11928
|
);
|
|
11685
|
-
|
|
11686
|
-
|
|
11687
|
-
|
|
11688
|
-
|
|
11689
|
-
|
|
11929
|
+
if (barInput) {
|
|
11930
|
+
barInput.setAttribute(
|
|
11931
|
+
"value",
|
|
11932
|
+
JSON.stringify({ type: "gradient", gradient: gradientToValueShape(this.#gradient) }),
|
|
11933
|
+
);
|
|
11690
11934
|
}
|
|
11691
11935
|
|
|
11692
11936
|
this.#updateChit();
|
|
@@ -11700,6 +11944,31 @@ class FigFillPicker extends HTMLElement {
|
|
|
11700
11944
|
);
|
|
11701
11945
|
if (!list) return;
|
|
11702
11946
|
|
|
11947
|
+
const existingRows = list.querySelectorAll(
|
|
11948
|
+
".fig-fill-picker-gradient-stop-row",
|
|
11949
|
+
);
|
|
11950
|
+
|
|
11951
|
+
if (existingRows.length === this.#gradient.stops.length) {
|
|
11952
|
+
this.#gradient.stops.forEach((stop, index) => {
|
|
11953
|
+
const row = existingRows[index];
|
|
11954
|
+
row.dataset.index = index;
|
|
11955
|
+
const posInput = row.querySelector(".fig-fill-picker-stop-position");
|
|
11956
|
+
if (posInput) posInput.setAttribute("value", stop.position);
|
|
11957
|
+
const colorInput = row.querySelector(".fig-fill-picker-stop-color");
|
|
11958
|
+
if (colorInput) colorInput.setAttribute("value", stop.color);
|
|
11959
|
+
const removeBtn = row.querySelector(".fig-fill-picker-stop-remove");
|
|
11960
|
+
if (removeBtn) {
|
|
11961
|
+
if (this.#gradient.stops.length <= 2) removeBtn.setAttribute("disabled", "");
|
|
11962
|
+
else removeBtn.removeAttribute("disabled");
|
|
11963
|
+
}
|
|
11964
|
+
});
|
|
11965
|
+
return;
|
|
11966
|
+
}
|
|
11967
|
+
|
|
11968
|
+
this.#rebuildGradientStopsList(list);
|
|
11969
|
+
}
|
|
11970
|
+
|
|
11971
|
+
#rebuildGradientStopsList(list) {
|
|
11703
11972
|
list.innerHTML = this.#gradient.stops
|
|
11704
11973
|
.map(
|
|
11705
11974
|
(stop, index) => `
|
|
@@ -11720,7 +11989,6 @@ class FigFillPicker extends HTMLElement {
|
|
|
11720
11989
|
)
|
|
11721
11990
|
.join("");
|
|
11722
11991
|
|
|
11723
|
-
// Setup event listeners for each stop
|
|
11724
11992
|
list
|
|
11725
11993
|
.querySelectorAll(".fig-fill-picker-gradient-stop-row")
|
|
11726
11994
|
.forEach((row) => {
|
|
@@ -11778,9 +12046,10 @@ class FigFillPicker extends HTMLElement {
|
|
|
11778
12046
|
const isP3 = this.#gamut === "display-p3";
|
|
11779
12047
|
const stops = gradient.stops
|
|
11780
12048
|
.map((s) => {
|
|
12049
|
+
const alpha = (s.opacity ?? 100) / 100;
|
|
11781
12050
|
const color = isP3
|
|
11782
|
-
? this.#hexToP3(s.color,
|
|
11783
|
-
: this.#hexToRGBA(s.color,
|
|
12051
|
+
? this.#hexToP3(s.color, alpha)
|
|
12052
|
+
: this.#hexToRGBA(s.color, alpha);
|
|
11784
12053
|
return `${color} ${s.position}%`;
|
|
11785
12054
|
})
|
|
11786
12055
|
.join(", ");
|
|
@@ -14480,7 +14749,7 @@ class FigHandle extends HTMLElement {
|
|
|
14480
14749
|
document.addEventListener("keydown", this.#handleKeyDown);
|
|
14481
14750
|
const initial = this.getAttribute("value");
|
|
14482
14751
|
if (initial) this.#applyValue(initial);
|
|
14483
|
-
if (this.#hasControlMode
|
|
14752
|
+
if (this.#hasControlMode) this.#showColorTip();
|
|
14484
14753
|
}
|
|
14485
14754
|
|
|
14486
14755
|
disconnectedCallback() {
|
|
@@ -14544,7 +14813,7 @@ class FigHandle extends HTMLElement {
|
|
|
14544
14813
|
if (name === "value" && !this.#applyingValue && !this.#isDragging) {
|
|
14545
14814
|
this.#applyValue(value);
|
|
14546
14815
|
}
|
|
14547
|
-
if (name === "control"
|
|
14816
|
+
if (name === "control") {
|
|
14548
14817
|
if (this.#hasControlMode) {
|
|
14549
14818
|
this.#hideColorTip();
|
|
14550
14819
|
this.#showColorTip();
|
package/package.json
CHANGED