@rogieking/figui3 8.9.49 → 8.10.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/.cursor/skills/fig-editor/SKILL.md +3 -3
- package/.cursor/skills/fig-editor/components.md +2 -2
- package/.cursor/skills/fig-editor/reference.md +3 -0
- package/.cursor/skills/fig-lab/SKILL.md +14 -5
- package/.cursor/skills/fig-lab/components.md +90 -12
- package/.cursor/skills/fig-lab/reference.md +107 -11
- package/.cursor/skills/figui3/components.md +3 -0
- package/.cursor/skills/figui3/react.md +4 -0
- package/README.md +171 -56
- package/components.css +34 -12
- package/dist/components.css +1 -1
- package/dist/fig-editor.css +1 -1
- package/dist/fig-editor.js +18 -5
- package/dist/fig-lab.css +1 -1
- package/dist/fig-lab.js +1 -3
- package/dist/fig.css +1 -1
- package/dist/fig.js +7 -7
- package/fig-editor.css +10 -0
- package/fig-editor.js +100 -10
- package/fig-lab.css +1497 -450
- package/fig-lab.js +2171 -1146
- package/fig.js +73 -30
- package/package.json +1 -1
package/fig.js
CHANGED
|
@@ -633,7 +633,7 @@ class FigButton extends HTMLElement {
|
|
|
633
633
|
const style = document.createElement("style");
|
|
634
634
|
style.textContent = `
|
|
635
635
|
button, button:hover, button:active, .fig-button-control {
|
|
636
|
-
padding: 0 var(--spacer-2);
|
|
636
|
+
padding: var(--fig-button-control-padding, 0 var(--spacer-2));
|
|
637
637
|
appearance: none;
|
|
638
638
|
display: flex;
|
|
639
639
|
border: 0;
|
|
@@ -646,7 +646,7 @@ class FigButton extends HTMLElement {
|
|
|
646
646
|
outline: 0;
|
|
647
647
|
place-items: center;
|
|
648
648
|
background: transparent;
|
|
649
|
-
margin: calc(var(--spacer-2)*-1);
|
|
649
|
+
margin: var(--fig-button-control-margin, calc(var(--spacer-2)*-1));
|
|
650
650
|
height: var(--spacer-4);
|
|
651
651
|
white-space: nowrap;
|
|
652
652
|
overflow: hidden;
|
|
@@ -14054,6 +14054,7 @@ figDefineElement("fig-input-file", FigInputFile);
|
|
|
14054
14054
|
/**
|
|
14055
14055
|
* A bezier / spring easing curve editor with draggable control points.
|
|
14056
14056
|
* @attr {string} value - Bezier: "0.42, 0, 0.58, 1" or Spring: "spring(200, 15, 1)"
|
|
14057
|
+
* @attr {string} mode - Optional editor constraint: "bezier" or "spring".
|
|
14057
14058
|
* @attr {number} precision - Decimal places for output values (default 2)
|
|
14058
14059
|
* @attr {boolean} edit - Show the editor and custom preset options (default true; set "false" for presets only)
|
|
14059
14060
|
*/
|
|
@@ -14153,14 +14154,17 @@ class FigEasingCurve extends HTMLElement {
|
|
|
14153
14154
|
];
|
|
14154
14155
|
|
|
14155
14156
|
static get observedAttributes() {
|
|
14156
|
-
return ["value", "precision", "aspect-ratio", "edit"];
|
|
14157
|
+
return ["value", "mode", "precision", "aspect-ratio", "edit"];
|
|
14157
14158
|
}
|
|
14158
14159
|
|
|
14159
14160
|
connectedCallback() {
|
|
14160
14161
|
this.#precision = parseInt(this.getAttribute("precision") || "2");
|
|
14161
14162
|
figSyncCssVar(this, "--aspect-ratio", this.getAttribute("aspect-ratio"));
|
|
14163
|
+
const constrainedMode = this.#constrainedMode();
|
|
14164
|
+
if (constrainedMode) this.#mode = constrainedMode;
|
|
14162
14165
|
const val = this.getAttribute("value");
|
|
14163
14166
|
if (val) this.#parseValue(val);
|
|
14167
|
+
this.#applyModeConstraint();
|
|
14164
14168
|
this.#presetName = this.#matchPreset();
|
|
14165
14169
|
this.#render();
|
|
14166
14170
|
this.#setupResizeObserver();
|
|
@@ -14191,6 +14195,13 @@ class FigEasingCurve extends HTMLElement {
|
|
|
14191
14195
|
return;
|
|
14192
14196
|
}
|
|
14193
14197
|
|
|
14198
|
+
if (name === "mode") {
|
|
14199
|
+
this.#applyModeConstraint();
|
|
14200
|
+
this.#presetName = this.#matchPreset();
|
|
14201
|
+
if (this.isConnected) this.#render();
|
|
14202
|
+
return;
|
|
14203
|
+
}
|
|
14204
|
+
|
|
14194
14205
|
if (name === "value" && newValue) {
|
|
14195
14206
|
const prevMode = this.#mode;
|
|
14196
14207
|
this.#parseValue(newValue);
|
|
@@ -14242,11 +14253,26 @@ class FigEasingCurve extends HTMLElement {
|
|
|
14242
14253
|
this.setAttribute("value", v);
|
|
14243
14254
|
}
|
|
14244
14255
|
|
|
14256
|
+
#constrainedMode() {
|
|
14257
|
+
const mode = this.getAttribute("mode")?.trim().toLowerCase();
|
|
14258
|
+
return mode === "bezier" || mode === "spring" ? mode : null;
|
|
14259
|
+
}
|
|
14260
|
+
|
|
14261
|
+
#applyModeConstraint() {
|
|
14262
|
+
const mode = this.#constrainedMode();
|
|
14263
|
+
if (mode) this.#mode = mode;
|
|
14264
|
+
}
|
|
14265
|
+
|
|
14266
|
+
#allowsPreset(preset) {
|
|
14267
|
+
const mode = this.#constrainedMode();
|
|
14268
|
+
return !mode || preset.type === mode;
|
|
14269
|
+
}
|
|
14270
|
+
|
|
14245
14271
|
#parseValue(str) {
|
|
14246
14272
|
const springMatch = str.match(
|
|
14247
14273
|
/^spring\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)\s*\)$/,
|
|
14248
14274
|
);
|
|
14249
|
-
if (springMatch) {
|
|
14275
|
+
if (springMatch && this.#constrainedMode() !== "bezier") {
|
|
14250
14276
|
this.#mode = "spring";
|
|
14251
14277
|
this.#spring.stiffness = parseFloat(springMatch[1]);
|
|
14252
14278
|
this.#spring.damping = parseFloat(springMatch[2]);
|
|
@@ -14254,7 +14280,11 @@ class FigEasingCurve extends HTMLElement {
|
|
|
14254
14280
|
return true;
|
|
14255
14281
|
}
|
|
14256
14282
|
const parts = str.split(",").map((s) => parseFloat(s.trim()));
|
|
14257
|
-
if (
|
|
14283
|
+
if (
|
|
14284
|
+
parts.length >= 4 &&
|
|
14285
|
+
parts.every((n) => !isNaN(n)) &&
|
|
14286
|
+
this.#constrainedMode() !== "spring"
|
|
14287
|
+
) {
|
|
14258
14288
|
this.#mode = "bezier";
|
|
14259
14289
|
this.#cp1.x = parts[0];
|
|
14260
14290
|
this.#cp1.y = parts[1];
|
|
@@ -14473,6 +14503,7 @@ class FigEasingCurve extends HTMLElement {
|
|
|
14473
14503
|
let currentGroup = undefined;
|
|
14474
14504
|
let parent = dropdown;
|
|
14475
14505
|
for (const preset of FigEasingCurve.PRESETS) {
|
|
14506
|
+
if (!this.#allowsPreset(preset)) continue;
|
|
14476
14507
|
if (!this.#isEditEnabled() && !preset.value && !preset.spring) continue;
|
|
14477
14508
|
if (preset.group !== currentGroup) {
|
|
14478
14509
|
currentGroup = preset.group;
|
|
@@ -14494,6 +14525,7 @@ class FigEasingCurve extends HTMLElement {
|
|
|
14494
14525
|
const options = document.createElement("fig-select-options");
|
|
14495
14526
|
let currentGroup = undefined;
|
|
14496
14527
|
for (const p of FigEasingCurve.PRESETS) {
|
|
14528
|
+
if (!this.#allowsPreset(p)) continue;
|
|
14497
14529
|
if (!this.#isEditEnabled() && !p.value && !p.spring) continue;
|
|
14498
14530
|
if (p.group !== currentGroup) {
|
|
14499
14531
|
if (p.group) {
|
|
@@ -14962,19 +14994,41 @@ class FigEasingCurve extends HTMLElement {
|
|
|
14962
14994
|
return parts;
|
|
14963
14995
|
}
|
|
14964
14996
|
|
|
14997
|
+
#parseManualSpringValue(value) {
|
|
14998
|
+
const match = value.match(
|
|
14999
|
+
/^spring\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)\s*\)$/,
|
|
15000
|
+
);
|
|
15001
|
+
if (!match) return null;
|
|
15002
|
+
const spring = {
|
|
15003
|
+
stiffness: Number(match[1]),
|
|
15004
|
+
damping: Number(match[2]),
|
|
15005
|
+
mass: Number(match[3]),
|
|
15006
|
+
};
|
|
15007
|
+
return Object.values(spring).every((part) => part > 0) ? spring : null;
|
|
15008
|
+
}
|
|
15009
|
+
|
|
14965
15010
|
#applyManualValue(value, eventType) {
|
|
14966
|
-
const
|
|
14967
|
-
|
|
15011
|
+
const constrainedMode = this.#constrainedMode();
|
|
15012
|
+
const spring =
|
|
15013
|
+
constrainedMode === "bezier" ? null : this.#parseManualSpringValue(value);
|
|
15014
|
+
const bezier =
|
|
15015
|
+
constrainedMode === "spring" ? null : this.#parseManualBezierValue(value);
|
|
15016
|
+
if (!spring && !bezier) {
|
|
14968
15017
|
if (eventType === "change") this.#syncValueInput();
|
|
14969
15018
|
return;
|
|
14970
15019
|
}
|
|
14971
15020
|
|
|
14972
15021
|
const prevMode = this.#mode;
|
|
14973
|
-
|
|
14974
|
-
|
|
14975
|
-
|
|
14976
|
-
|
|
14977
|
-
|
|
15022
|
+
if (spring) {
|
|
15023
|
+
this.#mode = "spring";
|
|
15024
|
+
this.#spring = spring;
|
|
15025
|
+
} else {
|
|
15026
|
+
this.#mode = "bezier";
|
|
15027
|
+
this.#cp1.x = bezier[0];
|
|
15028
|
+
this.#cp1.y = bezier[1];
|
|
15029
|
+
this.#cp2.x = bezier[2];
|
|
15030
|
+
this.#cp2.y = bezier[3];
|
|
15031
|
+
}
|
|
14978
15032
|
|
|
14979
15033
|
this.#presetName = this.#matchPreset();
|
|
14980
15034
|
if (prevMode !== this.#mode) {
|
|
@@ -16453,18 +16507,12 @@ class FigInputJoystick extends HTMLElement {
|
|
|
16453
16507
|
const planeContainer = figCreateElement("div", {
|
|
16454
16508
|
className: "fig-input-joystick-plane-container",
|
|
16455
16509
|
});
|
|
16456
|
-
const createAxisLabel = (position, text
|
|
16510
|
+
const createAxisLabel = (position, text) =>
|
|
16457
16511
|
text
|
|
16458
16512
|
? figCreateElement(
|
|
16459
16513
|
"label",
|
|
16460
16514
|
{
|
|
16461
|
-
className: [
|
|
16462
|
-
"fig-joystick-axis-label",
|
|
16463
|
-
position,
|
|
16464
|
-
noRotate ? "no-rotate" : "",
|
|
16465
|
-
]
|
|
16466
|
-
.filter(Boolean)
|
|
16467
|
-
.join(" "),
|
|
16515
|
+
className: ["fig-joystick-axis-label", position].join(" "),
|
|
16468
16516
|
"aria-hidden": "true",
|
|
16469
16517
|
},
|
|
16470
16518
|
text,
|
|
@@ -16472,11 +16520,7 @@ class FigInputJoystick extends HTMLElement {
|
|
|
16472
16520
|
: null;
|
|
16473
16521
|
planeContainer.append(
|
|
16474
16522
|
...[
|
|
16475
|
-
createAxisLabel(
|
|
16476
|
-
"left",
|
|
16477
|
-
axisLabels.left,
|
|
16478
|
-
axisLabels.leftNoRotate,
|
|
16479
|
-
),
|
|
16523
|
+
createAxisLabel("left", axisLabels.left),
|
|
16480
16524
|
createAxisLabel("right", axisLabels.right),
|
|
16481
16525
|
createAxisLabel("top", axisLabels.top),
|
|
16482
16526
|
createAxisLabel("bottom", axisLabels.bottom),
|
|
@@ -16548,7 +16592,7 @@ class FigInputJoystick extends HTMLElement {
|
|
|
16548
16592
|
#getAxisLabels() {
|
|
16549
16593
|
const raw = (this.getAttribute("axis-labels") || "").trim();
|
|
16550
16594
|
if (!raw) {
|
|
16551
|
-
return { left: "", right: "", top: "", bottom: ""
|
|
16595
|
+
return { left: "", right: "", top: "", bottom: "" };
|
|
16552
16596
|
}
|
|
16553
16597
|
const tokens = raw.split(/[\s,]+/).filter(Boolean);
|
|
16554
16598
|
if (tokens.length === 1) {
|
|
@@ -16557,18 +16601,17 @@ class FigInputJoystick extends HTMLElement {
|
|
|
16557
16601
|
right: "",
|
|
16558
16602
|
top: tokens[0],
|
|
16559
16603
|
bottom: "",
|
|
16560
|
-
leftNoRotate: false,
|
|
16561
16604
|
};
|
|
16562
16605
|
}
|
|
16563
16606
|
if (tokens.length === 2) {
|
|
16564
16607
|
const [x, y] = tokens;
|
|
16565
|
-
return { left: x, right: "", top: "", bottom: y
|
|
16608
|
+
return { left: x, right: "", top: "", bottom: y };
|
|
16566
16609
|
}
|
|
16567
16610
|
if (tokens.length === 4) {
|
|
16568
16611
|
const [left, right, top, bottom] = tokens;
|
|
16569
|
-
return { left, right, top, bottom
|
|
16612
|
+
return { left, right, top, bottom };
|
|
16570
16613
|
}
|
|
16571
|
-
return { left: "", right: "", top: "", bottom: ""
|
|
16614
|
+
return { left: "", right: "", top: "", bottom: "" };
|
|
16572
16615
|
}
|
|
16573
16616
|
|
|
16574
16617
|
#setupListeners() {
|
package/package.json
CHANGED