@superleapai/flow-ui 2.6.21 → 2.6.23

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.
@@ -187,18 +187,18 @@
187
187
  * @param {string} config.value - Current value (record id)
188
188
  * @param {Function} config.onChange - Change handler (value, record?) => void
189
189
  * @param {boolean} [config.disabled] - Whether select is disabled
190
+ * @param {boolean} [config.showDisplayFields] - If true, fetch schema and show secondary fields from objectSchema.properties.display_fields
190
191
  * @param {string} [config.variant] - 'default' | 'error' | 'warning' | 'borderless' | 'inline'
191
192
  * @param {string} [config.size] - 'default' | 'large' | 'small'
192
193
  * @param {boolean} [config.canClear] - Show clear button when value is set
193
194
  * @param {number} [config.initialLimit] - Initial fetch limit (default 50)
194
195
  * @param {Object} [config.initialFilter] - Optional filter object to merge with search (e.g. { field: "status", operator: "exact", value: "active" } or { and: [...] })
195
- * @param {Object} [config.objectSchema] - Optional ObjectType; display_singular_name/display_plural_name/slug used for placeholder/search text; properties.icon_data { icon?, color? } for static icon (not used for user; user shows Vivid Avatar)
196
196
  * @returns {HTMLElement} Record select container element
197
197
  */
198
198
  function createRecordSelect(config) {
199
199
  var fieldId = config.fieldId;
200
200
  var objectSlug = config.objectSlug;
201
- var objectSchema = config.objectSchema || null;
201
+ var objectSchema = null;
202
202
  var displaySingular = getObjectDisplayName(objectSchema, objectSlug, "singular");
203
203
  var displayPlural = getObjectDisplayName(objectSchema, objectSlug, "plural");
204
204
  var placeholder =
@@ -208,6 +208,7 @@
208
208
  config.searchPlaceholder ||
209
209
  "Search " + (displayPlural || objectSlug || "") + "...";
210
210
  var onChange = config.onChange;
211
+ var showDisplayFields = config.showDisplayFields === true;
211
212
  var variant = config.variant || "default";
212
213
  var size = config.size || "default";
213
214
  var canClear = !!config.canClear;
@@ -247,6 +248,21 @@
247
248
  var currentPage = 1;
248
249
  var isFetchingMore = false;
249
250
  var totalFetched = 0;
251
+ var schemaLoaded = false;
252
+ var schemaLoading = false;
253
+
254
+ function getSchemaDisplayFields() {
255
+ if (!showDisplayFields) return [];
256
+ var fields =
257
+ objectSchema &&
258
+ objectSchema.properties &&
259
+ Array.isArray(objectSchema.properties.display_fields)
260
+ ? objectSchema.properties.display_fields
261
+ : [];
262
+ return fields.filter(function (field) {
263
+ return typeof field === "string" && field.length > 0;
264
+ });
265
+ }
250
266
 
251
267
  // Trigger wrapper + button (same structure as Select)
252
268
  var triggerWrapper = document.createElement("span");
@@ -408,6 +424,7 @@
408
424
  popover.panel.style.minWidth = triggerWidthPx;
409
425
  popover.panel.style.width = triggerWidthPx;
410
426
  }
427
+ if (showDisplayFields) loadObjectSchema();
411
428
  loadInitialAndRender();
412
429
  setTimeout(function () {
413
430
  if (searchInputEl) searchInputEl.focus();
@@ -443,6 +460,31 @@
443
460
  if (clearBtn)
444
461
  clearBtn.style.display = canClear && value && !disabled ? "" : "none";
445
462
 
463
+ function loadObjectSchema() {
464
+ if (schemaLoaded || schemaLoading) return;
465
+ if (!showDisplayFields) return;
466
+ var client = getClient();
467
+ if (!client || typeof client.getSdk !== "function") return;
468
+ var sdk = client.getSdk();
469
+ if (!sdk) return;
470
+ var model = sdk.model(objectSlug);
471
+ if (!model || typeof model.getSchema !== "function") return;
472
+
473
+ schemaLoading = true;
474
+ model
475
+ .getSchema()
476
+ .then(function (schema) {
477
+ objectSchema = schema && schema.data ? schema.data : schema;
478
+ schemaLoaded = true;
479
+ if (filteredRecords.length > 0) renderOptions();
480
+ else updateTriggerDisplay();
481
+ })
482
+ .catch(function () {})
483
+ .finally(function () {
484
+ schemaLoading = false;
485
+ });
486
+ }
487
+
446
488
  function setValue(newVal) {
447
489
  value = newVal !== undefined && newVal !== null ? newVal : "";
448
490
  selectedRecord = null;
@@ -552,7 +594,8 @@
552
594
  var sdk = client.getSdk();
553
595
  if (!sdk) return Promise.resolve({ records: [], hasMore: false });
554
596
  var model = sdk.model(objectSlug);
555
- var fields = ["id", "name"];
597
+ var schemaDisplayFields = getSchemaDisplayFields();
598
+ var fields = ["id", "name"].concat(schemaDisplayFields);
556
599
  var actualLimit = limit || initialLimit;
557
600
  var offset = page ? (page - 1) * actualLimit : 0;
558
601
 
@@ -602,6 +645,9 @@
602
645
  value: d.id,
603
646
  name: d.name || d.id,
604
647
  label: d.name || d.id,
648
+ displayLabels: schemaDisplayFields.map(function (field) {
649
+ return d[field] || "";
650
+ }),
605
651
  };
606
652
  });
607
653
  // If we got fewer records than the limit, there are no more
@@ -631,8 +677,9 @@
631
677
  return;
632
678
  }
633
679
  var model = sdk.model(objectSlug);
680
+ var schemaDisplayFields = getSchemaDisplayFields();
634
681
  model
635
- .select("id", "name")
682
+ .select.apply(model, ["id", "name"].concat(schemaDisplayFields))
636
683
  .where({ id: value })
637
684
  .limit(1)
638
685
  .first()
@@ -644,6 +691,9 @@
644
691
  value: d.id,
645
692
  name: d.name || d.id,
646
693
  label: d.name || d.id,
694
+ displayLabels: schemaDisplayFields.map(function (field) {
695
+ return d[field] || "";
696
+ }),
647
697
  };
648
698
  }
649
699
  updateTriggerDisplay();
@@ -654,6 +704,7 @@
654
704
  value: value,
655
705
  name: value,
656
706
  label: value,
707
+ displayLabels: [],
657
708
  };
658
709
  updateTriggerDisplay();
659
710
  });
@@ -747,7 +798,9 @@
747
798
  );
748
799
 
749
800
  var optContent = document.createElement("span");
750
- optContent.className = "flex items-center gap-8 flex-1 truncate";
801
+ optContent.className = "flex flex-col flex-1 truncate min-w-0";
802
+ var primaryRow = document.createElement("div");
803
+ primaryRow.className = "flex items-center gap-8 truncate";
751
804
  if (objectSlug === STANDARD_OBJECT_SLUGS_USERS) {
752
805
  var Avatar = getAvatar();
753
806
  if (Avatar && typeof Avatar.createVivid === "function") {
@@ -756,13 +809,13 @@
756
809
  size: "small",
757
810
  shape: "circle",
758
811
  });
759
- optContent.appendChild(avatarEl);
812
+ primaryRow.appendChild(avatarEl);
760
813
  } else {
761
814
  var pl = document.createElement("span");
762
815
  pl.className =
763
816
  "size-20 rounded-full bg-primary-surface text-primary-text flex items-center justify-center text-reg-12 font-semibold shrink-0";
764
817
  pl.textContent = (optionLabel || "?").charAt(0).toUpperCase();
765
- optContent.appendChild(pl);
818
+ primaryRow.appendChild(pl);
766
819
  }
767
820
  } else {
768
821
  var IconComponent = getIcon();
@@ -775,18 +828,39 @@
775
828
  defaultIcon: true,
776
829
  className: "size-20 shrink-0",
777
830
  });
778
- if (iconEl) optContent.appendChild(iconEl);
831
+ if (iconEl) primaryRow.appendChild(iconEl);
779
832
  } else {
780
833
  var pl = document.createElement("span");
781
834
  pl.className =
782
835
  "size-20 rounded-4 flex items-center justify-center shrink-0 bg-neutral-surface-hover text-neutral-text-base";
783
836
  pl.textContent = "?";
784
- optContent.appendChild(pl);
837
+ primaryRow.appendChild(pl);
785
838
  }
786
839
  }
787
840
  var labelSpan = document.createElement("span");
841
+ labelSpan.className = "truncate";
788
842
  labelSpan.textContent = optionLabel;
789
- optContent.appendChild(labelSpan);
843
+ primaryRow.appendChild(labelSpan);
844
+ optContent.appendChild(primaryRow);
845
+
846
+ if (showDisplayFields && rec.displayLabels && rec.displayLabels.length > 0 && rec.displayLabels.some(function (l) { return l; })) {
847
+ var secondaryRow = document.createElement("div");
848
+ secondaryRow.className = "flex items-center gap-4 truncate text-reg-10 text-typography-tertiary-text mt-2 ml-28";
849
+ rec.displayLabels.forEach(function (label, index) {
850
+ if (label) {
851
+ var secondaryLabel = document.createElement("span");
852
+ secondaryLabel.className = "truncate";
853
+ secondaryLabel.textContent = label;
854
+ secondaryRow.appendChild(secondaryLabel);
855
+ if (index < rec.displayLabels.length - 1 && rec.displayLabels[index + 1]) {
856
+ var separator = document.createElement("span");
857
+ separator.textContent = " • ";
858
+ secondaryRow.appendChild(separator);
859
+ }
860
+ }
861
+ });
862
+ optContent.appendChild(secondaryRow);
863
+ }
790
864
  option.appendChild(optContent);
791
865
 
792
866
  option.addEventListener("click", function (e) {
@@ -983,6 +1057,7 @@
983
1057
 
984
1058
  if (value) loadSelectedRecord();
985
1059
  else updateTriggerDisplay();
1060
+ if (showDisplayFields) loadObjectSchema();
986
1061
 
987
1062
  return container;
988
1063
  }
package/core/bridge.js CHANGED
@@ -1,12 +1,12 @@
1
1
  /**
2
- * Superleap-Flow Bridge Transport Layer
2
+ * SuperLeap-Flow Bridge Transport Layer
3
3
  *
4
4
  * Handles postMessage / MessageChannel communication between an iframe
5
5
  * (running this library) and the host CRM window. Also supports React
6
6
  * Native WebView via window.ReactNativeWebView.
7
7
  *
8
8
  * This module is transport-only — it knows nothing about CRM concepts,
9
- * the Superleap SDK, or FlowUI state. The higher-level core/crm.js
9
+ * the SuperLeap SDK, or FlowUI state. The higher-level core/crm.js
10
10
  * builds on top of it.
11
11
  *
12
12
  * Exposed temporarily as window.SuperleapBridge, then captured into
@@ -327,7 +327,7 @@
327
327
  if (!_bridgeId) {
328
328
  reject(
329
329
  new Error(
330
- "SuperleapBridge: No _bridgeId found in URL. Is this page embedded in the Superleap CRM?",
330
+ "SuperleapBridge: No _bridgeId found in URL. Is this page embedded in the SuperLeap CRM?",
331
331
  ),
332
332
  );
333
333
  return;
@@ -391,7 +391,7 @@
391
391
  var err = new Error(
392
392
  "SuperleapBridge: Handshake timed out after " +
393
393
  timeoutMs +
394
- "ms. Is this page embedded in the Superleap CRM?",
394
+ "ms. Is this page embedded in the SuperLeap CRM?",
395
395
  );
396
396
  if (_pendingReject) _pendingReject(err);
397
397
  cleanup();
package/core/crm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Superleap-Flow CRM Bridge Extensions
2
+ * SuperLeap-Flow CRM Bridge Extensions
3
3
  *
4
- * This module extends the existing Superleap object (from superleapClient.js)
4
+ * This module extends the existing SuperLeap object (from superleapClient.js)
5
5
  * with CRM bridge functionality. It wraps the low-level bridge transport
6
6
  * (core/bridge.js) and adds:
7
7
  *
@@ -14,7 +14,7 @@
14
14
  * read from the URL). User code should listen for the 'superleap-flow:ready'
15
15
  * event — by the time it fires, the SDK is initialized and context is available.
16
16
  *
17
- * This extends the existing Superleap API from superleapClient.js which
17
+ * This extends the existing SuperLeap API from superleapClient.js which
18
18
  * already has: init(), getSdk(), isAvailable(), getDefaultConfig().
19
19
  */
20
20
 
@@ -73,7 +73,7 @@
73
73
  if (c) return c;
74
74
  }
75
75
  if (global.superleapClient) return global.superleapClient;
76
- if (global.Superleap) return global.Superleap;
76
+ if (global.SuperLeap) return global.SuperLeap;
77
77
  return null;
78
78
  }
79
79
 
@@ -84,7 +84,7 @@
84
84
  /**
85
85
  * Connect to the CRM. Performs the postMessage handshake, receives
86
86
  * credentials and context, and (by default) auto-initializes the
87
- * Superleap SDK.
87
+ * SuperLeap SDK.
88
88
  *
89
89
  * If already connected, silently resolves with the existing context/config.
90
90
  * If a connection is in flight (e.g. auto-connect), returns the same promise.
@@ -92,7 +92,7 @@
92
92
  * @param {Object} [options]
93
93
  * @param {string} [options.bridgeId] – explicit bridgeId override (auto-read from URL)
94
94
  * @param {string} [options.crmOrigin] – expected CRM origin for validation
95
- * @param {boolean} [options.autoInit] – auto-call Superleap.init() (default true)
95
+ * @param {boolean} [options.autoInit] – auto-call SuperLeap.init() (default true)
96
96
  * @param {number} [options.timeout] – handshake timeout in ms (default 5000)
97
97
  * @returns {Promise<{ context: Object, config: Object }>}
98
98
  */
@@ -125,7 +125,7 @@
125
125
  _context = (payload && payload.context) || {};
126
126
  _config = (payload && payload.config) || {};
127
127
 
128
- // Auto-initialize the Superleap SDK
128
+ // Auto-initialize the SuperLeap SDK
129
129
  var sdkConfig = payload && payload.sdkConfig;
130
130
  if (opts.autoInit !== false && sdkConfig) {
131
131
  var client = getSuperLeapClient();
@@ -324,7 +324,7 @@
324
324
  }
325
325
 
326
326
  // ---------------------------------------------------------------------------
327
- // Extend the existing superleapClient (which becomes Superleap)
327
+ // Extend the existing superleapClient (which becomes SuperLeap)
328
328
  // ---------------------------------------------------------------------------
329
329
 
330
330
  // Wait for superleapClient to be defined, then extend it
@@ -347,7 +347,7 @@
347
347
  // superleapClient not loaded yet — this shouldn't happen if scripts
348
348
  // load in order, but handle it gracefully
349
349
  console.warn(
350
- "Superleap CRM Bridge: superleapClient not found. Make sure core/superleapClient.js loads before core/crm.js",
350
+ "SuperLeap CRM Bridge: superleapClient not found. Make sure core/superleapClient.js loads before core/crm.js",
351
351
  );
352
352
  }
353
353
  })(typeof window !== "undefined" ? window : this);
package/core/flow.js CHANGED
@@ -321,7 +321,16 @@
321
321
  * @returns {HTMLElement} Field element
322
322
  */
323
323
  function createSelect(config) {
324
- const { label, fieldId, options = [], required = false, onChange, showSearch = false, disabled = false, helpText = null } = config;
324
+ const {
325
+ label,
326
+ fieldId,
327
+ options = [],
328
+ required = false,
329
+ onChange,
330
+ showSearch = false,
331
+ disabled = false,
332
+ helpText = null,
333
+ } = config;
325
334
 
326
335
  const field = createFieldWrapper(label, required, helpText);
327
336
 
@@ -784,7 +793,20 @@
784
793
  * @returns {HTMLElement} Field element
785
794
  */
786
795
  function createMultiSelect(config) {
787
- const { label, fieldId, options = [], required = false, onChange, placeholder, helpText = null, variant, size, type, showSearch = false, disabled = false } = config;
796
+ const {
797
+ label,
798
+ fieldId,
799
+ options = [],
800
+ required = false,
801
+ onChange,
802
+ placeholder,
803
+ helpText = null,
804
+ variant,
805
+ size,
806
+ type,
807
+ showSearch = false,
808
+ disabled = false,
809
+ } = config;
788
810
 
789
811
  const field = createFieldWrapper(label, required, helpText);
790
812
 
@@ -865,6 +887,7 @@
865
887
  * @param {string} [config.variant] - 'default' | 'error' | 'warning' | 'borderless' | 'inline'
866
888
  * @param {string} [config.size] - 'default' | 'large' | 'small'
867
889
  * @param {boolean} [config.canClear] - Show clear button when value is set
890
+ * @param {boolean} [config.showDisplayFields=false] - Show secondary fields from object schema display_fields
868
891
  * @param {number} [config.initialLimit] - Initial fetch limit
869
892
  * @param {string} [config.helpText] - Optional help text for tooltip
870
893
  * @returns {HTMLElement} Field element
@@ -882,6 +905,7 @@
882
905
  variant,
883
906
  size,
884
907
  canClear,
908
+ showDisplayFields = false,
885
909
  initialLimit,
886
910
  initialFilter,
887
911
  helpText = null,
@@ -902,6 +926,7 @@
902
926
  variant: variant || "default",
903
927
  size: size || "default",
904
928
  canClear: !!canClear,
929
+ showDisplayFields: !!showDisplayFields,
905
930
  initialLimit,
906
931
  initialFilter,
907
932
  onChange: (value, record) => {
@@ -918,7 +943,7 @@
918
943
  const fallback = document.createElement("div");
919
944
  fallback.className = "text-reg-13 text-typography-quaternary-text";
920
945
  fallback.textContent =
921
- "Record select requires RecordSelect component and Superleap client.";
946
+ "Record select requires RecordSelect component and SuperLeap client.";
922
947
  field.appendChild(fallback);
923
948
  return field;
924
949
  }
@@ -936,8 +961,8 @@
936
961
  * @param {boolean} [config.disabled=false]
937
962
  * @param {string} [config.variant] - 'default' | 'error' | 'warning' | 'borderless' | 'inline'
938
963
  * @param {string} [config.size] - 'default' | 'large' | 'small'
964
+ * @param {boolean} [config.showDisplayFields=false] - Show secondary fields from object schema display_fields
939
965
  * @param {number} [config.initialLimit] - Initial fetch limit
940
- * @param {Array<string>} [config.displayFields] - Fields to show as secondary info
941
966
  * @param {string} [config.helpText] - Optional help text for tooltip
942
967
  * @returns {HTMLElement} Field element
943
968
  */
@@ -953,9 +978,9 @@
953
978
  disabled = false,
954
979
  variant,
955
980
  size,
981
+ showDisplayFields = false,
956
982
  initialLimit,
957
983
  initialFilter,
958
- displayFields,
959
984
  helpText = null,
960
985
  } = config;
961
986
 
@@ -975,9 +1000,9 @@
975
1000
  disabled,
976
1001
  variant: variant || "default",
977
1002
  size: size || "default",
1003
+ showDisplayFields: !!showDisplayFields,
978
1004
  initialLimit,
979
1005
  initialFilter,
980
- displayFields: displayFields || [],
981
1006
  onValuesChange: (values, records) => {
982
1007
  set(fieldId, values);
983
1008
  if (onChange) onChange(values, records);
@@ -991,13 +1016,13 @@
991
1016
  const fallback = document.createElement("div");
992
1017
  fallback.className = "text-reg-13 text-typography-quaternary-text";
993
1018
  fallback.textContent =
994
- "Record multi-select requires RecordMultiSelect component and Superleap client.";
1019
+ "Record multi-select requires RecordMultiSelect component and SuperLeap client.";
995
1020
  field.appendChild(fallback);
996
1021
  return field;
997
1022
  }
998
1023
 
999
1024
  /**
1000
- * Create an enum select field (options from Superleap object column)
1025
+ * Create an enum select field (options from SuperLeap object column)
1001
1026
  * @param {Object} config - Configuration object
1002
1027
  * @param {string} config.label - Field label
1003
1028
  * @param {string} config.fieldId - State key for this field
@@ -1059,13 +1084,13 @@
1059
1084
  const fallback = document.createElement("div");
1060
1085
  fallback.className = "text-reg-13 text-typography-quaternary-text";
1061
1086
  fallback.textContent =
1062
- "Enum select requires EnumSelect component and Superleap client.";
1087
+ "Enum select requires EnumSelect component and SuperLeap client.";
1063
1088
  field.appendChild(fallback);
1064
1089
  return field;
1065
1090
  }
1066
1091
 
1067
1092
  /**
1068
- * Create an enum multi-select field (options from Superleap object column)
1093
+ * Create an enum multi-select field (options from SuperLeap object column)
1069
1094
  * @param {Object} config - Configuration object
1070
1095
  * @param {string} config.label - Field label
1071
1096
  * @param {string} config.fieldId - State key (stores array of values)
@@ -1130,7 +1155,7 @@
1130
1155
  const fallback = document.createElement("div");
1131
1156
  fallback.className = "text-reg-13 text-typography-quaternary-text";
1132
1157
  fallback.textContent =
1133
- "Enum multi-select requires EnumMultiSelect component and Superleap client.";
1158
+ "Enum multi-select requires EnumMultiSelect component and SuperLeap client.";
1134
1159
  field.appendChild(fallback);
1135
1160
  return field;
1136
1161
  }
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Superleap-Flow SDK client
3
- * Thin wrapper around the Superleap SDK (createSuperLeapSDK from sdk.js or superleap.js).
2
+ * SuperLeap-Flow SDK client
3
+ * Thin wrapper around the SuperLeap SDK (createSuperLeapSDK from sdk.js or superleap.js).
4
4
  * Exposes getSdk() for record-select, file-input, etc.
5
5
  * Load the SDK script before this script; then call superleapClient.init(config).
6
6
  *
@@ -39,7 +39,7 @@
39
39
  _sdkInstance = new global.SuperLeapSDK(_config);
40
40
  } else {
41
41
  console.warn(
42
- "[superleapClient] Superleap SDK not found. Install with: npm install superleap-sdk",
42
+ "[superleapClient] SuperLeap SDK not found. Install with: npm install superleap-sdk",
43
43
  );
44
44
  _sdkInstance = null;
45
45
  }