@abydahana/aksara-ui 1.2.1 → 1.2.3

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/dist/aksara.css CHANGED
@@ -23681,7 +23681,8 @@ img,svg,video {
23681
23681
  background:var(--aksara-surface);
23682
23682
  border:1px solid var(--aksara-border-subtle);
23683
23683
  border-radius:var(--aksara-radius);
23684
- box-shadow:var(--aksara-shadow-md)
23684
+ box-shadow:var(--aksara-shadow-md);
23685
+ overscroll-behavior:contain
23685
23686
  }
23686
23687
  .dropdown-top .dropdown-menu,.dropdown-menu.dropdown-top {
23687
23688
  bottom:100%;
@@ -26397,8 +26398,7 @@ textarea.form-control {
26397
26398
  .empty-state {
26398
26399
  padding:3rem 1.5rem;
26399
26400
  text-align:center;
26400
- margin:1rem auto;
26401
- max-width:32rem
26401
+ margin:1rem auto
26402
26402
  }
26403
26403
  .empty-state-icon-wrap {
26404
26404
  display:inline-flex;
package/dist/aksara.d.ts CHANGED
@@ -114,7 +114,8 @@ export declare class Dropdown extends Component {
114
114
  isOpen: boolean;
115
115
  originalParent: Node | null;
116
116
  originalSibling: Node | null;
117
- scrollHandler: (() => void) | null;
117
+ scrollHandler: ((event?: Event) => void) | null;
118
+ wheelHandler: ((event: WheelEvent) => void) | null;
118
119
  placement: string;
119
120
  container: string | HTMLElement;
120
121
  offset: number;
@@ -326,6 +326,7 @@ export class Dropdown extends Component {
326
326
  originalParent;
327
327
  originalSibling;
328
328
  scrollHandler;
329
+ wheelHandler;
329
330
  placement;
330
331
  container;
331
332
  offset;
@@ -372,6 +373,7 @@ export class Dropdown extends Component {
372
373
  this.originalParent = null;
373
374
  this.originalSibling = null;
374
375
  this.scrollHandler = null;
376
+ this.wheelHandler = null;
375
377
  this.updateOptions(options);
376
378
  if (this.trigger?.matches(".btn-sm, .input-sm, .form-control-sm, .form-select-sm") ||
377
379
  this.element.classList.contains("dropdown-sm")) {
@@ -427,9 +429,14 @@ export class Dropdown extends Component {
427
429
  position() {
428
430
  if (!this.menu || !this.isOpen || !this.trigger)
429
431
  return;
432
+ if (!this.trigger.isConnected || !document.body.contains(this.trigger)) {
433
+ this.hide();
434
+ return;
435
+ }
430
436
  this.menu.style.display = "block";
431
437
  this.menu.style.position = "absolute";
432
438
  this.menu.style.zIndex = "1000";
439
+ this.menu.style.overscrollBehavior = "contain";
433
440
  const triggerRect = this.trigger.getBoundingClientRect();
434
441
  if (this.trigger.classList.contains("form-select") ||
435
442
  this.element.classList.contains("variant-form-select") ||
@@ -441,10 +448,10 @@ export class Dropdown extends Component {
441
448
  const gap = this.offset;
442
449
  let top;
443
450
  let left;
451
+ const spaceBelow = window.innerHeight - triggerRect.bottom;
452
+ const spaceAbove = triggerRect.top;
444
453
  let placement = this.placement;
445
454
  if (placement === "auto") {
446
- const spaceBelow = window.innerHeight - triggerRect.bottom;
447
- const spaceAbove = triggerRect.top;
448
455
  placement = spaceBelow >= menuRect.height || spaceBelow >= spaceAbove ? "bottom" : "top";
449
456
  }
450
457
  this.menu.classList.remove("dropdown-top", "dropdown-bottom", "dropdown-start", "dropdown-end");
@@ -468,6 +475,11 @@ export class Dropdown extends Component {
468
475
  }
469
476
  const viewportWidth = window.innerWidth;
470
477
  left = Math.max(8, Math.min(left, viewportWidth - menuRect.width - 8));
478
+ const availableHeight = Math.max(120, Math.floor(placement === "top" ? spaceAbove - gap - 16 : spaceBelow - gap - 16));
479
+ if (this.menu.scrollHeight > availableHeight || availableHeight < 300) {
480
+ this.menu.style.maxHeight = `${availableHeight}px`;
481
+ this.menu.style.overflowY = "auto";
482
+ }
471
483
  this.menu.style.top = `${top + window.scrollY}px`;
472
484
  this.menu.style.left = `${left + window.scrollX}px`;
473
485
  this.menu.style.bottom = "auto";
@@ -490,9 +502,30 @@ export class Dropdown extends Component {
490
502
  this.menu.classList.add("dropdown-open");
491
503
  this.trigger?.setAttribute("aria-expanded", "true");
492
504
  this.position();
493
- this.scrollHandler = () => this.position();
494
- window.addEventListener("scroll", this.scrollHandler, { passive: true });
505
+ this.scrollHandler = (event) => {
506
+ if ((this.menu && (this.menu.matches(":hover") || this.menu.contains(document.activeElement))) ||
507
+ (this.trigger && this.trigger.matches(":hover")) ||
508
+ (event?.target && this.menu && (this.menu === event.target || this.menu.contains(event.target)))) {
509
+ return;
510
+ }
511
+ this.position();
512
+ };
513
+ window.addEventListener("scroll", this.scrollHandler, { passive: true, capture: true });
495
514
  window.addEventListener("resize", this.scrollHandler);
515
+ this.wheelHandler = (e) => {
516
+ if (!this.menu)
517
+ return;
518
+ const { deltaY } = e;
519
+ if (deltaY === 0)
520
+ return;
521
+ const atTop = this.menu.scrollTop <= 0;
522
+ const atBottom = this.menu.scrollTop + this.menu.clientHeight >= this.menu.scrollHeight - 1;
523
+ if ((deltaY < 0 && atTop) || (deltaY > 0 && atBottom) || this.menu.scrollHeight <= this.menu.clientHeight) {
524
+ e.preventDefault();
525
+ e.stopPropagation();
526
+ }
527
+ };
528
+ this.menu.addEventListener("wheel", this.wheelHandler, { passive: false });
496
529
  emit(this.element, "dropdown:show", { instance: this });
497
530
  return this;
498
531
  }
@@ -501,10 +534,14 @@ export class Dropdown extends Component {
501
534
  return this;
502
535
  this.isOpen = false;
503
536
  if (this.scrollHandler) {
504
- window.removeEventListener("scroll", this.scrollHandler);
537
+ window.removeEventListener("scroll", this.scrollHandler, { capture: true });
505
538
  window.removeEventListener("resize", this.scrollHandler);
506
539
  this.scrollHandler = null;
507
540
  }
541
+ if (this.wheelHandler && this.menu) {
542
+ this.menu.removeEventListener("wheel", this.wheelHandler);
543
+ this.wheelHandler = null;
544
+ }
508
545
  this.menu.classList.remove("dropdown-open", "dropdown-top", "dropdown-bottom", "dropdown-start", "dropdown-end");
509
546
  this.trigger?.setAttribute("aria-expanded", "false");
510
547
  if (this.originalParent) {
package/dist/aksara.js CHANGED
@@ -327,6 +327,7 @@ class Dropdown extends Component {
327
327
  originalParent;
328
328
  originalSibling;
329
329
  scrollHandler;
330
+ wheelHandler;
330
331
  placement;
331
332
  container;
332
333
  offset;
@@ -373,6 +374,7 @@ class Dropdown extends Component {
373
374
  this.originalParent = null;
374
375
  this.originalSibling = null;
375
376
  this.scrollHandler = null;
377
+ this.wheelHandler = null;
376
378
  this.updateOptions(options);
377
379
  if (this.trigger?.matches(".btn-sm, .input-sm, .form-control-sm, .form-select-sm") ||
378
380
  this.element.classList.contains("dropdown-sm")) {
@@ -428,9 +430,14 @@ class Dropdown extends Component {
428
430
  position() {
429
431
  if (!this.menu || !this.isOpen || !this.trigger)
430
432
  return;
433
+ if (!this.trigger.isConnected || !document.body.contains(this.trigger)) {
434
+ this.hide();
435
+ return;
436
+ }
431
437
  this.menu.style.display = "block";
432
438
  this.menu.style.position = "absolute";
433
439
  this.menu.style.zIndex = "1000";
440
+ this.menu.style.overscrollBehavior = "contain";
434
441
  const triggerRect = this.trigger.getBoundingClientRect();
435
442
  if (this.trigger.classList.contains("form-select") ||
436
443
  this.element.classList.contains("variant-form-select") ||
@@ -442,10 +449,10 @@ class Dropdown extends Component {
442
449
  const gap = this.offset;
443
450
  let top;
444
451
  let left;
452
+ const spaceBelow = window.innerHeight - triggerRect.bottom;
453
+ const spaceAbove = triggerRect.top;
445
454
  let placement = this.placement;
446
455
  if (placement === "auto") {
447
- const spaceBelow = window.innerHeight - triggerRect.bottom;
448
- const spaceAbove = triggerRect.top;
449
456
  placement = spaceBelow >= menuRect.height || spaceBelow >= spaceAbove ? "bottom" : "top";
450
457
  }
451
458
  this.menu.classList.remove("dropdown-top", "dropdown-bottom", "dropdown-start", "dropdown-end");
@@ -469,6 +476,11 @@ class Dropdown extends Component {
469
476
  }
470
477
  const viewportWidth = window.innerWidth;
471
478
  left = Math.max(8, Math.min(left, viewportWidth - menuRect.width - 8));
479
+ const availableHeight = Math.max(120, Math.floor(placement === "top" ? spaceAbove - gap - 16 : spaceBelow - gap - 16));
480
+ if (this.menu.scrollHeight > availableHeight || availableHeight < 300) {
481
+ this.menu.style.maxHeight = `${availableHeight}px`;
482
+ this.menu.style.overflowY = "auto";
483
+ }
472
484
  this.menu.style.top = `${top + window.scrollY}px`;
473
485
  this.menu.style.left = `${left + window.scrollX}px`;
474
486
  this.menu.style.bottom = "auto";
@@ -491,9 +503,30 @@ class Dropdown extends Component {
491
503
  this.menu.classList.add("dropdown-open");
492
504
  this.trigger?.setAttribute("aria-expanded", "true");
493
505
  this.position();
494
- this.scrollHandler = () => this.position();
495
- window.addEventListener("scroll", this.scrollHandler, { passive: true });
506
+ this.scrollHandler = (event) => {
507
+ if ((this.menu && (this.menu.matches(":hover") || this.menu.contains(document.activeElement))) ||
508
+ (this.trigger && this.trigger.matches(":hover")) ||
509
+ (event?.target && this.menu && (this.menu === event.target || this.menu.contains(event.target)))) {
510
+ return;
511
+ }
512
+ this.position();
513
+ };
514
+ window.addEventListener("scroll", this.scrollHandler, { passive: true, capture: true });
496
515
  window.addEventListener("resize", this.scrollHandler);
516
+ this.wheelHandler = (e) => {
517
+ if (!this.menu)
518
+ return;
519
+ const { deltaY } = e;
520
+ if (deltaY === 0)
521
+ return;
522
+ const atTop = this.menu.scrollTop <= 0;
523
+ const atBottom = this.menu.scrollTop + this.menu.clientHeight >= this.menu.scrollHeight - 1;
524
+ if ((deltaY < 0 && atTop) || (deltaY > 0 && atBottom) || this.menu.scrollHeight <= this.menu.clientHeight) {
525
+ e.preventDefault();
526
+ e.stopPropagation();
527
+ }
528
+ };
529
+ this.menu.addEventListener("wheel", this.wheelHandler, { passive: false });
497
530
  emit(this.element, "dropdown:show", { instance: this });
498
531
  return this;
499
532
  }
@@ -502,10 +535,14 @@ class Dropdown extends Component {
502
535
  return this;
503
536
  this.isOpen = false;
504
537
  if (this.scrollHandler) {
505
- window.removeEventListener("scroll", this.scrollHandler);
538
+ window.removeEventListener("scroll", this.scrollHandler, { capture: true });
506
539
  window.removeEventListener("resize", this.scrollHandler);
507
540
  this.scrollHandler = null;
508
541
  }
542
+ if (this.wheelHandler && this.menu) {
543
+ this.menu.removeEventListener("wheel", this.wheelHandler);
544
+ this.wheelHandler = null;
545
+ }
509
546
  this.menu.classList.remove("dropdown-open", "dropdown-top", "dropdown-bottom", "dropdown-start", "dropdown-end");
510
547
  this.trigger?.setAttribute("aria-expanded", "false");
511
548
  if (this.originalParent) {