@ni/spright-components 0.0.15 → 0.0.16

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.
@@ -5208,7 +5208,7 @@
5208
5208
  * @param array - the array to test
5209
5209
  * @param predicate - find calls predicate once for each element of the array, in descending order, until it finds one where predicate returns true. If such an element is found, findLastIndex immediately returns that element index. Otherwise, findIndex returns -1.
5210
5210
  */
5211
- function findLastIndex(array, predicate) {
5211
+ function findLastIndex$1(array, predicate) {
5212
5212
  let k = array.length;
5213
5213
  while (k--) {
5214
5214
  if (predicate(array[k], k, array)) {
@@ -8234,7 +8234,7 @@
8234
8234
  */
8235
8235
  selectLastOption() {
8236
8236
  if (!this.disabled) {
8237
- this.selectedIndex = findLastIndex(this.options, o => !o.disabled);
8237
+ this.selectedIndex = findLastIndex$1(this.options, o => !o.disabled);
8238
8238
  }
8239
8239
  }
8240
8240
  /**
@@ -16333,7 +16333,7 @@
16333
16333
 
16334
16334
  /**
16335
16335
  * Do not edit directly
16336
- * Generated on Tue, 07 May 2024 13:04:38 GMT
16336
+ * Generated on Tue, 07 May 2024 16:11:49 GMT
16337
16337
  */
16338
16338
 
16339
16339
  const Information100DarkUi = "#a46eff";
@@ -16696,6 +16696,22 @@
16696
16696
  const prefix = 'ni-nimble';
16697
16697
  const styleNameFromTokenName = (tokenName) => `${prefix}-${tokenName}`;
16698
16698
 
16699
+ /**
16700
+ * Returns the index of the last element in the array where predicate is true, and -1 otherwise.
16701
+ *
16702
+ * @param array - the array to test
16703
+ * @param predicate - find calls predicate once for each element of the array, in descending order, until it finds one where predicate returns true. If such an element is found, findLastIndex immediately returns that element index. Otherwise, findIndex returns -1.
16704
+ */
16705
+ function findLastIndex(array, predicate) {
16706
+ let k = array.length;
16707
+ while (k--) {
16708
+ if (predicate(array[k], k, array)) {
16709
+ return k;
16710
+ }
16711
+ }
16712
+ return -1;
16713
+ }
16714
+
16699
16715
  /**
16700
16716
  * This set of exported strings reference https://developer.mozilla.org/en-US/docs/Web/Events
16701
16717
  * and should include all non-deprecated and non-experimental Standard events
@@ -24861,6 +24877,15 @@
24861
24877
  * by the filtering process.
24862
24878
  */
24863
24879
  this.visuallyHidden = false;
24880
+ /**
24881
+ * @internal
24882
+ * This attribute is used to control the visual selected state of an option. This
24883
+ * is handled independently of the public 'selected' attribute, as 'selected' is
24884
+ * representative of the current value of the container control. However, while
24885
+ * a dropdown is open users can navigate through the options (requiring visual
24886
+ * updates) without changing the value of the container control.
24887
+ */
24888
+ this.activeOption = false;
24864
24889
  /** @internal */
24865
24890
  this.hasOverflow = false;
24866
24891
  }
@@ -24890,6 +24915,9 @@
24890
24915
  __decorate$1([
24891
24916
  attr({ attribute: 'visually-hidden', mode: 'boolean' })
24892
24917
  ], ListOption.prototype, "visuallyHidden", void 0);
24918
+ __decorate$1([
24919
+ attr({ attribute: 'active-option', mode: 'boolean' })
24920
+ ], ListOption.prototype, "activeOption", void 0);
24893
24921
  __decorate$1([
24894
24922
  observable
24895
24923
  ], ListOption.prototype, "hasOverflow", void 0);
@@ -58677,6 +58705,18 @@ img.ProseMirror-separator {
58677
58705
  overflow: auto;
58678
58706
  }
58679
58707
 
58708
+ ::slotted([role='option']) {
58709
+ background-color: transparent;
58710
+ }
58711
+
58712
+ ::slotted([role='option'][active-option]) {
58713
+ background-color: ${fillSelectedColor};
58714
+ }
58715
+
58716
+ ::slotted([role='option'][active-option]:hover) {
58717
+ background-color: ${fillHoverSelectedColor};
58718
+ }
58719
+
58680
58720
  .no-results-label {
58681
58721
  color: ${placeholderFontColor};
58682
58722
  height: ${controlHeight};
@@ -58885,7 +58925,9 @@ img.ProseMirror-separator {
58885
58925
  connectedCallback() {
58886
58926
  super.connectedCallback();
58887
58927
  this.forcedPosition = !!this.positionAttribute;
58888
- this.initializeOpenState();
58928
+ if (this.open) {
58929
+ this.initializeOpenState();
58930
+ }
58889
58931
  }
58890
58932
  get value() {
58891
58933
  Observable.track(this, 'value');
@@ -58984,7 +59026,7 @@ img.ProseMirror-separator {
58984
59026
  }
58985
59027
  super.clickHandler(e);
58986
59028
  this.open = this.collapsible && !this.open;
58987
- if (!this.open && this.indexWhenOpened !== this.selectedIndex) {
59029
+ if (!this.open && this.selectedIndex !== -1) {
58988
59030
  this.updateValue(true);
58989
59031
  }
58990
59032
  }
@@ -59094,22 +59136,19 @@ img.ProseMirror-separator {
59094
59136
  */
59095
59137
  inputHandler(e) {
59096
59138
  this.filter = this.filterInput?.value ?? '';
59097
- this.clearSelection();
59098
59139
  this.filterOptions();
59099
- if (this.filteredOptions.length > 0) {
59100
- const enabledOptions = this.filteredOptions.filter(o => !o.disabled);
59101
- if (enabledOptions.length > 0) {
59102
- enabledOptions[0].selected = true;
59103
- }
59104
- else {
59105
- // only filtered option is disabled
59106
- this.selectedOptions = [];
59107
- this.selectedIndex = -1;
59108
- }
59140
+ const enabledOptions = this.filteredOptions.filter(o => !o.disabled);
59141
+ let activeOptionIndex = this.filter !== ''
59142
+ ? this.openActiveIndex ?? this.selectedIndex
59143
+ : this.selectedIndex;
59144
+ if (enabledOptions.length > 0
59145
+ && !enabledOptions.find(o => o === this.options[activeOptionIndex])) {
59146
+ activeOptionIndex = this.options.indexOf(enabledOptions[0]);
59109
59147
  }
59110
- else if (this.committedSelectedOption) {
59111
- this.committedSelectedOption.selected = true;
59148
+ else if (enabledOptions.length === 0) {
59149
+ activeOptionIndex = -1;
59112
59150
  }
59151
+ this.setActiveOption(activeOptionIndex);
59113
59152
  if (e.inputType.includes('deleteContent') || !this.filter.length) {
59114
59153
  return true;
59115
59154
  }
@@ -59130,11 +59169,13 @@ img.ProseMirror-separator {
59130
59169
  return true;
59131
59170
  }
59132
59171
  if (!this.options?.includes(focusTarget)) {
59172
+ let currentActiveIndex = this.openActiveIndex ?? this.selectedIndex;
59133
59173
  this.open = false;
59134
- if (this.selectedIndex === -1) {
59135
- this.selectedIndex = this.indexWhenOpened;
59174
+ if (currentActiveIndex === -1) {
59175
+ currentActiveIndex = this.selectedIndex;
59136
59176
  }
59137
- if (this.indexWhenOpened !== this.selectedIndex) {
59177
+ if (this.selectedIndex !== currentActiveIndex) {
59178
+ this.selectedIndex = currentActiveIndex;
59138
59179
  this.updateValue(true);
59139
59180
  }
59140
59181
  }
@@ -59144,11 +59185,13 @@ img.ProseMirror-separator {
59144
59185
  * @internal
59145
59186
  */
59146
59187
  keydownHandler(e) {
59188
+ const initialSelectedIndex = this.selectedIndex;
59147
59189
  super.keydownHandler(e);
59148
59190
  const key = e.key;
59149
59191
  if (e.ctrlKey || e.shiftKey) {
59150
59192
  return true;
59151
59193
  }
59194
+ let currentActiveIndex = this.openActiveIndex ?? this.selectedIndex;
59152
59195
  switch (key) {
59153
59196
  case keySpace: {
59154
59197
  // when dropdown is open allow user to enter a space for filter text
@@ -59189,24 +59232,16 @@ img.ProseMirror-separator {
59189
59232
  e.preventDefault();
59190
59233
  this.open = false;
59191
59234
  }
59192
- if (this.selectedIndex !== this.indexWhenOpened) {
59193
- this.options[this.selectedIndex].selected = false;
59194
- this.selectedIndex = this.indexWhenOpened;
59195
- }
59235
+ currentActiveIndex = this.selectedIndex;
59196
59236
  this.focus();
59197
59237
  break;
59198
59238
  }
59199
- case keyTab: {
59200
- if (this.collapsible && this.open) {
59201
- e.preventDefault();
59202
- this.open = false;
59203
- }
59204
- return true;
59205
- }
59206
59239
  }
59207
- if (!this.open && this.indexWhenOpened !== this.selectedIndex) {
59240
+ if (!this.open && this.selectedIndex !== currentActiveIndex) {
59241
+ this.selectedIndex = currentActiveIndex;
59242
+ }
59243
+ if (!this.open && initialSelectedIndex !== this.selectedIndex) {
59208
59244
  this.updateValue(true);
59209
- this.indexWhenOpened = this.selectedIndex;
59210
59245
  }
59211
59246
  return !(key === keyArrowDown || key === keyArrowUp);
59212
59247
  }
@@ -59224,8 +59259,28 @@ img.ProseMirror-separator {
59224
59259
  // implementation handles skipping non-selected disabled options for the initial
59225
59260
  // selected value.
59226
59261
  this.setSelectedOptions();
59262
+ if (this.open) {
59263
+ this.setActiveOption(this.selectedIndex);
59264
+ }
59227
59265
  this.updateValue();
59228
59266
  }
59267
+ /**
59268
+ * @internal
59269
+ * Fork of Listbox implementation, so that the selectedIndex is not changed while the dropdown
59270
+ * is open.
59271
+ */
59272
+ typeaheadBufferChanged(_, __) {
59273
+ if (this.$fastController.isConnected) {
59274
+ const typeaheadMatches = this.getTypeaheadMatches();
59275
+ if (typeaheadMatches.length) {
59276
+ const activeOptionIndex = this.options.indexOf(typeaheadMatches[0]);
59277
+ if (!(this.open && this.filterMode !== FilterMode.none)) {
59278
+ this.setActiveOption(activeOptionIndex);
59279
+ }
59280
+ }
59281
+ this.typeaheadExpired = false;
59282
+ }
59283
+ }
59229
59284
  /**
59230
59285
  * Synchronize the `aria-disabled` property when the `disabled` property changes.
59231
59286
  *
@@ -59254,30 +59309,52 @@ img.ProseMirror-separator {
59254
59309
  this.selectedIndex = 0;
59255
59310
  }
59256
59311
  }
59312
+ /**
59313
+ * @internal
59314
+ */
59257
59315
  selectNextOption() {
59258
59316
  // don't call super.selectNextOption as that relies on side-effecty
59259
59317
  // behavior to not select disabled option (which no longer works)
59260
- for (let i = this.selectedIndex + 1; i < this.options.length; i++) {
59318
+ const startIndex = this.openActiveIndex ?? this.selectedIndex;
59319
+ for (let i = startIndex + 1; i < this.options.length; i++) {
59261
59320
  const listOption = this.options[i];
59262
59321
  if (isNimbleListOption(listOption)
59263
59322
  && isOptionSelectable(listOption)) {
59264
- this.selectedIndex = i;
59323
+ this.setActiveOption(i);
59265
59324
  break;
59266
59325
  }
59267
59326
  }
59268
59327
  }
59328
+ /**
59329
+ * @internal
59330
+ */
59269
59331
  selectPreviousOption() {
59270
59332
  // don't call super.selectPreviousOption as that relies on side-effecty
59271
59333
  // behavior to not select disabled option (which no longer works)
59272
- for (let i = this.selectedIndex - 1; i >= 0; i--) {
59334
+ const startIndex = this.openActiveIndex ?? this.selectedIndex;
59335
+ for (let i = startIndex - 1; i >= 0; i--) {
59273
59336
  const listOption = this.options[i];
59274
59337
  if (isNimbleListOption(listOption)
59275
59338
  && isOptionSelectable(listOption)) {
59276
- this.selectedIndex = i;
59339
+ this.setActiveOption(i);
59277
59340
  break;
59278
59341
  }
59279
59342
  }
59280
59343
  }
59344
+ /**
59345
+ * @internal
59346
+ */
59347
+ selectFirstOption() {
59348
+ const newActiveOptionIndex = this.options.findIndex(o => isNimbleListOption(o) && isOptionSelectable(o));
59349
+ this.setActiveOption(newActiveOptionIndex);
59350
+ }
59351
+ /**
59352
+ * @internal
59353
+ */
59354
+ selectLastOption() {
59355
+ const newActiveOptionIndex = findLastIndex(this.options, o => isNimbleListOption(o) && isOptionSelectable(o));
59356
+ this.setActiveOption(newActiveOptionIndex);
59357
+ }
59281
59358
  /**
59282
59359
  * @internal
59283
59360
  */
@@ -59310,6 +59387,11 @@ img.ProseMirror-separator {
59310
59387
  });
59311
59388
  }
59312
59389
  }
59390
+ getTypeaheadMatches() {
59391
+ const matches = super.getTypeaheadMatches();
59392
+ // Don't allow placeholder to be matched
59393
+ return matches.filter(o => !o.hidden && !o.disabled);
59394
+ }
59313
59395
  positionChanged(_, next) {
59314
59396
  this.positionAttribute = next;
59315
59397
  this.setPositioning();
@@ -59335,9 +59417,13 @@ img.ProseMirror-separator {
59335
59417
  }
59336
59418
  if (this.open) {
59337
59419
  this.initializeOpenState();
59338
- this.indexWhenOpened = this.selectedIndex;
59339
59420
  return;
59340
59421
  }
59422
+ const activeOption = this.options[this.openActiveIndex ?? this.selectedIndex];
59423
+ if (isNimbleListOption(activeOption)) {
59424
+ activeOption.activeOption = false;
59425
+ }
59426
+ this.openActiveIndex = undefined;
59341
59427
  this.filter = '';
59342
59428
  if (this.filterInput) {
59343
59429
  this.filterInput.value = '';
@@ -59404,6 +59490,40 @@ img.ProseMirror-separator {
59404
59490
  }
59405
59491
  this.committedSelectedOption = options[this.selectedIndex];
59406
59492
  }
59493
+ setActiveOption(newActiveIndex) {
59494
+ const activeOption = this.options[newActiveIndex];
59495
+ if (this.open) {
59496
+ if (isNimbleListOption(activeOption)) {
59497
+ activeOption.activeOption = true;
59498
+ }
59499
+ const previousActiveIndex = this.openActiveIndex ?? this.selectedIndex;
59500
+ const previousActiveOption = this.options[previousActiveIndex];
59501
+ if (previousActiveIndex !== newActiveIndex
59502
+ && isNimbleListOption(previousActiveOption)) {
59503
+ previousActiveOption.activeOption = false;
59504
+ }
59505
+ this.openActiveIndex = newActiveIndex;
59506
+ this.focusAndScrollActiveOptionIntoView();
59507
+ }
59508
+ else {
59509
+ this.selectedIndex = newActiveIndex;
59510
+ }
59511
+ this.ariaActiveDescendant = activeOption?.id ?? '';
59512
+ }
59513
+ focusAndScrollActiveOptionIntoView() {
59514
+ const optionToFocus = this.options[this.openActiveIndex ?? this.selectedIndex];
59515
+ // Copied from FAST: To ensure that the browser handles both `focus()` and
59516
+ // `scrollIntoView()`, the timing here needs to guarantee that they happen on
59517
+ // different frames. Since this function is typically called from the `openChanged`
59518
+ // observer, `DOM.queueUpdate` causes the calls to be grouped into the same frame.
59519
+ // To prevent this, `requestAnimationFrame` is used instead of `DOM.queueUpdate`.
59520
+ if (optionToFocus !== undefined && this.contains(optionToFocus)) {
59521
+ optionToFocus.focus();
59522
+ requestAnimationFrame(() => {
59523
+ optionToFocus.scrollIntoView({ block: 'nearest' });
59524
+ });
59525
+ }
59526
+ }
59407
59527
  committedSelectedOptionChanged() {
59408
59528
  this.updateDisplayValue();
59409
59529
  }
@@ -59499,11 +59619,6 @@ img.ProseMirror-separator {
59499
59619
  });
59500
59620
  }
59501
59621
  }
59502
- clearSelection() {
59503
- this.options.forEach(option => {
59504
- option.selected = false;
59505
- });
59506
- }
59507
59622
  filterChanged() {
59508
59623
  this.filterOptions();
59509
59624
  }
@@ -59511,12 +59626,8 @@ img.ProseMirror-separator {
59511
59626
  this.updateListboxMaxHeightCssVariable();
59512
59627
  }
59513
59628
  initializeOpenState() {
59514
- if (!this.open) {
59515
- this.ariaExpanded = 'false';
59516
- this.ariaControls = '';
59517
- return;
59518
- }
59519
59629
  this.committedSelectedOption = this.options[this.selectedIndex];
59630
+ this.setActiveOption(this.selectedIndex);
59520
59631
  this.ariaControls = this.listboxId;
59521
59632
  this.ariaExpanded = 'true';
59522
59633
  this.setPositioning();