@rogieking/figui3 1.9.6 → 1.9.7
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 +0 -30
- package/example.html +1 -0
- package/fig.js +194 -0
- package/package.json +1 -1
package/components.css
CHANGED
|
@@ -2079,38 +2079,8 @@ dialog,
|
|
|
2079
2079
|
}
|
|
2080
2080
|
}
|
|
2081
2081
|
dialog[is="fig-dialog"] {
|
|
2082
|
-
--offset: 1rem;
|
|
2083
|
-
--translate-x: -50%;
|
|
2084
|
-
--translate-y: -50%;
|
|
2085
2082
|
--z-index: 999999;
|
|
2086
|
-
|
|
2087
|
-
position: fixed;
|
|
2088
|
-
top: 50%;
|
|
2089
|
-
left: 50%;
|
|
2090
|
-
margin: 0;
|
|
2091
2083
|
z-index: var(--z-index);
|
|
2092
|
-
transform: translate(var(--translate-x), var(--translate-y));
|
|
2093
|
-
|
|
2094
|
-
&[position*="bottom"] {
|
|
2095
|
-
bottom: var(--offset);
|
|
2096
|
-
top: auto;
|
|
2097
|
-
--translate-y: 0;
|
|
2098
|
-
}
|
|
2099
|
-
&[position*="top"] {
|
|
2100
|
-
top: var(--offset);
|
|
2101
|
-
bottom: auto;
|
|
2102
|
-
--translate-y: 0;
|
|
2103
|
-
}
|
|
2104
|
-
&[position*="right"] {
|
|
2105
|
-
right: var(--offset);
|
|
2106
|
-
left: auto;
|
|
2107
|
-
--translate-x: 0;
|
|
2108
|
-
}
|
|
2109
|
-
&[position*="left"] {
|
|
2110
|
-
left: var(--offset);
|
|
2111
|
-
right: auto;
|
|
2112
|
-
--translate-x: 0;
|
|
2113
|
-
}
|
|
2114
2084
|
}
|
|
2115
2085
|
|
|
2116
2086
|
/* Tooltip */
|
package/example.html
CHANGED
package/fig.js
CHANGED
|
@@ -592,20 +592,214 @@ customElements.define("fig-popover", FigPopover);
|
|
|
592
592
|
* @attr {boolean} modal - Whether the dialog should be modal
|
|
593
593
|
*/
|
|
594
594
|
class FigDialog extends HTMLDialogElement {
|
|
595
|
+
#isDragging = false;
|
|
596
|
+
#dragOffset = { x: 0, y: 0 };
|
|
597
|
+
#boundPointerDown;
|
|
598
|
+
#boundPointerMove;
|
|
599
|
+
#boundPointerUp;
|
|
600
|
+
#offset = 16; // 1rem in pixels
|
|
601
|
+
#positionInitialized = false;
|
|
602
|
+
|
|
603
|
+
constructor() {
|
|
604
|
+
super();
|
|
605
|
+
this.#boundPointerDown = this.#handlePointerDown.bind(this);
|
|
606
|
+
this.#boundPointerMove = this.#handlePointerMove.bind(this);
|
|
607
|
+
this.#boundPointerUp = this.#handlePointerUp.bind(this);
|
|
608
|
+
}
|
|
609
|
+
|
|
595
610
|
connectedCallback() {
|
|
596
611
|
this.modal =
|
|
597
612
|
this.hasAttribute("modal") && this.getAttribute("modal") !== "false";
|
|
613
|
+
|
|
614
|
+
// Set up drag functionality
|
|
615
|
+
this.drag =
|
|
616
|
+
this.hasAttribute("drag") && this.getAttribute("drag") !== "false";
|
|
617
|
+
|
|
598
618
|
requestAnimationFrame(() => {
|
|
599
619
|
this.#addCloseListeners();
|
|
620
|
+
this.#setupDragListeners();
|
|
621
|
+
this.#applyPosition();
|
|
600
622
|
});
|
|
601
623
|
}
|
|
602
624
|
|
|
625
|
+
disconnectedCallback() {
|
|
626
|
+
this.#removeDragListeners();
|
|
627
|
+
}
|
|
628
|
+
|
|
603
629
|
#addCloseListeners() {
|
|
604
630
|
this.querySelectorAll("fig-button[close-dialog]").forEach((button) => {
|
|
605
631
|
button.removeEventListener("click", this.close);
|
|
606
632
|
button.addEventListener("click", this.close.bind(this));
|
|
607
633
|
});
|
|
608
634
|
}
|
|
635
|
+
|
|
636
|
+
#applyPosition() {
|
|
637
|
+
const position = this.getAttribute("position") || "";
|
|
638
|
+
const rect = this.getBoundingClientRect();
|
|
639
|
+
const viewportWidth = window.innerWidth;
|
|
640
|
+
const viewportHeight = window.innerHeight;
|
|
641
|
+
|
|
642
|
+
// Default to centered
|
|
643
|
+
let top = (viewportHeight - rect.height) / 2;
|
|
644
|
+
let left = (viewportWidth - rect.width) / 2;
|
|
645
|
+
|
|
646
|
+
// Parse position attribute
|
|
647
|
+
const hasTop = position.includes("top");
|
|
648
|
+
const hasBottom = position.includes("bottom");
|
|
649
|
+
const hasLeft = position.includes("left");
|
|
650
|
+
const hasRight = position.includes("right");
|
|
651
|
+
|
|
652
|
+
// Vertical positioning
|
|
653
|
+
if (hasTop) {
|
|
654
|
+
top = this.#offset;
|
|
655
|
+
} else if (hasBottom) {
|
|
656
|
+
top = viewportHeight - rect.height - this.#offset;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// Horizontal positioning
|
|
660
|
+
if (hasLeft) {
|
|
661
|
+
left = this.#offset;
|
|
662
|
+
} else if (hasRight) {
|
|
663
|
+
left = viewportWidth - rect.width - this.#offset;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// Apply position using fixed positioning with pixels
|
|
667
|
+
this.style.position = "fixed";
|
|
668
|
+
this.style.top = `${top}px`;
|
|
669
|
+
this.style.left = `${left}px`;
|
|
670
|
+
this.style.transform = "none";
|
|
671
|
+
this.style.margin = "0";
|
|
672
|
+
|
|
673
|
+
this.#positionInitialized = true;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
#setupDragListeners() {
|
|
677
|
+
if (this.drag) {
|
|
678
|
+
this.addEventListener("pointerdown", this.#boundPointerDown);
|
|
679
|
+
// Set move cursor only on fig-header elements
|
|
680
|
+
const header = this.querySelector("fig-header, header");
|
|
681
|
+
if (header) {
|
|
682
|
+
header.style.cursor = "move";
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
#removeDragListeners() {
|
|
688
|
+
this.removeEventListener("pointerdown", this.#boundPointerDown);
|
|
689
|
+
document.removeEventListener("pointermove", this.#boundPointerMove);
|
|
690
|
+
document.removeEventListener("pointerup", this.#boundPointerUp);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
#isInteractiveElement(element) {
|
|
694
|
+
// List of interactive element types and attributes to avoid dragging on
|
|
695
|
+
const interactiveSelectors = [
|
|
696
|
+
"input",
|
|
697
|
+
"button",
|
|
698
|
+
"select",
|
|
699
|
+
"textarea",
|
|
700
|
+
"a",
|
|
701
|
+
"label",
|
|
702
|
+
'[contenteditable="true"]',
|
|
703
|
+
"[tabindex]",
|
|
704
|
+
"fig-button",
|
|
705
|
+
"fig-input-text",
|
|
706
|
+
"fig-input-number",
|
|
707
|
+
"fig-slider",
|
|
708
|
+
"fig-checkbox",
|
|
709
|
+
"fig-radio",
|
|
710
|
+
"fig-tab",
|
|
711
|
+
"fig-dropdown",
|
|
712
|
+
"fig-chit",
|
|
713
|
+
];
|
|
714
|
+
|
|
715
|
+
// Check if the element itself is interactive
|
|
716
|
+
if (interactiveSelectors.some((selector) => element.matches?.(selector))) {
|
|
717
|
+
return true;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// Check if any parent element up to the dialog is interactive
|
|
721
|
+
let parent = element.parentElement;
|
|
722
|
+
while (parent && parent !== this) {
|
|
723
|
+
if (interactiveSelectors.some((selector) => parent.matches?.(selector))) {
|
|
724
|
+
return true;
|
|
725
|
+
}
|
|
726
|
+
parent = parent.parentElement;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
return false;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
#handlePointerDown(e) {
|
|
733
|
+
if (!this.drag || this.#isInteractiveElement(e.target)) {
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
this.#isDragging = true;
|
|
738
|
+
this.setPointerCapture(e.pointerId);
|
|
739
|
+
|
|
740
|
+
// Get current position from computed style
|
|
741
|
+
const rect = this.getBoundingClientRect();
|
|
742
|
+
|
|
743
|
+
// Store offset from pointer to dialog top-left corner
|
|
744
|
+
this.#dragOffset.x = e.clientX - rect.left;
|
|
745
|
+
this.#dragOffset.y = e.clientY - rect.top;
|
|
746
|
+
|
|
747
|
+
document.addEventListener("pointermove", this.#boundPointerMove);
|
|
748
|
+
document.addEventListener("pointerup", this.#boundPointerUp);
|
|
749
|
+
|
|
750
|
+
e.preventDefault();
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
#handlePointerMove(e) {
|
|
754
|
+
if (!this.#isDragging) return;
|
|
755
|
+
|
|
756
|
+
// Calculate new position based on pointer position minus offset
|
|
757
|
+
const newLeft = e.clientX - this.#dragOffset.x;
|
|
758
|
+
const newTop = e.clientY - this.#dragOffset.y;
|
|
759
|
+
|
|
760
|
+
// Apply position directly with pixels
|
|
761
|
+
this.style.left = `${newLeft}px`;
|
|
762
|
+
this.style.top = `${newTop}px`;
|
|
763
|
+
|
|
764
|
+
e.preventDefault();
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
#handlePointerUp(e) {
|
|
768
|
+
if (!this.#isDragging) return;
|
|
769
|
+
|
|
770
|
+
this.#isDragging = false;
|
|
771
|
+
this.releasePointerCapture(e.pointerId);
|
|
772
|
+
|
|
773
|
+
document.removeEventListener("pointermove", this.#boundPointerMove);
|
|
774
|
+
document.removeEventListener("pointerup", this.#boundPointerUp);
|
|
775
|
+
|
|
776
|
+
e.preventDefault();
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
static get observedAttributes() {
|
|
780
|
+
return ["modal", "drag", "position"];
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
784
|
+
if (name === "drag") {
|
|
785
|
+
this.drag = newValue !== null && newValue !== "false";
|
|
786
|
+
|
|
787
|
+
if (this.drag) {
|
|
788
|
+
this.#setupDragListeners();
|
|
789
|
+
} else {
|
|
790
|
+
this.#removeDragListeners();
|
|
791
|
+
// Remove move cursor from header
|
|
792
|
+
const header = this.querySelector("fig-header, header");
|
|
793
|
+
if (header) {
|
|
794
|
+
header.style.cursor = "";
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
if (name === "position" && this.#positionInitialized) {
|
|
800
|
+
this.#applyPosition();
|
|
801
|
+
}
|
|
802
|
+
}
|
|
609
803
|
}
|
|
610
804
|
customElements.define("fig-dialog", FigDialog, { extends: "dialog" });
|
|
611
805
|
|