@gridkitjs/dom 0.1.0 → 0.2.1
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/README.md +22 -13
- package/dist/index.d.ts +252 -12
- package/dist/index.js +617 -36
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -66,6 +66,111 @@ function bodyRowFrom(target) {
|
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
// src/contextMenu/attachContextMenuTrigger.ts
|
|
70
|
+
var LONG_PRESS_DELAY = 500;
|
|
71
|
+
var LONG_PRESS_SLOP = 10;
|
|
72
|
+
function isContextMenuKey(event) {
|
|
73
|
+
if (event.ctrlKey || event.altKey || event.metaKey) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
return event.key === "ContextMenu" || event.key === "F10" && event.shiftKey;
|
|
77
|
+
}
|
|
78
|
+
function attachContextMenuTrigger(root, options) {
|
|
79
|
+
let swallowContextMenu = false;
|
|
80
|
+
let swallowClick = false;
|
|
81
|
+
let press = null;
|
|
82
|
+
function ask(event, point, source) {
|
|
83
|
+
const { target } = event;
|
|
84
|
+
return !event.defaultPrevented && target instanceof Element && root.contains(target) && options.onRequest({ target, point, source });
|
|
85
|
+
}
|
|
86
|
+
function request(event, point, source) {
|
|
87
|
+
if (!ask(event, point, source)) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
event.preventDefault();
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
function cancelPress() {
|
|
94
|
+
if (press !== null) {
|
|
95
|
+
window.clearTimeout(press.timer);
|
|
96
|
+
press = null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function onKeyDown2(event) {
|
|
100
|
+
swallowContextMenu = false;
|
|
101
|
+
swallowClick = false;
|
|
102
|
+
if (isContextMenuKey(event) && request(event, null, "keyboard")) {
|
|
103
|
+
swallowContextMenu = true;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function onPointerDown(event) {
|
|
107
|
+
swallowContextMenu = false;
|
|
108
|
+
swallowClick = false;
|
|
109
|
+
cancelPress();
|
|
110
|
+
if (event.pointerType !== "touch" || !event.isPrimary) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const point = { x: event.clientX, y: event.clientY };
|
|
114
|
+
press = {
|
|
115
|
+
pointerId: event.pointerId,
|
|
116
|
+
...point,
|
|
117
|
+
timer: window.setTimeout(() => {
|
|
118
|
+
press = null;
|
|
119
|
+
if (ask(event, point, "pointer")) {
|
|
120
|
+
swallowContextMenu = true;
|
|
121
|
+
swallowClick = true;
|
|
122
|
+
}
|
|
123
|
+
}, LONG_PRESS_DELAY)
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function onPointerMove(event) {
|
|
127
|
+
if (press?.pointerId === event.pointerId && Math.hypot(event.clientX - press.x, event.clientY - press.y) > LONG_PRESS_SLOP) {
|
|
128
|
+
cancelPress();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function onPointerEnd(event) {
|
|
132
|
+
if (press?.pointerId === event.pointerId) {
|
|
133
|
+
cancelPress();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function onClick(event) {
|
|
137
|
+
if (swallowClick) {
|
|
138
|
+
swallowClick = false;
|
|
139
|
+
event.preventDefault();
|
|
140
|
+
event.stopPropagation();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function onContextMenu(event) {
|
|
144
|
+
if (swallowContextMenu) {
|
|
145
|
+
swallowContextMenu = false;
|
|
146
|
+
event.preventDefault();
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const touching = press !== null;
|
|
150
|
+
cancelPress();
|
|
151
|
+
if (request(event, { x: event.clientX, y: event.clientY }, "pointer") && touching) {
|
|
152
|
+
swallowClick = true;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
document.addEventListener("keydown", onKeyDown2);
|
|
156
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
157
|
+
document.addEventListener("pointermove", onPointerMove, true);
|
|
158
|
+
document.addEventListener("pointerup", onPointerEnd, true);
|
|
159
|
+
document.addEventListener("pointercancel", onPointerEnd, true);
|
|
160
|
+
document.addEventListener("click", onClick, true);
|
|
161
|
+
document.addEventListener("contextmenu", onContextMenu);
|
|
162
|
+
return () => {
|
|
163
|
+
cancelPress();
|
|
164
|
+
document.removeEventListener("keydown", onKeyDown2);
|
|
165
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
166
|
+
document.removeEventListener("pointermove", onPointerMove, true);
|
|
167
|
+
document.removeEventListener("pointerup", onPointerEnd, true);
|
|
168
|
+
document.removeEventListener("pointercancel", onPointerEnd, true);
|
|
169
|
+
document.removeEventListener("click", onClick, true);
|
|
170
|
+
document.removeEventListener("contextmenu", onContextMenu);
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
69
174
|
// src/columnResize.ts
|
|
70
175
|
import { applyColumnResize } from "@gridkitjs/core";
|
|
71
176
|
|
|
@@ -79,7 +184,7 @@ function startPointerGesture(element, pointerId, handlers) {
|
|
|
79
184
|
element.removeEventListener("pointermove", move);
|
|
80
185
|
element.removeEventListener("pointerup", end);
|
|
81
186
|
element.removeEventListener("pointercancel", cancel);
|
|
82
|
-
window.removeEventListener("keydown",
|
|
187
|
+
window.removeEventListener("keydown", onKeyDown2);
|
|
83
188
|
if (element.hasPointerCapture(pointerId)) {
|
|
84
189
|
element.releasePointerCapture(pointerId);
|
|
85
190
|
}
|
|
@@ -95,7 +200,7 @@ function startPointerGesture(element, pointerId, handlers) {
|
|
|
95
200
|
stop();
|
|
96
201
|
handlers.onCancel();
|
|
97
202
|
}
|
|
98
|
-
function
|
|
203
|
+
function onKeyDown2(event) {
|
|
99
204
|
if (event.key === "Escape") {
|
|
100
205
|
cancel();
|
|
101
206
|
}
|
|
@@ -103,7 +208,7 @@ function startPointerGesture(element, pointerId, handlers) {
|
|
|
103
208
|
element.addEventListener("pointermove", move);
|
|
104
209
|
element.addEventListener("pointerup", end);
|
|
105
210
|
element.addEventListener("pointercancel", cancel);
|
|
106
|
-
window.addEventListener("keydown",
|
|
211
|
+
window.addEventListener("keydown", onKeyDown2);
|
|
107
212
|
}
|
|
108
213
|
|
|
109
214
|
// src/columnResize.ts
|
|
@@ -425,6 +530,219 @@ function attachInfiniteScroll(root, options) {
|
|
|
425
530
|
};
|
|
426
531
|
}
|
|
427
532
|
|
|
533
|
+
// src/menu/attachMenu.ts
|
|
534
|
+
import { nextMenuIndex, typeaheadIndex } from "@gridkitjs/core";
|
|
535
|
+
var ITEM = [
|
|
536
|
+
'[role="menuitem"][data-gridkit-menu-item]',
|
|
537
|
+
'[role="menuitemcheckbox"][data-gridkit-menu-item]',
|
|
538
|
+
'[role="menuitemradio"][data-gridkit-menu-item]'
|
|
539
|
+
].join(", ");
|
|
540
|
+
var HOVER_DELAY = 150;
|
|
541
|
+
var TYPEAHEAD_TIMEOUT = 500;
|
|
542
|
+
var AS_ENTRY = { type: "item" };
|
|
543
|
+
var MOVES = {
|
|
544
|
+
ArrowDown: "next",
|
|
545
|
+
ArrowUp: "previous",
|
|
546
|
+
Home: "first",
|
|
547
|
+
End: "last"
|
|
548
|
+
};
|
|
549
|
+
function idOf(item) {
|
|
550
|
+
return item.getAttribute("data-gridkit-menu-item") ?? "";
|
|
551
|
+
}
|
|
552
|
+
function isDisabled(item) {
|
|
553
|
+
return item.getAttribute("aria-disabled") === "true";
|
|
554
|
+
}
|
|
555
|
+
function opensSubmenu(item) {
|
|
556
|
+
const popup = item.getAttribute("aria-haspopup");
|
|
557
|
+
return popup === "menu" || popup === "true";
|
|
558
|
+
}
|
|
559
|
+
function labelOf(item) {
|
|
560
|
+
return (item.getAttribute("aria-label") ?? item.textContent).trim();
|
|
561
|
+
}
|
|
562
|
+
function isTypeahead(event) {
|
|
563
|
+
return /^\S$/u.test(event.key) && !event.ctrlKey && !event.metaKey && !event.altKey;
|
|
564
|
+
}
|
|
565
|
+
function attachMenu(panel, options) {
|
|
566
|
+
let typed = "";
|
|
567
|
+
let typeaheadTimer;
|
|
568
|
+
let hovered = null;
|
|
569
|
+
let hoverTimer;
|
|
570
|
+
function items() {
|
|
571
|
+
return Array.from(panel.querySelectorAll(ITEM));
|
|
572
|
+
}
|
|
573
|
+
function itemOf(target) {
|
|
574
|
+
const item = target instanceof Element ? target.closest(ITEM) : null;
|
|
575
|
+
return item !== null && panel.contains(item) ? item : null;
|
|
576
|
+
}
|
|
577
|
+
function setTabStop(stop) {
|
|
578
|
+
for (const item of items()) {
|
|
579
|
+
item.tabIndex = item === stop ? 0 : -1;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
function focus(item) {
|
|
583
|
+
setTabStop(item);
|
|
584
|
+
item.focus();
|
|
585
|
+
}
|
|
586
|
+
function openSubmenu(item, focusTo) {
|
|
587
|
+
if (!isDisabled(item)) {
|
|
588
|
+
options.onOpenSubmenu?.(idOf(item), { focus: focusTo });
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
function choose(item, focusTo) {
|
|
592
|
+
if (opensSubmenu(item)) {
|
|
593
|
+
openSubmenu(item, focusTo);
|
|
594
|
+
} else if (!isDisabled(item)) {
|
|
595
|
+
options.onActivate(idOf(item));
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
function typeahead(key, all, from) {
|
|
599
|
+
typed += key;
|
|
600
|
+
window.clearTimeout(typeaheadTimer);
|
|
601
|
+
typeaheadTimer = window.setTimeout(() => {
|
|
602
|
+
typed = "";
|
|
603
|
+
}, TYPEAHEAD_TIMEOUT);
|
|
604
|
+
const match = all[typeaheadIndex(all.map(labelOf), from, typed)];
|
|
605
|
+
if (match !== void 0) {
|
|
606
|
+
focus(match);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
function onKeyDown2(event) {
|
|
610
|
+
if (event.isComposing) {
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
const all = items();
|
|
614
|
+
const item = itemOf(event.target);
|
|
615
|
+
const from = item === null ? -1 : all.indexOf(item);
|
|
616
|
+
const move = MOVES[event.key];
|
|
617
|
+
if (move !== void 0) {
|
|
618
|
+
const next = all[nextMenuIndex(
|
|
619
|
+
all.map(() => AS_ENTRY),
|
|
620
|
+
from,
|
|
621
|
+
move
|
|
622
|
+
)];
|
|
623
|
+
if (next !== void 0) {
|
|
624
|
+
focus(next);
|
|
625
|
+
}
|
|
626
|
+
} else if (event.key === "Enter" || event.key === " ") {
|
|
627
|
+
if (item !== null) {
|
|
628
|
+
choose(item, "first");
|
|
629
|
+
}
|
|
630
|
+
} else if (event.key === "ArrowRight") {
|
|
631
|
+
if (item !== null && opensSubmenu(item)) {
|
|
632
|
+
openSubmenu(item, "first");
|
|
633
|
+
}
|
|
634
|
+
} else if (event.key === "ArrowLeft") {
|
|
635
|
+
options.onCloseSubmenu?.();
|
|
636
|
+
} else if (event.key === "Tab") {
|
|
637
|
+
options.onClose("tab");
|
|
638
|
+
} else if (isTypeahead(event)) {
|
|
639
|
+
typeahead(event.key, all, from);
|
|
640
|
+
} else {
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
event.preventDefault();
|
|
644
|
+
}
|
|
645
|
+
function onFocusIn(event) {
|
|
646
|
+
const item = itemOf(event.target);
|
|
647
|
+
if (item !== null) {
|
|
648
|
+
setTabStop(item);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
function onClick(event) {
|
|
652
|
+
const item = itemOf(event.target);
|
|
653
|
+
if (item !== null) {
|
|
654
|
+
choose(item, "none");
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
function onPointerMove(event) {
|
|
658
|
+
if (event.pointerType === "touch") {
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
const item = itemOf(event.target);
|
|
662
|
+
if (item !== null && document.activeElement !== item) {
|
|
663
|
+
focus(item);
|
|
664
|
+
}
|
|
665
|
+
if (item === hovered) {
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
hovered = item;
|
|
669
|
+
window.clearTimeout(hoverTimer);
|
|
670
|
+
if (item !== null) {
|
|
671
|
+
hoverTimer = window.setTimeout(() => {
|
|
672
|
+
if (opensSubmenu(item) && !isDisabled(item)) {
|
|
673
|
+
openSubmenu(item, "none");
|
|
674
|
+
} else {
|
|
675
|
+
options.onCollapseSubmenu?.();
|
|
676
|
+
}
|
|
677
|
+
}, HOVER_DELAY);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
function onPointerLeave() {
|
|
681
|
+
hovered = null;
|
|
682
|
+
window.clearTimeout(hoverTimer);
|
|
683
|
+
}
|
|
684
|
+
const focused = itemOf(document.activeElement);
|
|
685
|
+
setTabStop(focused ?? items()[0]);
|
|
686
|
+
panel.addEventListener("keydown", onKeyDown2);
|
|
687
|
+
panel.addEventListener("focusin", onFocusIn);
|
|
688
|
+
panel.addEventListener("click", onClick);
|
|
689
|
+
panel.addEventListener("pointermove", onPointerMove);
|
|
690
|
+
panel.addEventListener("pointerleave", onPointerLeave);
|
|
691
|
+
return {
|
|
692
|
+
focusItem(which) {
|
|
693
|
+
const all = items();
|
|
694
|
+
const item = typeof which === "number" ? all[which] : all.find((candidate) => idOf(candidate) === which);
|
|
695
|
+
if (item !== void 0) {
|
|
696
|
+
focus(item);
|
|
697
|
+
}
|
|
698
|
+
},
|
|
699
|
+
detach() {
|
|
700
|
+
window.clearTimeout(typeaheadTimer);
|
|
701
|
+
window.clearTimeout(hoverTimer);
|
|
702
|
+
panel.removeEventListener("keydown", onKeyDown2);
|
|
703
|
+
panel.removeEventListener("focusin", onFocusIn);
|
|
704
|
+
panel.removeEventListener("click", onClick);
|
|
705
|
+
panel.removeEventListener("pointermove", onPointerMove);
|
|
706
|
+
panel.removeEventListener("pointerleave", onPointerLeave);
|
|
707
|
+
}
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// src/overlay/overlayStack.ts
|
|
712
|
+
var stack = [];
|
|
713
|
+
function onKeyDown(event) {
|
|
714
|
+
const topmost = stack.at(-1);
|
|
715
|
+
if (event.key !== "Escape" || event.isComposing || topmost === void 0) {
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
event.preventDefault();
|
|
719
|
+
event.stopPropagation();
|
|
720
|
+
topmost.onEscape();
|
|
721
|
+
}
|
|
722
|
+
function pushOverlay(overlay) {
|
|
723
|
+
if (stack.length === 0) {
|
|
724
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
725
|
+
}
|
|
726
|
+
stack.push(overlay);
|
|
727
|
+
}
|
|
728
|
+
function removeOverlay(overlay) {
|
|
729
|
+
const index = stack.indexOf(overlay);
|
|
730
|
+
if (index === -1) {
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
const above = stack.splice(index).slice(1).reverse();
|
|
734
|
+
for (const child of above) {
|
|
735
|
+
child.onParentDetached();
|
|
736
|
+
}
|
|
737
|
+
if (stack.length === 0) {
|
|
738
|
+
window.removeEventListener("keydown", onKeyDown, true);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
function isInsideOverlayAbove(overlay, target) {
|
|
742
|
+
const index = stack.indexOf(overlay);
|
|
743
|
+
return index !== -1 && stack.slice(index + 1).some((above) => above.panel.contains(target));
|
|
744
|
+
}
|
|
745
|
+
|
|
428
746
|
// src/overlay/placeOverlay.ts
|
|
429
747
|
var OPPOSITE_SIDE = {
|
|
430
748
|
top: "bottom",
|
|
@@ -480,6 +798,7 @@ function clampIntoView(value, limit) {
|
|
|
480
798
|
function placeOverlay(anchor, panel, viewport, options = {}) {
|
|
481
799
|
const [preferredSide, preferredAlign] = (options.placement ?? "bottom-start").split("-");
|
|
482
800
|
const gap = options.gap ?? 0;
|
|
801
|
+
const offset = options.offset ?? 0;
|
|
483
802
|
const vertical = isVertical(preferredSide);
|
|
484
803
|
const side = chooseSide(
|
|
485
804
|
preferredSide,
|
|
@@ -487,7 +806,7 @@ function placeOverlay(anchor, panel, viewport, options = {}) {
|
|
|
487
806
|
anchor,
|
|
488
807
|
viewport
|
|
489
808
|
);
|
|
490
|
-
const anchorStart = vertical ? anchor.left : anchor.top;
|
|
809
|
+
const anchorStart = (vertical ? anchor.left : anchor.top) + offset;
|
|
491
810
|
const anchorEnd = anchorStart + (vertical ? anchor.width : anchor.height);
|
|
492
811
|
const extent = vertical ? panel.width : panel.height;
|
|
493
812
|
const room = vertical ? viewport.width : viewport.height;
|
|
@@ -514,24 +833,59 @@ function anchorRect(anchor) {
|
|
|
514
833
|
}
|
|
515
834
|
return { top: anchor.y, left: anchor.x, width: 0, height: 0 };
|
|
516
835
|
}
|
|
836
|
+
function initialFocusTarget(panel, initialFocus) {
|
|
837
|
+
if (initialFocus === "none") {
|
|
838
|
+
return null;
|
|
839
|
+
}
|
|
840
|
+
if (initialFocus instanceof HTMLElement) {
|
|
841
|
+
return initialFocus;
|
|
842
|
+
}
|
|
843
|
+
const first = initialFocus === "first" ? panel.querySelector(FOCUSABLE) : null;
|
|
844
|
+
if (first !== null) {
|
|
845
|
+
return first;
|
|
846
|
+
}
|
|
847
|
+
if (!panel.hasAttribute("tabindex")) {
|
|
848
|
+
panel.tabIndex = -1;
|
|
849
|
+
}
|
|
850
|
+
return panel;
|
|
851
|
+
}
|
|
517
852
|
function attachOverlay(anchor, panel, options) {
|
|
518
853
|
const { onDismiss } = options;
|
|
519
854
|
const returnFocusTo = options.returnFocusTo === void 0 ? document.activeElement instanceof HTMLElement ? document.activeElement : null : options.returnFocusTo;
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
function onKeyDown(event) {
|
|
524
|
-
if (event.key === "Escape") {
|
|
855
|
+
const stacked = {
|
|
856
|
+
panel,
|
|
857
|
+
onEscape: () => {
|
|
525
858
|
onDismiss("escape");
|
|
859
|
+
},
|
|
860
|
+
onParentDetached: () => {
|
|
861
|
+
onDismiss("parent");
|
|
862
|
+
detach();
|
|
526
863
|
}
|
|
864
|
+
};
|
|
865
|
+
function inside(target) {
|
|
866
|
+
return target instanceof Node && (panel.contains(target) || isInsideOverlayAbove(stacked, target));
|
|
867
|
+
}
|
|
868
|
+
function belongs(target) {
|
|
869
|
+
return inside(target) || anchor instanceof Element && target instanceof Node && anchor.contains(target);
|
|
527
870
|
}
|
|
528
871
|
function onPointerDown(event) {
|
|
529
872
|
if (!belongs(event.target)) {
|
|
530
873
|
onDismiss("outside");
|
|
531
874
|
}
|
|
532
875
|
}
|
|
876
|
+
let settlingFrame = null;
|
|
877
|
+
function onInput() {
|
|
878
|
+
if (settlingFrame !== null) {
|
|
879
|
+
cancelAnimationFrame(settlingFrame);
|
|
880
|
+
}
|
|
881
|
+
settlingFrame = requestAnimationFrame(() => {
|
|
882
|
+
settlingFrame = requestAnimationFrame(() => {
|
|
883
|
+
settlingFrame = null;
|
|
884
|
+
});
|
|
885
|
+
});
|
|
886
|
+
}
|
|
533
887
|
function onScroll(event) {
|
|
534
|
-
if (!(event.target
|
|
888
|
+
if (!inside(event.target) && settlingFrame === null) {
|
|
535
889
|
onDismiss("scroll");
|
|
536
890
|
}
|
|
537
891
|
}
|
|
@@ -546,50 +900,72 @@ function attachOverlay(anchor, panel, options) {
|
|
|
546
900
|
function onWindowBlur() {
|
|
547
901
|
onDismiss("blur");
|
|
548
902
|
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
{ width, height },
|
|
556
|
-
{
|
|
557
|
-
width: document.documentElement.clientWidth,
|
|
558
|
-
height: document.documentElement.clientHeight
|
|
559
|
-
},
|
|
560
|
-
options
|
|
561
|
-
);
|
|
562
|
-
panel.style.top = `${String(position.top)}px`;
|
|
563
|
-
panel.style.left = `${String(position.left)}px`;
|
|
564
|
-
panel.setAttribute("data-gridkit-placement", position.placement);
|
|
565
|
-
const first = panel.querySelector(FOCUSABLE);
|
|
566
|
-
if (first === null && !panel.hasAttribute("tabindex")) {
|
|
567
|
-
panel.tabIndex = -1;
|
|
903
|
+
let lastAnchorBox = null;
|
|
904
|
+
function anchorBox() {
|
|
905
|
+
if (lastAnchorBox === null || !(anchor instanceof Element) || anchor.isConnected) {
|
|
906
|
+
lastAnchorBox = anchorRect(anchor);
|
|
907
|
+
}
|
|
908
|
+
return lastAnchorBox;
|
|
568
909
|
}
|
|
569
|
-
(
|
|
570
|
-
|
|
910
|
+
function place() {
|
|
911
|
+
panel.style.top = "0px";
|
|
912
|
+
panel.style.left = "0px";
|
|
913
|
+
const { width, height } = panel.getBoundingClientRect();
|
|
914
|
+
const position = placeOverlay(
|
|
915
|
+
anchorBox(),
|
|
916
|
+
{ width, height },
|
|
917
|
+
{
|
|
918
|
+
width: document.documentElement.clientWidth,
|
|
919
|
+
height: document.documentElement.clientHeight
|
|
920
|
+
},
|
|
921
|
+
options
|
|
922
|
+
);
|
|
923
|
+
panel.style.top = `${String(position.top)}px`;
|
|
924
|
+
panel.style.left = `${String(position.left)}px`;
|
|
925
|
+
panel.setAttribute("data-gridkit-placement", position.placement);
|
|
926
|
+
}
|
|
927
|
+
panel.style.position = "fixed";
|
|
928
|
+
place();
|
|
929
|
+
const resizeObserver = new ResizeObserver(place);
|
|
930
|
+
resizeObserver.observe(panel);
|
|
931
|
+
pushOverlay(stacked);
|
|
932
|
+
initialFocusTarget(panel, options.initialFocus ?? "first")?.focus({
|
|
933
|
+
preventScroll: true
|
|
934
|
+
});
|
|
571
935
|
document.addEventListener("pointerdown", onPointerDown, true);
|
|
572
936
|
window.addEventListener("scroll", onScroll, { capture: true, passive: true });
|
|
573
937
|
window.addEventListener("resize", onResize);
|
|
574
938
|
window.addEventListener("blur", onWindowBlur);
|
|
575
939
|
panel.addEventListener("focusout", onFocusOut);
|
|
940
|
+
if (options.ignoreScrollAfterInput === true) {
|
|
941
|
+
panel.addEventListener("input", onInput);
|
|
942
|
+
panel.addEventListener("change", onInput);
|
|
943
|
+
}
|
|
576
944
|
let attached = true;
|
|
577
|
-
|
|
945
|
+
function detach() {
|
|
578
946
|
if (!attached) {
|
|
579
947
|
return;
|
|
580
948
|
}
|
|
581
949
|
attached = false;
|
|
582
|
-
document.
|
|
950
|
+
const active = document.activeElement;
|
|
951
|
+
const focusInside = active === null || active === document.body || inside(active);
|
|
952
|
+
removeOverlay(stacked);
|
|
953
|
+
resizeObserver.disconnect();
|
|
583
954
|
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
584
955
|
window.removeEventListener("scroll", onScroll, { capture: true });
|
|
585
956
|
window.removeEventListener("resize", onResize);
|
|
586
957
|
window.removeEventListener("blur", onWindowBlur);
|
|
587
958
|
panel.removeEventListener("focusout", onFocusOut);
|
|
588
|
-
|
|
589
|
-
|
|
959
|
+
panel.removeEventListener("input", onInput);
|
|
960
|
+
panel.removeEventListener("change", onInput);
|
|
961
|
+
if (settlingFrame !== null) {
|
|
962
|
+
cancelAnimationFrame(settlingFrame);
|
|
963
|
+
}
|
|
964
|
+
if (returnFocusTo !== null && focusInside) {
|
|
590
965
|
returnFocusTo.focus({ preventScroll: true });
|
|
591
966
|
}
|
|
592
|
-
}
|
|
967
|
+
}
|
|
968
|
+
return detach;
|
|
593
969
|
}
|
|
594
970
|
|
|
595
971
|
// src/rowVirtualizer.ts
|
|
@@ -716,10 +1092,214 @@ function createRowVirtualizer(scrollElement, options) {
|
|
|
716
1092
|
}
|
|
717
1093
|
};
|
|
718
1094
|
}
|
|
1095
|
+
|
|
1096
|
+
// src/toolbar/attachToolbar.ts
|
|
1097
|
+
import { nextMenuIndex as nextMenuIndex2 } from "@gridkitjs/core";
|
|
1098
|
+
var ENTRY = "[data-gridkit-toolbar-item]";
|
|
1099
|
+
var FOCUSABLE2 = [
|
|
1100
|
+
"button:not(:disabled)",
|
|
1101
|
+
"input:not(:disabled)",
|
|
1102
|
+
"select:not(:disabled)",
|
|
1103
|
+
"textarea:not(:disabled)",
|
|
1104
|
+
"a[href]",
|
|
1105
|
+
"[tabindex]"
|
|
1106
|
+
].join(", ");
|
|
1107
|
+
var MOVES2 = {
|
|
1108
|
+
ArrowRight: "next",
|
|
1109
|
+
ArrowLeft: "previous",
|
|
1110
|
+
Home: "first",
|
|
1111
|
+
End: "last"
|
|
1112
|
+
};
|
|
1113
|
+
var AS_ENTRY2 = { type: "item" };
|
|
1114
|
+
var CARETLESS_INPUTS = /* @__PURE__ */ new Set([
|
|
1115
|
+
"button",
|
|
1116
|
+
"checkbox",
|
|
1117
|
+
"color",
|
|
1118
|
+
"file",
|
|
1119
|
+
"image",
|
|
1120
|
+
"radio",
|
|
1121
|
+
"range",
|
|
1122
|
+
"reset",
|
|
1123
|
+
"submit"
|
|
1124
|
+
]);
|
|
1125
|
+
function targetOf(entry) {
|
|
1126
|
+
return entry.matches(FOCUSABLE2) ? entry : entry.querySelector(FOCUSABLE2);
|
|
1127
|
+
}
|
|
1128
|
+
function textFieldOf(target) {
|
|
1129
|
+
return target instanceof HTMLTextAreaElement || target instanceof HTMLInputElement && !CARETLESS_INPUTS.has(target.type) ? target : null;
|
|
1130
|
+
}
|
|
1131
|
+
function belongsToField(target, move) {
|
|
1132
|
+
if (target instanceof HTMLElement && target.isContentEditable) {
|
|
1133
|
+
return true;
|
|
1134
|
+
}
|
|
1135
|
+
const field = textFieldOf(target);
|
|
1136
|
+
if (field === null) {
|
|
1137
|
+
return false;
|
|
1138
|
+
}
|
|
1139
|
+
const { selectionStart, selectionEnd, value } = field;
|
|
1140
|
+
if (move === "first" || move === "last" || selectionStart === null || selectionStart !== selectionEnd) {
|
|
1141
|
+
return true;
|
|
1142
|
+
}
|
|
1143
|
+
return move === "previous" ? selectionStart > 0 : selectionStart < value.length;
|
|
1144
|
+
}
|
|
1145
|
+
function attachToolbar(toolbar) {
|
|
1146
|
+
let stop;
|
|
1147
|
+
function controls() {
|
|
1148
|
+
return Array.from(toolbar.querySelectorAll(ENTRY)).flatMap(
|
|
1149
|
+
(entry) => {
|
|
1150
|
+
const target = targetOf(entry);
|
|
1151
|
+
return target === null ? [] : [{ entry, target }];
|
|
1152
|
+
}
|
|
1153
|
+
);
|
|
1154
|
+
}
|
|
1155
|
+
function indexOf(all2, node) {
|
|
1156
|
+
return node instanceof Node ? all2.findIndex((control) => control.entry.contains(node)) : -1;
|
|
1157
|
+
}
|
|
1158
|
+
function setTabStop(next) {
|
|
1159
|
+
stop = next;
|
|
1160
|
+
for (const { target } of controls()) {
|
|
1161
|
+
target.tabIndex = target === next ? 0 : -1;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
function onKeyDown2(event) {
|
|
1165
|
+
const move = MOVES2[event.key];
|
|
1166
|
+
if (move === void 0 || event.isComposing || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || belongsToField(event.target, move)) {
|
|
1167
|
+
return;
|
|
1168
|
+
}
|
|
1169
|
+
const all2 = controls();
|
|
1170
|
+
const from = indexOf(all2, event.target);
|
|
1171
|
+
if (from === -1) {
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
const next = all2[nextMenuIndex2(
|
|
1175
|
+
all2.map(() => AS_ENTRY2),
|
|
1176
|
+
from,
|
|
1177
|
+
move
|
|
1178
|
+
)];
|
|
1179
|
+
if (next !== void 0) {
|
|
1180
|
+
event.preventDefault();
|
|
1181
|
+
setTabStop(next.target);
|
|
1182
|
+
next.target.focus();
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
function onFocusIn(event) {
|
|
1186
|
+
const all2 = controls();
|
|
1187
|
+
const control = all2[indexOf(all2, event.target)];
|
|
1188
|
+
if (control !== void 0) {
|
|
1189
|
+
setTabStop(control.target);
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
const observer = new MutationObserver(() => {
|
|
1193
|
+
const all2 = controls();
|
|
1194
|
+
setTabStop(
|
|
1195
|
+
all2.find(({ target }) => target === stop)?.target ?? all2[0]?.target
|
|
1196
|
+
);
|
|
1197
|
+
});
|
|
1198
|
+
const all = controls();
|
|
1199
|
+
setTabStop(
|
|
1200
|
+
all[indexOf(all, document.activeElement)]?.target ?? all[0]?.target
|
|
1201
|
+
);
|
|
1202
|
+
toolbar.addEventListener("keydown", onKeyDown2);
|
|
1203
|
+
toolbar.addEventListener("focusin", onFocusIn);
|
|
1204
|
+
observer.observe(toolbar, { childList: true, subtree: true });
|
|
1205
|
+
return () => {
|
|
1206
|
+
observer.disconnect();
|
|
1207
|
+
toolbar.removeEventListener("keydown", onKeyDown2);
|
|
1208
|
+
toolbar.removeEventListener("focusin", onFocusIn);
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
// src/toolbar/observeToolbarOverflow.ts
|
|
1213
|
+
import {
|
|
1214
|
+
fitToolbarItems,
|
|
1215
|
+
isPinnedToolbarItem
|
|
1216
|
+
} from "@gridkitjs/core";
|
|
1217
|
+
var ENTRY_ATTRIBUTE = "data-gridkit-toolbar-item";
|
|
1218
|
+
var MORE_ATTRIBUTE = "data-gridkit-toolbar-more";
|
|
1219
|
+
function pixels(value) {
|
|
1220
|
+
return Number.parseFloat(value) || 0;
|
|
1221
|
+
}
|
|
1222
|
+
function outerWidth(element) {
|
|
1223
|
+
const style = getComputedStyle(element);
|
|
1224
|
+
return element.getBoundingClientRect().width + pixels(style.marginLeft) + pixels(style.marginRight);
|
|
1225
|
+
}
|
|
1226
|
+
function observeToolbarOverflow(toolbar, options) {
|
|
1227
|
+
let current = options;
|
|
1228
|
+
const widths = /* @__PURE__ */ new Map();
|
|
1229
|
+
let moreWidth = 0;
|
|
1230
|
+
let reported;
|
|
1231
|
+
function drawnEntries() {
|
|
1232
|
+
return Array.from(
|
|
1233
|
+
toolbar.querySelectorAll(`[${ENTRY_ATTRIBUTE}]`)
|
|
1234
|
+
);
|
|
1235
|
+
}
|
|
1236
|
+
function measure() {
|
|
1237
|
+
for (const element of drawnEntries()) {
|
|
1238
|
+
if (element.hasAttribute(MORE_ATTRIBUTE)) {
|
|
1239
|
+
moreWidth = outerWidth(element);
|
|
1240
|
+
} else {
|
|
1241
|
+
widths.set(
|
|
1242
|
+
element.getAttribute(ENTRY_ATTRIBUTE) ?? "",
|
|
1243
|
+
outerWidth(element)
|
|
1244
|
+
);
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
const style = getComputedStyle(toolbar);
|
|
1248
|
+
const gap = pixels(style.columnGap);
|
|
1249
|
+
const fit = fitToolbarItems({
|
|
1250
|
+
widths: current.items.map(
|
|
1251
|
+
(item) => (item.type === "spacer" ? 0 : widths.get(item.key) ?? 0) + gap
|
|
1252
|
+
),
|
|
1253
|
+
available: toolbar.clientWidth - pixels(style.paddingLeft) - pixels(style.paddingRight) + gap,
|
|
1254
|
+
moreWidth: moreWidth + gap,
|
|
1255
|
+
pinned: current.items.map(isPinnedToolbarItem)
|
|
1256
|
+
});
|
|
1257
|
+
if (fit !== reported) {
|
|
1258
|
+
reported = fit;
|
|
1259
|
+
current.onChange(fit);
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
const resizes = new ResizeObserver(measure);
|
|
1263
|
+
function observeSizes() {
|
|
1264
|
+
resizes.disconnect();
|
|
1265
|
+
resizes.observe(toolbar);
|
|
1266
|
+
for (const element of drawnEntries()) {
|
|
1267
|
+
resizes.observe(element);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
const draws = new MutationObserver(() => {
|
|
1271
|
+
observeSizes();
|
|
1272
|
+
measure();
|
|
1273
|
+
});
|
|
1274
|
+
observeSizes();
|
|
1275
|
+
draws.observe(toolbar, { childList: true, subtree: true });
|
|
1276
|
+
measure();
|
|
1277
|
+
return {
|
|
1278
|
+
update(next) {
|
|
1279
|
+
const labels = new Map(
|
|
1280
|
+
current.items.map((item) => [item.key, item.label])
|
|
1281
|
+
);
|
|
1282
|
+
for (const item of next.items) {
|
|
1283
|
+
if (labels.has(item.key) && labels.get(item.key) !== item.label) {
|
|
1284
|
+
widths.delete(item.key);
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
current = next;
|
|
1288
|
+
measure();
|
|
1289
|
+
},
|
|
1290
|
+
detach() {
|
|
1291
|
+
resizes.disconnect();
|
|
1292
|
+
draws.disconnect();
|
|
1293
|
+
}
|
|
1294
|
+
};
|
|
1295
|
+
}
|
|
719
1296
|
export {
|
|
720
1297
|
NO_DRAG,
|
|
1298
|
+
attachContextMenuTrigger,
|
|
721
1299
|
attachInfiniteScroll,
|
|
1300
|
+
attachMenu,
|
|
722
1301
|
attachOverlay,
|
|
1302
|
+
attachToolbar,
|
|
723
1303
|
bodyCellFrom,
|
|
724
1304
|
bodyRowFrom,
|
|
725
1305
|
createGridFocus,
|
|
@@ -730,6 +1310,7 @@ export {
|
|
|
730
1310
|
measureColumnContent,
|
|
731
1311
|
measurePageSize,
|
|
732
1312
|
observeElementWidth,
|
|
1313
|
+
observeToolbarOverflow,
|
|
733
1314
|
placeOverlay,
|
|
734
1315
|
resolveColumnDropTarget,
|
|
735
1316
|
resolveGroupByDropTarget,
|