@aquera/ngx-smart-table 0.0.16-alpha → 0.0.17-patch-0.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.
@@ -3678,6 +3678,8 @@ class NileSelectEditor {
3678
3678
  this.acceptsInitialKeypress = false;
3679
3679
  this.eventListeners = [];
3680
3680
  this.currentOptions = [];
3681
+ this.trackedValues = []; // Track selected values for virtual scroll
3682
+ this.hasChangeOccurred = false; // Whether a nile-change event has fired
3681
3683
  // Handle Observable options
3682
3684
  if (isObservable(options.options)) {
3683
3685
  this.optionsSubscription = options.options.subscribe(opts => {
@@ -3721,13 +3723,15 @@ class NileSelectEditor {
3721
3723
  // Clear container and append select
3722
3724
  context.container.innerHTML = '';
3723
3725
  context.container.appendChild(this.select);
3724
- // Focus and auto-open after render
3726
+ // Focus the select after render
3725
3727
  setTimeout(() => {
3726
- if (this.select) {
3727
- this.select.focus();
3728
- this.select.open = true;
3728
+ try {
3729
+ this.select?.focus();
3729
3730
  }
3730
- }, 0);
3731
+ catch (e) {
3732
+ // Ignore errors
3733
+ }
3734
+ }, 50);
3731
3735
  }
3732
3736
  /**
3733
3737
  * Set the initial value for the select
@@ -3735,21 +3739,26 @@ class NileSelectEditor {
3735
3739
  setInitialValue(value) {
3736
3740
  if (!this.select)
3737
3741
  return;
3742
+ this.hasChangeOccurred = false;
3738
3743
  if (this.options.multiple) {
3739
3744
  // Handle multiple selection - value should be array
3740
3745
  if (Array.isArray(value)) {
3741
3746
  this.select.value = value;
3747
+ this.trackedValues = [...value]; // Initialize tracked values
3742
3748
  }
3743
3749
  else if (value) {
3744
3750
  this.select.value = [String(value)];
3751
+ this.trackedValues = [String(value)];
3745
3752
  }
3746
3753
  else {
3747
3754
  this.select.value = [];
3755
+ this.trackedValues = [];
3748
3756
  }
3749
3757
  }
3750
3758
  else {
3751
3759
  // Handle single selection
3752
3760
  this.select.value = value ? String(value) : '';
3761
+ this.trackedValues = value ? [String(value)] : [];
3753
3762
  }
3754
3763
  }
3755
3764
  /**
@@ -3833,12 +3842,17 @@ class NileSelectEditor {
3833
3842
  updateOptions() {
3834
3843
  if (!this.select)
3835
3844
  return;
3836
- // Clear existing options
3837
- while (this.select.firstChild) {
3838
- this.select.removeChild(this.select.firstChild);
3845
+ // For virtual scroll mode, just update the data property (no DOM children to clear)
3846
+ if (this.options.enableVirtualScroll) {
3847
+ this.createAndAppendOptions(this.currentOptions);
3848
+ }
3849
+ else {
3850
+ // Standard mode: clear existing nile-option elements first
3851
+ while (this.select.firstChild) {
3852
+ this.select.removeChild(this.select.firstChild);
3853
+ }
3854
+ this.createAndAppendOptions(this.currentOptions);
3839
3855
  }
3840
- // Re-append with new options
3841
- this.createAndAppendOptions(this.currentOptions);
3842
3856
  // Trigger update on the web component
3843
3857
  if (this.select.requestUpdate) {
3844
3858
  this.select.requestUpdate();
@@ -3846,11 +3860,22 @@ class NileSelectEditor {
3846
3860
  }
3847
3861
  /**
3848
3862
  * Create NileOption elements and append them to the select
3863
+ * When enableVirtualScroll is true, uses data property instead of DOM elements
3864
+ * @see https://nile.aqueralabs.com/select-virtual?theme=enterprise
3849
3865
  * @param options - The options to render
3850
3866
  */
3851
3867
  createAndAppendOptions(options) {
3852
3868
  if (!this.select)
3853
3869
  return;
3870
+ // Virtual scroll mode: use data property instead of DOM elements
3871
+ if (this.options.enableVirtualScroll) {
3872
+ const virtualData = options.map(opt => typeof opt === 'string'
3873
+ ? { value: opt, label: opt }
3874
+ : { value: opt.value, label: opt.label, disabled: opt.disabled });
3875
+ this.select.data = virtualData;
3876
+ return;
3877
+ }
3878
+ // Standard mode: create nile-option elements
3854
3879
  options.forEach(opt => {
3855
3880
  const nileOption = document.createElement('nile-option');
3856
3881
  // Auto-detect format: string or SelectOption object
@@ -3899,15 +3924,38 @@ class NileSelectEditor {
3899
3924
  if (!this.options.multiple) {
3900
3925
  const changeHandler = (e) => {
3901
3926
  const customEvent = e;
3902
- if (validateOnSave && !this.select?.checkValidity()) {
3903
- this.select?.reportValidity();
3904
- return;
3927
+ try {
3928
+ if (validateOnSave && this.select && !this.select.checkValidity()) {
3929
+ this.select.reportValidity();
3930
+ return;
3931
+ }
3932
+ }
3933
+ catch (err) {
3934
+ // Ignore validation errors - nile-select internals may not be ready
3905
3935
  }
3906
3936
  context.onSave(this.parseValue(customEvent.detail.value));
3907
3937
  };
3908
3938
  this.select.addEventListener('nile-change', changeHandler);
3909
3939
  this.eventListeners.push({ event: 'nile-change', handler: changeHandler });
3910
3940
  }
3941
+ // For multi-select, track value changes (needed for virtual scroll where value property doesn't update)
3942
+ if (this.options.multiple) {
3943
+ const trackValueHandler = (e) => {
3944
+ const customEvent = e;
3945
+ const newValue = customEvent.detail?.value;
3946
+ if (newValue !== undefined) {
3947
+ this.hasChangeOccurred = true;
3948
+ if (Array.isArray(newValue)) {
3949
+ this.trackedValues = [...newValue];
3950
+ }
3951
+ else {
3952
+ this.trackedValues = newValue ? [newValue] : [];
3953
+ }
3954
+ }
3955
+ };
3956
+ this.select.addEventListener('nile-change', trackValueHandler);
3957
+ this.eventListeners.push({ event: 'nile-change', handler: trackValueHandler });
3958
+ }
3911
3959
  // Track if save was already triggered (to prevent double save)
3912
3960
  let saveTriggered = false;
3913
3961
  // Use mousedown on document to detect clicks outside the select and portal
@@ -3916,23 +3964,47 @@ class NileSelectEditor {
3916
3964
  return;
3917
3965
  if (!this.select)
3918
3966
  return;
3919
- const target = e.target;
3920
- // Check if click is inside the select element
3921
- if (this.select.contains(target)) {
3922
- return;
3967
+ // Use composedPath to traverse shadow DOM boundaries
3968
+ const path = e.composedPath();
3969
+ // Check if click is inside the select element or any nile-select related elements
3970
+ for (const element of path) {
3971
+ if (!(element instanceof HTMLElement))
3972
+ continue;
3973
+ // Check if it's our select element
3974
+ if (element === this.select) {
3975
+ return;
3976
+ }
3977
+ // Check for nile-select portals (various class names)
3978
+ if (element.classList?.contains('nile-select-portal-append') ||
3979
+ element.classList?.contains('select__listbox') ||
3980
+ element.classList?.contains('select__options') ||
3981
+ element.tagName?.toLowerCase() === 'nile-option' ||
3982
+ element.tagName?.toLowerCase() === 'nile-select') {
3983
+ return;
3984
+ }
3985
+ // Check for any element with nile-select in its class
3986
+ if (element.className && typeof element.className === 'string' &&
3987
+ element.className.includes('nile-select')) {
3988
+ return;
3989
+ }
3923
3990
  }
3924
- // Check if click is inside any nile-select portal
3925
- const portals = document.querySelectorAll('.nile-select-portal-append');
3991
+ // Also check portal containers directly
3992
+ const portals = document.querySelectorAll('.nile-select-portal-append, [class*="select__listbox"]');
3926
3993
  for (let i = 0; i < portals.length; i++) {
3927
- if (portals[i].contains(target)) {
3994
+ if (portals[i].contains(e.target)) {
3928
3995
  return;
3929
3996
  }
3930
3997
  }
3931
3998
  // Click is outside - save and exit
3932
3999
  saveTriggered = true;
3933
- if (validateOnSave && !this.select?.checkValidity()) {
3934
- this.select?.reportValidity();
3935
- return;
4000
+ try {
4001
+ if (validateOnSave && this.select && !this.select.checkValidity()) {
4002
+ this.select.reportValidity();
4003
+ return;
4004
+ }
4005
+ }
4006
+ catch (err) {
4007
+ // Ignore validation errors - nile-select internals may not be ready
3936
4008
  }
3937
4009
  context.onSave(this.getCurrentValue());
3938
4010
  };
@@ -4000,19 +4072,28 @@ class NileSelectEditor {
4000
4072
  }
4001
4073
  }
4002
4074
  focus() {
4003
- this.select?.focus();
4075
+ try {
4076
+ this.select?.focus();
4077
+ }
4078
+ catch (e) {
4079
+ // Ignore focus errors - nile-select internals may not be ready
4080
+ }
4004
4081
  }
4005
4082
  getCurrentValue() {
4006
4083
  if (!this.select) {
4007
4084
  return (this.options.multiple ? [] : '');
4008
4085
  }
4009
- const value = this.select.value;
4010
- // Handle multiple selection
4011
4086
  if (this.options.multiple) {
4012
- return (Array.isArray(value) ? value : [value]);
4087
+ // If a change event fired, always use trackedValues (even if empty = all unchecked).
4088
+ // Only fall back to the component value when no change has occurred yet.
4089
+ let values = this.hasChangeOccurred ? this.trackedValues : this.select.value;
4090
+ if (Array.isArray(values)) {
4091
+ return values.filter((v) => v !== undefined && v !== null && v !== '');
4092
+ }
4093
+ return (values ? [values] : []);
4013
4094
  }
4014
- // Handle single selection
4015
- return (Array.isArray(value) ? (value.length > 0 ? value[0] : '') : value);
4095
+ let value = this.hasChangeOccurred ? (this.trackedValues[0] ?? '') : this.select.value;
4096
+ return (Array.isArray(value) ? (value.length > 0 ? value[0] : '') : (value || ''));
4016
4097
  }
4017
4098
  }
4018
4099