@ni/nimble-components 21.8.2 → 21.9.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.
@@ -16301,7 +16301,7 @@
16301
16301
 
16302
16302
  /**
16303
16303
  * Do not edit directly
16304
- * Generated on Mon, 04 Mar 2024 18:45:22 GMT
16304
+ * Generated on Tue, 05 Mar 2024 22:11:22 GMT
16305
16305
  */
16306
16306
 
16307
16307
  const Information100DarkUi = "#a46eff";
@@ -24309,17 +24309,6 @@
24309
24309
  height: ${controlHeight};
24310
24310
  }
24311
24311
 
24312
- [part='start'] {
24313
- display: none;
24314
- }
24315
-
24316
- .content {
24317
- padding: 8px 4px;
24318
- white-space: nowrap;
24319
- overflow: hidden;
24320
- text-overflow: ellipsis;
24321
- }
24322
-
24323
24312
  :host([aria-selected='true']) {
24324
24313
  box-shadow: none;
24325
24314
  outline: none;
@@ -24356,6 +24345,21 @@
24356
24345
  cursor: default;
24357
24346
  }
24358
24347
 
24348
+ :host([visually-hidden]) {
24349
+ display: none;
24350
+ }
24351
+
24352
+ [part='start'] {
24353
+ display: none;
24354
+ }
24355
+
24356
+ .content {
24357
+ padding: 8px 4px;
24358
+ white-space: nowrap;
24359
+ overflow: hidden;
24360
+ text-overflow: ellipsis;
24361
+ }
24362
+
24359
24363
  .content[disabled] {
24360
24364
  box-shadow: none;
24361
24365
  outline: none;
@@ -24403,6 +24407,23 @@
24403
24407
  class ListOption extends ListboxOption {
24404
24408
  constructor() {
24405
24409
  super(...arguments);
24410
+ /**
24411
+ * The hidden state of the element.
24412
+ *
24413
+ * @public
24414
+ * @defaultValue - false
24415
+ * @remarks
24416
+ * HTML Attribute: hidden
24417
+ */
24418
+ this.hidden = false;
24419
+ /**
24420
+ * @internal
24421
+ * This attribute is required to allow use-cases that offer dynamic filtering
24422
+ * (like the Select) to visually hide options that are filtered out, but still
24423
+ * allow users to use the native 'hidden' attribute without it being affected
24424
+ * by the filtering process.
24425
+ */
24426
+ this.visuallyHidden = false;
24406
24427
  /** @internal */
24407
24428
  this.hasOverflow = false;
24408
24429
  }
@@ -24414,6 +24435,12 @@
24414
24435
  .join(' ');
24415
24436
  }
24416
24437
  }
24438
+ __decorate$1([
24439
+ attr({ mode: 'boolean' })
24440
+ ], ListOption.prototype, "hidden", void 0);
24441
+ __decorate$1([
24442
+ attr({ attribute: 'visually-hidden', mode: 'boolean' })
24443
+ ], ListOption.prototype, "visuallyHidden", void 0);
24417
24444
  __decorate$1([
24418
24445
  observable
24419
24446
  ], ListOption.prototype, "hasOverflow", void 0);
@@ -57884,7 +57911,12 @@ img.ProseMirror-separator {
57884
57911
  ${
57885
57912
  /* We are using flex `order` to define the visual ordering of the selected value,
57886
57913
  error icon, and dropdown arrow because they are not "interactive" i.e. part of the tab order */ ''}
57887
- [part='selected-value'] {
57914
+
57915
+ .selected-value.placeholder {
57916
+ color: ${placeholderFontColor};
57917
+ }
57918
+
57919
+ .selected-value {
57888
57920
  order: 1;
57889
57921
  }
57890
57922
 
@@ -58025,7 +58057,7 @@ img.ProseMirror-separator {
58025
58057
  >
58026
58058
  ${startSlotTemplate(context, definition)}
58027
58059
  <slot name="button-container">
58028
- <div class="selected-value" part="selected-value" ${overflow('hasOverflow')} title=${x => (x.hasOverflow && x.displayValue ? x.displayValue : null)}>
58060
+ <div class="selected-value ${x => (x.displayPlaceholder ? 'placeholder' : '')}" part="selected-value" ${overflow('hasOverflow')} title=${x => (x.hasOverflow && x.displayValue ? x.displayValue : null)}>
58029
58061
  <slot name="selected-value">${x => x.displayValue}</slot>
58030
58062
  </div>
58031
58063
  <div aria-hidden="true" class="indicator" part="indicator">
@@ -58081,7 +58113,7 @@ img.ProseMirror-separator {
58081
58113
  class="scrollable-region">
58082
58114
  <slot
58083
58115
  ${slotted({
58084
- filter: (n) => n instanceof HTMLElement && Listbox$1.slottedOptionFilter(n),
58116
+ filter: (n) => n instanceof HTMLElement && isListboxOption(n),
58085
58117
  flatten: true,
58086
58118
  property: 'slottedOptions',
58087
58119
  })}
@@ -58116,6 +58148,9 @@ img.ProseMirror-separator {
58116
58148
  }
58117
58149
  }
58118
58150
 
58151
+ const isNimbleListOption = (el) => {
58152
+ return el instanceof ListOption;
58153
+ };
58119
58154
  /**
58120
58155
  * A nimble-styled HTML select.
58121
58156
  */
@@ -58125,6 +58160,10 @@ img.ProseMirror-separator {
58125
58160
  this.appearance = DropdownAppearance.underline;
58126
58161
  this.errorVisible = false;
58127
58162
  this.filterMode = FilterMode.none;
58163
+ /**
58164
+ * @internal
58165
+ */
58166
+ this.displayPlaceholder = false;
58128
58167
  /**
58129
58168
  * @internal
58130
58169
  */
@@ -58145,10 +58184,6 @@ img.ProseMirror-separator {
58145
58184
  * @internal
58146
58185
  */
58147
58186
  this.filter = '';
58148
- /**
58149
- * @internal
58150
- */
58151
- this.committedSelectedOption = undefined;
58152
58187
  /**
58153
58188
  * The max height for the listbox when opened.
58154
58189
  *
@@ -58174,24 +58209,6 @@ img.ProseMirror-separator {
58174
58209
  this.forcedPosition = !!this.positionAttribute;
58175
58210
  this.initializeOpenState();
58176
58211
  }
58177
- /**
58178
- * The list of options. This mirrors FAST's override implementation for this
58179
- * member for the Combobox to support a filtered list in the dropdown.
58180
- *
58181
- * @public
58182
- * @remarks
58183
- * Overrides `Listbox.options`.
58184
- */
58185
- get options() {
58186
- Observable.track(this, 'options');
58187
- return this.filteredOptions?.length
58188
- ? this.filteredOptions
58189
- : this._options;
58190
- }
58191
- set options(value) {
58192
- this._options = value;
58193
- Observable.notify(this, 'options');
58194
- }
58195
58212
  get value() {
58196
58213
  Observable.track(this, 'value');
58197
58214
  return this._value;
@@ -58199,8 +58216,6 @@ img.ProseMirror-separator {
58199
58216
  set value(next) {
58200
58217
  const prev = this._value;
58201
58218
  let newValue = next;
58202
- // use 'options' here instead of '_options' as 'selectedIndex' may be relative
58203
- // to filtered set
58204
58219
  if (this.options?.length) {
58205
58220
  const newValueIndex = this.options.findIndex(el => el.value === newValue);
58206
58221
  const prevSelectedValue = this.options[this.selectedIndex]?.value ?? null;
@@ -58216,7 +58231,7 @@ img.ProseMirror-separator {
58216
58231
  this._value = newValue;
58217
58232
  super.valueChanged(prev, newValue);
58218
58233
  if (!this.open) {
58219
- this.committedSelectedOption = this._options.find(o => o.value === newValue);
58234
+ this.committedSelectedOption = this.options.find(o => o.value === newValue);
58220
58235
  }
58221
58236
  Observable.notify(this, 'value');
58222
58237
  if (this.collapsible) {
@@ -58252,14 +58267,18 @@ img.ProseMirror-separator {
58252
58267
  */
58253
58268
  slottedOptionsChanged(prev, next) {
58254
58269
  const value = this.value;
58255
- this._options.forEach(o => {
58270
+ this.options.forEach(o => {
58256
58271
  const notifier = Observable.getNotifier(o);
58257
58272
  notifier.unsubscribe(this, 'value');
58273
+ notifier.unsubscribe(this, 'hidden');
58274
+ notifier.unsubscribe(this, 'disabled');
58258
58275
  });
58259
58276
  super.slottedOptionsChanged(prev, next);
58260
- this._options.forEach(o => {
58277
+ this.options.forEach(o => {
58261
58278
  const notifier = Observable.getNotifier(o);
58262
58279
  notifier.subscribe(this, 'value');
58280
+ notifier.subscribe(this, 'hidden');
58281
+ notifier.subscribe(this, 'disabled');
58263
58282
  });
58264
58283
  this.setProxyOptions();
58265
58284
  this.updateValue();
@@ -58281,9 +58300,6 @@ img.ProseMirror-separator {
58281
58300
  }
58282
58301
  if (this.open) {
58283
58302
  const captured = e.target.closest('option,[role=option]');
58284
- if (!captured?.disabled) {
58285
- this.updateSelectedIndexFromFilteredSet();
58286
- }
58287
58303
  if (captured?.disabled) {
58288
58304
  return;
58289
58305
  }
@@ -58304,9 +58320,32 @@ img.ProseMirror-separator {
58304
58320
  * @override
58305
58321
  */
58306
58322
  handleChange(source, propertyName) {
58307
- super.handleChange(source, propertyName);
58308
- if (propertyName === 'value') {
58309
- this.updateValue();
58323
+ // don't call super.handleChange so hidden options can be selected programmatically
58324
+ const sourceElement = source;
58325
+ switch (propertyName) {
58326
+ case 'value': {
58327
+ this.updateValue();
58328
+ break;
58329
+ }
58330
+ case 'selected': {
58331
+ if (isNimbleListOption(sourceElement)) {
58332
+ this.selectedIndex = this.options.indexOf(sourceElement);
58333
+ }
58334
+ this.setSelectedOptions();
58335
+ this.updateDisplayValue();
58336
+ break;
58337
+ }
58338
+ case 'hidden': {
58339
+ if (isNimbleListOption(sourceElement)) {
58340
+ sourceElement.visuallyHidden = sourceElement.hidden;
58341
+ }
58342
+ this.updateDisplayValue();
58343
+ break;
58344
+ }
58345
+ case 'disabled': {
58346
+ this.updateDisplayValue();
58347
+ break;
58348
+ }
58310
58349
  }
58311
58350
  }
58312
58351
  /**
@@ -58357,6 +58396,14 @@ img.ProseMirror-separator {
58357
58396
  * @internal
58358
58397
  */
58359
58398
  updateDisplayValue() {
58399
+ if (this.committedSelectedOption?.disabled
58400
+ && this.committedSelectedOption?.hidden
58401
+ && this.committedSelectedOption?.selected) {
58402
+ this.displayPlaceholder = true;
58403
+ }
58404
+ else {
58405
+ this.displayPlaceholder = false;
58406
+ }
58360
58407
  if (this.collapsible) {
58361
58408
  Observable.notify(this, 'displayValue');
58362
58409
  }
@@ -58369,14 +58416,9 @@ img.ProseMirror-separator {
58369
58416
  */
58370
58417
  inputHandler(e) {
58371
58418
  this.filter = this.filterInput?.value ?? '';
58372
- if (!this.committedSelectedOption) {
58373
- this.committedSelectedOption = this._options.find(option => option.selected);
58374
- }
58375
58419
  this.clearSelection();
58376
58420
  this.filterOptions();
58377
- if (this.filteredOptions.length > 0
58378
- && this.committedSelectedOption
58379
- && !this.filteredOptions.includes(this.committedSelectedOption)) {
58421
+ if (this.filteredOptions.length > 0) {
58380
58422
  const enabledOptions = this.filteredOptions.filter(o => !o.disabled);
58381
58423
  if (enabledOptions.length > 0) {
58382
58424
  enabledOptions[0].selected = true;
@@ -58400,7 +58442,6 @@ img.ProseMirror-separator {
58400
58442
  * @internal
58401
58443
  */
58402
58444
  focusoutHandler(e) {
58403
- this.updateSelectedIndexFromFilteredSet();
58404
58445
  super.focusoutHandler(e);
58405
58446
  if (!this.open) {
58406
58447
  return true;
@@ -58412,6 +58453,9 @@ img.ProseMirror-separator {
58412
58453
  }
58413
58454
  if (!this.options?.includes(focusTarget)) {
58414
58455
  this.open = false;
58456
+ if (this.selectedIndex === -1) {
58457
+ this.selectedIndex = this.indexWhenOpened;
58458
+ }
58415
58459
  if (this.indexWhenOpened !== this.selectedIndex) {
58416
58460
  this.updateValue(true);
58417
58461
  }
@@ -58453,7 +58497,6 @@ img.ProseMirror-separator {
58453
58497
  || this.filteredOptions.every(o => o.disabled)) {
58454
58498
  return false;
58455
58499
  }
58456
- this.updateSelectedIndexFromFilteredSet();
58457
58500
  this.open = !this.open;
58458
58501
  if (!this.open) {
58459
58502
  this.focus();
@@ -58461,21 +58504,16 @@ img.ProseMirror-separator {
58461
58504
  break;
58462
58505
  }
58463
58506
  case keyEscape: {
58464
- // clear filter as update to "selectedIndex" will result in processing
58465
- // "options" and not "_options"
58466
- this.filter = '';
58467
- if (this.committedSelectedOption) {
58468
- this.clearSelection();
58469
- this.selectedIndex = this._options.indexOf(this.committedSelectedOption);
58507
+ if (!this.open) {
58508
+ break;
58470
58509
  }
58471
58510
  if (this.collapsible && this.open) {
58472
58511
  e.preventDefault();
58473
58512
  this.open = false;
58474
58513
  }
58475
- // reset 'selected' state otherwise the selected state doesn't stick.
58476
- const selectedOption = this._options[this.selectedIndex];
58477
- if (selectedOption) {
58478
- selectedOption.selected = true;
58514
+ if (this.selectedIndex !== this.indexWhenOpened) {
58515
+ this.options[this.selectedIndex].selected = false;
58516
+ this.selectedIndex = this.indexWhenOpened;
58479
58517
  }
58480
58518
  this.focus();
58481
58519
  break;
@@ -58502,8 +58540,12 @@ img.ProseMirror-separator {
58502
58540
  *
58503
58541
  * @internal
58504
58542
  */
58505
- selectedIndexChanged(prev, next) {
58506
- super.selectedIndexChanged(prev, next);
58543
+ selectedIndexChanged(_, __) {
58544
+ // Don't call super.selectedIndexChanged as this will disallow disabled options
58545
+ // from being valid initial selected values. Our setDefaultSelectedOption
58546
+ // implementation handles skipping non-selected disabled options for the initial
58547
+ // selected value.
58548
+ this.setSelectedOptions();
58507
58549
  this.updateValue();
58508
58550
  }
58509
58551
  /**
@@ -58534,6 +58576,26 @@ img.ProseMirror-separator {
58534
58576
  this.selectedIndex = 0;
58535
58577
  }
58536
58578
  }
58579
+ selectNextOption() {
58580
+ // don't call super.selectNextOption as that relies on side-effecty
58581
+ // behavior to not select disabled option (which no longer works)
58582
+ for (let i = this.selectedIndex + 1; i < this.options.length; i++) {
58583
+ if (!this.options[i]?.disabled) {
58584
+ this.selectedIndex = i;
58585
+ break;
58586
+ }
58587
+ }
58588
+ }
58589
+ selectPreviousOption() {
58590
+ // don't call super.selectPreviousOption as that relies on side-effecty
58591
+ // behavior to not select disabled option (which no longer works)
58592
+ for (let i = this.selectedIndex - 1; i >= 0; i--) {
58593
+ if (!this.options[i]?.disabled) {
58594
+ this.selectedIndex = i;
58595
+ break;
58596
+ }
58597
+ }
58598
+ }
58537
58599
  // Prevents parent classes from resetting selectedIndex to a positive
58538
58600
  // value while filtering, which can result in a disabled option being
58539
58601
  // selected.
@@ -58595,9 +58657,14 @@ img.ProseMirror-separator {
58595
58657
  * @override
58596
58658
  * @internal
58597
58659
  */
58598
- selectedOptionsChanged(prev, next) {
58599
- super.selectedOptionsChanged(prev, next);
58660
+ selectedOptionsChanged(_prev, next) {
58661
+ // don't call super.selectedOptionsChanged so we don't filter out hidden elements
58662
+ // when updating 'selected' state (copied relevant super implementation)
58600
58663
  this.options?.forEach((o, i) => {
58664
+ const notifier = Observable.getNotifier(o);
58665
+ notifier.unsubscribe(this, 'selected');
58666
+ o.selected = next.includes(o);
58667
+ notifier.subscribe(this, 'selected');
58601
58668
  const proxyOption = this.proxy?.options.item(i);
58602
58669
  if (proxyOption) {
58603
58670
  proxyOption.selected = o.selected;
@@ -58613,15 +58680,37 @@ img.ProseMirror-separator {
58613
58680
  */
58614
58681
  setDefaultSelectedOption() {
58615
58682
  const options = this.options
58616
- ?? Array.from(this.children).filter(o => Listbox$1.slottedOptionFilter(o));
58617
- const selectedIndex = options?.findIndex(el => el.hasAttribute('selected')
58618
- || el.selected
58619
- || el.value === this.value);
58683
+ ?? Array.from(this.children).filter(o => isNimbleListOption(o));
58684
+ const optionIsSelected = (option) => {
58685
+ return option.hasAttribute('selected') || option.selected;
58686
+ };
58687
+ const optionIsDisabled = (option) => {
58688
+ return option.hasAttribute('disabled') || option.disabled;
58689
+ };
58690
+ let selectedIndex = -1;
58691
+ let firstValidOptionIndex = -1;
58692
+ for (let i = 0; i < options?.length; i++) {
58693
+ const option = options[i];
58694
+ if (optionIsSelected(option) || option?.value === this.value) {
58695
+ selectedIndex = i;
58696
+ }
58697
+ if (firstValidOptionIndex === -1 && !optionIsDisabled(option)) {
58698
+ firstValidOptionIndex = i;
58699
+ }
58700
+ }
58620
58701
  if (selectedIndex !== -1) {
58621
58702
  this.selectedIndex = selectedIndex;
58622
- return;
58623
58703
  }
58624
- this.selectedIndex = 0;
58704
+ else if (firstValidOptionIndex !== -1) {
58705
+ this.selectedIndex = firstValidOptionIndex;
58706
+ }
58707
+ else {
58708
+ this.selectedIndex = 0;
58709
+ }
58710
+ this.committedSelectedOption = options[this.selectedIndex];
58711
+ }
58712
+ committedSelectedOptionChanged() {
58713
+ this.updateDisplayValue();
58625
58714
  }
58626
58715
  setPositioning() {
58627
58716
  if (!this.$fastController.isConnected) {
@@ -58657,15 +58746,24 @@ img.ProseMirror-separator {
58657
58746
  filterOptions() {
58658
58747
  const filter = this.filter.toLowerCase();
58659
58748
  if (filter) {
58660
- this.filteredOptions = this._options.filter(option => {
58661
- return diacriticInsensitiveStringNormalizer(option.text).includes(diacriticInsensitiveStringNormalizer(filter));
58749
+ this.filteredOptions = this.options.filter(option => {
58750
+ const normalizedFilter = diacriticInsensitiveStringNormalizer(filter);
58751
+ return (!option.hidden
58752
+ && diacriticInsensitiveStringNormalizer(option.text).includes(normalizedFilter));
58662
58753
  });
58663
58754
  }
58664
58755
  else {
58665
- this.filteredOptions = this._options;
58756
+ this.filteredOptions = this.options.filter(option => !option.hidden);
58666
58757
  }
58667
- this._options.forEach(o => {
58668
- o.hidden = !this.filteredOptions.includes(o);
58758
+ this.options.forEach(o => {
58759
+ if (isNimbleListOption(o)) {
58760
+ if (!this.filteredOptions.includes(o)) {
58761
+ o.visuallyHidden = true;
58762
+ }
58763
+ else {
58764
+ o.visuallyHidden = false;
58765
+ }
58766
+ }
58669
58767
  });
58670
58768
  }
58671
58769
  /**
@@ -58723,7 +58821,7 @@ img.ProseMirror-separator {
58723
58821
  this.ariaControls = '';
58724
58822
  return;
58725
58823
  }
58726
- this.committedSelectedOption = this._options[this.selectedIndex];
58824
+ this.committedSelectedOption = this.options[this.selectedIndex];
58727
58825
  this.ariaControls = this.listboxId;
58728
58826
  this.ariaExpanded = 'true';
58729
58827
  this.setPositioning();
@@ -58734,24 +58832,6 @@ img.ProseMirror-separator {
58734
58832
  this.listbox.style.setProperty('--ni-private-select-max-height', `${this.maxHeight}px`);
58735
58833
  }
58736
58834
  }
58737
- updateSelectedIndexFromFilteredSet() {
58738
- const selectedItem = this.filteredOptions.length > 0
58739
- ? this.options[this.selectedIndex]
58740
- ?? this.committedSelectedOption
58741
- : this.committedSelectedOption;
58742
- if (!selectedItem) {
58743
- return;
58744
- }
58745
- // Clear filter so any logic resolving against 'this.options' resolves against all options,
58746
- // since selectedIndex should be relative to entire set.
58747
- this.filter = '';
58748
- // translate selectedIndex for filtered list to selectedIndex for all items
58749
- this.selectedIndex = this._options.indexOf(selectedItem);
58750
- // force selected to true again if the selection hasn't actually changed
58751
- if (selectedItem === this.committedSelectedOption) {
58752
- selectedItem.selected = true;
58753
- }
58754
- }
58755
58835
  }
58756
58836
  __decorate$1([
58757
58837
  attr
@@ -58768,6 +58848,9 @@ img.ProseMirror-separator {
58768
58848
  __decorate$1([
58769
58849
  attr({ attribute: 'filter-mode' })
58770
58850
  ], Select.prototype, "filterMode", void 0);
58851
+ __decorate$1([
58852
+ observable
58853
+ ], Select.prototype, "displayPlaceholder", void 0);
58771
58854
  __decorate$1([
58772
58855
  attr({ attribute: 'open', mode: 'boolean' })
58773
58856
  ], Select.prototype, "open", void 0);
@@ -58804,6 +58887,9 @@ img.ProseMirror-separator {
58804
58887
  __decorate$1([
58805
58888
  volatile
58806
58889
  ], Select.prototype, "collapsible", null);
58890
+ __decorate$1([
58891
+ volatile
58892
+ ], Select.prototype, "displayValue", null);
58807
58893
  const nimbleSelect = Select.compose({
58808
58894
  baseName: 'select',
58809
58895
  baseClass: Select$2,