@rogieking/figui3 1.9.5 → 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 -31
- package/example.html +22 -0
- package/fig.js +194 -0
- package/package.json +1 -1
package/components.css
CHANGED
|
@@ -666,7 +666,6 @@ input[type="text"][list] {
|
|
|
666
666
|
::picker(select) {
|
|
667
667
|
position-area: auto;
|
|
668
668
|
align-self: auto;
|
|
669
|
-
position-try-fallbacks: none;
|
|
670
669
|
max-block-size: 100vh;
|
|
671
670
|
appearance: base-select;
|
|
672
671
|
scrollbar-width: thin;
|
|
@@ -2080,38 +2079,8 @@ dialog,
|
|
|
2080
2079
|
}
|
|
2081
2080
|
}
|
|
2082
2081
|
dialog[is="fig-dialog"] {
|
|
2083
|
-
--offset: 1rem;
|
|
2084
|
-
--translate-x: -50%;
|
|
2085
|
-
--translate-y: -50%;
|
|
2086
2082
|
--z-index: 999999;
|
|
2087
|
-
|
|
2088
|
-
position: fixed;
|
|
2089
|
-
top: 50%;
|
|
2090
|
-
left: 50%;
|
|
2091
|
-
margin: 0;
|
|
2092
2083
|
z-index: var(--z-index);
|
|
2093
|
-
transform: translate(var(--translate-x), var(--translate-y));
|
|
2094
|
-
|
|
2095
|
-
&[position*="bottom"] {
|
|
2096
|
-
bottom: var(--offset);
|
|
2097
|
-
top: auto;
|
|
2098
|
-
--translate-y: 0;
|
|
2099
|
-
}
|
|
2100
|
-
&[position*="top"] {
|
|
2101
|
-
top: var(--offset);
|
|
2102
|
-
bottom: auto;
|
|
2103
|
-
--translate-y: 0;
|
|
2104
|
-
}
|
|
2105
|
-
&[position*="right"] {
|
|
2106
|
-
right: var(--offset);
|
|
2107
|
-
left: auto;
|
|
2108
|
-
--translate-x: 0;
|
|
2109
|
-
}
|
|
2110
|
-
&[position*="left"] {
|
|
2111
|
-
left: var(--offset);
|
|
2112
|
-
right: auto;
|
|
2113
|
-
--translate-x: 0;
|
|
2114
|
-
}
|
|
2115
2084
|
}
|
|
2116
2085
|
|
|
2117
2086
|
/* Tooltip */
|
package/example.html
CHANGED
|
@@ -25,6 +25,27 @@
|
|
|
25
25
|
|
|
26
26
|
<h2><label>Effects/</label>UI3 Components</h2>
|
|
27
27
|
<fig-spinner></fig-spinner>
|
|
28
|
+
|
|
29
|
+
<fig-button icon="true"
|
|
30
|
+
variant="ghost"
|
|
31
|
+
type="select"
|
|
32
|
+
style="position: absolute; right: 0;">
|
|
33
|
+
<svg width="24"
|
|
34
|
+
height="24"
|
|
35
|
+
viewBox="0 0 24 24"
|
|
36
|
+
fill="none"
|
|
37
|
+
xmlns="http://www.w3.org/2000/svg">
|
|
38
|
+
<path fill-rule="evenodd"
|
|
39
|
+
clip-rule="evenodd"
|
|
40
|
+
d="M9.64645 11.1464C9.84171 10.9512 10.1583 10.9512 10.3536 11.1464L12 12.7929L13.6464 11.1464C13.8417 10.9512 14.1583 10.9512 14.3536 11.1464C14.5488 11.3417 14.5488 11.6583 14.3536 11.8536L12.3536 13.8536C12.1583 14.0488 11.8417 14.0488 11.6464 13.8536L9.64645 11.8536C9.45118 11.6583 9.45118 11.3417 9.64645 11.1464Z"
|
|
41
|
+
fill="currentColor"
|
|
42
|
+
fill-opacity="0.9" />
|
|
43
|
+
</svg>
|
|
44
|
+
<fig-dropdown variant="neue">
|
|
45
|
+
<option>One if by sea</option>
|
|
46
|
+
<option>Two if by land</option>
|
|
47
|
+
</fig-dropdown>
|
|
48
|
+
</fig-button>
|
|
28
49
|
</fig-header>
|
|
29
50
|
|
|
30
51
|
<br /><br /><br /><br /><br /><br /><br /><br />
|
|
@@ -573,6 +594,7 @@
|
|
|
573
594
|
</fig-field>
|
|
574
595
|
|
|
575
596
|
<dialog open="true"
|
|
597
|
+
drag="true"
|
|
576
598
|
position="bottom right"
|
|
577
599
|
is="fig-dialog">
|
|
578
600
|
<fig-header>
|
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
|
|