@aquera/ngx-smart-table 0.0.17-patch-0.3 → 0.0.17-patch-0.5

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.
@@ -2289,6 +2289,122 @@ class WorkbookState {
2289
2289
  }
2290
2290
  }
2291
2291
 
2292
+ /**
2293
+ * Convert an LDAP Distinguished Name (DN) string to a human-readable path.
2294
+ *
2295
+ * @example
2296
+ * "OU=Engineering,OU=India,DC=company,DC=com"
2297
+ * → "Engineering / India (company.com)"
2298
+ *
2299
+ * "CN=John Smith,OU=Admins,OU=Engineering,DC=company,DC=com"
2300
+ * → "John Smith / Admins / Engineering (company.com)"
2301
+ *
2302
+ * "OU=R\\,D,OU=Teams,DC=example,DC=org"
2303
+ * → "R,D / Teams (example.org)"
2304
+ */
2305
+ function dnToHumanReadable(dn) {
2306
+ if (!/^\s*\S/.test(dn)) {
2307
+ return '';
2308
+ }
2309
+ const pathParts = [];
2310
+ const domainParts = [];
2311
+ for (const match of dn.matchAll(/(?:^|(?<!\\),)\s*(CN|OU|DC)=((?:\\.|[^,])+)/g)) {
2312
+ const key = match[1];
2313
+ const value = match[2]
2314
+ .trim()
2315
+ .replace(/\\([,\\#+<>;"=])/g, '$1');
2316
+ if (/^(?:CN|OU)$/.test(key)) {
2317
+ pathParts.push(value);
2318
+ }
2319
+ else if (/^DC$/.test(key)) {
2320
+ domainParts.push(value);
2321
+ }
2322
+ }
2323
+ const path = pathParts.join(' / ');
2324
+ const domain = domainParts.join('.');
2325
+ return path && domain
2326
+ ? `${path} (${domain})`
2327
+ : path || domain || dn;
2328
+ }
2329
+ /**
2330
+ * Cell formatter that converts LDAP Distinguished Name (DN) strings
2331
+ * into human-readable OU paths with optional domain suffix.
2332
+ *
2333
+ * @example
2334
+ * // In column config:
2335
+ * formatter: new OUFormatter()
2336
+ *
2337
+ * // With options:
2338
+ * formatter: new OUFormatter({ separator: ' > ', showDomain: false })
2339
+ *
2340
+ * // Handles arrays from multiselect:
2341
+ * // ['OU=Eng,DC=co,DC=com', 'OU=HR,DC=co,DC=com'] → "Eng (co.com), HR (co.com)"
2342
+ */
2343
+ class OUFormatter {
2344
+ constructor(options) {
2345
+ this.options = options;
2346
+ }
2347
+ format(value) {
2348
+ if (Array.isArray(value)) {
2349
+ return value
2350
+ .map(v => this.formatSingle(v))
2351
+ .filter(v => !!v)
2352
+ .join(this.options?.arraySeparator ?? ', ');
2353
+ }
2354
+ return this.formatSingle(value);
2355
+ }
2356
+ formatSingle(value) {
2357
+ if (value === null || value === undefined || typeof value !== 'string' || !/^\s*\S/.test(value)) {
2358
+ return this.options?.emptyText ?? '';
2359
+ }
2360
+ const separator = this.options?.separator ?? ' / ';
2361
+ const showDomain = this.options?.showDomain !== false;
2362
+ const pathParts = [];
2363
+ const domainParts = [];
2364
+ for (const match of value.matchAll(/(?:^|(?<!\\),)\s*(CN|OU|DC)=((?:\\.|[^,])+)/g)) {
2365
+ const key = match[1];
2366
+ const val = match[2]
2367
+ .trim()
2368
+ .replace(/\\([,\\#+<>;"=])/g, '$1');
2369
+ if (/^(?:CN|OU)$/.test(key)) {
2370
+ pathParts.push(val);
2371
+ }
2372
+ else if (/^DC$/.test(key)) {
2373
+ domainParts.push(val);
2374
+ }
2375
+ }
2376
+ const path = pathParts.join(separator);
2377
+ const domain = domainParts.join('.');
2378
+ if (path && domain && showDomain)
2379
+ return `${path} (${domain})`;
2380
+ if (path)
2381
+ return path;
2382
+ if (domain && showDomain)
2383
+ return domain;
2384
+ return value;
2385
+ }
2386
+ }
2387
+
2388
+ const BUILTIN_FORMATTERS = {
2389
+ ouFormatter: () => new OUFormatter(),
2390
+ };
2391
+ const customFormatters = {};
2392
+ /**
2393
+ * Resolve a formatter by name. Looks up custom formatters first, then built-in.
2394
+ * Returns undefined if the name is not registered.
2395
+ */
2396
+ function resolveFormatter(name) {
2397
+ const factory = customFormatters[name] ?? BUILTIN_FORMATTERS[name];
2398
+ return factory ? factory() : undefined;
2399
+ }
2400
+ /**
2401
+ * Register a custom formatter so it can be referenced by string name
2402
+ * in column configs (e.g. `formatter: 'myFormatter'`).
2403
+ */
2404
+ function registerFormatter(name, factory) {
2405
+ customFormatters[name] = factory;
2406
+ }
2407
+
2292
2408
  /**
2293
2409
  * Cell class - represents individual cell instances
2294
2410
  * Combines ColumnConfig (Flyweight) with CellState (unique per instance)
@@ -2353,17 +2469,22 @@ class Cell {
2353
2469
  * Render cell value as formatted string (delegates to formatter strategy)
2354
2470
  */
2355
2471
  render() {
2356
- if (!this.columnConfig.formatter) {
2472
+ let formatter = this.columnConfig.formatter;
2473
+ if (!formatter) {
2357
2474
  return String(this.state.value ?? '');
2358
2475
  }
2359
- if (this.columnConfig.formatter.formatWithContext) {
2360
- return this.columnConfig.formatter.formatWithContext(this.state.value, this.rowData, this.columnConfig.key);
2476
+ if (typeof formatter === 'string') {
2477
+ formatter = resolveFormatter(formatter);
2478
+ if (!formatter) {
2479
+ return String(this.state.value ?? '');
2480
+ }
2361
2481
  }
2362
- // Ensure format method exists before calling it
2363
- if (this.columnConfig.formatter.format) {
2364
- return this.columnConfig.formatter.format(this.state.value);
2482
+ if (formatter.formatWithContext) {
2483
+ return formatter.formatWithContext(this.state.value, this.rowData, this.columnConfig.key);
2484
+ }
2485
+ if (formatter.format) {
2486
+ return formatter.format(this.state.value);
2365
2487
  }
2366
- // Fallback if formatter exists but has no methods
2367
2488
  return String(this.state.value ?? '');
2368
2489
  }
2369
2490
  /**
@@ -2816,7 +2937,9 @@ class BaseColumnConfig {
2816
2937
  this.key = merged.key;
2817
2938
  this.header = merged.header;
2818
2939
  this.dataType = merged.dataType;
2819
- this.formatter = merged.formatter;
2940
+ this.formatter = typeof merged.formatter === 'string'
2941
+ ? resolveFormatter(merged.formatter)
2942
+ : merged.formatter;
2820
2943
  this.validator = merged.validator;
2821
2944
  this.editor = merged.editor;
2822
2945
  this.parser = merged.parser;
@@ -2977,11 +3100,15 @@ class BaseColumnConfig {
2977
3100
  * Format value for display (can be overridden)
2978
3101
  */
2979
3102
  formatValue(value, rowData) {
2980
- if (this.formatter) {
2981
- if (this.formatter.formatWithContext && rowData) {
2982
- return this.formatter.formatWithContext(value, rowData, this.key);
3103
+ let formatter = this.formatter;
3104
+ if (typeof formatter === 'string') {
3105
+ formatter = resolveFormatter(formatter);
3106
+ }
3107
+ if (formatter) {
3108
+ if (formatter.formatWithContext && rowData) {
3109
+ return formatter.formatWithContext(value, rowData, this.key);
2983
3110
  }
2984
- return this.formatter.format(value);
3111
+ return formatter.format(value);
2985
3112
  }
2986
3113
  return String(value ?? '');
2987
3114
  }
@@ -4781,11 +4908,13 @@ function injectCodeEditorStyles() {
4781
4908
  const style = document.createElement('style');
4782
4909
  style.id = styleId;
4783
4910
  style.textContent = `
4784
- /* Nile Code Editor cell styling */
4911
+ /* Nile Code Editor cell styling - constrained to cell height */
4785
4912
  nile-code-editor.st-cell-editor {
4786
4913
  display: block;
4787
4914
  width: 100%;
4788
4915
  height: 100%;
4916
+ max-height: 32px;
4917
+ overflow: hidden;
4789
4918
  font-size: inherit !important;
4790
4919
  font-family: inherit !important;
4791
4920
  line-height: inherit !important;
@@ -4793,19 +4922,31 @@ function injectCodeEditorStyles() {
4793
4922
  nile-code-editor.st-cell-editor::part(code-editor-base) {
4794
4923
  border: none !important;
4795
4924
  min-height: 100% !important;
4925
+ max-height: 32px !important;
4796
4926
  background: transparent !important;
4797
4927
  font-size: inherit !important;
4798
4928
  font-family: inherit !important;
4799
4929
  line-height: inherit !important;
4930
+ overflow: hidden !important;
4800
4931
  }
4801
4932
  /* Ensure proper sizing within table cell */
4802
4933
  .st-nile-code-editor {
4803
4934
  width: 100%;
4804
4935
  height: 100%;
4936
+ max-height: 32px;
4805
4937
  min-height: 28px;
4806
4938
  font-size: inherit !important;
4939
+ overflow: hidden;
4940
+ }
4941
+ /* CodeMirror content should inherit font size and be constrained */
4942
+ nile-code-editor.st-cell-editor .cm-editor {
4943
+ max-height: 32px !important;
4944
+ overflow: hidden !important;
4945
+ }
4946
+ nile-code-editor.st-cell-editor .cm-scroller {
4947
+ max-height: 32px !important;
4948
+ overflow: hidden !important;
4807
4949
  }
4808
- /* CodeMirror content should inherit font size */
4809
4950
  nile-code-editor.st-cell-editor .cm-content,
4810
4951
  nile-code-editor.st-cell-editor .cm-line {
4811
4952
  font-size: inherit !important;
@@ -4818,12 +4959,15 @@ function injectCodeEditorStyles() {
4818
4959
  align-items: center;
4819
4960
  width: 100%;
4820
4961
  height: 100%;
4962
+ max-height: 32px;
4821
4963
  gap: 4px;
4822
4964
  }
4823
4965
  .st-code-editor-wrapper .st-code-editor-input {
4824
4966
  flex: 1;
4825
4967
  min-width: 0;
4826
4968
  height: 100%;
4969
+ max-height: 32px;
4970
+ overflow: hidden;
4827
4971
  }
4828
4972
  .st-code-editor-wrapper .st-expand-button {
4829
4973
  display: flex;
@@ -4844,13 +4988,22 @@ function injectCodeEditorStyles() {
4844
4988
  background: var(--nile-color-neutral-100, #f3f4f6);
4845
4989
  color: var(--nile-color-neutral-700, #374151);
4846
4990
  }
4847
- /* Dialog code editor styling */
4991
+ /* Dialog code editor styling - fixed header/footer, scrollable content */
4848
4992
  .st-code-editor-dialog::part(panel) {
4849
4993
  max-height: var(--max-height, 80vh) !important;
4850
4994
  overflow: hidden !important;
4995
+ display: flex !important;
4996
+ flex-direction: column !important;
4997
+ }
4998
+ .st-code-editor-dialog::part(header) {
4999
+ flex-shrink: 0 !important;
4851
5000
  }
4852
5001
  .st-code-editor-dialog::part(body) {
4853
- overflow: auto !important;
5002
+ overflow: hidden !important;
5003
+ flex: 1 !important;
5004
+ display: flex !important;
5005
+ flex-direction: column !important;
5006
+ padding: 0 !important;
4854
5007
  }
4855
5008
  .st-code-editor-dialog nile-code-editor {
4856
5009
  width: 100%;
@@ -4859,14 +5012,6 @@ function injectCodeEditorStyles() {
4859
5012
  .st-code-editor-dialog nile-code-editor::part(code-editor-base) {
4860
5013
  border: 1px solid var(--nile-color-neutral-200, #e5e7eb) !important;
4861
5014
  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
5015
  }
4871
5016
  `;
4872
5017
  document.head.appendChild(style);
@@ -4883,6 +5028,10 @@ class NileCodeEditor {
4883
5028
  this.dialogOpen = false;
4884
5029
  this.expandButtonClicked = false;
4885
5030
  this.trackedValue = null;
5031
+ this.syncingFromDialog = false; // Flag to prevent inline editor from overwriting multiline content
5032
+ this.userEditedInline = false; // Flag to track if user has typed in inline editor
5033
+ this.dialogOriginalValue = ''; // Store original value when dialog opens
5034
+ this.dialogCurrentValue = ''; // Track current value in dialog
4886
5035
  }
4887
5036
  edit(context) {
4888
5037
  if (!context.container) {
@@ -4890,7 +5039,10 @@ class NileCodeEditor {
4890
5039
  return;
4891
5040
  }
4892
5041
  this.context = context;
4893
- this.trackedValue = null;
5042
+ // Initialize tracked value from context
5043
+ this.trackedValue = String(context.value ?? '');
5044
+ this.syncingFromDialog = false;
5045
+ this.userEditedInline = false;
4894
5046
  // Inject global styles once
4895
5047
  injectCodeEditorStyles();
4896
5048
  // Check if we should show expand button (default: true)
@@ -4910,6 +5062,11 @@ class NileCodeEditor {
4910
5062
  this.editor.style.height = '100%';
4911
5063
  this.editor.style.boxSizing = 'border-box';
4912
5064
  this.editor.noborder = this.options?.noborder !== false;
5065
+ // Enable multiline by default for inline editor to support paste and multiline content
5066
+ this.editor.multiline = this.options?.multiline !== false;
5067
+ this.editor.hasScroller = true;
5068
+ // No line numbers for inline editor
5069
+ this.editor.lineNumbers = false;
4913
5070
  editorContainer.appendChild(this.editor);
4914
5071
  this.wrapper.appendChild(editorContainer);
4915
5072
  // Create expand button
@@ -4943,6 +5100,11 @@ class NileCodeEditor {
4943
5100
  this.editor.style.height = '100%';
4944
5101
  this.editor.style.boxSizing = 'border-box';
4945
5102
  this.editor.noborder = this.options?.noborder !== false;
5103
+ // Enable multiline by default for inline editor to support paste and multiline content
5104
+ this.editor.multiline = this.options?.multiline !== false;
5105
+ this.editor.hasScroller = true;
5106
+ // No line numbers for inline editor
5107
+ this.editor.lineNumbers = false;
4946
5108
  // Clear container and append editor
4947
5109
  context.container.innerHTML = '';
4948
5110
  context.container.appendChild(this.editor);
@@ -4993,8 +5155,17 @@ class NileCodeEditor {
4993
5155
  /**
4994
5156
  * Read the live value directly from CodeMirror's internal state,
4995
5157
  * bypassing debounced nile-change events and the possibly-stale .value property.
5158
+ *
5159
+ * Priority order:
5160
+ * 1. trackedValue - always up to date from change events
5161
+ * 2. CodeMirror internal state - for real-time reading
5162
+ * 3. editor.value property - fallback
4996
5163
  */
4997
5164
  getLiveEditorValue() {
5165
+ // Use tracked value if available (updated by change events)
5166
+ if (this.trackedValue !== null) {
5167
+ return this.trackedValue;
5168
+ }
4998
5169
  if (!this.editor)
4999
5170
  return '';
5000
5171
  try {
@@ -5009,8 +5180,6 @@ class NileCodeEditor {
5009
5180
  catch {
5010
5181
  // Fall through to other methods
5011
5182
  }
5012
- if (this.trackedValue !== null)
5013
- return this.trackedValue;
5014
5183
  return this.editor.value ?? '';
5015
5184
  }
5016
5185
  /**
@@ -5021,6 +5190,8 @@ class NileCodeEditor {
5021
5190
  return;
5022
5191
  this.dialogOpen = true;
5023
5192
  this.expandButtonClicked = false; // Reset flag now that dialog is opening
5193
+ // Store original value for cancel functionality
5194
+ this.dialogOriginalValue = this.getLiveEditorValue();
5024
5195
  // Create dialog with configurable dimensions
5025
5196
  const dialogWidth = this.options?.dialogWidth || '600px';
5026
5197
  const dialogMaxHeight = this.options?.dialogMaxHeight || '80vh';
@@ -5031,26 +5202,26 @@ class NileCodeEditor {
5031
5202
  this.dialog.label = dialogTitle;
5032
5203
  this.dialog.style.setProperty('--width', dialogWidth);
5033
5204
  this.dialog.style.setProperty('--max-height', dialogMaxHeight);
5034
- // Create dialog content
5205
+ // Create dialog content wrapper - flex column to handle fixed header/footer
5206
+ const contentWrapper = document.createElement('div');
5207
+ contentWrapper.style.display = 'flex';
5208
+ contentWrapper.style.flexDirection = 'column';
5209
+ contentWrapper.style.height = `calc(${dialogMaxHeight} - 60px)`; // Account for dialog header
5210
+ contentWrapper.style.maxHeight = `calc(${dialogMaxHeight} - 60px)`;
5211
+ // Create editor content area - this is the scrollable part
5035
5212
  const content = document.createElement('div');
5036
5213
  content.style.padding = '16px';
5037
- content.style.maxHeight = `calc(${dialogMaxHeight} - 80px)`;
5214
+ content.style.paddingBottom = '8px';
5215
+ content.style.flex = '1';
5038
5216
  content.style.overflow = 'auto';
5217
+ content.style.minHeight = '0'; // Important for flex shrinking
5039
5218
  // Create full editor
5040
5219
  this.dialogEditor = document.createElement('nile-code-editor');
5041
- const minLines = this.options?.dialogMinLines ?? 20;
5042
- const currentValue = this.getLiveEditorValue();
5043
- const currentLineCount = (currentValue.match(/\n/g) || []).length + 1;
5044
- const paddingLines = Math.max(0, minLines - currentLineCount);
5045
- this.dialogEditor.value = currentValue + '\n'.repeat(paddingLines);
5220
+ this.dialogEditor.value = this.dialogOriginalValue;
5046
5221
  this.dialogEditor.multiline = true;
5047
5222
  this.dialogEditor.lineNumbersMultiline = true;
5048
5223
  this.dialogEditor.hasScroller = true;
5049
- const lineHeightPx = 20;
5050
- const minHeightFromLines = `${minLines * lineHeightPx}px`;
5051
- this.dialogEditor.style.minHeight = `max(${dialogEditorHeight}, ${minHeightFromLines})`;
5052
- this.dialogEditor.style.maxHeight = `calc(${dialogMaxHeight} - 120px)`;
5053
- content.style.setProperty('--dialog-editor-min-height', `max(${dialogEditorHeight}, ${minHeightFromLines})`);
5224
+ this.dialogEditor.style.minHeight = dialogEditorHeight;
5054
5225
  // Apply same options to dialog editor
5055
5226
  if (this.options?.language) {
5056
5227
  this.dialogEditor.language = this.options.language;
@@ -5077,38 +5248,44 @@ class NileCodeEditor {
5077
5248
  this.dialogEditor.customThemeCSS = this.options.customThemeCSS;
5078
5249
  }
5079
5250
  this.dialogEditor.expandable = false;
5080
- // Real-time sync: Update cell editor whenever dialog editor changes
5251
+ // Initialize dialog current value
5252
+ this.dialogCurrentValue = this.dialogOriginalValue;
5253
+ // Track changes in dialog editor
5081
5254
  this.dialogEditor.addEventListener('nile-change', (e) => {
5082
- const dialogValue = e.detail?.value || '';
5083
- this.trackedValue = dialogValue;
5084
- if (this.editor) {
5085
- this.editor.value = dialogValue;
5086
- }
5087
- if (this.context) {
5088
- this.context.onChange(dialogValue);
5089
- }
5255
+ this.dialogCurrentValue = e.detail?.value ?? '';
5090
5256
  });
5091
5257
  content.appendChild(this.dialogEditor);
5092
- this.dialog.appendChild(content);
5093
- // Handle dialog close events (clicking X button - stay in edit mode)
5258
+ contentWrapper.appendChild(content);
5259
+ // Create footer with Ok button - fixed at bottom
5260
+ const footer = document.createElement('div');
5261
+ footer.style.display = 'flex';
5262
+ footer.style.justifyContent = 'flex-end';
5263
+ footer.style.padding = '12px 16px';
5264
+ footer.style.borderTop = '1px solid var(--nile-color-neutral-200, #e5e7eb)';
5265
+ footer.style.gap = '8px';
5266
+ footer.style.flexShrink = '0'; // Prevent footer from shrinking
5267
+ footer.style.backgroundColor = 'var(--nile-color-neutral-0, #ffffff)';
5268
+ const okButton = document.createElement('nile-button');
5269
+ okButton.setAttribute('variant', 'primary');
5270
+ okButton.textContent = 'Ok';
5271
+ okButton.addEventListener('click', () => {
5272
+ this.applyDialogChanges();
5273
+ });
5274
+ footer.appendChild(okButton);
5275
+ contentWrapper.appendChild(footer);
5276
+ this.dialog.appendChild(contentWrapper);
5277
+ // Handle dialog close events (clicking X button - cancel changes)
5094
5278
  this.dialog.addEventListener('nile-request-close', (e) => {
5095
- const customEvent = e;
5096
- // Check if close was triggered by overlay click (clicking outside)
5097
- if (customEvent.detail?.source === 'overlay') {
5098
- // Clicking outside the dialog - save and exit edit mode
5099
- this.closeDialog(true);
5100
- }
5101
- else {
5102
- // Clicking X button - stay in edit mode
5103
- this.closeDialog(false);
5104
- }
5279
+ e.preventDefault();
5280
+ // X button or overlay click - cancel changes
5281
+ this.cancelDialogChanges();
5105
5282
  });
5106
- // Handle Escape key in dialog - stay in edit mode
5283
+ // Handle Escape key in dialog - cancel changes
5107
5284
  this.dialog.addEventListener('keydown', (e) => {
5108
5285
  if (e.key === 'Escape') {
5109
5286
  e.preventDefault();
5110
5287
  e.stopPropagation();
5111
- this.closeDialog(false);
5288
+ this.cancelDialogChanges();
5112
5289
  }
5113
5290
  });
5114
5291
  // Append to body and show
@@ -5125,34 +5302,113 @@ class NileCodeEditor {
5125
5302
  }, 0);
5126
5303
  }
5127
5304
  /**
5128
- * Close the dialog and optionally save/exit edit mode
5305
+ * Get the current value from the dialog editor
5306
+ */
5307
+ getDialogEditorValue() {
5308
+ // Use tracked value from change events (most reliable)
5309
+ if (this.dialogCurrentValue) {
5310
+ return this.dialogCurrentValue.replace(/\n+$/, '');
5311
+ }
5312
+ if (!this.dialogEditor)
5313
+ return this.dialogOriginalValue;
5314
+ // Try to get value from CodeMirror's internal state
5315
+ try {
5316
+ const shadowRoot = this.dialogEditor.shadowRoot;
5317
+ if (shadowRoot) {
5318
+ const cmEditor = shadowRoot.querySelector('.cm-editor');
5319
+ if (cmEditor?.cmView?.view) {
5320
+ const value = cmEditor.cmView.view.state.doc.toString();
5321
+ return value.replace(/\n+$/, '');
5322
+ }
5323
+ }
5324
+ }
5325
+ catch {
5326
+ // Fall through to other methods
5327
+ }
5328
+ // Fallback to value property
5329
+ const value = this.dialogEditor.value;
5330
+ return (value ?? '').replace(/\n+$/, '');
5331
+ }
5332
+ /**
5333
+ * Apply changes from dialog and close it
5129
5334
  */
5130
- closeDialog(saveAndExit = false) {
5335
+ applyDialogChanges() {
5131
5336
  if (!this.dialogOpen)
5132
5337
  return;
5133
- // Reset flag immediately so document click handler works
5338
+ // Get the value from dialog editor - try multiple sources
5339
+ let dialogValue = this.dialogCurrentValue;
5340
+ // If no tracked value, try reading directly from dialog editor
5341
+ if (!dialogValue && this.dialogEditor) {
5342
+ try {
5343
+ const shadowRoot = this.dialogEditor.shadowRoot;
5344
+ if (shadowRoot) {
5345
+ const cmEditor = shadowRoot.querySelector('.cm-editor');
5346
+ if (cmEditor?.cmView?.view) {
5347
+ dialogValue = cmEditor.cmView.view.state.doc.toString();
5348
+ }
5349
+ }
5350
+ }
5351
+ catch {
5352
+ // Fall through
5353
+ }
5354
+ // Fallback to value property
5355
+ if (!dialogValue) {
5356
+ dialogValue = this.dialogEditor.value ?? '';
5357
+ }
5358
+ }
5359
+ // Strip trailing newlines
5360
+ dialogValue = (dialogValue || '').replace(/\n+$/, '');
5361
+ // Update tracked value and inline editor
5362
+ this.trackedValue = dialogValue;
5363
+ this.userEditedInline = false;
5364
+ this.syncingFromDialog = true;
5365
+ if (this.editor) {
5366
+ this.editor.value = dialogValue;
5367
+ }
5368
+ setTimeout(() => {
5369
+ this.syncingFromDialog = false;
5370
+ }, 0);
5371
+ // Notify context of the change
5372
+ if (this.context) {
5373
+ this.context.onChange(dialogValue);
5374
+ }
5375
+ // Close dialog
5376
+ this.closeDialogUI();
5377
+ // Refocus the cell editor to stay in edit mode
5378
+ setTimeout(() => {
5379
+ this.focusEditor();
5380
+ }, 50);
5381
+ }
5382
+ /**
5383
+ * Cancel dialog changes and revert to original value
5384
+ */
5385
+ cancelDialogChanges() {
5386
+ if (!this.dialogOpen)
5387
+ return;
5388
+ // Revert to original value (don't change anything)
5389
+ // trackedValue and inline editor remain as they were before dialog opened
5390
+ // Close dialog
5391
+ this.closeDialogUI();
5392
+ // Refocus the cell editor to stay in edit mode
5393
+ setTimeout(() => {
5394
+ this.focusEditor();
5395
+ }, 50);
5396
+ }
5397
+ /**
5398
+ * Close and remove the dialog UI
5399
+ */
5400
+ closeDialogUI() {
5134
5401
  this.dialogOpen = false;
5135
- // Close and remove dialog
5402
+ this.dialogCurrentValue = '';
5136
5403
  if (this.dialog) {
5137
5404
  this.dialog.open = false;
5138
5405
  const dialogRef = this.dialog;
5139
- const dialogEditorRef = this.dialogEditor;
5140
5406
  this.dialog = undefined;
5141
5407
  this.dialogEditor = undefined;
5142
5408
  // Remove from DOM after animation
5143
5409
  setTimeout(() => {
5144
5410
  dialogRef?.remove();
5145
5411
  }, 200);
5146
- if (saveAndExit && this.context) {
5147
- // Save and exit edit mode
5148
- this.context.onSave(this.getCurrentValue());
5149
- }
5150
- else {
5151
- // Refocus the cell editor to stay in edit mode
5152
- setTimeout(() => {
5153
- this.focusEditor();
5154
- }, 50);
5155
- }
5156
5412
  }
5157
5413
  }
5158
5414
  /**
@@ -5314,6 +5570,11 @@ class NileCodeEditor {
5314
5570
  const changeHandler = (e) => {
5315
5571
  const customEvent = e;
5316
5572
  const newValue = customEvent.detail?.value ?? '';
5573
+ // Don't process if we're syncing from dialog (prevents feedback loop)
5574
+ if (this.syncingFromDialog) {
5575
+ return;
5576
+ }
5577
+ // Update tracked value
5317
5578
  this.trackedValue = newValue;
5318
5579
  context.onChange(newValue);
5319
5580
  };
@@ -5379,6 +5640,11 @@ class NileCodeEditor {
5379
5640
  this.expandButton = undefined;
5380
5641
  this.context = undefined;
5381
5642
  this.expandButtonClicked = false;
5643
+ this.syncingFromDialog = false;
5644
+ this.trackedValue = null;
5645
+ this.userEditedInline = false;
5646
+ this.dialogOriginalValue = '';
5647
+ this.dialogCurrentValue = '';
5382
5648
  }
5383
5649
  focus() {
5384
5650
  this.editor?.focus();
@@ -8687,7 +8953,7 @@ class StTableComponent {
8687
8953
  const columns = this.getActiveColumns();
8688
8954
  const oldGrid = this.internalCellGrid;
8689
8955
  this.internalCellGrid = this.data.map((rowData, rowIndex) => columns.map((column, colIndex) => {
8690
- const newCell = new Cell(column, rowData[column.key], rowData, rowIndex);
8956
+ const newCell = column.createCell(rowData, rowIndex);
8691
8957
  const oldCell = oldGrid?.[rowIndex]?.[colIndex];
8692
8958
  if (oldCell && oldCell.getColumnConfig().key === column.key) {
8693
8959
  oldCell.setReplacement(newCell);
@@ -13084,5 +13350,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
13084
13350
  * Generated bundle index. Do not edit.
13085
13351
  */
13086
13352
 
13087
- export { ArrayFormatter, AutosaveService, BaseColumnConfig, BooleanEditor, BooleanFormatter, BuilderPreviewComponent, BuilderToolbarComponent, Cell, CellAlignment, CellDataType, CellLifecycleState, CellVerticalAlignment, ChainValidator, ClickOutsideDirective, ColumnConfigFactory, ColumnEditorComponent, ColumnListComponent, Columns, CurrencyFormatter, DEFAULT_AUTOSAVE_CONFIG, DEFAULT_COLUMN_CONFIG, DEFAULT_TABLE_CONFIG, DateEditor, DateFormatter, DateRangeValidator, DefaultFormatter, DefinitionBuilderComponent, DefinitionBuilderModule, DefinitionBuilderService, DefinitionExportService, DefinitionImportService, EditMode, EmailValidator, FilterOperator, FunctionFormatter, FunctionValidator, JsonSchemaValidatorService, LengthValidator, NavigationDirection, NavigationKey, NileAutoCompleteEditor, NileCalendarEditor, NileCodeEditor, NileDatePickerEditor, NileInputEditor, NileSelectEditor, NumberEditor, NumberFormatter, PatternValidators, PercentageFormatter, RangeValidator, RegexValidator, RequiredValidator, RowValidationService, SampleDataGeneratorService, SelectEditor, SharedTableComponentsModule, SheetState, SimpleColumnConfig, SmartTableModule, SortDirection, StAddColumnButtonComponent, StCellComponent, StColumnEditorModalComponent, StColumnFilterComponent, StColumnMenuDropdownComponent, StColumnResizeDirective, StColumnVisibilityComponent, StHeaderComponent, StKeyboardNavigationDirective, StPaginationComponent, StRowActionsDropdownComponent, StSheetActionsComponent, StSheetComponent, StTableActionsComponent, StTableComponent, StWorkbookComponent, StringFormatter, TableConfigEditorComponent, TableState, TableZIndex, TemplateFormatter, TextAreaEditor, TextEditor, UrlValidator, ValidationLoggerService, VirtualScrollService, WorkbookState, canEdit, createCellState, createMemento, isCellValid, isDisplayMode, isNullOrUndefined, isValidDate, isValidationSuccess, mergeTableConfig, restoreFromMemento };
13353
+ export { ArrayFormatter, AutosaveService, BaseColumnConfig, BooleanEditor, BooleanFormatter, BuilderPreviewComponent, BuilderToolbarComponent, Cell, CellAlignment, CellDataType, CellLifecycleState, CellVerticalAlignment, ChainValidator, ClickOutsideDirective, ColumnConfigFactory, ColumnEditorComponent, ColumnListComponent, Columns, CurrencyFormatter, DEFAULT_AUTOSAVE_CONFIG, DEFAULT_COLUMN_CONFIG, DEFAULT_TABLE_CONFIG, DateEditor, DateFormatter, DateRangeValidator, DefaultFormatter, DefinitionBuilderComponent, DefinitionBuilderModule, DefinitionBuilderService, DefinitionExportService, DefinitionImportService, EditMode, EmailValidator, FilterOperator, FunctionFormatter, FunctionValidator, JsonSchemaValidatorService, LengthValidator, NavigationDirection, NavigationKey, NileAutoCompleteEditor, NileCalendarEditor, NileCodeEditor, NileDatePickerEditor, NileInputEditor, NileSelectEditor, NumberEditor, NumberFormatter, OUFormatter, PatternValidators, PercentageFormatter, RangeValidator, RegexValidator, RequiredValidator, RowValidationService, SampleDataGeneratorService, SelectEditor, SharedTableComponentsModule, SheetState, SimpleColumnConfig, SmartTableModule, SortDirection, StAddColumnButtonComponent, StCellComponent, StColumnEditorModalComponent, StColumnFilterComponent, StColumnMenuDropdownComponent, StColumnResizeDirective, StColumnVisibilityComponent, StHeaderComponent, StKeyboardNavigationDirective, StPaginationComponent, StRowActionsDropdownComponent, StSheetActionsComponent, StSheetComponent, StTableActionsComponent, StTableComponent, StWorkbookComponent, StringFormatter, TableConfigEditorComponent, TableState, TableZIndex, TemplateFormatter, TextAreaEditor, TextEditor, UrlValidator, ValidationLoggerService, VirtualScrollService, WorkbookState, canEdit, createCellState, createMemento, dnToHumanReadable, isCellValid, isDisplayMode, isNullOrUndefined, isValidDate, isValidationSuccess, mergeTableConfig, registerFormatter, resolveFormatter, restoreFromMemento };
13088
13354
  //# sourceMappingURL=aquera-ngx-smart-table.mjs.map