@aquera/ngx-smart-table 0.0.14-alpha → 0.0.15-alpha

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.
@@ -3613,6 +3613,8 @@ class NileSelectEditor {
3613
3613
  this.eventListeners = [];
3614
3614
  this.currentOptions = [];
3615
3615
  this.isInitializing = false; // Flag to prevent immediate close during initialization
3616
+ this.hasSaved = false; // Flag to prevent double-save
3617
+ this.lastSelectedValue = ''; // Track the last selected value
3616
3618
  // Handle Observable options
3617
3619
  if (isObservable(options.options)) {
3618
3620
  this.optionsSubscription = options.options.subscribe(opts => {
@@ -3709,6 +3711,8 @@ class NileSelectEditor {
3709
3711
  }
3710
3712
  // Set initializing flag to prevent immediate close
3711
3713
  this.isInitializing = true;
3714
+ this.hasSaved = false;
3715
+ this.lastSelectedValue = '';
3712
3716
  // Create NileSelect custom element using document.createElement
3713
3717
  this.select = document.createElement('nile-select');
3714
3718
  this.select.className = 'st-cell-editor';
@@ -3915,12 +3919,29 @@ class NileSelectEditor {
3915
3919
  return;
3916
3920
  const validateOnSave = this.options.validateOnSave !== false;
3917
3921
  // Prevent click events from bubbling up to the cell container
3918
- // This prevents parent handlers from interfering with nile-select's toggle
3919
- const clickHandler = (e) => {
3922
+ const selectClickHandler = (e) => {
3920
3923
  e.stopPropagation();
3921
3924
  };
3922
- this.select.addEventListener('click', clickHandler);
3923
- this.eventListeners.push({ event: 'click', handler: clickHandler });
3925
+ this.select.addEventListener('click', selectClickHandler);
3926
+ this.eventListeners.push({ event: 'click', handler: selectClickHandler });
3927
+ // For single-select with portal, listen to document mousedown to detect option selection
3928
+ // Use mousedown because it fires before blur
3929
+ if (!this.options.multiple) {
3930
+ const documentMouseDownHandler = (e) => {
3931
+ const composedPath = e.composedPath?.() || [];
3932
+ // Look for nile-option in the event path
3933
+ for (const el of composedPath) {
3934
+ if (el instanceof HTMLElement && el.tagName?.toLowerCase() === 'nile-option') {
3935
+ const optionValue = el.getAttribute('value') || el.value || '';
3936
+ this.lastSelectedValue = optionValue;
3937
+ return;
3938
+ }
3939
+ }
3940
+ };
3941
+ // Add listener immediately (mousedown fires before blur, so no need for delay)
3942
+ document.addEventListener('mousedown', documentMouseDownHandler, true); // capture phase
3943
+ this.eventListeners.push({ event: 'document-mousedown', handler: documentMouseDownHandler });
3944
+ }
3924
3945
  // Handle keyboard events (keydown is not replaced by custom events)
3925
3946
  const keydownHandler = (e) => {
3926
3947
  const keyEvent = e;
@@ -3932,43 +3953,45 @@ class NileSelectEditor {
3932
3953
  };
3933
3954
  this.select.addEventListener('keydown', keydownHandler);
3934
3955
  this.eventListeners.push({ event: 'keydown', handler: keydownHandler });
3935
- // Use nile-change custom event as primary save trigger
3936
- const changeHandler = (e) => {
3937
- // Ignore change events during initialization (can fire when setting initial value)
3938
- if (this.isInitializing) {
3939
- return;
3940
- }
3941
- const customEvent = e;
3942
- if (validateOnSave && !this.select?.checkValidity()) {
3943
- this.select?.reportValidity();
3956
+ // Use nile-blur event as save trigger for single-select
3957
+ // Add a small delay to allow the value to update before reading
3958
+ const singleSelectSaveHandler = (e) => {
3959
+ // Don't save again if already saved
3960
+ // Ignore events that fire during initialization (e.g. when setting initial value)
3961
+ if (this.hasSaved || this.isInitializing) {
3944
3962
  return;
3945
3963
  }
3946
- // Only save immediately for single-select
3947
- // Multi-select saves on outside click
3964
+ // Only save for single-select
3948
3965
  if (!this.options.multiple) {
3949
- context.onSave(this.parseValue(customEvent.detail.value));
3950
- }
3951
- };
3952
- this.select.addEventListener('nile-change', changeHandler);
3953
- this.eventListeners.push({ event: 'nile-change', handler: changeHandler });
3954
- // Handle blur as secondary save trigger - only for single-select
3955
- // Multi-select uses hide event instead
3956
- const blurHandler = (e) => {
3957
- // Ignore blur during initialization
3958
- if (this.isInitializing) {
3959
- return;
3960
- }
3961
- if (validateOnSave && !this.select?.checkValidity()) {
3962
- this.select?.reportValidity();
3963
- return;
3964
- }
3965
- // For single-select, save on blur (when clicking outside)
3966
- if (!this.options.multiple) {
3967
- context.onSave(this.getCurrentValue());
3966
+ // Add a small delay to let the value update after selection
3967
+ setTimeout(() => {
3968
+ // Check again after timeout in case saved by another handler
3969
+ if (this.hasSaved) {
3970
+ return;
3971
+ }
3972
+ if (validateOnSave && !this.select?.checkValidity()) {
3973
+ this.select?.reportValidity();
3974
+ return;
3975
+ }
3976
+ // Use lastSelectedValue if available, otherwise get from element
3977
+ const target = e.target;
3978
+ const value = this.lastSelectedValue || target?.value || this.select?.value || '';
3979
+ this.hasSaved = true;
3980
+ context.onSave(this.parseValue(value));
3981
+ }, 50); // 50ms delay to allow value to update
3968
3982
  }
3969
3983
  };
3970
- this.select.addEventListener('nile-blur', blurHandler);
3971
- this.eventListeners.push({ event: 'nile-blur', handler: blurHandler });
3984
+ // Listen to blur and nile-blur events for focus loss detection
3985
+ // Nile web components emit nile-blur custom event instead of native blur
3986
+ this.select.addEventListener('blur', singleSelectSaveHandler);
3987
+ this.eventListeners.push({ event: 'blur', handler: singleSelectSaveHandler });
3988
+ this.select.addEventListener('nile-blur', singleSelectSaveHandler);
3989
+ this.eventListeners.push({ event: 'nile-blur', handler: singleSelectSaveHandler });
3990
+ // Also listen to change events as fallback
3991
+ this.select.addEventListener('nile-change', singleSelectSaveHandler);
3992
+ this.eventListeners.push({ event: 'nile-change', handler: singleSelectSaveHandler });
3993
+ this.select.addEventListener('change', singleSelectSaveHandler);
3994
+ this.eventListeners.push({ event: 'change', handler: singleSelectSaveHandler });
3972
3995
  // Handle clear button if enabled
3973
3996
  if (this.options.clearable) {
3974
3997
  const clearHandler = (e) => {
@@ -4043,8 +4066,10 @@ class NileSelectEditor {
4043
4066
  return value;
4044
4067
  }
4045
4068
  destroy() {
4046
- // Reset initialization flag
4069
+ // Reset flags
4047
4070
  this.isInitializing = false;
4071
+ this.hasSaved = false;
4072
+ this.lastSelectedValue = '';
4048
4073
  // Unsubscribe from options Observable
4049
4074
  if (this.optionsSubscription) {
4050
4075
  this.optionsSubscription.unsubscribe();
@@ -4057,6 +4082,10 @@ class NileSelectEditor {
4057
4082
  // Remove from document for multi-select click handler (bubbling phase)
4058
4083
  document.removeEventListener('click', handler, false);
4059
4084
  }
4085
+ else if (event === 'document-mousedown') {
4086
+ // Remove from document for single-select option mousedown handler (capture phase)
4087
+ document.removeEventListener('mousedown', handler, true);
4088
+ }
4060
4089
  else {
4061
4090
  // Remove from select element
4062
4091
  this.select?.removeEventListener(event, handler);