@rogieking/figui3 2.20.0 → 2.22.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 +9 -5
- package/fig.js +301 -170
- package/index.html +36 -2
- package/package.json +1 -1
package/components.css
CHANGED
|
@@ -1412,7 +1412,8 @@ input[type="checkbox"]:not(.switch) {
|
|
|
1412
1412
|
/* Light theme checkbox hover (black checkmark preview) */
|
|
1413
1413
|
/* @media is a no-JS fallback — ignored when setTheme() sets classes */
|
|
1414
1414
|
@media (prefers-color-scheme: light) {
|
|
1415
|
-
:root:not(.figma-dark):not(.figma-light)
|
|
1415
|
+
:root:not(.figma-dark):not(.figma-light)
|
|
1416
|
+
input[type="checkbox"]:not(.switch):not(:disabled):hover {
|
|
1416
1417
|
background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4.50012 7.5L7.50012 10.5L11.5001 4.5' stroke='black' opacity='0.25' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.125' /%3E%3C/svg%3E%0A");
|
|
1417
1418
|
}
|
|
1418
1419
|
}
|
|
@@ -2030,12 +2031,15 @@ dialog[is="fig-popup"] {
|
|
|
2030
2031
|
position: fixed;
|
|
2031
2032
|
margin: 0;
|
|
2032
2033
|
min-width: 0;
|
|
2033
|
-
|
|
2034
|
-
max-width: calc(100vw - var(--spacer-4));
|
|
2035
|
-
max-height: calc(100vh - var(--spacer-4));
|
|
2036
|
-
padding: var(--spacer-2);
|
|
2034
|
+
padding: 0;
|
|
2037
2035
|
overflow: auto;
|
|
2038
2036
|
|
|
2037
|
+
&[autoresize]:not([autoresize="false"]) {
|
|
2038
|
+
width: max-content;
|
|
2039
|
+
max-width: calc(100vw - var(--spacer-4));
|
|
2040
|
+
max-height: calc(100vh - var(--spacer-4));
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2039
2043
|
&[open] {
|
|
2040
2044
|
display: block;
|
|
2041
2045
|
}
|
package/fig.js
CHANGED
|
@@ -863,13 +863,12 @@ class FigDialog extends HTMLDialogElement {
|
|
|
863
863
|
#setupDragListeners() {
|
|
864
864
|
if (this.drag) {
|
|
865
865
|
this.addEventListener("pointerdown", this.#boundPointerDown);
|
|
866
|
-
// Set move cursor on handle element (or fig-header by default)
|
|
867
866
|
const handleSelector = this.getAttribute("handle");
|
|
868
867
|
const handleEl = handleSelector
|
|
869
868
|
? this.querySelector(handleSelector)
|
|
870
869
|
: this.querySelector("fig-header, header");
|
|
871
870
|
if (handleEl) {
|
|
872
|
-
handleEl.style.cursor = "
|
|
871
|
+
handleEl.style.cursor = "grab";
|
|
873
872
|
}
|
|
874
873
|
}
|
|
875
874
|
}
|
|
@@ -977,16 +976,12 @@ class FigDialog extends HTMLDialogElement {
|
|
|
977
976
|
const dy = Math.abs(e.clientY - this.#dragStartPos.y);
|
|
978
977
|
|
|
979
978
|
if (dx > this.#dragThreshold || dy > this.#dragThreshold) {
|
|
980
|
-
// Start actual drag
|
|
981
979
|
this.#isDragging = true;
|
|
982
980
|
this.#dragPending = false;
|
|
983
981
|
this.setPointerCapture(e.pointerId);
|
|
982
|
+
this.style.cursor = "grabbing";
|
|
984
983
|
|
|
985
|
-
// Get current position from computed style
|
|
986
984
|
const rect = this.getBoundingClientRect();
|
|
987
|
-
|
|
988
|
-
// Convert to pixel-based top/left positioning for dragging
|
|
989
|
-
// (clears margin: auto centering)
|
|
990
985
|
this.style.top = `${rect.top}px`;
|
|
991
986
|
this.style.left = `${rect.left}px`;
|
|
992
987
|
this.style.bottom = "auto";
|
|
@@ -997,21 +992,15 @@ class FigDialog extends HTMLDialogElement {
|
|
|
997
992
|
|
|
998
993
|
if (!this.#isDragging) return;
|
|
999
994
|
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
const newTop = e.clientY - this.#dragOffset.y;
|
|
1003
|
-
|
|
1004
|
-
// Apply position directly with pixels
|
|
1005
|
-
this.style.left = `${newLeft}px`;
|
|
1006
|
-
this.style.top = `${newTop}px`;
|
|
1007
|
-
|
|
995
|
+
this.style.left = `${e.clientX - this.#dragOffset.x}px`;
|
|
996
|
+
this.style.top = `${e.clientY - this.#dragOffset.y}px`;
|
|
1008
997
|
e.preventDefault();
|
|
1009
998
|
}
|
|
1010
999
|
|
|
1011
1000
|
#handlePointerUp(e) {
|
|
1012
|
-
// Clean up pending or active drag
|
|
1013
1001
|
if (this.#isDragging) {
|
|
1014
1002
|
this.releasePointerCapture(e.pointerId);
|
|
1003
|
+
this.style.cursor = "";
|
|
1015
1004
|
}
|
|
1016
1005
|
|
|
1017
1006
|
this.#isDragging = false;
|
|
@@ -1035,7 +1024,6 @@ class FigDialog extends HTMLDialogElement {
|
|
|
1035
1024
|
this.#setupDragListeners();
|
|
1036
1025
|
} else {
|
|
1037
1026
|
this.#removeDragListeners();
|
|
1038
|
-
// Remove move cursor from header
|
|
1039
1027
|
const header = this.querySelector("fig-header, header");
|
|
1040
1028
|
if (header) {
|
|
1041
1029
|
header.style.cursor = "";
|
|
@@ -1070,16 +1058,29 @@ class FigPopup extends HTMLDialogElement {
|
|
|
1070
1058
|
#boundScroll;
|
|
1071
1059
|
#boundOutsidePointerDown;
|
|
1072
1060
|
#rafId = null;
|
|
1061
|
+
#anchorRef = null;
|
|
1062
|
+
|
|
1063
|
+
#isDragging = false;
|
|
1064
|
+
#dragPending = false;
|
|
1065
|
+
#dragStartPos = { x: 0, y: 0 };
|
|
1066
|
+
#dragOffset = { x: 0, y: 0 };
|
|
1067
|
+
#dragThreshold = 3;
|
|
1068
|
+
#boundPointerDown;
|
|
1069
|
+
#boundPointerMove;
|
|
1070
|
+
#boundPointerUp;
|
|
1073
1071
|
|
|
1074
1072
|
constructor() {
|
|
1075
1073
|
super();
|
|
1076
1074
|
this.#boundReposition = this.#queueReposition.bind(this);
|
|
1077
1075
|
this.#boundScroll = this.#queueReposition.bind(this);
|
|
1078
1076
|
this.#boundOutsidePointerDown = this.#handleOutsidePointerDown.bind(this);
|
|
1077
|
+
this.#boundPointerDown = this.#handlePointerDown.bind(this);
|
|
1078
|
+
this.#boundPointerMove = this.#handlePointerMove.bind(this);
|
|
1079
|
+
this.#boundPointerUp = this.#handlePointerUp.bind(this);
|
|
1079
1080
|
}
|
|
1080
1081
|
|
|
1081
1082
|
static get observedAttributes() {
|
|
1082
|
-
return ["open", "anchor", "position", "offset", "variant", "theme"];
|
|
1083
|
+
return ["open", "anchor", "position", "offset", "variant", "theme", "drag", "handle", "autoresize"];
|
|
1083
1084
|
}
|
|
1084
1085
|
|
|
1085
1086
|
get open() {
|
|
@@ -1096,6 +1097,22 @@ class FigPopup extends HTMLDialogElement {
|
|
|
1096
1097
|
this.setAttribute("open", "true");
|
|
1097
1098
|
}
|
|
1098
1099
|
|
|
1100
|
+
get anchor() {
|
|
1101
|
+
return this.#anchorRef ?? this.getAttribute("anchor");
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
set anchor(value) {
|
|
1105
|
+
if (value instanceof Element) {
|
|
1106
|
+
this.#anchorRef = value;
|
|
1107
|
+
} else if (typeof value === "string") {
|
|
1108
|
+
this.#anchorRef = null;
|
|
1109
|
+
this.setAttribute("anchor", value);
|
|
1110
|
+
} else {
|
|
1111
|
+
this.#anchorRef = null;
|
|
1112
|
+
}
|
|
1113
|
+
if (this.open) this.#queueReposition();
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1099
1116
|
connectedCallback() {
|
|
1100
1117
|
if (!this.hasAttribute("position")) {
|
|
1101
1118
|
this.setAttribute("position", "top center");
|
|
@@ -1103,11 +1120,13 @@ class FigPopup extends HTMLDialogElement {
|
|
|
1103
1120
|
if (!this.hasAttribute("role")) {
|
|
1104
1121
|
this.setAttribute("role", "dialog");
|
|
1105
1122
|
}
|
|
1106
|
-
// Default dialog outside-close behavior.
|
|
1107
1123
|
if (!this.hasAttribute("closedby")) {
|
|
1108
1124
|
this.setAttribute("closedby", "any");
|
|
1109
1125
|
}
|
|
1110
1126
|
|
|
1127
|
+
this.drag =
|
|
1128
|
+
this.hasAttribute("drag") && this.getAttribute("drag") !== "false";
|
|
1129
|
+
|
|
1111
1130
|
this.addEventListener("close", () => {
|
|
1112
1131
|
this.#teardownObservers();
|
|
1113
1132
|
if (this.hasAttribute("open")) {
|
|
@@ -1115,6 +1134,10 @@ class FigPopup extends HTMLDialogElement {
|
|
|
1115
1134
|
}
|
|
1116
1135
|
});
|
|
1117
1136
|
|
|
1137
|
+
requestAnimationFrame(() => {
|
|
1138
|
+
this.#setupDragListeners();
|
|
1139
|
+
});
|
|
1140
|
+
|
|
1118
1141
|
if (this.open) {
|
|
1119
1142
|
this.#showPopup();
|
|
1120
1143
|
} else {
|
|
@@ -1124,6 +1147,7 @@ class FigPopup extends HTMLDialogElement {
|
|
|
1124
1147
|
|
|
1125
1148
|
disconnectedCallback() {
|
|
1126
1149
|
this.#teardownObservers();
|
|
1150
|
+
this.#removeDragListeners();
|
|
1127
1151
|
document.removeEventListener(
|
|
1128
1152
|
"pointerdown",
|
|
1129
1153
|
this.#boundOutsidePointerDown,
|
|
@@ -1147,6 +1171,16 @@ class FigPopup extends HTMLDialogElement {
|
|
|
1147
1171
|
return;
|
|
1148
1172
|
}
|
|
1149
1173
|
|
|
1174
|
+
if (name === "drag") {
|
|
1175
|
+
this.drag = newValue !== null && newValue !== "false";
|
|
1176
|
+
if (this.drag) {
|
|
1177
|
+
this.#setupDragListeners();
|
|
1178
|
+
} else {
|
|
1179
|
+
this.#removeDragListeners();
|
|
1180
|
+
}
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1150
1184
|
if (this.open) {
|
|
1151
1185
|
this.#queueReposition();
|
|
1152
1186
|
this.#setupObservers();
|
|
@@ -1176,9 +1210,15 @@ class FigPopup extends HTMLDialogElement {
|
|
|
1176
1210
|
document.addEventListener("pointerdown", this.#boundOutsidePointerDown, true);
|
|
1177
1211
|
this.#queueReposition();
|
|
1178
1212
|
this.#isPopupActive = true;
|
|
1213
|
+
|
|
1214
|
+
const anchor = this.#resolveAnchor();
|
|
1215
|
+
if (anchor) anchor.classList.add("has-popup-open");
|
|
1179
1216
|
}
|
|
1180
1217
|
|
|
1181
1218
|
#hidePopup() {
|
|
1219
|
+
const anchor = this.#resolveAnchor();
|
|
1220
|
+
if (anchor) anchor.classList.remove("has-popup-open");
|
|
1221
|
+
|
|
1182
1222
|
this.#isPopupActive = false;
|
|
1183
1223
|
this.#teardownObservers();
|
|
1184
1224
|
document.removeEventListener(
|
|
@@ -1196,6 +1236,11 @@ class FigPopup extends HTMLDialogElement {
|
|
|
1196
1236
|
}
|
|
1197
1237
|
}
|
|
1198
1238
|
|
|
1239
|
+
get autoresize() {
|
|
1240
|
+
const val = this.getAttribute("autoresize");
|
|
1241
|
+
return val === null || val !== "false";
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1199
1244
|
#setupObservers() {
|
|
1200
1245
|
this.#teardownObservers();
|
|
1201
1246
|
|
|
@@ -1205,17 +1250,19 @@ class FigPopup extends HTMLDialogElement {
|
|
|
1205
1250
|
this.#anchorObserver.observe(anchor);
|
|
1206
1251
|
}
|
|
1207
1252
|
|
|
1208
|
-
if (
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1253
|
+
if (this.autoresize) {
|
|
1254
|
+
if ("ResizeObserver" in window) {
|
|
1255
|
+
this.#contentObserver = new ResizeObserver(this.#boundReposition);
|
|
1256
|
+
this.#contentObserver.observe(this);
|
|
1257
|
+
}
|
|
1212
1258
|
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1259
|
+
this.#mutationObserver = new MutationObserver(this.#boundReposition);
|
|
1260
|
+
this.#mutationObserver.observe(this, {
|
|
1261
|
+
childList: true,
|
|
1262
|
+
subtree: true,
|
|
1263
|
+
characterData: true,
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1219
1266
|
|
|
1220
1267
|
window.addEventListener("resize", this.#boundReposition);
|
|
1221
1268
|
window.addEventListener("scroll", this.#boundScroll, true);
|
|
@@ -1246,10 +1293,141 @@ class FigPopup extends HTMLDialogElement {
|
|
|
1246
1293
|
if (!(target instanceof Node)) return;
|
|
1247
1294
|
if (this.contains(target)) return;
|
|
1248
1295
|
|
|
1296
|
+
const anchor = this.#resolveAnchor();
|
|
1297
|
+
if (anchor && anchor.contains(target)) return;
|
|
1298
|
+
|
|
1299
|
+
if (this.#isInsideDescendantPopup(target)) return;
|
|
1300
|
+
|
|
1249
1301
|
this.open = false;
|
|
1250
1302
|
}
|
|
1251
1303
|
|
|
1304
|
+
#isInsideDescendantPopup(target) {
|
|
1305
|
+
const targetDialog = target.closest?.('dialog[is="fig-popup"]');
|
|
1306
|
+
if (!targetDialog || targetDialog === this) return false;
|
|
1307
|
+
|
|
1308
|
+
let current = targetDialog;
|
|
1309
|
+
const visited = new Set();
|
|
1310
|
+
while (current && !visited.has(current)) {
|
|
1311
|
+
visited.add(current);
|
|
1312
|
+
const popupAnchor = current.anchor;
|
|
1313
|
+
if (!(popupAnchor instanceof Element)) break;
|
|
1314
|
+
if (this.contains(popupAnchor)) return true;
|
|
1315
|
+
current = popupAnchor.closest?.('dialog[is="fig-popup"]');
|
|
1316
|
+
}
|
|
1317
|
+
return false;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
// ---- Drag support ----
|
|
1321
|
+
|
|
1322
|
+
#setupDragListeners() {
|
|
1323
|
+
if (this.drag) {
|
|
1324
|
+
this.addEventListener("pointerdown", this.#boundPointerDown);
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
#removeDragListeners() {
|
|
1329
|
+
this.removeEventListener("pointerdown", this.#boundPointerDown);
|
|
1330
|
+
document.removeEventListener("pointermove", this.#boundPointerMove);
|
|
1331
|
+
document.removeEventListener("pointerup", this.#boundPointerUp);
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
#isInteractiveElement(element) {
|
|
1335
|
+
const interactiveSelectors = [
|
|
1336
|
+
"input", "button", "select", "textarea", "a",
|
|
1337
|
+
"label", "details", "summary",
|
|
1338
|
+
'[contenteditable="true"]', "[tabindex]",
|
|
1339
|
+
];
|
|
1340
|
+
|
|
1341
|
+
const nonInteractiveFigElements = [
|
|
1342
|
+
"FIG-HEADER", "FIG-DIALOG", "FIG-POPUP", "FIG-FIELD",
|
|
1343
|
+
"FIG-TOOLTIP", "FIG-CONTENT", "FIG-TABS", "FIG-TAB",
|
|
1344
|
+
"FIG-POPOVER", "FIG-SHIMMER", "FIG-LAYER", "FIG-FILL-PICKER",
|
|
1345
|
+
];
|
|
1346
|
+
|
|
1347
|
+
const isInteractive = (el) =>
|
|
1348
|
+
interactiveSelectors.some((s) => el.matches?.(s)) ||
|
|
1349
|
+
(el.tagName?.startsWith("FIG-") &&
|
|
1350
|
+
!nonInteractiveFigElements.includes(el.tagName));
|
|
1351
|
+
|
|
1352
|
+
if (isInteractive(element)) return true;
|
|
1353
|
+
|
|
1354
|
+
let parent = element.parentElement;
|
|
1355
|
+
while (parent && parent !== this) {
|
|
1356
|
+
if (isInteractive(parent)) return true;
|
|
1357
|
+
parent = parent.parentElement;
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
return false;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
#handlePointerDown(e) {
|
|
1364
|
+
if (!this.drag) return;
|
|
1365
|
+
if (this.#isInteractiveElement(e.target)) return;
|
|
1366
|
+
|
|
1367
|
+
const handleSelector = this.getAttribute("handle");
|
|
1368
|
+
if (handleSelector && handleSelector.trim()) {
|
|
1369
|
+
const handleEl = this.querySelector(handleSelector);
|
|
1370
|
+
if (!handleEl || !handleEl.contains(e.target)) return;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
this.#dragPending = true;
|
|
1374
|
+
this.#dragStartPos.x = e.clientX;
|
|
1375
|
+
this.#dragStartPos.y = e.clientY;
|
|
1376
|
+
|
|
1377
|
+
const rect = this.getBoundingClientRect();
|
|
1378
|
+
this.#dragOffset.x = e.clientX - rect.left;
|
|
1379
|
+
this.#dragOffset.y = e.clientY - rect.top;
|
|
1380
|
+
|
|
1381
|
+
document.addEventListener("pointermove", this.#boundPointerMove);
|
|
1382
|
+
document.addEventListener("pointerup", this.#boundPointerUp);
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
#handlePointerMove(e) {
|
|
1386
|
+
if (this.#dragPending && !this.#isDragging) {
|
|
1387
|
+
const dx = Math.abs(e.clientX - this.#dragStartPos.x);
|
|
1388
|
+
const dy = Math.abs(e.clientY - this.#dragStartPos.y);
|
|
1389
|
+
|
|
1390
|
+
if (dx > this.#dragThreshold || dy > this.#dragThreshold) {
|
|
1391
|
+
this.#isDragging = true;
|
|
1392
|
+
this.#dragPending = false;
|
|
1393
|
+
this.setPointerCapture(e.pointerId);
|
|
1394
|
+
this.style.cursor = "grabbing";
|
|
1395
|
+
|
|
1396
|
+
const rect = this.getBoundingClientRect();
|
|
1397
|
+
this.style.top = `${rect.top}px`;
|
|
1398
|
+
this.style.left = `${rect.left}px`;
|
|
1399
|
+
this.style.bottom = "auto";
|
|
1400
|
+
this.style.right = "auto";
|
|
1401
|
+
this.style.margin = "0";
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
if (!this.#isDragging) return;
|
|
1406
|
+
|
|
1407
|
+
this.style.left = `${e.clientX - this.#dragOffset.x}px`;
|
|
1408
|
+
this.style.top = `${e.clientY - this.#dragOffset.y}px`;
|
|
1409
|
+
e.preventDefault();
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
#handlePointerUp(e) {
|
|
1413
|
+
if (this.#isDragging) {
|
|
1414
|
+
this.releasePointerCapture(e.pointerId);
|
|
1415
|
+
this.style.cursor = "";
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
this.#isDragging = false;
|
|
1419
|
+
this.#dragPending = false;
|
|
1420
|
+
|
|
1421
|
+
document.removeEventListener("pointermove", this.#boundPointerMove);
|
|
1422
|
+
document.removeEventListener("pointerup", this.#boundPointerUp);
|
|
1423
|
+
e.preventDefault();
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
// ---- Anchor resolution ----
|
|
1427
|
+
|
|
1252
1428
|
#resolveAnchor() {
|
|
1429
|
+
if (this.#anchorRef) return this.#anchorRef;
|
|
1430
|
+
|
|
1253
1431
|
const selector = this.getAttribute("anchor");
|
|
1254
1432
|
if (!selector) return null;
|
|
1255
1433
|
|
|
@@ -1360,21 +1538,49 @@ class FigPopup extends HTMLDialogElement {
|
|
|
1360
1538
|
};
|
|
1361
1539
|
}
|
|
1362
1540
|
|
|
1363
|
-
#
|
|
1364
|
-
const
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1541
|
+
#getPlacementCandidates(vertical, horizontal, shorthand) {
|
|
1542
|
+
const opp = { top: "bottom", bottom: "top", left: "right", right: "left", center: "center" };
|
|
1543
|
+
|
|
1544
|
+
if (shorthand) {
|
|
1545
|
+
const perp = (shorthand === "left" || shorthand === "right")
|
|
1546
|
+
? ["top", "bottom"]
|
|
1547
|
+
: ["left", "right"];
|
|
1548
|
+
return [
|
|
1549
|
+
{ v: vertical, h: horizontal, s: shorthand },
|
|
1550
|
+
{ v: vertical, h: horizontal, s: opp[shorthand] },
|
|
1551
|
+
{ v: vertical, h: horizontal, s: perp[0] },
|
|
1552
|
+
{ v: vertical, h: horizontal, s: perp[1] },
|
|
1553
|
+
];
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
if (vertical === "center") {
|
|
1557
|
+
return [
|
|
1558
|
+
{ v: "center", h: horizontal, s: null },
|
|
1559
|
+
{ v: "center", h: opp[horizontal], s: null },
|
|
1560
|
+
{ v: "top", h: horizontal, s: null },
|
|
1561
|
+
{ v: "bottom", h: horizontal, s: null },
|
|
1562
|
+
{ v: "top", h: opp[horizontal], s: null },
|
|
1563
|
+
{ v: "bottom", h: opp[horizontal], s: null },
|
|
1564
|
+
];
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
if (horizontal === "center") {
|
|
1568
|
+
return [
|
|
1569
|
+
{ v: vertical, h: "center", s: null },
|
|
1570
|
+
{ v: opp[vertical], h: "center", s: null },
|
|
1571
|
+
{ v: vertical, h: "left", s: null },
|
|
1572
|
+
{ v: vertical, h: "right", s: null },
|
|
1573
|
+
{ v: opp[vertical], h: "left", s: null },
|
|
1574
|
+
{ v: opp[vertical], h: "right", s: null },
|
|
1575
|
+
];
|
|
1576
|
+
}
|
|
1374
1577
|
|
|
1375
|
-
return
|
|
1376
|
-
|
|
1377
|
-
:
|
|
1578
|
+
return [
|
|
1579
|
+
{ v: vertical, h: horizontal, s: null },
|
|
1580
|
+
{ v: opp[vertical], h: horizontal, s: null },
|
|
1581
|
+
{ v: vertical, h: opp[horizontal], s: null },
|
|
1582
|
+
{ v: opp[vertical], h: opp[horizontal], s: null },
|
|
1583
|
+
];
|
|
1378
1584
|
}
|
|
1379
1585
|
|
|
1380
1586
|
#computeCoords(anchorRect, popupRect, vertical, horizontal, offset, shorthand) {
|
|
@@ -1417,12 +1623,24 @@ class FigPopup extends HTMLDialogElement {
|
|
|
1417
1623
|
top = anchorRect.top + (anchorRect.height - popupRect.height) / 2;
|
|
1418
1624
|
}
|
|
1419
1625
|
|
|
1420
|
-
if (
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1626
|
+
if (vertical === "center") {
|
|
1627
|
+
// Side placement: popup beside the anchor
|
|
1628
|
+
if (horizontal === "left") {
|
|
1629
|
+
left = anchorRect.left - popupRect.width - offset.xPx;
|
|
1630
|
+
} else if (horizontal === "right") {
|
|
1631
|
+
left = anchorRect.right + offset.xPx;
|
|
1632
|
+
} else {
|
|
1633
|
+
left = anchorRect.left + (anchorRect.width - popupRect.width) / 2;
|
|
1634
|
+
}
|
|
1424
1635
|
} else {
|
|
1425
|
-
|
|
1636
|
+
// Edge alignment: popup above/below, aligned to anchor edge
|
|
1637
|
+
if (horizontal === "left") {
|
|
1638
|
+
left = anchorRect.left + offset.xPx;
|
|
1639
|
+
} else if (horizontal === "right") {
|
|
1640
|
+
left = anchorRect.right - popupRect.width - offset.xPx;
|
|
1641
|
+
} else {
|
|
1642
|
+
left = anchorRect.left + (anchorRect.width - popupRect.width) / 2;
|
|
1643
|
+
}
|
|
1426
1644
|
}
|
|
1427
1645
|
|
|
1428
1646
|
return { top, left };
|
|
@@ -1516,8 +1734,6 @@ class FigPopup extends HTMLDialogElement {
|
|
|
1516
1734
|
const popupRect = this.getBoundingClientRect();
|
|
1517
1735
|
const offset = this.#parseOffset();
|
|
1518
1736
|
const { vertical, horizontal, shorthand } = this.#parsePosition();
|
|
1519
|
-
const verticalOrder = this.#getOrder(vertical, "vertical");
|
|
1520
|
-
const horizontalOrder = this.#getOrder(horizontal, "horizontal");
|
|
1521
1737
|
const anchor = this.#resolveAnchor();
|
|
1522
1738
|
|
|
1523
1739
|
if (!anchor) {
|
|
@@ -1533,52 +1749,32 @@ class FigPopup extends HTMLDialogElement {
|
|
|
1533
1749
|
}
|
|
1534
1750
|
|
|
1535
1751
|
const anchorRect = anchor.getBoundingClientRect();
|
|
1752
|
+
const candidates = this.#getPlacementCandidates(vertical, horizontal, shorthand);
|
|
1536
1753
|
let best = null;
|
|
1537
1754
|
let bestSide = "top";
|
|
1538
1755
|
let bestScore = Number.POSITIVE_INFINITY;
|
|
1539
1756
|
|
|
1540
|
-
for (const v of
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
this.#updatePopoverBeak(
|
|
1555
|
-
anchorRect,
|
|
1556
|
-
popupRect,
|
|
1557
|
-
coords.left,
|
|
1558
|
-
coords.top,
|
|
1559
|
-
placementSide
|
|
1560
|
-
);
|
|
1561
|
-
return;
|
|
1562
|
-
}
|
|
1563
|
-
const score = this.#overflowScore(coords, popupRect);
|
|
1564
|
-
if (score < bestScore) {
|
|
1565
|
-
bestScore = score;
|
|
1566
|
-
best = coords;
|
|
1567
|
-
bestSide = placementSide;
|
|
1568
|
-
}
|
|
1757
|
+
for (const { v, h, s } of candidates) {
|
|
1758
|
+
const coords = this.#computeCoords(anchorRect, popupRect, v, h, offset, s);
|
|
1759
|
+
const placementSide = this.#getPlacementSide(v, h, s);
|
|
1760
|
+
if (this.#fits(coords, popupRect)) {
|
|
1761
|
+
this.style.left = `${coords.left}px`;
|
|
1762
|
+
this.style.top = `${coords.top}px`;
|
|
1763
|
+
this.#updatePopoverBeak(anchorRect, popupRect, coords.left, coords.top, placementSide);
|
|
1764
|
+
return;
|
|
1765
|
+
}
|
|
1766
|
+
const score = this.#overflowScore(coords, popupRect);
|
|
1767
|
+
if (score < bestScore) {
|
|
1768
|
+
bestScore = score;
|
|
1769
|
+
best = coords;
|
|
1770
|
+
bestSide = placementSide;
|
|
1569
1771
|
}
|
|
1570
1772
|
}
|
|
1571
1773
|
|
|
1572
1774
|
const clamped = this.#clamp(best || { left: 0, top: 0 }, popupRect);
|
|
1573
1775
|
this.style.left = `${clamped.left}px`;
|
|
1574
1776
|
this.style.top = `${clamped.top}px`;
|
|
1575
|
-
this.#updatePopoverBeak(
|
|
1576
|
-
anchorRect,
|
|
1577
|
-
popupRect,
|
|
1578
|
-
clamped.left,
|
|
1579
|
-
clamped.top,
|
|
1580
|
-
bestSide
|
|
1581
|
-
);
|
|
1777
|
+
this.#updatePopoverBeak(anchorRect, popupRect, clamped.left, clamped.top, bestSide);
|
|
1582
1778
|
}
|
|
1583
1779
|
|
|
1584
1780
|
#queueReposition() {
|
|
@@ -3173,6 +3369,8 @@ class FigInputColor extends HTMLElement {
|
|
|
3173
3369
|
const showAlpha = this.getAttribute("alpha") === "true";
|
|
3174
3370
|
const experimental = this.getAttribute("experimental");
|
|
3175
3371
|
const expAttr = experimental ? `experimental="${experimental}"` : "";
|
|
3372
|
+
const dialogPos = this.getAttribute("dialog-position") || "left";
|
|
3373
|
+
const dialogPosAttr = `dialog-position="${dialogPos}"`;
|
|
3176
3374
|
|
|
3177
3375
|
let html = ``;
|
|
3178
3376
|
if (this.getAttribute("text")) {
|
|
@@ -3197,7 +3395,7 @@ class FigInputColor extends HTMLElement {
|
|
|
3197
3395
|
let swatchElement = "";
|
|
3198
3396
|
if (!hidePicker) {
|
|
3199
3397
|
swatchElement = useFigmaPicker
|
|
3200
|
-
? `<fig-fill-picker mode="solid" ${expAttr} ${
|
|
3398
|
+
? `<fig-fill-picker mode="solid" ${dialogPosAttr} ${expAttr} ${
|
|
3201
3399
|
showAlpha ? "" : 'alpha="false"'
|
|
3202
3400
|
} value='{"type":"solid","color":"${this.hexOpaque}","opacity":${
|
|
3203
3401
|
this.alpha
|
|
@@ -3215,7 +3413,7 @@ class FigInputColor extends HTMLElement {
|
|
|
3215
3413
|
html = ``;
|
|
3216
3414
|
} else {
|
|
3217
3415
|
html = useFigmaPicker
|
|
3218
|
-
? `<fig-fill-picker mode="solid" ${expAttr} ${
|
|
3416
|
+
? `<fig-fill-picker mode="solid" ${dialogPosAttr} ${expAttr} ${
|
|
3219
3417
|
showAlpha ? "" : 'alpha="false"'
|
|
3220
3418
|
} value='{"type":"solid","color":"${this.hexOpaque}","opacity":${
|
|
3221
3419
|
this.alpha
|
|
@@ -3407,7 +3605,7 @@ class FigInputColor extends HTMLElement {
|
|
|
3407
3605
|
}
|
|
3408
3606
|
|
|
3409
3607
|
static get observedAttributes() {
|
|
3410
|
-
return ["value", "style", "mode", "picker", "experimental"];
|
|
3608
|
+
return ["value", "style", "mode", "picker", "experimental", "dialog-position"];
|
|
3411
3609
|
}
|
|
3412
3610
|
|
|
3413
3611
|
get mode() {
|
|
@@ -3743,7 +3941,7 @@ class FigInputFill extends HTMLElement {
|
|
|
3743
3941
|
const experimentalAttr = this.getAttribute("experimental");
|
|
3744
3942
|
this.innerHTML = `
|
|
3745
3943
|
<div class="input-combo">
|
|
3746
|
-
<fig-fill-picker value='${fillPickerValue}' ${
|
|
3944
|
+
<fig-fill-picker dialog-position="left" value='${fillPickerValue}' ${
|
|
3747
3945
|
disabled ? "disabled" : ""
|
|
3748
3946
|
} ${modeAttr ? `mode="${modeAttr}"` : ""} ${experimentalAttr ? `experimental="${experimentalAttr}"` : ""}></fig-fill-picker>
|
|
3749
3947
|
${controlsHtml}
|
|
@@ -6007,7 +6205,7 @@ customElements.define("fig-layer", FigLayer);
|
|
|
6007
6205
|
* @attr {string} value - JSON-encoded fill value
|
|
6008
6206
|
* @attr {boolean} disabled - Whether the picker is disabled
|
|
6009
6207
|
* @attr {boolean} alpha - Whether to show alpha/opacity controls (default: true)
|
|
6010
|
-
* @attr {string} dialog-position - Position of the
|
|
6208
|
+
* @attr {string} dialog-position - Position of the popup (default: "left")
|
|
6011
6209
|
*/
|
|
6012
6210
|
class FigFillPicker extends HTMLElement {
|
|
6013
6211
|
#trigger = null;
|
|
@@ -6213,21 +6411,10 @@ class FigFillPicker extends HTMLElement {
|
|
|
6213
6411
|
this.#createDialog();
|
|
6214
6412
|
}
|
|
6215
6413
|
|
|
6216
|
-
// Position off-screen first to prevent scroll jump
|
|
6217
|
-
this.#dialog.style.position = "fixed";
|
|
6218
|
-
this.#dialog.style.top = "-9999px";
|
|
6219
|
-
this.#dialog.style.left = "-9999px";
|
|
6220
|
-
|
|
6221
|
-
this.#dialog.show();
|
|
6222
6414
|
this.#switchTab(this.#fillType);
|
|
6415
|
+
this.#dialog.open = true;
|
|
6223
6416
|
|
|
6224
|
-
// Position after dialog has rendered and has dimensions
|
|
6225
|
-
// Use nested RAF to ensure canvas is fully ready for drawing
|
|
6226
6417
|
requestAnimationFrame(() => {
|
|
6227
|
-
this.#positionDialog();
|
|
6228
|
-
this.#dialog.setAttribute("closedby", "any");
|
|
6229
|
-
|
|
6230
|
-
// Second RAF ensures the dialog is visible and canvas is ready
|
|
6231
6418
|
requestAnimationFrame(() => {
|
|
6232
6419
|
this.#drawColorArea();
|
|
6233
6420
|
this.#updateHandlePosition();
|
|
@@ -6235,72 +6422,17 @@ class FigFillPicker extends HTMLElement {
|
|
|
6235
6422
|
});
|
|
6236
6423
|
}
|
|
6237
6424
|
|
|
6238
|
-
#positionDialog() {
|
|
6239
|
-
const triggerRect = this.#trigger.getBoundingClientRect();
|
|
6240
|
-
const dialogRect = this.#dialog.getBoundingClientRect();
|
|
6241
|
-
const padding = 8; // Gap between trigger and dialog
|
|
6242
|
-
const viewportPadding = 16; // Min distance from viewport edges
|
|
6243
|
-
|
|
6244
|
-
// Calculate available space in each direction
|
|
6245
|
-
const spaceBelow =
|
|
6246
|
-
window.innerHeight - triggerRect.bottom - viewportPadding;
|
|
6247
|
-
const spaceAbove = triggerRect.top - viewportPadding;
|
|
6248
|
-
const spaceRight = window.innerWidth - triggerRect.left - viewportPadding;
|
|
6249
|
-
const spaceLeft = triggerRect.right - viewportPadding;
|
|
6250
|
-
|
|
6251
|
-
let top, left;
|
|
6252
|
-
|
|
6253
|
-
// Vertical positioning: prefer below, fallback to above
|
|
6254
|
-
if (spaceBelow >= dialogRect.height || spaceBelow >= spaceAbove) {
|
|
6255
|
-
// Position below trigger
|
|
6256
|
-
top = triggerRect.bottom + padding;
|
|
6257
|
-
} else {
|
|
6258
|
-
// Position above trigger
|
|
6259
|
-
top = triggerRect.top - dialogRect.height - padding;
|
|
6260
|
-
}
|
|
6261
|
-
|
|
6262
|
-
// Horizontal positioning: align left edge with trigger, adjust if needed
|
|
6263
|
-
left = triggerRect.left;
|
|
6264
|
-
|
|
6265
|
-
// Adjust if dialog would go off right edge
|
|
6266
|
-
if (left + dialogRect.width > window.innerWidth - viewportPadding) {
|
|
6267
|
-
left = window.innerWidth - dialogRect.width - viewportPadding;
|
|
6268
|
-
}
|
|
6269
|
-
|
|
6270
|
-
// Adjust if dialog would go off left edge
|
|
6271
|
-
if (left < viewportPadding) {
|
|
6272
|
-
left = viewportPadding;
|
|
6273
|
-
}
|
|
6274
|
-
|
|
6275
|
-
// Clamp vertical position to viewport
|
|
6276
|
-
if (top < viewportPadding) {
|
|
6277
|
-
top = viewportPadding;
|
|
6278
|
-
}
|
|
6279
|
-
if (top + dialogRect.height > window.innerHeight - viewportPadding) {
|
|
6280
|
-
top = window.innerHeight - dialogRect.height - viewportPadding;
|
|
6281
|
-
}
|
|
6282
|
-
|
|
6283
|
-
// Apply position (override fig-dialog's default positioning)
|
|
6284
|
-
this.#dialog.style.position = "fixed";
|
|
6285
|
-
this.#dialog.style.top = `${top}px`;
|
|
6286
|
-
this.#dialog.style.left = `${left}px`;
|
|
6287
|
-
this.#dialog.style.bottom = "auto";
|
|
6288
|
-
this.#dialog.style.right = "auto";
|
|
6289
|
-
this.#dialog.style.margin = "0";
|
|
6290
|
-
}
|
|
6291
|
-
|
|
6292
6425
|
#createDialog() {
|
|
6293
|
-
this.#dialog = document.createElement("dialog", { is: "fig-
|
|
6294
|
-
this.#dialog.setAttribute("is", "fig-
|
|
6426
|
+
this.#dialog = document.createElement("dialog", { is: "fig-popup" });
|
|
6427
|
+
this.#dialog.setAttribute("is", "fig-popup");
|
|
6295
6428
|
this.#dialog.setAttribute("drag", "true");
|
|
6296
6429
|
this.#dialog.setAttribute("handle", "fig-header");
|
|
6430
|
+
this.#dialog.setAttribute("autoresize", "false");
|
|
6297
6431
|
this.#dialog.classList.add("fig-fill-picker-dialog");
|
|
6298
6432
|
|
|
6299
|
-
|
|
6300
|
-
const dialogPosition = this.getAttribute("dialog-position");
|
|
6301
|
-
|
|
6302
|
-
this.#dialog.setAttribute("position", dialogPosition);
|
|
6303
|
-
}
|
|
6433
|
+
this.#dialog.anchor = this.#trigger;
|
|
6434
|
+
const dialogPosition = this.getAttribute("dialog-position") || "left";
|
|
6435
|
+
this.#dialog.setAttribute("position", dialogPosition);
|
|
6304
6436
|
|
|
6305
6437
|
// Check for allowed modes (supports comma-separated values like "solid,gradient")
|
|
6306
6438
|
const mode = this.getAttribute("mode");
|
|
@@ -6333,7 +6465,7 @@ class FigFillPicker extends HTMLElement {
|
|
|
6333
6465
|
|
|
6334
6466
|
let headerContent;
|
|
6335
6467
|
if (allowedModes.length === 1) {
|
|
6336
|
-
headerContent = `<
|
|
6468
|
+
headerContent = `<h3 class="fig-fill-picker-type-label">${modeLabels[allowedModes[0]]}</h3>`;
|
|
6337
6469
|
} else {
|
|
6338
6470
|
const options = allowedModes
|
|
6339
6471
|
.map((m) => `<option value="${m}">${modeLabels[m]}</option>`)
|
|
@@ -6346,7 +6478,7 @@ class FigFillPicker extends HTMLElement {
|
|
|
6346
6478
|
this.#dialog.innerHTML = `
|
|
6347
6479
|
<fig-header>
|
|
6348
6480
|
${headerContent}
|
|
6349
|
-
<fig-button icon variant="ghost" close
|
|
6481
|
+
<fig-button icon variant="ghost" class="fig-fill-picker-close">
|
|
6350
6482
|
<span class="fig-mask-icon" style="--icon: var(--icon-close)"></span>
|
|
6351
6483
|
</fig-button>
|
|
6352
6484
|
</fig-header>
|
|
@@ -6369,11 +6501,10 @@ class FigFillPicker extends HTMLElement {
|
|
|
6369
6501
|
});
|
|
6370
6502
|
}
|
|
6371
6503
|
|
|
6372
|
-
// Close button
|
|
6373
6504
|
this.#dialog
|
|
6374
|
-
.querySelector("fig-
|
|
6505
|
+
.querySelector(".fig-fill-picker-close")
|
|
6375
6506
|
.addEventListener("click", () => {
|
|
6376
|
-
this.#dialog.
|
|
6507
|
+
this.#dialog.open = false;
|
|
6377
6508
|
});
|
|
6378
6509
|
|
|
6379
6510
|
// Emit change on close
|
|
@@ -6845,7 +6976,7 @@ class FigFillPicker extends HTMLElement {
|
|
|
6845
6976
|
<fig-input-number class="fig-fill-picker-stop-position" min="0" max="100" value="${
|
|
6846
6977
|
stop.position
|
|
6847
6978
|
}" units="%"></fig-input-number>
|
|
6848
|
-
<fig-input-color class="fig-fill-picker-stop-color" text="true" alpha="true" picker="figma" value="${
|
|
6979
|
+
<fig-input-color class="fig-fill-picker-stop-color" text="true" alpha="true" picker="figma" dialog-position="right" value="${
|
|
6849
6980
|
stop.color
|
|
6850
6981
|
}"></fig-input-color>
|
|
6851
6982
|
<fig-button icon variant="ghost" class="fig-fill-picker-stop-remove" ${
|
package/index.html
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
nav {
|
|
26
26
|
position: fixed;
|
|
27
|
-
width:
|
|
27
|
+
width: 240px;
|
|
28
28
|
height: 100vh;
|
|
29
29
|
overflow-y: auto;
|
|
30
30
|
background: var(--figma-color-bg-secondary);
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
main {
|
|
108
|
-
margin-left:
|
|
108
|
+
margin-left: 240px;
|
|
109
109
|
padding: 24px 32px;
|
|
110
110
|
max-width: 800px;
|
|
111
111
|
min-height: 100vh;
|
|
@@ -1806,6 +1806,13 @@
|
|
|
1806
1806
|
alpha="true"
|
|
1807
1807
|
picker="figma"></fig-input-color>
|
|
1808
1808
|
|
|
1809
|
+
<h4>Figma Picker (Experimental Modern)</h4>
|
|
1810
|
+
<fig-input-color value="#E84393"
|
|
1811
|
+
text="true"
|
|
1812
|
+
alpha="true"
|
|
1813
|
+
picker="figma"
|
|
1814
|
+
experimental="modern"></fig-input-color>
|
|
1815
|
+
|
|
1809
1816
|
<h4>No Picker (text input only)</h4>
|
|
1810
1817
|
<fig-input-color value="#9747FF"
|
|
1811
1818
|
text="true"
|
|
@@ -1995,6 +2002,10 @@
|
|
|
1995
2002
|
<h3>Webcam Fill</h3>
|
|
1996
2003
|
<fig-input-fill value='{"type":"webcam","webcam":{"opacity":1}}'></fig-input-fill>
|
|
1997
2004
|
|
|
2005
|
+
<h3>Experimental Modern</h3>
|
|
2006
|
+
<fig-input-fill experimental="modern"
|
|
2007
|
+
value='{"type":"solid","color":"#E84393","alpha":1}'></fig-input-fill>
|
|
2008
|
+
|
|
1998
2009
|
<h3>Disabled</h3>
|
|
1999
2010
|
<fig-input-fill disabled
|
|
2000
2011
|
value='{"type":"solid","color":"#AA96DA","alpha":1}'></fig-input-fill>
|
|
@@ -3109,6 +3120,28 @@
|
|
|
3109
3120
|
<dialog is="fig-popup" anchor="#popup-open-right-single" position="right" offset="12 8">
|
|
3110
3121
|
...
|
|
3111
3122
|
</dialog></code></pre>
|
|
3123
|
+
|
|
3124
|
+
<h4>Left (top edges aligned)</h4>
|
|
3125
|
+
<hstack>
|
|
3126
|
+
<fig-button id="popup-open-left-single">Open Left (single)</fig-button>
|
|
3127
|
+
<fig-button id="popup-close-left-single"
|
|
3128
|
+
variant="secondary">Close</fig-button>
|
|
3129
|
+
</hstack>
|
|
3130
|
+
<dialog id="popup-left-single"
|
|
3131
|
+
is="fig-popup"
|
|
3132
|
+
anchor="#popup-open-left-single"
|
|
3133
|
+
position="left"
|
|
3134
|
+
offset="12 8">
|
|
3135
|
+
<vstack style="min-width: 11rem;">
|
|
3136
|
+
<strong style="padding: 0 var(--spacer-1);">Left Shorthand</strong>
|
|
3137
|
+
<fig-input-text placeholder="position='left'"></fig-input-text>
|
|
3138
|
+
</vstack>
|
|
3139
|
+
</dialog>
|
|
3140
|
+
<pre><code><fig-button id="popup-open-left-single">Open Left (single)</fig-button>
|
|
3141
|
+
<dialog is="fig-popup" anchor="#popup-open-left-single" position="left" offset="12 8">
|
|
3142
|
+
...
|
|
3143
|
+
</dialog></code></pre>
|
|
3144
|
+
|
|
3112
3145
|
</section>
|
|
3113
3146
|
<hr>
|
|
3114
3147
|
|
|
@@ -4452,6 +4485,7 @@ button.addEventListener('click', () => {
|
|
|
4452
4485
|
['popup-open-center-left', 'popup-close-center-left', 'popup-center-left'],
|
|
4453
4486
|
['popup-open-top-single', 'popup-close-top-single', 'popup-top-single'],
|
|
4454
4487
|
['popup-open-right-single', 'popup-close-right-single', 'popup-right-single'],
|
|
4488
|
+
['popup-open-left-single', 'popup-close-left-single', 'popup-left-single'],
|
|
4455
4489
|
];
|
|
4456
4490
|
|
|
4457
4491
|
popupExamples.forEach(([openId, closeId, popupId]) => {
|
package/package.json
CHANGED