@node-projects/web-component-designer 0.1.320 → 0.1.323

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.
@@ -364,7 +364,7 @@ export function getResultingTransformationBetweenElementAndAllAncestors(node, an
364
364
  }
365
365
  let lastOffsetParent = null;
366
366
  while (actualElement != ancestor && actualElement != null) {
367
- const parentElement = getParentElementIncludingSlots(actualElement, iframes);
367
+ let parentElement = getParentElementIncludingSlots(actualElement, iframes);
368
368
  if (actualElement.assignedSlot != null) {
369
369
  const l = offsetTopLeftPolyfill(actualElement, 'offsetLeft');
370
370
  const t = offsetTopLeftPolyfill(actualElement, 'offsetTop');
@@ -372,7 +372,16 @@ export function getResultingTransformationBetweenElementAndAllAncestors(node, an
372
372
  originalElementAndAllParentsMultipliedMatrix = mvMat.multiplySelf(originalElementAndAllParentsMultipliedMatrix);
373
373
  }
374
374
  else {
375
- if ((actualElement instanceof HTMLElement || actualElement instanceof (actualElement.ownerDocument.defaultView ?? window).HTMLElement)) {
375
+ if (!(actualElement instanceof SVGSVGElement) && !(actualElement instanceof (actualElement.ownerDocument.defaultView ?? window).SVGSVGElement) &&
376
+ (actualElement instanceof SVGGraphicsElement || actualElement instanceof (actualElement.ownerDocument.defaultView ?? window).SVGGraphicsElement)) {
377
+ const ctm = actualElement.getCTM();
378
+ const bb = actualElement.getBBox();
379
+ const mvMat = new DOMMatrix().translateSelf(bb.x, bb.y);
380
+ originalElementAndAllParentsMultipliedMatrix = mvMat.multiplySelf(originalElementAndAllParentsMultipliedMatrix);
381
+ originalElementAndAllParentsMultipliedMatrix = new DOMMatrix([ctm.a, ctm.b, ctm.c, ctm.d, ctm.e, ctm.f]).multiplySelf(originalElementAndAllParentsMultipliedMatrix);
382
+ parentElement = actualElement.ownerSVGElement;
383
+ }
384
+ else if ((actualElement instanceof HTMLElement || actualElement instanceof (actualElement.ownerDocument.defaultView ?? window).HTMLElement)) {
376
385
  if (lastOffsetParent !== actualElement.offsetParent && !((actualElement instanceof HTMLSlotElement || actualElement instanceof (actualElement.ownerDocument.defaultView ?? window).HTMLSlotElement))) {
377
386
  const offsets = getElementOffsetsInContainer(actualElement, actualElement !== node, iframes);
378
387
  lastOffsetParent = actualElement.offsetParent;
@@ -411,6 +420,130 @@ export function getResultingTransformationBetweenElementAndAllAncestors(node, an
411
420
  }
412
421
  return originalElementAndAllParentsMultipliedMatrix;
413
422
  }
423
+ /*
424
+ getResultingTransformationBetweenElementAndAllAncestors -> but with extra layout matrix (does not work yet....)
425
+
426
+ export function getResultingTransformationBetweenElementAndAllAncestors(node, ancestor, iframes) {
427
+ let key;
428
+ if (transformCache) {
429
+ let i1 = hash.get(node);
430
+ if (i1 === undefined)
431
+ hash.set(node, i1 = hashId++);
432
+ let i2 = hash.get(ancestor);
433
+ if (i2 === undefined)
434
+ hash.set(ancestor, i2 = hashId++);
435
+ key = i1 + '_' + i2;
436
+ const q = transformCache.get(key);
437
+ if (q)
438
+ return q;
439
+ }
440
+
441
+ // NEW — two matrices instead of one
442
+ let layoutMatrix = new DOMMatrix();
443
+
444
+ let actualElement = node;
445
+
446
+ let transformMatrix = getElementCombinedTransform(actualElement, iframes); //.multiplySelf(transformMatrix);
447
+
448
+
449
+ const perspectiveParent = getParentElementIncludingSlots(actualElement, iframes);
450
+ if (perspectiveParent) {
451
+ const s = getCachedComputedStyle(perspectiveParent);
452
+ if (s.transformStyle !== "preserve-3d")
453
+ projectTo2D(transformMatrix);
454
+ }
455
+
456
+
457
+ let lastOffsetParent = null;
458
+
459
+ while (actualElement !== ancestor && actualElement != null) {
460
+
461
+ const parentElement = getParentElementIncludingSlots(actualElement, iframes);
462
+
463
+ // ------------------------
464
+ // LAYOUT MATRIX (offsets)
465
+ // ------------------------
466
+
467
+ if (actualElement.assignedSlot != null) {
468
+
469
+ const l = offsetTopLeftPolyfill(actualElement, "offsetLeft");
470
+ const t = offsetTopLeftPolyfill(actualElement, "offsetTop");
471
+ layoutMatrix = new DOMMatrix().translateSelf(l, t).multiplySelf(layoutMatrix);
472
+
473
+ } else {
474
+
475
+ if (actualElement instanceof HTMLElement ||
476
+ actualElement instanceof (actualElement.ownerDocument.defaultView ?? window).HTMLElement) {
477
+
478
+ if (lastOffsetParent !== actualElement.offsetParent &&
479
+ !(actualElement instanceof HTMLSlotElement)) {
480
+
481
+ const offsets = getElementOffsetsInContainer(actualElement, actualElement !== node, iframes);
482
+ lastOffsetParent = actualElement.offsetParent;
483
+
484
+ layoutMatrix = new DOMMatrix().translateSelf(offsets.x, offsets.y).multiplySelf(layoutMatrix);
485
+ }
486
+
487
+ } else {
488
+
489
+ const offsets = getElementOffsetsInContainer(actualElement, actualElement !== node, iframes);
490
+ lastOffsetParent = null;
491
+
492
+ layoutMatrix = new DOMMatrix().translateSelf(offsets.x, offsets.y).multiplySelf(layoutMatrix);
493
+ }
494
+ }
495
+
496
+ // ------------------------
497
+ // TRANSFORM MATRIX (CSS)
498
+ // ------------------------
499
+
500
+ if (parentElement) {
501
+
502
+ // NEW — only affects transform pipeline
503
+ const parentTransform = getElementCombinedTransform(parentElement, iframes);
504
+ transformMatrix = parentTransform.multiply(transformMatrix);
505
+
506
+ // flattening boundary
507
+ const perspectiveParent = getParentElementIncludingSlots(parentElement, iframes);
508
+ if (perspectiveParent) {
509
+ const s = getCachedComputedStyle(perspectiveParent);
510
+ if (s.transformStyle !== "preserve-3d")
511
+ projectTo2D(transformMatrix);
512
+ }
513
+
514
+ // ------------------------
515
+ // EXIT CONDITION
516
+ // ------------------------
517
+
518
+ if (parentElement === ancestor) {
519
+
520
+ // NEW — scroll offsets belong to layout
521
+ if (parentElement.scrollTop || parentElement.scrollLeft) {
522
+ layoutMatrix = new DOMMatrix()
523
+ .translate(-parentElement.scrollLeft, -parentElement.scrollTop)
524
+ .multiply(layoutMatrix);
525
+ }
526
+
527
+ const result = layoutMatrix.multiply(transformMatrix);
528
+
529
+ if (transformCache)
530
+ transformCache.set(key, result);
531
+
532
+ return result;
533
+ }
534
+ }
535
+
536
+ actualElement = parentElement;
537
+ }
538
+
539
+ const result = layoutMatrix.multiply(transformMatrix);
540
+
541
+ if (transformCache)
542
+ transformCache.set(key, result);
543
+
544
+ return result;
545
+ }
546
+ */
414
547
  /**
415
548
  * @param {Node} node
416
549
  * @param {HTMLIFrameElement[]} iframes
@@ -447,7 +580,7 @@ export function getElementCombinedTransform(element, iframes) {
447
580
  const originX = parseFloat(origin[0]);
448
581
  const originY = parseFloat(origin[1]);
449
582
  const originZ = origin[2] ? parseFloat(origin[2]) : 0;
450
- const mOri = new DOMMatrix().translate(originX, originY, originZ);
583
+ const mOri = new DOMMatrix().translateSelf(originX, originY, originZ);
451
584
  if (s.translate != 'none' && s.translate) {
452
585
  let tr = s.translate;
453
586
  if (tr.includes('%')) {
@@ -467,17 +600,17 @@ export function getElementCombinedTransform(element, iframes) {
467
600
  if (s.scale != 'none' && s.scale) {
468
601
  m.multiplySelf(new DOMMatrix('scale(' + s.scale.replaceAll(' ', ',') + ')'));
469
602
  }
470
- if (s.transform != 'none' && s.transform) {
471
- m.multiplySelf(new DOMMatrix(s.transform));
472
- }
473
- m = mOri.multiply(m.multiply(mOri.inverse()));
474
603
  if (s.offsetPath && s.offsetPath !== 'none') {
475
604
  m.multiplySelf(computeOffsetTransformMatrix(element));
476
605
  }
606
+ if (s.transform != 'none' && s.transform) {
607
+ m.multiplySelf(new DOMMatrix(s.transform));
608
+ }
609
+ m = mOri.multiply(m.multiplySelf(mOri.inverse()));
477
610
  //@ts-ignore
478
611
  const pt = getElementPerspectiveTransform(element, iframes);
479
612
  if (pt != null) {
480
- m = pt.multiply(m);
613
+ m = pt.multiplySelf(m);
481
614
  }
482
615
  return m;
483
616
  }
@@ -531,9 +664,9 @@ function getElementPerspectiveTransform(element, iframes) {
531
664
  const origin = s.perspectiveOrigin.split(' ');
532
665
  const originX = parseFloat(origin[0]) - element.offsetLeft;
533
666
  const originY = parseFloat(origin[1]) - element.offsetTop;
534
- const mOri = new DOMMatrix().translate(originX, originY);
535
- const mOriInv = new DOMMatrix().translate(-originX, -originY);
536
- return mOri.multiply(m.multiply(mOriInv));
667
+ const mOri = new DOMMatrix().translateSelf(originX, originY);
668
+ const mOriInv = new DOMMatrix().translateSelf(-originX, -originY);
669
+ return mOri.multiplySelf(m.multiplySelf(mOriInv));
537
670
  }
538
671
  }
539
672
  }
@@ -634,7 +767,7 @@ function computeOffsetPathPoint(elem, offsetPath, distNorm) {
634
767
  if (value.startsWith("ellipse("))
635
768
  return computeEllipse(value, distNorm);
636
769
  if (value.startsWith("inset("))
637
- return computeInset(value, distNorm);
770
+ return computeInset(value, elem, distNorm);
638
771
  if (value.startsWith("rect("))
639
772
  return computeRect(value, distNorm);
640
773
  if (value.startsWith("xywh("))
@@ -709,12 +842,6 @@ function computeEllipse(str, t) {
709
842
  let tangentAngleDeg = Math.atan2(dy, dx) * 180 / Math.PI;
710
843
  return { x, y, angle: tangentAngleDeg };
711
844
  }
712
- function computeInset(str, t) {
713
- let m = str.match(/inset\(([^)]+)\)/);
714
- let nums = m[1].split(/\s+/).map(s => parseFloat(s));
715
- let top = nums[0], right = nums[1], bottom = nums[2], left = nums[3];
716
- return rectPath(top, left, right, bottom, t);
717
- }
718
845
  function computeRect(str, t) {
719
846
  let m = str.match(/rect\(([^)]+)\)/);
720
847
  let nums = m[1].split(/\s+/).map(s => parseFloat(s));
@@ -790,6 +917,236 @@ function rectPath(top, left, right, bottom, t) {
790
917
  let y = bottom - dist;
791
918
  return { x: left, y, angle: 270 };
792
919
  }
920
+ // normalized inset uses calc
921
+ function tokenizeCalc(input) {
922
+ let tokens = [];
923
+ let i = 0;
924
+ while (i < input.length) {
925
+ let ch = input[i];
926
+ if (/\s/.test(ch)) {
927
+ i++;
928
+ continue;
929
+ }
930
+ // operators & parentheses
931
+ if ("+-*/()".includes(ch)) {
932
+ tokens.push({ type: ch, value: ch });
933
+ i++;
934
+ continue;
935
+ }
936
+ // numbers or dimensions or %
937
+ if (/[0-9.]/.test(ch)) {
938
+ let start = i;
939
+ while (/[0-9.]/.test(input[i]))
940
+ i++;
941
+ let num = input.slice(start, i);
942
+ if (input[i] === "%") {
943
+ i++;
944
+ tokens.push({ type: "percentage", value: parseFloat(num) });
945
+ continue;
946
+ }
947
+ // only px supported
948
+ if (input.slice(i, i + 2) === "px") {
949
+ i += 2;
950
+ tokens.push({ type: "dimension", value: parseFloat(num), unit: "px" });
951
+ continue;
952
+ }
953
+ // plain number
954
+ tokens.push({ type: "number", value: parseFloat(num) });
955
+ continue;
956
+ }
957
+ // function name (calc)
958
+ if (/[a-zA-Z]/.test(ch)) {
959
+ let start = i;
960
+ while (/[a-zA-Z]/.test(input[i]))
961
+ i++;
962
+ let name = input.slice(start, i);
963
+ if (name === "calc" && input[i] === "(") {
964
+ tokens.push({ type: "func", value: "calc" });
965
+ continue;
966
+ }
967
+ throw new Error("Unsupported function: " + name);
968
+ }
969
+ throw new Error("Unexpected character in calc(): " + ch);
970
+ }
971
+ return tokens;
972
+ }
973
+ // normalized inset uses calc
974
+ function parseCalc(tokens) {
975
+ let i = 0;
976
+ function peek() { return tokens[i]; }
977
+ function consume() { return tokens[i++]; }
978
+ function parseExpression() {
979
+ let node = parseTerm();
980
+ while (peek() && (peek().type === "+" || peek().type === "-")) {
981
+ let op = consume().type;
982
+ let right = parseTerm();
983
+ node = { type: "binary", op, left: node, right };
984
+ }
985
+ return node;
986
+ }
987
+ function parseTerm() {
988
+ let node = parseFactor();
989
+ while (peek() && (peek().type === "*" || peek().type === "/")) {
990
+ let op = consume().type;
991
+ let right = parseFactor();
992
+ node = { type: "binary", op, left: node, right };
993
+ }
994
+ return node;
995
+ }
996
+ function parseFactor() {
997
+ let t = peek();
998
+ if (!t)
999
+ throw "Unexpected end in calc()";
1000
+ if (t.type === "number") {
1001
+ consume();
1002
+ return { type: "number", value: t.value };
1003
+ }
1004
+ if (t.type === "dimension") {
1005
+ consume();
1006
+ return { type: "dimension", value: t.value, unit: t.unit };
1007
+ }
1008
+ if (t.type === "percentage") {
1009
+ consume();
1010
+ return { type: "percentage", value: t.value };
1011
+ }
1012
+ if (t.type === "func") {
1013
+ consume(); // "calc"
1014
+ if (peek().type !== "(")
1015
+ throw "Expected '(' after calc";
1016
+ consume();
1017
+ let node = parseExpression();
1018
+ if (!peek() || peek().type !== ")")
1019
+ throw "Expected ')'";
1020
+ consume();
1021
+ return node;
1022
+ }
1023
+ if (t.type === "(") {
1024
+ consume();
1025
+ let node = parseExpression();
1026
+ if (!peek() || peek().type !== ")")
1027
+ throw "Expected ')'";
1028
+ consume();
1029
+ return node;
1030
+ }
1031
+ throw new Error("Unexpected calc token " + JSON.stringify(t));
1032
+ }
1033
+ let ast = parseExpression();
1034
+ if (i !== tokens.length)
1035
+ throw "Extra tokens after calc";
1036
+ return ast;
1037
+ }
1038
+ // normalized inset uses calc
1039
+ function evalCalc(ast, env) {
1040
+ switch (ast.type) {
1041
+ case "number":
1042
+ return ast.value;
1043
+ case "dimension":
1044
+ return ast.value; // px only → already a number
1045
+ case "percentage":
1046
+ return env.percentBase * (ast.value / 100);
1047
+ case "binary": {
1048
+ let l = evalCalc(ast.left, env);
1049
+ let r = evalCalc(ast.right, env);
1050
+ switch (ast.op) {
1051
+ case "+": return l + r;
1052
+ case "-": return l - r;
1053
+ case "*": return l * r;
1054
+ case "/": return l / r;
1055
+ }
1056
+ }
1057
+ }
1058
+ throw "Invalid AST node " + ast.type;
1059
+ }
1060
+ function resolveLength(expr, element) {
1061
+ expr = expr.trim();
1062
+ // Fast path: pure px
1063
+ if (/^[0-9.]+px$/.test(expr))
1064
+ return parseFloat(expr);
1065
+ // Pure %
1066
+ if (/^[0-9.]+%$/.test(expr)) {
1067
+ let p = parseFloat(expr);
1068
+ let base = element.offsetWidth; // <- width reference
1069
+ return base * (p / 100);
1070
+ }
1071
+ // calc(...) or mixed values
1072
+ const ast = parseCalc(tokenizeCalc(expr));
1073
+ return evalCalc(ast, {
1074
+ percentBase: element.offsetWidth
1075
+ });
1076
+ }
1077
+ function parseInsetArgs(str) {
1078
+ let inside = str.trim()
1079
+ .replace(/^inset\s*\(/, "")
1080
+ .replace(/\)\s*$/, "");
1081
+ let args = [];
1082
+ let current = "";
1083
+ let depth = 0;
1084
+ for (let i = 0; i < inside.length; i++) {
1085
+ let ch = inside[i];
1086
+ if (ch === "(") {
1087
+ depth++;
1088
+ current += ch;
1089
+ }
1090
+ else if (ch === ")") {
1091
+ depth--;
1092
+ current += ch;
1093
+ }
1094
+ else if (/\s/.test(ch) && depth === 0) {
1095
+ if (current.trim() !== "") {
1096
+ args.push(current.trim());
1097
+ current = "";
1098
+ }
1099
+ }
1100
+ else {
1101
+ current += ch;
1102
+ }
1103
+ }
1104
+ if (current.trim() !== "") {
1105
+ args.push(current.trim());
1106
+ }
1107
+ return args;
1108
+ }
1109
+ /**
1110
+ *
1111
+ * @param {string} str
1112
+ * @param {HTMLElement} element
1113
+ * @param {number} progress
1114
+ * @returns
1115
+ */
1116
+ function computeInset(str, element, progress) {
1117
+ const args = parseInsetArgs(str);
1118
+ if (args.length !== 4)
1119
+ throw new Error("inset() must have 4 arguments");
1120
+ const [topPx, rightPx, bottomPx, leftPx] = args.map(a => resolveLength(a, element));
1121
+ const w = element.offsetWidth;
1122
+ const h = element.offsetHeight;
1123
+ // Actual rectangle coordinates
1124
+ const x1 = leftPx;
1125
+ const y1 = topPx;
1126
+ const x2 = w - rightPx;
1127
+ const y2 = h - bottomPx;
1128
+ // Rectangle perimeter
1129
+ const P = 2 * ((x2 - x1) + (y2 - y1));
1130
+ let d = P * progress;
1131
+ // Walk the rectangle clockwise, return point
1132
+ // Top edge: (x1 → x2, y1)
1133
+ let len = x2 - x1;
1134
+ if (d <= len)
1135
+ return { x: x1 + d, y: y1 };
1136
+ d -= len;
1137
+ // Right edge: (x2, y1 → y2)
1138
+ len = y2 - y1;
1139
+ if (d <= len)
1140
+ return { x: x2, y: y1 + d };
1141
+ d -= len;
1142
+ // Bottom edge: (x2 → x1, y2)
1143
+ len = x2 - x1;
1144
+ if (d <= len)
1145
+ return { x: x2 - d, y: y2 };
1146
+ d -= len;
1147
+ // Left edge: (x1, y2 → y1)
1148
+ return { x: x1, y: y2 - d };
1149
+ }
793
1150
  //Code from: https://github.com/floating-ui/floating-ui/blob/master/packages/utils/src/dom.ts
794
1151
  const transformProperties = ['transform', 'translate', 'scale', 'rotate', 'perspective'];
795
1152
  const willChangeValues = ['transform', 'translate', 'scale', 'rotate', 'perspective', 'filter'];