@schukai/monster 4.141.2 → 4.142.0

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.
@@ -73,6 +73,11 @@ import {
73
73
  resolveClippingBoundaryElement,
74
74
  resolveParentPopperContentBoundary,
75
75
  } from "./util/floating-ui.mjs";
76
+ import {
77
+ FLOATING_LAYOUT_REASON,
78
+ cancelFloatingLayout,
79
+ enqueueFloatingLayout,
80
+ } from "./util/floating-layout-queue.mjs";
76
81
  import { Pathfinder } from "../../data/pathfinder.mjs";
77
82
  import { TokenList } from "../../types/tokenlist.mjs";
78
83
 
@@ -144,6 +149,7 @@ const layoutCycleModeSymbol = Symbol("layoutCycleMode");
144
149
  const layoutCyclePendingFlagsSymbol = Symbol("layoutCyclePendingFlags");
145
150
  const layoutCyclePendingPrioritySymbol = Symbol("layoutCyclePendingPriority");
146
151
  const layoutCycleRunningSymbol = Symbol("layoutCycleRunning");
152
+ const pendingOpenIntentSymbol = Symbol("pendingOpenIntent");
147
153
  const visualViewportResizeHandlerSymbol = Symbol("visualViewportResizeHandler");
148
154
  const visualViewportScrollHandlerSymbol = Symbol("visualViewportScrollHandler");
149
155
  const visibilityChangeHandlerSymbol = Symbol("visibilityChangeHandler");
@@ -151,6 +157,10 @@ const windowResizeHandlerSymbol = Symbol("windowResizeHandler");
151
157
  const windowOrientationChangeHandlerSymbol = Symbol(
152
158
  "windowOrientationChangeHandler",
153
159
  );
160
+ const stablePopperControlWidthSymbol = Symbol("stablePopperControlWidth");
161
+ const stablePopperHostStyleSnapshotSymbol = Symbol(
162
+ "stablePopperHostStyleSnapshot",
163
+ );
154
164
 
155
165
  /**
156
166
  * local symbol
@@ -952,6 +962,7 @@ class Select extends CustomControl {
952
962
  */
953
963
  disconnectedCallback() {
954
964
  super.disconnectedCallback();
965
+ clearPendingOpenIntent.call(this);
955
966
  if (!this[usesHostDismissSymbol]) {
956
967
  const document = getDocument();
957
968
  // close on outside ui-events
@@ -2339,17 +2350,46 @@ function performSelectLayoutCycle(layoutReasons = SELECT_LAYOUT_REASON_ALL) {
2339
2350
  return Promise.resolve();
2340
2351
  }
2341
2352
 
2342
- return new Processing(() => {
2343
- applySelectLayoutState.call(this, layoutReasons);
2344
- if (layoutReasons & SELECT_LAYOUT_REASON_POSITION) {
2345
- return positionPopper.call(
2346
- this,
2347
- this[controlElementSymbol],
2348
- this[popperElementSymbol],
2349
- getSelectPopperPositionOptions.call(this),
2350
- );
2351
- }
2352
- }).run();
2353
+ return enqueueFloatingLayout({
2354
+ owner: this,
2355
+ popperElement: this[popperElementSymbol],
2356
+ reason: resolveFloatingLayoutReasonFromSelectLayout(layoutReasons),
2357
+ isActive: () =>
2358
+ isPositionedPopperOpen(this[popperElementSymbol]) &&
2359
+ this.getOption("disabled", false) !== true,
2360
+ mutate: () => {
2361
+ applySelectLayoutState.call(this, layoutReasons);
2362
+ },
2363
+ position: () => {
2364
+ if (layoutReasons & SELECT_LAYOUT_REASON_POSITION) {
2365
+ return positionPopper.call(
2366
+ this,
2367
+ this[controlElementSymbol],
2368
+ this[popperElementSymbol],
2369
+ getSelectPopperPositionOptions.call(this),
2370
+ );
2371
+ }
2372
+ },
2373
+ onError: (error) => {
2374
+ addErrorAttribute(this, error);
2375
+ },
2376
+ });
2377
+ }
2378
+
2379
+ function resolveFloatingLayoutReasonFromSelectLayout(layoutReasons) {
2380
+ let reason = 0;
2381
+
2382
+ if (layoutReasons & SELECT_LAYOUT_REASON_OPTION_STATE) {
2383
+ reason |= FLOATING_LAYOUT_REASON.CONTENT;
2384
+ }
2385
+ if (layoutReasons & SELECT_LAYOUT_REASON_PAGINATION) {
2386
+ reason |= FLOATING_LAYOUT_REASON.CONTENT;
2387
+ }
2388
+ if (layoutReasons & SELECT_LAYOUT_REASON_POSITION) {
2389
+ reason |= FLOATING_LAYOUT_REASON.POSITION;
2390
+ }
2391
+
2392
+ return reason || FLOATING_LAYOUT_REASON.CONTENT;
2353
2393
  }
2354
2394
 
2355
2395
  function cancelScheduledSelectLayoutCycle() {
@@ -2468,6 +2508,52 @@ function scheduleSelectLayoutCycle(
2468
2508
  });
2469
2509
  }
2470
2510
 
2511
+ function hasConfiguredOptionsWaitingForRender() {
2512
+ const options = this.getOption("options");
2513
+
2514
+ if (isArray(options)) {
2515
+ return options.length > 0;
2516
+ }
2517
+
2518
+ if (!isIterable(options) || isString(options)) {
2519
+ return false;
2520
+ }
2521
+
2522
+ for (const option of options) {
2523
+ void option;
2524
+ return true;
2525
+ }
2526
+
2527
+ return false;
2528
+ }
2529
+
2530
+ function queuePendingOpenIntent() {
2531
+ this[pendingOpenIntentSymbol] = true;
2532
+ }
2533
+
2534
+ function clearPendingOpenIntent() {
2535
+ delete this[pendingOpenIntentSymbol];
2536
+ }
2537
+
2538
+ function retryPendingOpenIntent() {
2539
+ if (this[pendingOpenIntentSymbol] !== true) {
2540
+ return;
2541
+ }
2542
+
2543
+ if (isPositionedPopperOpen(this[popperElementSymbol])) {
2544
+ clearPendingOpenIntent.call(this);
2545
+ return;
2546
+ }
2547
+
2548
+ if (getOptionElements.call(this).length === 0) {
2549
+ clearPendingOpenIntent.call(this);
2550
+ return;
2551
+ }
2552
+
2553
+ clearPendingOpenIntent.call(this);
2554
+ show.call(this);
2555
+ }
2556
+
2471
2557
  /**
2472
2558
  * @private
2473
2559
  * @returns {string}
@@ -3213,7 +3299,7 @@ function calcAndSetOptionsDimension() {
3213
3299
  margin,
3214
3300
  });
3215
3301
  const widthConstraints = resolveSelectPopperWidthConstraints({
3216
- controlWidth: this[controlElementSymbol].getBoundingClientRect().width,
3302
+ controlWidth: getStableSelectPopperControlWidth.call(this),
3217
3303
  availableWidth: geometry.availableWidth,
3218
3304
  });
3219
3305
 
@@ -3332,6 +3418,55 @@ function resolveSelectPopperWidthConstraints({
3332
3418
  };
3333
3419
  }
3334
3420
 
3421
+ function getStableSelectPopperControlWidth() {
3422
+ const stableWidth = this[stablePopperControlWidthSymbol];
3423
+ if (Number.isFinite(stableWidth) && stableWidth > 0) {
3424
+ return stableWidth;
3425
+ }
3426
+
3427
+ return this[controlElementSymbol].getBoundingClientRect().width;
3428
+ }
3429
+
3430
+ function lockControlBarSelectHostWidthForOpenPopper() {
3431
+ if (!isInControlBar.call(this)) {
3432
+ return;
3433
+ }
3434
+
3435
+ const controlWidth = this[controlElementSymbol].getBoundingClientRect().width;
3436
+ const hostWidth = this.getBoundingClientRect().width;
3437
+ const stableWidth = Math.ceil(Math.max(controlWidth, hostWidth));
3438
+ if (!Number.isFinite(stableWidth) || stableWidth <= 0) {
3439
+ return;
3440
+ }
3441
+
3442
+ this[stablePopperControlWidthSymbol] = stableWidth;
3443
+ if (!this[stablePopperHostStyleSnapshotSymbol]) {
3444
+ this[stablePopperHostStyleSnapshotSymbol] = {
3445
+ flex: this.style.flex,
3446
+ inlineSize: this.style.inlineSize,
3447
+ minInlineSize: this.style.minInlineSize,
3448
+ };
3449
+ }
3450
+
3451
+ this.style.flex = `0 0 ${stableWidth}px`;
3452
+ this.style.inlineSize = `${stableWidth}px`;
3453
+ this.style.minInlineSize = `${stableWidth}px`;
3454
+ }
3455
+
3456
+ function unlockControlBarSelectHostWidthAfterOpenPopper() {
3457
+ const snapshot = this[stablePopperHostStyleSnapshotSymbol];
3458
+ delete this[stablePopperControlWidthSymbol];
3459
+ delete this[stablePopperHostStyleSnapshotSymbol];
3460
+
3461
+ if (!snapshot) {
3462
+ return;
3463
+ }
3464
+
3465
+ this.style.flex = snapshot.flex;
3466
+ this.style.inlineSize = snapshot.inlineSize;
3467
+ this.style.minInlineSize = snapshot.minInlineSize;
3468
+ }
3469
+
3335
3470
  function resolveSelectListDimension({
3336
3471
  visibleOptionHeights = [],
3337
3472
  maxVisibleOptions = 10,
@@ -3473,10 +3608,13 @@ function getSelectPopperGeometry() {
3473
3608
  this[controlElementSymbol],
3474
3609
  this[popperElementSymbol],
3475
3610
  );
3611
+ const effectiveBoundaryElement = isInControlBar.call(this)
3612
+ ? null
3613
+ : boundaryElement;
3476
3614
  const controlRect = this[controlElementSymbol].getBoundingClientRect();
3477
3615
  const boundaryRect =
3478
- boundaryElement instanceof HTMLElement
3479
- ? boundaryElement.getBoundingClientRect()
3616
+ effectiveBoundaryElement instanceof HTMLElement
3617
+ ? effectiveBoundaryElement.getBoundingClientRect()
3480
3618
  : null;
3481
3619
  const visibleRect = resolveSelectVisibleRect({
3482
3620
  viewportMetrics: viewport,
@@ -3491,7 +3629,7 @@ function getSelectPopperGeometry() {
3491
3629
  spaceBelow,
3492
3630
  availableHeight,
3493
3631
  availableWidth: visibleRect.width,
3494
- boundaryElement,
3632
+ boundaryElement: effectiveBoundaryElement,
3495
3633
  };
3496
3634
  }
3497
3635
 
@@ -3535,6 +3673,7 @@ function getSelectPopperPositionOptions() {
3535
3673
  // Popper content rendered outside a 40px control-bar host must be hit-testable
3536
3674
  // against the viewport instead of the host's compact shadow boundary.
3537
3675
  popperOptions.strategy = "fixed";
3676
+ popperOptions.boundaryElement = null;
3538
3677
  }
3539
3678
 
3540
3679
  return popperOptions;
@@ -4766,8 +4905,11 @@ function fetchData(url) {
4766
4905
  * @private
4767
4906
  */
4768
4907
  function hide() {
4908
+ clearPendingOpenIntent.call(this);
4909
+ cancelFloatingLayout(this[popperElementSymbol]);
4769
4910
  resetSelectPopperDimensionStyles.call(this);
4770
4911
  closePositionedPopper(this[popperElementSymbol]);
4912
+ unlockControlBarSelectHostWidthAfterOpenPopper.call(this);
4771
4913
  setStatusOrRemoveBadges.call(this, "closed");
4772
4914
  removeAttributeToken(this[controlElementSymbol], "class", "open");
4773
4915
  unregisterFromHost.call(this);
@@ -4826,10 +4968,16 @@ function show() {
4826
4968
 
4827
4969
  const options = getOptionElements.call(this);
4828
4970
  if (options.length === 0 && hasPopperFilterFlag === false) {
4971
+ if (hasConfiguredOptionsWaitingForRender.call(this)) {
4972
+ queuePendingOpenIntent.call(this);
4973
+ }
4829
4974
  return;
4830
4975
  }
4831
4976
 
4977
+ clearPendingOpenIntent.call(this);
4978
+
4832
4979
  resetSelectPopperDimensionStyles.call(this);
4980
+ lockControlBarSelectHostWidthForOpenPopper.call(this);
4833
4981
  this[popperElementSymbol].style.visibility = "hidden";
4834
4982
  openPositionedPopper(
4835
4983
  this[controlElementSymbol],
@@ -5064,6 +5212,8 @@ function refreshSelectPaginationLayout() {
5064
5212
  function toggle() {
5065
5213
  if (isPositionedPopperOpen(this[popperElementSymbol])) {
5066
5214
  hide.call(this);
5215
+ } else if (this[pendingOpenIntentSymbol] === true) {
5216
+ return;
5067
5217
  } else {
5068
5218
  show.call(this);
5069
5219
  }
@@ -5316,6 +5466,7 @@ function initEventHandler() {
5316
5466
  SELECT_LAYOUT_PRIORITY_INTERACTIVE,
5317
5467
  SELECT_LAYOUT_REASON_ALL,
5318
5468
  );
5469
+ retryPendingOpenIntent.call(self);
5319
5470
  delete this[debounceOptionsMutationObserverSymbol];
5320
5471
  },
5321
5472
  );
@@ -5580,32 +5731,33 @@ function getTemplate() {
5580
5731
  \${selected}
5581
5732
  </div>
5582
5733
 
5583
- <div data-monster-role="popper" part="popper" tabindex="-1" class="monster-color-primary-1">
5584
- <div class="option-filter-control" role="search" part="popper-filter-control">
5585
- <input type="text" role="searchbox"
5586
- data-monster-attributes="placeholder path:placeholder.filter"
5587
- part="popper-filter" name="popper-filter"
5588
- data-monster-role="filter"
5589
- autocomplete="off"
5590
- tabindex="0">
5591
- </div>
5592
-
5593
- <div part="content" class="flex" data-monster-replace="path:content">
5594
- <div part="options" data-monster-role="options" data-monster-insert="options path:options"
5595
- tabindex="-1"></div>
5596
- </div>
5597
- <monster-pagination data-monster-role="pagination" part="pagination"></monster-pagination>
5598
- <div part="remote-info"
5599
- data-monster-role="remote-info"
5600
- data-monster-attributes="class path:classes.remoteInfo"
5601
- data-monster-replace="path:messages.total"></div>
5602
- <div part="no-options" data-monster-role="no-options"
5603
- data-monster-attributes="class path:classes.noOptions"
5604
- data-monster-replace="path:messages.emptyOptions"></div>
5605
- </div>
5606
5734
  <div part="status-or-remove-badges" data-monster-role="status-or-remove-badges"
5607
5735
  data-monster-attributes="class path:classes.statusOrRemoveBadge"></div>
5608
5736
  </div>
5737
+
5738
+ <div data-monster-role="popper" part="popper" tabindex="-1" class="monster-color-primary-1">
5739
+ <div class="option-filter-control" role="search" part="popper-filter-control">
5740
+ <input type="text" role="searchbox"
5741
+ data-monster-attributes="placeholder path:placeholder.filter"
5742
+ part="popper-filter" name="popper-filter"
5743
+ data-monster-role="filter"
5744
+ autocomplete="off"
5745
+ tabindex="0">
5746
+ </div>
5747
+
5748
+ <div part="content" class="flex" data-monster-replace="path:content">
5749
+ <div part="options" data-monster-role="options" data-monster-insert="options path:options"
5750
+ tabindex="-1"></div>
5751
+ </div>
5752
+ <monster-pagination data-monster-role="pagination" part="pagination"></monster-pagination>
5753
+ <div part="remote-info"
5754
+ data-monster-role="remote-info"
5755
+ data-monster-attributes="class path:classes.remoteInfo"
5756
+ data-monster-replace="path:messages.total"></div>
5757
+ <div part="no-options" data-monster-role="no-options"
5758
+ data-monster-attributes="class path:classes.noOptions"
5759
+ data-monster-replace="path:messages.emptyOptions"></div>
5760
+ </div>
5609
5761
  `;
5610
5762
  }
5611
5763
 
@@ -50,9 +50,11 @@ div[data-monster-role="control"] {
50
50
  & ::slotted(*) {
51
51
  display: flex;
52
52
  box-sizing: border-box;
53
+ flex: 0 0 auto !important;
53
54
  align-self: stretch;
54
55
  height: var(--monster-control-bar-height);
55
56
  min-height: var(--monster-control-bar-height);
57
+ min-width: 0;
56
58
  }
57
59
 
58
60
  & ::slotted(form),
@@ -76,13 +78,22 @@ div[data-monster-role="control"] {
76
78
  line-height: 1.5;
77
79
  height: var(--monster-control-bar-height);
78
80
  padding: var(--monster-select-control-padding, 0.4rem 0.6rem);
81
+ width: auto !important;
82
+ inline-size: auto !important;
79
83
  }
80
84
 
81
85
  & ::slotted(monster-select) {
86
+ --monster-select-container-align-self: stretch;
87
+ --monster-select-container-block-size: 100%;
82
88
  --monster-select-container-overflow: hidden;
83
89
  --monster-select-selection-flex-wrap: nowrap;
84
90
  --monster-select-selection-margin: 0;
85
91
  --monster-select-control-padding: 0.4rem 0.6rem;
92
+ width: auto !important;
93
+ inline-size: auto !important;
94
+ max-inline-size: 100%;
95
+ min-inline-size: var(--monster-control-bar-select-min-inline-size, 12rem) !important;
96
+ min-width: var(--monster-control-bar-select-min-inline-size, 12rem) !important;
86
97
  }
87
98
 
88
99
  & ::slotted(monster-input-group) {
@@ -139,6 +150,8 @@ div[data-monster-role="control"] {
139
150
  }
140
151
 
141
152
  &::slotted(monster-select) {
153
+ --monster-select-container-align-self: stretch;
154
+ --monster-select-container-block-size: 100%;
142
155
  --monster-select-container-overflow: hidden;
143
156
  --monster-select-selection-flex-wrap: nowrap;
144
157
  --monster-select-selection-margin: 0;
@@ -14,6 +14,8 @@
14
14
  min-height: 0;
15
15
  flex: 4 0 90%;
16
16
  width: 100%;
17
+ block-size: var(--monster-select-container-block-size, auto);
18
+ align-self: var(--monster-select-container-align-self, auto);
17
19
  overflow: var(--monster-select-container-overflow, auto);
18
20
  display: flex;
19
21
  align-items: center;
@@ -87,6 +89,10 @@ div[data-monster-role="control"] {
87
89
 
88
90
  }
89
91
 
92
+ [data-monster-role=popper] {
93
+ z-index: var(--monster-z-index-popover);
94
+ }
95
+
90
96
  @media (prefers-color-scheme: light) {
91
97
  [data-monster-role=control] {
92
98
  background-color: var(--monster-bg-color-primary-1);