@unvired/turboforms-embed-sdk 2.0.59 → 2.0.61

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.
@@ -7168,12 +7168,30 @@
7168
7168
  min-width: 50px !important;
7169
7169
  }
7170
7170
 
7171
- /* 7b. Truncate long labels in DataGrid to prevent horizontal bloat */
7172
- .tf-embed-sdk .formio-component-datagrid .col-form-label {
7173
- max-width: 100% !important;
7174
- overflow: hidden !important;
7175
- text-overflow: ellipsis !important;
7176
- white-space: nowrap !important;
7171
+ /* 7b. Hide inner component labels and control-label--hidden inside DataGrid table body cells */
7172
+ .tf-embed-sdk .formio-component-datagrid table tbody td label:not(.form-check-label):not(.custom-control-label),
7173
+ .tf-embed-sdk .formio-component-datagrid table tbody td .col-form-label,
7174
+ .tf-embed-sdk .formio-component-datagrid table tbody td .control-label--hidden,
7175
+ .tf-embed-sdk .formio-component-datagrid table tbody td [ref="label"],
7176
+ .tf-embed-sdk .formio-component-datagrid .formio-component-label-hidden label:not(.form-check-label):not(.custom-control-label),
7177
+ .tf-embed-sdk .formio-component-datagrid .formio-component-label-hidden .col-form-label,
7178
+ .tf-embed-sdk .formio-component-datagrid .formio-component-label-hidden .control-label--hidden {
7179
+ display: none !important;
7180
+ margin: 0 !important;
7181
+ padding: 0 !important;
7182
+ height: 0 !important;
7183
+ min-height: 0 !important;
7184
+ line-height: 0 !important;
7185
+ font-size: 0 !important;
7186
+ border: none !important;
7187
+ visibility: hidden !important;
7188
+ }
7189
+
7190
+ /* Remove component vertical margins inside DataGrid cells for tight layout */
7191
+ .tf-embed-sdk .formio-component-datagrid table tbody td .formio-form-group,
7192
+ .tf-embed-sdk .formio-component-datagrid table tbody td .formio-component {
7193
+ margin-top: 0 !important;
7194
+ margin-bottom: 0 !important;
7177
7195
  }
7178
7196
 
7179
7197
  /* 8. Responsive Table Equality and Rescue */
@@ -7193,17 +7211,6 @@
7193
7211
  .tf-embed-sdk .table td .formio-component {
7194
7212
  width: 100% !important;
7195
7213
  max-width: 100% !important;
7196
- }
7197
-
7198
- /* Ensure labels inside table cells don't break the responsive horizontal layout */
7199
- .tf-embed-sdk .table td label:not(.custom-control-label) {
7200
- max-width: 100% !important;
7201
- word-break: break-word !important;
7202
- white-space: normal !important;
7203
- line-height: 1.1 !important;
7204
- font-size: 0.75rem !important;
7205
- margin-bottom: 2px !important;
7206
- display: block !important;
7207
7214
  }</style>
7208
7215
  <style>/* TABS RENDERER - UI NORMALIZATION */
7209
7216
 
@@ -32372,7 +32379,38 @@ class SmartSelectComponent extends SmartSelectField {
32372
32379
  isEntireObjectDisplay() {
32373
32380
  return this.component.dataSrc === 'resource' && this.valueProperty === 'data';
32374
32381
  }
32382
+ findMasterdataItem(val) {
32383
+ if (!this.component.masterdata || val == null) return null;
32384
+ const valStr = String(val);
32385
+ const valProp = this.component.valueProperty || this.valueProperty;
32386
+ return this.component.masterdata.find(item => {
32387
+ if (!item || typeof item !== 'object') return false;
32388
+ if (valProp) {
32389
+ let pVal = _.get(item, valProp);
32390
+ if (pVal !== undefined && pVal !== null && String(pVal) === valStr) return true;
32391
+ if (valProp.startsWith('data.')) {
32392
+ pVal = _.get(item, valProp.replace(/^data\./, ''));
32393
+ if (pVal !== undefined && pVal !== null && String(pVal) === valStr) return true;
32394
+ }
32395
+ if (item[valProp] !== undefined && item[valProp] !== null && String(item[valProp]) === valStr) return true;
32396
+ }
32397
+ const raw = item.data || item;
32398
+ for (const k of Object.keys(raw)) {
32399
+ if (/id$/i.test(k) || k === 'value' || k === '_id' || k === 'id') {
32400
+ if (raw[k] !== undefined && raw[k] !== null && String(raw[k]) === valStr) {
32401
+ return true;
32402
+ }
32403
+ }
32404
+ }
32405
+ return false;
32406
+ });
32407
+ }
32408
+
32375
32409
  selectValueAndLabel(data) {
32410
+ if ((typeof data === 'string' || typeof data === 'number') && this.component.dataSrc === 'masterdata' && this.component.masterdata) {
32411
+ const matched = this.findMasterdataItem(data);
32412
+ if (matched) data = matched;
32413
+ }
32376
32414
  const value = this.getOptionValue((this.isEntireObjectDisplay() && !this.itemValue(data)) ? data : this.itemValue(data));
32377
32415
  return {
32378
32416
  value,
@@ -32385,8 +32423,13 @@ class SmartSelectComponent extends SmartSelectField {
32385
32423
  return '';
32386
32424
  }
32387
32425
 
32426
+ if ((typeof data === 'string' || typeof data === 'number') && this.component.dataSrc === 'masterdata' && this.component.masterdata) {
32427
+ const matched = this.findMasterdataItem(data);
32428
+ if (matched) data = matched;
32429
+ }
32430
+
32388
32431
  // If they wish to show the value in read only mode, then just return the itemValue here.
32389
- if (this.options.readOnly && this.component.readOnlyValue) {
32432
+ if (this.options.readOnly && this.component.readOnlyValue && !this.component.template && !this.component.labelProperty) {
32390
32433
  return this.itemValue(data);
32391
32434
  }
32392
32435
  // Perform a fast interpretation if we should not use the template.
@@ -32435,7 +32478,7 @@ class SmartSelectComponent extends SmartSelectField {
32435
32478
  }
32436
32479
 
32437
32480
  let templateData = data;
32438
- if (typeof data === 'object' && !data.data && this.component.template && this.component.template.indexOf('item.data.') !== -1) {
32481
+ if (typeof data === 'object' && data !== null && !data.data) {
32439
32482
  templateData = Object.assign({ data: data }, data);
32440
32483
  }
32441
32484
 
@@ -33085,11 +33128,8 @@ class SmartSelectComponent extends SmartSelectField {
33085
33128
  case 'masterdata':
33086
33129
  logger.info(`[TF_SDK:181] ✅ masterdata case for '${this.key}'. masterdata length:`, this.filteredMasterdata ? this.filteredMasterdata.length : 0);
33087
33130
  let safeMasterData = this.filteredMasterdata || [];
33088
- if (safeMasterData.length > 0 && !safeMasterData[0].data) {
33089
- const expectsData = (this.component.template && this.component.template.includes('item.data.')) || (this.component.valueProperty && this.component.valueProperty.startsWith('data.'));
33090
- if (expectsData) {
33091
- safeMasterData = safeMasterData.map(item => Object.assign({ data: item }, item));
33092
- }
33131
+ if (safeMasterData.length > 0) {
33132
+ safeMasterData = safeMasterData.map(item => (item && typeof item === 'object' && !item.data) ? Object.assign({ data: item }, item) : item);
33093
33133
  }
33094
33134
 
33095
33135
  if (!this.isFromSearch && !this.isScrollLoading && !this.component.dropdownOpened) {
@@ -34546,6 +34586,21 @@ class SmartSelectComponent extends SmartSelectField {
34546
34586
 
34547
34587
  value = convertToString(value);
34548
34588
 
34589
+ if (this.component.dataSrc === 'masterdata' && this.component.masterdata) {
34590
+ const convertMasterdata = (v) => {
34591
+ if (typeof v === 'string' || typeof v === 'number') {
34592
+ const matched = this.findMasterdataItem(v);
34593
+ return matched || v;
34594
+ }
34595
+ return v;
34596
+ };
34597
+ if (Array.isArray(value)) {
34598
+ value = value.map(convertMasterdata);
34599
+ } else if (value != null) {
34600
+ value = convertMasterdata(value);
34601
+ }
34602
+ }
34603
+
34549
34604
  if (['values', 'custom'].includes(this.component.dataSrc) && !this.asyncCustomValues()) {
34550
34605
  const {
34551
34606
  items,
@@ -34569,7 +34624,7 @@ class SmartSelectComponent extends SmartSelectField {
34569
34624
  : value;
34570
34625
  }
34571
34626
 
34572
- if (_.isString(value)) {
34627
+ if (_.isString(value) && this.component.dataSrc !== 'masterdata') {
34573
34628
  return value;
34574
34629
  }
34575
34630
  const getTemplateValue = (v) => {
@@ -39009,11 +39064,11 @@ async function loadTRform(
39009
39064
  if (sdkLoader) {
39010
39065
  logger.info("[TF_SDK:312] ✅ Loader found, hiding...");
39011
39066
  sdkLoader.classList.add("hidden");
39012
- document.querySelectorAll('.tf-form-loading').forEach(el => el.classList.remove('tf-form-loading'));
39013
39067
  logger.info("[TF_SDK:313] ✅ Loader hidden");
39014
39068
  } else {
39015
39069
  logger.warn("[TF_SDK:314] ✅ Loader element not found");
39016
39070
  }
39071
+ document.querySelectorAll('.tf-form-loading').forEach(el => el.classList.remove('tf-form-loading'));
39017
39072
 
39018
39073
  // Dispatch custom event
39019
39074
  logger.info("[TF_SDK:315] ✅ Dispatching FormRenderingComplete event...");
@@ -39377,9 +39432,52 @@ function getValueFromData(data, path) {
39377
39432
  function isComponentEmpty(inst) {
39378
39433
  if (!inst) return true;
39379
39434
  const val = inst.getValue ? inst.getValue() : inst.dataValue;
39380
- return inst.isEmpty
39381
- ? inst.isEmpty(val)
39382
- : (val === undefined || val === null || val === "" || (Array.isArray(val) && val.length === 0));
39435
+ if (inst.isEmpty) {
39436
+ return inst.isEmpty(val);
39437
+ }
39438
+ if (val === undefined || val === null || val === "") return true;
39439
+ if (Array.isArray(val) && val.length === 0) return true;
39440
+ if (typeof val === "object" && !Array.isArray(val) && Object.keys(val).length === 0) return true;
39441
+ return false;
39442
+ }
39443
+
39444
+ /**
39445
+ * Helper to retrieve the exact component instance associated with an error,
39446
+ * including specific row instances inside DataGrids/EditGrids.
39447
+ */
39448
+ function getComponentByError(form, err) {
39449
+ if (!form || !err) return null;
39450
+
39451
+ // 1. Direct component instance reference on error object
39452
+ if (err.component && err.component.element) {
39453
+ return err.component;
39454
+ }
39455
+
39456
+ // 2. Try exact path (e.g., "dataGrid[0].crewLead", "dataGrid.0.crewLead")
39457
+ const path = err.path || err.context?.path || err.context?.hasPath;
39458
+ if (path) {
39459
+ let inst = typeof form.getComponent === "function" ? form.getComponent(path) : null;
39460
+ if (inst && inst.element) return inst;
39461
+
39462
+ // Convert array notation dataGrid[0].crewLead -> dataGrid.0.crewLead
39463
+ const dotPath = String(path).replace(/\[(\d+)\]/g, ".$1");
39464
+ inst = typeof form.getComponent === "function" ? form.getComponent(dotPath) : null;
39465
+ if (inst && inst.element) return inst;
39466
+
39467
+ // Convert dot notation dataGrid.0.crewLead -> dataGrid[0].crewLead
39468
+ const bracketPath = String(path).replace(/\.(\d+)\./g, "[$1].");
39469
+ inst = typeof form.getComponent === "function" ? form.getComponent(bracketPath) : null;
39470
+ if (inst && inst.element) return inst;
39471
+ }
39472
+
39473
+ // 3. Fallback to component key
39474
+ const key = err.context?.component?.key || err.component?.key || (typeof err.context?.component === "string" ? err.context.component : null);
39475
+ if (key && typeof form.getComponent === "function") {
39476
+ const inst = form.getComponent(key);
39477
+ if (inst && inst.element) return inst;
39478
+ }
39479
+
39480
+ return null;
39383
39481
  }
39384
39482
 
39385
39483
  /**
@@ -39597,21 +39695,31 @@ function FormOnComplete() {
39597
39695
  let isTrulyInvalid = false;
39598
39696
  let trueErrors = [];
39599
39697
 
39600
- if (formObj && formObj.errors && formObj.errors.length > 0) {
39601
- formObj.errors.forEach((err) => {
39602
- if (err.context && err.context.component) {
39603
- const inst = formObj.getComponent(err.context.component.key);
39604
- if (inst && inst.element) {
39605
- if (!isComponentEmpty(inst)) {
39606
- clearComponentErrorUI(inst);
39607
- } else {
39608
- isTrulyInvalid = true;
39609
- trueErrors.push(err);
39610
- showComponentErrorUI(inst, err);
39611
- }
39698
+ // Combine errors from formObj.errors, error (promise reject), error.errors, error.details
39699
+ let rawErrors = [];
39700
+ if (formObj && Array.isArray(formObj.errors) && formObj.errors.length > 0) {
39701
+ rawErrors = rawErrors.concat(formObj.errors);
39702
+ }
39703
+ if (Array.isArray(error)) {
39704
+ rawErrors = rawErrors.concat(error);
39705
+ } else if (error && Array.isArray(error.errors)) {
39706
+ rawErrors = rawErrors.concat(error.errors);
39707
+ } else if (error && Array.isArray(error.details)) {
39708
+ rawErrors = rawErrors.concat(error.details);
39709
+ } else if (error && typeof error === "object" && (error.message || error.context)) {
39710
+ rawErrors.push(error);
39711
+ }
39712
+
39713
+ if (rawErrors.length > 0) {
39714
+ rawErrors.forEach((err) => {
39715
+ const inst = getComponentByError(formObj, err);
39716
+ if (inst && inst.element) {
39717
+ if (!isComponentEmpty(inst)) {
39718
+ clearComponentErrorUI(inst);
39612
39719
  } else {
39613
39720
  isTrulyInvalid = true;
39614
39721
  trueErrors.push(err);
39722
+ showComponentErrorUI(inst, err);
39615
39723
  }
39616
39724
  } else {
39617
39725
  isTrulyInvalid = true;
@@ -41474,7 +41582,7 @@ initThemeHook();
41474
41582
  </div>
41475
41583
 
41476
41584
  <div id="sticky-footer">
41477
- <div class="build-version">SDK v2.0.59</div>
41585
+ <div class="build-version">SDK v2.0.61</div>
41478
41586
 
41479
41587
  <button class="footer-btn footer-btn-secondary" id="prevBtn" style="display:none" onclick="FormOnPrevious()">
41480
41588
  <i class="bi bi-chevron-left"></i> Previous
@@ -41962,6 +42070,9 @@ initThemeHook();
41962
42070
 
41963
42071
  if (showLoader && sdkLoader) {
41964
42072
  sdkLoader.classList.remove('hidden');
42073
+ } else {
42074
+ if (sdkLoader) sdkLoader.classList.add('hidden');
42075
+ document.querySelectorAll('.tf-form-loading').forEach(el => el.classList.remove('tf-form-loading'));
41965
42076
  }
41966
42077
 
41967
42078
  if (language) window.FORMIO_LANGUAGE = language;