@aquera/ngx-smart-table 0.0.17-patch-0.2 → 0.0.17-patch-0.4

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.
@@ -4781,11 +4781,13 @@ function injectCodeEditorStyles() {
4781
4781
  const style = document.createElement('style');
4782
4782
  style.id = styleId;
4783
4783
  style.textContent = `
4784
- /* Nile Code Editor cell styling */
4784
+ /* Nile Code Editor cell styling - constrained to cell height */
4785
4785
  nile-code-editor.st-cell-editor {
4786
4786
  display: block;
4787
4787
  width: 100%;
4788
4788
  height: 100%;
4789
+ max-height: 32px;
4790
+ overflow: hidden;
4789
4791
  font-size: inherit !important;
4790
4792
  font-family: inherit !important;
4791
4793
  line-height: inherit !important;
@@ -4793,19 +4795,31 @@ function injectCodeEditorStyles() {
4793
4795
  nile-code-editor.st-cell-editor::part(code-editor-base) {
4794
4796
  border: none !important;
4795
4797
  min-height: 100% !important;
4798
+ max-height: 32px !important;
4796
4799
  background: transparent !important;
4797
4800
  font-size: inherit !important;
4798
4801
  font-family: inherit !important;
4799
4802
  line-height: inherit !important;
4803
+ overflow: hidden !important;
4800
4804
  }
4801
4805
  /* Ensure proper sizing within table cell */
4802
4806
  .st-nile-code-editor {
4803
4807
  width: 100%;
4804
4808
  height: 100%;
4809
+ max-height: 32px;
4805
4810
  min-height: 28px;
4806
4811
  font-size: inherit !important;
4812
+ overflow: hidden;
4813
+ }
4814
+ /* CodeMirror content should inherit font size and be constrained */
4815
+ nile-code-editor.st-cell-editor .cm-editor {
4816
+ max-height: 32px !important;
4817
+ overflow: hidden !important;
4818
+ }
4819
+ nile-code-editor.st-cell-editor .cm-scroller {
4820
+ max-height: 32px !important;
4821
+ overflow: hidden !important;
4807
4822
  }
4808
- /* CodeMirror content should inherit font size */
4809
4823
  nile-code-editor.st-cell-editor .cm-content,
4810
4824
  nile-code-editor.st-cell-editor .cm-line {
4811
4825
  font-size: inherit !important;
@@ -4818,12 +4832,15 @@ function injectCodeEditorStyles() {
4818
4832
  align-items: center;
4819
4833
  width: 100%;
4820
4834
  height: 100%;
4835
+ max-height: 32px;
4821
4836
  gap: 4px;
4822
4837
  }
4823
4838
  .st-code-editor-wrapper .st-code-editor-input {
4824
4839
  flex: 1;
4825
4840
  min-width: 0;
4826
4841
  height: 100%;
4842
+ max-height: 32px;
4843
+ overflow: hidden;
4827
4844
  }
4828
4845
  .st-code-editor-wrapper .st-expand-button {
4829
4846
  display: flex;
@@ -4844,13 +4861,22 @@ function injectCodeEditorStyles() {
4844
4861
  background: var(--nile-color-neutral-100, #f3f4f6);
4845
4862
  color: var(--nile-color-neutral-700, #374151);
4846
4863
  }
4847
- /* Dialog code editor styling */
4864
+ /* Dialog code editor styling - fixed header/footer, scrollable content */
4848
4865
  .st-code-editor-dialog::part(panel) {
4849
4866
  max-height: var(--max-height, 80vh) !important;
4850
4867
  overflow: hidden !important;
4868
+ display: flex !important;
4869
+ flex-direction: column !important;
4870
+ }
4871
+ .st-code-editor-dialog::part(header) {
4872
+ flex-shrink: 0 !important;
4851
4873
  }
4852
4874
  .st-code-editor-dialog::part(body) {
4853
- overflow: auto !important;
4875
+ overflow: hidden !important;
4876
+ flex: 1 !important;
4877
+ display: flex !important;
4878
+ flex-direction: column !important;
4879
+ padding: 0 !important;
4854
4880
  }
4855
4881
  .st-code-editor-dialog nile-code-editor {
4856
4882
  width: 100%;
@@ -4859,14 +4885,6 @@ function injectCodeEditorStyles() {
4859
4885
  .st-code-editor-dialog nile-code-editor::part(code-editor-base) {
4860
4886
  border: 1px solid var(--nile-color-neutral-200, #e5e7eb) !important;
4861
4887
  border-radius: 4px !important;
4862
- overflow: auto !important;
4863
- min-height: var(--dialog-editor-min-height, 300px) !important;
4864
- }
4865
- .st-code-editor-dialog nile-code-editor .cm-editor {
4866
- min-height: var(--dialog-editor-min-height, 300px) !important;
4867
- }
4868
- .st-code-editor-dialog nile-code-editor .cm-content {
4869
- min-height: var(--dialog-editor-min-height, 300px) !important;
4870
4888
  }
4871
4889
  `;
4872
4890
  document.head.appendChild(style);
@@ -4883,6 +4901,10 @@ class NileCodeEditor {
4883
4901
  this.dialogOpen = false;
4884
4902
  this.expandButtonClicked = false;
4885
4903
  this.trackedValue = null;
4904
+ this.syncingFromDialog = false; // Flag to prevent inline editor from overwriting multiline content
4905
+ this.userEditedInline = false; // Flag to track if user has typed in inline editor
4906
+ this.dialogOriginalValue = ''; // Store original value when dialog opens
4907
+ this.dialogCurrentValue = ''; // Track current value in dialog
4886
4908
  }
4887
4909
  edit(context) {
4888
4910
  if (!context.container) {
@@ -4890,7 +4912,10 @@ class NileCodeEditor {
4890
4912
  return;
4891
4913
  }
4892
4914
  this.context = context;
4893
- this.trackedValue = null;
4915
+ // Initialize tracked value from context
4916
+ this.trackedValue = String(context.value ?? '');
4917
+ this.syncingFromDialog = false;
4918
+ this.userEditedInline = false;
4894
4919
  // Inject global styles once
4895
4920
  injectCodeEditorStyles();
4896
4921
  // Check if we should show expand button (default: true)
@@ -4910,6 +4935,11 @@ class NileCodeEditor {
4910
4935
  this.editor.style.height = '100%';
4911
4936
  this.editor.style.boxSizing = 'border-box';
4912
4937
  this.editor.noborder = this.options?.noborder !== false;
4938
+ // Enable multiline by default for inline editor to support paste and multiline content
4939
+ this.editor.multiline = this.options?.multiline !== false;
4940
+ this.editor.hasScroller = true;
4941
+ // No line numbers for inline editor
4942
+ this.editor.lineNumbers = false;
4913
4943
  editorContainer.appendChild(this.editor);
4914
4944
  this.wrapper.appendChild(editorContainer);
4915
4945
  // Create expand button
@@ -4943,6 +4973,11 @@ class NileCodeEditor {
4943
4973
  this.editor.style.height = '100%';
4944
4974
  this.editor.style.boxSizing = 'border-box';
4945
4975
  this.editor.noborder = this.options?.noborder !== false;
4976
+ // Enable multiline by default for inline editor to support paste and multiline content
4977
+ this.editor.multiline = this.options?.multiline !== false;
4978
+ this.editor.hasScroller = true;
4979
+ // No line numbers for inline editor
4980
+ this.editor.lineNumbers = false;
4946
4981
  // Clear container and append editor
4947
4982
  context.container.innerHTML = '';
4948
4983
  context.container.appendChild(this.editor);
@@ -4990,6 +5025,36 @@ class NileCodeEditor {
4990
5025
  // Silently handle any errors
4991
5026
  }
4992
5027
  }
5028
+ /**
5029
+ * Read the live value directly from CodeMirror's internal state,
5030
+ * bypassing debounced nile-change events and the possibly-stale .value property.
5031
+ *
5032
+ * Priority order:
5033
+ * 1. trackedValue - always up to date from change events
5034
+ * 2. CodeMirror internal state - for real-time reading
5035
+ * 3. editor.value property - fallback
5036
+ */
5037
+ getLiveEditorValue() {
5038
+ // Use tracked value if available (updated by change events)
5039
+ if (this.trackedValue !== null) {
5040
+ return this.trackedValue;
5041
+ }
5042
+ if (!this.editor)
5043
+ return '';
5044
+ try {
5045
+ const shadowRoot = this.editor.shadowRoot;
5046
+ if (shadowRoot) {
5047
+ const cmEditor = shadowRoot.querySelector('.cm-editor');
5048
+ if (cmEditor?.cmView?.view) {
5049
+ return cmEditor.cmView.view.state.doc.toString();
5050
+ }
5051
+ }
5052
+ }
5053
+ catch {
5054
+ // Fall through to other methods
5055
+ }
5056
+ return this.editor.value ?? '';
5057
+ }
4993
5058
  /**
4994
5059
  * Open the full editor dialog
4995
5060
  */
@@ -4998,6 +5063,8 @@ class NileCodeEditor {
4998
5063
  return;
4999
5064
  this.dialogOpen = true;
5000
5065
  this.expandButtonClicked = false; // Reset flag now that dialog is opening
5066
+ // Store original value for cancel functionality
5067
+ this.dialogOriginalValue = this.getLiveEditorValue();
5001
5068
  // Create dialog with configurable dimensions
5002
5069
  const dialogWidth = this.options?.dialogWidth || '600px';
5003
5070
  const dialogMaxHeight = this.options?.dialogMaxHeight || '80vh';
@@ -5008,26 +5075,26 @@ class NileCodeEditor {
5008
5075
  this.dialog.label = dialogTitle;
5009
5076
  this.dialog.style.setProperty('--width', dialogWidth);
5010
5077
  this.dialog.style.setProperty('--max-height', dialogMaxHeight);
5011
- // Create dialog content
5078
+ // Create dialog content wrapper - flex column to handle fixed header/footer
5079
+ const contentWrapper = document.createElement('div');
5080
+ contentWrapper.style.display = 'flex';
5081
+ contentWrapper.style.flexDirection = 'column';
5082
+ contentWrapper.style.height = `calc(${dialogMaxHeight} - 60px)`; // Account for dialog header
5083
+ contentWrapper.style.maxHeight = `calc(${dialogMaxHeight} - 60px)`;
5084
+ // Create editor content area - this is the scrollable part
5012
5085
  const content = document.createElement('div');
5013
5086
  content.style.padding = '16px';
5014
- content.style.maxHeight = `calc(${dialogMaxHeight} - 80px)`;
5087
+ content.style.paddingBottom = '8px';
5088
+ content.style.flex = '1';
5015
5089
  content.style.overflow = 'auto';
5090
+ content.style.minHeight = '0'; // Important for flex shrinking
5016
5091
  // Create full editor
5017
5092
  this.dialogEditor = document.createElement('nile-code-editor');
5018
- const minLines = this.options?.dialogMinLines ?? 20;
5019
- const currentValue = this.editor?.value || '';
5020
- const currentLineCount = (currentValue.match(/\n/g) || []).length + 1;
5021
- const paddingLines = Math.max(0, minLines - currentLineCount);
5022
- this.dialogEditor.value = currentValue + '\n'.repeat(paddingLines);
5093
+ this.dialogEditor.value = this.dialogOriginalValue;
5023
5094
  this.dialogEditor.multiline = true;
5024
5095
  this.dialogEditor.lineNumbersMultiline = true;
5025
5096
  this.dialogEditor.hasScroller = true;
5026
- const lineHeightPx = 20;
5027
- const minHeightFromLines = `${minLines * lineHeightPx}px`;
5028
- this.dialogEditor.style.minHeight = `max(${dialogEditorHeight}, ${minHeightFromLines})`;
5029
- this.dialogEditor.style.maxHeight = `calc(${dialogMaxHeight} - 120px)`;
5030
- content.style.setProperty('--dialog-editor-min-height', `max(${dialogEditorHeight}, ${minHeightFromLines})`);
5097
+ this.dialogEditor.style.minHeight = dialogEditorHeight;
5031
5098
  // Apply same options to dialog editor
5032
5099
  if (this.options?.language) {
5033
5100
  this.dialogEditor.language = this.options.language;
@@ -5054,38 +5121,44 @@ class NileCodeEditor {
5054
5121
  this.dialogEditor.customThemeCSS = this.options.customThemeCSS;
5055
5122
  }
5056
5123
  this.dialogEditor.expandable = false;
5057
- // Real-time sync: Update cell editor whenever dialog editor changes
5124
+ // Initialize dialog current value
5125
+ this.dialogCurrentValue = this.dialogOriginalValue;
5126
+ // Track changes in dialog editor
5058
5127
  this.dialogEditor.addEventListener('nile-change', (e) => {
5059
- const dialogValue = e.detail?.value || '';
5060
- this.trackedValue = dialogValue;
5061
- if (this.editor) {
5062
- this.editor.value = dialogValue;
5063
- }
5064
- if (this.context) {
5065
- this.context.onChange(dialogValue);
5066
- }
5128
+ this.dialogCurrentValue = e.detail?.value ?? '';
5067
5129
  });
5068
5130
  content.appendChild(this.dialogEditor);
5069
- this.dialog.appendChild(content);
5070
- // Handle dialog close events (clicking X button - stay in edit mode)
5131
+ contentWrapper.appendChild(content);
5132
+ // Create footer with Ok button - fixed at bottom
5133
+ const footer = document.createElement('div');
5134
+ footer.style.display = 'flex';
5135
+ footer.style.justifyContent = 'flex-end';
5136
+ footer.style.padding = '12px 16px';
5137
+ footer.style.borderTop = '1px solid var(--nile-color-neutral-200, #e5e7eb)';
5138
+ footer.style.gap = '8px';
5139
+ footer.style.flexShrink = '0'; // Prevent footer from shrinking
5140
+ footer.style.backgroundColor = 'var(--nile-color-neutral-0, #ffffff)';
5141
+ const okButton = document.createElement('nile-button');
5142
+ okButton.setAttribute('variant', 'primary');
5143
+ okButton.textContent = 'Ok';
5144
+ okButton.addEventListener('click', () => {
5145
+ this.applyDialogChanges();
5146
+ });
5147
+ footer.appendChild(okButton);
5148
+ contentWrapper.appendChild(footer);
5149
+ this.dialog.appendChild(contentWrapper);
5150
+ // Handle dialog close events (clicking X button - cancel changes)
5071
5151
  this.dialog.addEventListener('nile-request-close', (e) => {
5072
- const customEvent = e;
5073
- // Check if close was triggered by overlay click (clicking outside)
5074
- if (customEvent.detail?.source === 'overlay') {
5075
- // Clicking outside the dialog - save and exit edit mode
5076
- this.closeDialog(true);
5077
- }
5078
- else {
5079
- // Clicking X button - stay in edit mode
5080
- this.closeDialog(false);
5081
- }
5152
+ e.preventDefault();
5153
+ // X button or overlay click - cancel changes
5154
+ this.cancelDialogChanges();
5082
5155
  });
5083
- // Handle Escape key in dialog - stay in edit mode
5156
+ // Handle Escape key in dialog - cancel changes
5084
5157
  this.dialog.addEventListener('keydown', (e) => {
5085
5158
  if (e.key === 'Escape') {
5086
5159
  e.preventDefault();
5087
5160
  e.stopPropagation();
5088
- this.closeDialog(false);
5161
+ this.cancelDialogChanges();
5089
5162
  }
5090
5163
  });
5091
5164
  // Append to body and show
@@ -5102,34 +5175,113 @@ class NileCodeEditor {
5102
5175
  }, 0);
5103
5176
  }
5104
5177
  /**
5105
- * Close the dialog and optionally save/exit edit mode
5178
+ * Get the current value from the dialog editor
5106
5179
  */
5107
- closeDialog(saveAndExit = false) {
5180
+ getDialogEditorValue() {
5181
+ // Use tracked value from change events (most reliable)
5182
+ if (this.dialogCurrentValue) {
5183
+ return this.dialogCurrentValue.replace(/\n+$/, '');
5184
+ }
5185
+ if (!this.dialogEditor)
5186
+ return this.dialogOriginalValue;
5187
+ // Try to get value from CodeMirror's internal state
5188
+ try {
5189
+ const shadowRoot = this.dialogEditor.shadowRoot;
5190
+ if (shadowRoot) {
5191
+ const cmEditor = shadowRoot.querySelector('.cm-editor');
5192
+ if (cmEditor?.cmView?.view) {
5193
+ const value = cmEditor.cmView.view.state.doc.toString();
5194
+ return value.replace(/\n+$/, '');
5195
+ }
5196
+ }
5197
+ }
5198
+ catch {
5199
+ // Fall through to other methods
5200
+ }
5201
+ // Fallback to value property
5202
+ const value = this.dialogEditor.value;
5203
+ return (value ?? '').replace(/\n+$/, '');
5204
+ }
5205
+ /**
5206
+ * Apply changes from dialog and close it
5207
+ */
5208
+ applyDialogChanges() {
5108
5209
  if (!this.dialogOpen)
5109
5210
  return;
5110
- // Reset flag immediately so document click handler works
5211
+ // Get the value from dialog editor - try multiple sources
5212
+ let dialogValue = this.dialogCurrentValue;
5213
+ // If no tracked value, try reading directly from dialog editor
5214
+ if (!dialogValue && this.dialogEditor) {
5215
+ try {
5216
+ const shadowRoot = this.dialogEditor.shadowRoot;
5217
+ if (shadowRoot) {
5218
+ const cmEditor = shadowRoot.querySelector('.cm-editor');
5219
+ if (cmEditor?.cmView?.view) {
5220
+ dialogValue = cmEditor.cmView.view.state.doc.toString();
5221
+ }
5222
+ }
5223
+ }
5224
+ catch {
5225
+ // Fall through
5226
+ }
5227
+ // Fallback to value property
5228
+ if (!dialogValue) {
5229
+ dialogValue = this.dialogEditor.value ?? '';
5230
+ }
5231
+ }
5232
+ // Strip trailing newlines
5233
+ dialogValue = (dialogValue || '').replace(/\n+$/, '');
5234
+ // Update tracked value and inline editor
5235
+ this.trackedValue = dialogValue;
5236
+ this.userEditedInline = false;
5237
+ this.syncingFromDialog = true;
5238
+ if (this.editor) {
5239
+ this.editor.value = dialogValue;
5240
+ }
5241
+ setTimeout(() => {
5242
+ this.syncingFromDialog = false;
5243
+ }, 0);
5244
+ // Notify context of the change
5245
+ if (this.context) {
5246
+ this.context.onChange(dialogValue);
5247
+ }
5248
+ // Close dialog
5249
+ this.closeDialogUI();
5250
+ // Refocus the cell editor to stay in edit mode
5251
+ setTimeout(() => {
5252
+ this.focusEditor();
5253
+ }, 50);
5254
+ }
5255
+ /**
5256
+ * Cancel dialog changes and revert to original value
5257
+ */
5258
+ cancelDialogChanges() {
5259
+ if (!this.dialogOpen)
5260
+ return;
5261
+ // Revert to original value (don't change anything)
5262
+ // trackedValue and inline editor remain as they were before dialog opened
5263
+ // Close dialog
5264
+ this.closeDialogUI();
5265
+ // Refocus the cell editor to stay in edit mode
5266
+ setTimeout(() => {
5267
+ this.focusEditor();
5268
+ }, 50);
5269
+ }
5270
+ /**
5271
+ * Close and remove the dialog UI
5272
+ */
5273
+ closeDialogUI() {
5111
5274
  this.dialogOpen = false;
5112
- // Close and remove dialog
5275
+ this.dialogCurrentValue = '';
5113
5276
  if (this.dialog) {
5114
5277
  this.dialog.open = false;
5115
5278
  const dialogRef = this.dialog;
5116
- const dialogEditorRef = this.dialogEditor;
5117
5279
  this.dialog = undefined;
5118
5280
  this.dialogEditor = undefined;
5119
5281
  // Remove from DOM after animation
5120
5282
  setTimeout(() => {
5121
5283
  dialogRef?.remove();
5122
5284
  }, 200);
5123
- if (saveAndExit && this.context) {
5124
- // Save and exit edit mode
5125
- this.context.onSave(this.getCurrentValue());
5126
- }
5127
- else {
5128
- // Refocus the cell editor to stay in edit mode
5129
- setTimeout(() => {
5130
- this.focusEditor();
5131
- }, 50);
5132
- }
5133
5285
  }
5134
5286
  }
5135
5287
  /**
@@ -5291,6 +5443,11 @@ class NileCodeEditor {
5291
5443
  const changeHandler = (e) => {
5292
5444
  const customEvent = e;
5293
5445
  const newValue = customEvent.detail?.value ?? '';
5446
+ // Don't process if we're syncing from dialog (prevents feedback loop)
5447
+ if (this.syncingFromDialog) {
5448
+ return;
5449
+ }
5450
+ // Update tracked value
5294
5451
  this.trackedValue = newValue;
5295
5452
  context.onChange(newValue);
5296
5453
  };
@@ -5356,6 +5513,11 @@ class NileCodeEditor {
5356
5513
  this.expandButton = undefined;
5357
5514
  this.context = undefined;
5358
5515
  this.expandButtonClicked = false;
5516
+ this.syncingFromDialog = false;
5517
+ this.trackedValue = null;
5518
+ this.userEditedInline = false;
5519
+ this.dialogOriginalValue = '';
5520
+ this.dialogCurrentValue = '';
5359
5521
  }
5360
5522
  focus() {
5361
5523
  this.editor?.focus();
@@ -5363,7 +5525,7 @@ class NileCodeEditor {
5363
5525
  getCurrentValue() {
5364
5526
  if (!this.editor)
5365
5527
  return '';
5366
- const value = (this.trackedValue !== null ? this.trackedValue : this.editor.value ?? '');
5528
+ const value = this.getLiveEditorValue();
5367
5529
  return value.replace(/\n+$/, '');
5368
5530
  }
5369
5531
  /**