@superleapai/flow-ui 2.5.18 → 2.5.20
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.
- package/CHANGELOG.md +2 -2
- package/LICENSE +1 -1
- package/README.md +38 -38
- package/components/enum-multiselect.js +119 -56
- package/components/enum-select.js +90 -48
- package/components/file-input.js +111 -49
- package/components/multiselect.js +70 -3
- package/components/select.js +87 -55
- package/core/bridge.js +4 -6
- package/core/crm.js +17 -17
- package/core/flow.js +236 -61
- package/core/superleapClient.js +2 -2
- package/dist/superleap-flow.min.js +2 -2
- package/index.d.ts +33 -20
- package/index.js +41 -30
- package/package.json +2 -2
package/components/select.js
CHANGED
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
var X_SVG =
|
|
13
13
|
'<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" xmlns="http://www.w3.org/2000/svg"><path d="M18 6L6 18M6 6l12 12"/></svg>';
|
|
14
14
|
|
|
15
|
+
var SEARCH_ICON =
|
|
16
|
+
'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>';
|
|
17
|
+
|
|
15
18
|
function triggerClasses(variant, size, disabled, placeholder, hasClear) {
|
|
16
19
|
var v = variant || "default";
|
|
17
20
|
var base =
|
|
@@ -73,6 +76,7 @@
|
|
|
73
76
|
* @param {string} [config.size] - 'default' | 'large' | 'small'
|
|
74
77
|
* @param {boolean} [config.canClear] - Show clear button when value is set
|
|
75
78
|
* @param {Function} [config.onClear] - Called when clear is clicked
|
|
79
|
+
* @param {boolean} [config.showSearch] - Show search input (default: false)
|
|
76
80
|
* @returns {HTMLElement} Select container element
|
|
77
81
|
*/
|
|
78
82
|
function createCustomSelect(config) {
|
|
@@ -84,9 +88,11 @@
|
|
|
84
88
|
var size = config.size || "default";
|
|
85
89
|
var canClear = !!config.canClear;
|
|
86
90
|
var onClear = config.onClear;
|
|
91
|
+
var showSearch = !!config.showSearch;
|
|
87
92
|
var popoverWrapperClassName = config.popoverWrapperClassName || "";
|
|
88
93
|
var onOpenCallback = config.onOpenCallback || null;
|
|
89
94
|
var dropdownMaxHeightVh = config.dropdownMaxHeightVh != null ? config.dropdownMaxHeightVh : 30;
|
|
95
|
+
var searchQuery = "";
|
|
90
96
|
|
|
91
97
|
var disabled = config.disabled === true;
|
|
92
98
|
var value =
|
|
@@ -199,19 +205,76 @@
|
|
|
199
205
|
content.className = "custom-select-content w-full overflow-hidden flex flex-col";
|
|
200
206
|
content.style.maxHeight = dropdownMaxHeightVh + "vh";
|
|
201
207
|
|
|
208
|
+
var searchContainer = document.createElement("div");
|
|
209
|
+
searchContainer.className = showSearch ? "p-8 border-b-1/2 border-border-primary" : "p-8 hidden";
|
|
210
|
+
|
|
211
|
+
var searchInputWrapper = document.createElement("div");
|
|
212
|
+
searchInputWrapper.className = "flex items-center gap-8";
|
|
213
|
+
var searchIconSpan = document.createElement("span");
|
|
214
|
+
searchIconSpan.className = "shrink-0 text-typography-tertiary-text";
|
|
215
|
+
searchIconSpan.innerHTML = SEARCH_ICON;
|
|
216
|
+
searchInputWrapper.appendChild(searchIconSpan);
|
|
217
|
+
|
|
218
|
+
var searchInput = document.createElement("input");
|
|
219
|
+
searchInput.type = "text";
|
|
220
|
+
searchInput.placeholder = "Search...";
|
|
221
|
+
searchInput.className =
|
|
222
|
+
"w-full bg-transparent text-reg-13 text-typography-primary-text placeholder:text-typography-quaternary-text focus:outline-none border-none";
|
|
223
|
+
searchInput.setAttribute("aria-label", "Search options");
|
|
224
|
+
searchInput.addEventListener("input", function (e) {
|
|
225
|
+
searchQuery = e.target.value.trim();
|
|
226
|
+
renderOptions();
|
|
227
|
+
updateOptionsSelection();
|
|
228
|
+
});
|
|
229
|
+
searchInput.addEventListener("click", function (e) {
|
|
230
|
+
e.stopPropagation();
|
|
231
|
+
});
|
|
232
|
+
searchInput.addEventListener("keydown", function (e) {
|
|
233
|
+
e.stopPropagation();
|
|
234
|
+
});
|
|
235
|
+
searchInputWrapper.appendChild(searchInput);
|
|
236
|
+
searchContainer.appendChild(searchInputWrapper);
|
|
237
|
+
content.appendChild(searchContainer);
|
|
238
|
+
|
|
202
239
|
var optionsList = document.createElement("div");
|
|
203
240
|
optionsList.className =
|
|
204
241
|
"overflow-y-auto p-2 w-full rounded-4 bg-fill-quarternary-fill-white";
|
|
205
242
|
optionsList.style.maxHeight = dropdownMaxHeightVh + "vh";
|
|
206
243
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
244
|
+
function getFilteredOptions() {
|
|
245
|
+
if (!showSearch || !searchQuery) return options.slice();
|
|
246
|
+
var normalizedQuery = searchQuery.toLowerCase();
|
|
247
|
+
return options.filter(function (opt) {
|
|
248
|
+
var label =
|
|
249
|
+
opt.label || opt.name || opt.display_name || opt.value || "";
|
|
250
|
+
var optionValue =
|
|
251
|
+
opt.value !== undefined && opt.value !== null
|
|
252
|
+
? opt.value
|
|
253
|
+
: opt.slug || opt.id || "";
|
|
254
|
+
return (
|
|
255
|
+
String(label).toLowerCase().includes(normalizedQuery) ||
|
|
256
|
+
String(optionValue).toLowerCase().includes(normalizedQuery)
|
|
257
|
+
);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function renderOptions() {
|
|
262
|
+
optionsList.innerHTML = "";
|
|
263
|
+
var filteredOptions = getFilteredOptions();
|
|
264
|
+
if (filteredOptions.length === 0) {
|
|
265
|
+
var noOpt = document.createElement("div");
|
|
266
|
+
noOpt.className =
|
|
267
|
+
"flex h-full min-h-[100px] w-full items-center justify-center p-4 !text-reg-13 text-typography-quaternary-text";
|
|
268
|
+
noOpt.textContent =
|
|
269
|
+
options.length === 0
|
|
270
|
+
? "No options available"
|
|
271
|
+
: searchQuery
|
|
272
|
+
? "No options found"
|
|
273
|
+
: "No options available";
|
|
274
|
+
optionsList.appendChild(noOpt);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
filteredOptions.forEach(function (opt) {
|
|
215
278
|
var optionValue =
|
|
216
279
|
opt.value !== undefined && opt.value !== null
|
|
217
280
|
? opt.value
|
|
@@ -250,6 +313,7 @@
|
|
|
250
313
|
optionsList.appendChild(option);
|
|
251
314
|
});
|
|
252
315
|
}
|
|
316
|
+
renderOptions();
|
|
253
317
|
|
|
254
318
|
content.appendChild(optionsList);
|
|
255
319
|
|
|
@@ -278,6 +342,8 @@
|
|
|
278
342
|
});
|
|
279
343
|
trigger.setAttribute("aria-expanded", "true");
|
|
280
344
|
chevron.style.transform = "rotate(180deg)";
|
|
345
|
+
renderOptions();
|
|
346
|
+
updateOptionsSelection();
|
|
281
347
|
highlightOptionByValue(value);
|
|
282
348
|
if (popover.panel) {
|
|
283
349
|
var triggerWidthPx = trigger.offsetWidth + "px";
|
|
@@ -285,11 +351,22 @@
|
|
|
285
351
|
popover.panel.style.minWidth = triggerWidthPx;
|
|
286
352
|
popover.panel.style.width = triggerWidthPx;
|
|
287
353
|
}
|
|
354
|
+
if (showSearch) {
|
|
355
|
+
setTimeout(function () {
|
|
356
|
+
searchInput.focus();
|
|
357
|
+
}, 50);
|
|
358
|
+
}
|
|
288
359
|
},
|
|
289
360
|
onClose: function () {
|
|
290
361
|
trigger.setAttribute("aria-expanded", "false");
|
|
291
362
|
chevron.style.transform = "";
|
|
292
363
|
highlightedIndex = -1;
|
|
364
|
+
if (showSearch) {
|
|
365
|
+
searchQuery = "";
|
|
366
|
+
searchInput.value = "";
|
|
367
|
+
renderOptions();
|
|
368
|
+
updateOptionsSelection();
|
|
369
|
+
}
|
|
293
370
|
},
|
|
294
371
|
});
|
|
295
372
|
container.popoverInstance = popover;
|
|
@@ -486,53 +563,8 @@
|
|
|
486
563
|
container.updateOptions = function (newOptions) {
|
|
487
564
|
options.length = 0;
|
|
488
565
|
options.push.apply(options, newOptions);
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
if (newOptions.length === 0) {
|
|
492
|
-
var noOpt = document.createElement("div");
|
|
493
|
-
noOpt.className =
|
|
494
|
-
"flex h-full min-h-[100px] w-full items-center justify-center p-4 !text-reg-13 text-typography-quaternary-text";
|
|
495
|
-
noOpt.textContent = "No options available";
|
|
496
|
-
optionsList.appendChild(noOpt);
|
|
497
|
-
return;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
newOptions.forEach(function (opt) {
|
|
501
|
-
var optionValue =
|
|
502
|
-
opt.value !== undefined && opt.value !== null
|
|
503
|
-
? opt.value
|
|
504
|
-
: opt.slug || opt.id;
|
|
505
|
-
var optionLabel =
|
|
506
|
-
opt.label || opt.name || opt.display_name || opt.value;
|
|
507
|
-
var isSelected = optionValue === value;
|
|
508
|
-
|
|
509
|
-
var option = document.createElement("div");
|
|
510
|
-
option.setAttribute("role", "option");
|
|
511
|
-
option.setAttribute("data-value", optionValue);
|
|
512
|
-
option.setAttribute("aria-selected", isSelected);
|
|
513
|
-
option.className = join(
|
|
514
|
-
"relative flex w-full cursor-pointer select-none items-center gap-8 rounded-2 px-12 py-6 text-reg-13 outline-none first:rounded-t-4 last:rounded-b-4",
|
|
515
|
-
"hover:bg-fill-tertiary-fill-light-gray focus:bg-fill-tertiary-fill-light-gray",
|
|
516
|
-
isSelected
|
|
517
|
-
? "bg-primary-surface hover:!bg-primary-surface-hover"
|
|
518
|
-
: ""
|
|
519
|
-
);
|
|
520
|
-
|
|
521
|
-
var optionContent = document.createElement("span");
|
|
522
|
-
optionContent.className = "flex items-center gap-8 flex-1 truncate";
|
|
523
|
-
optionContent.textContent = optionLabel;
|
|
524
|
-
option.appendChild(optionContent);
|
|
525
|
-
|
|
526
|
-
option.addEventListener("click", function () {
|
|
527
|
-
if (disabled) return;
|
|
528
|
-
selectOption(optionValue);
|
|
529
|
-
});
|
|
530
|
-
option.addEventListener("mouseenter", function () {
|
|
531
|
-
if (disabled) return;
|
|
532
|
-
highlightOption(option);
|
|
533
|
-
});
|
|
534
|
-
optionsList.appendChild(option);
|
|
535
|
-
});
|
|
566
|
+
renderOptions();
|
|
567
|
+
updateOptionsSelection();
|
|
536
568
|
};
|
|
537
569
|
|
|
538
570
|
container.setDisabled = function (isDisabled) {
|
package/core/bridge.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Native WebView via window.ReactNativeWebView.
|
|
7
7
|
*
|
|
8
8
|
* This module is transport-only — it knows nothing about CRM concepts,
|
|
9
|
-
* the
|
|
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
|
|
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
|
|
394
|
+
"ms. Is this page embedded in the Superleap CRM?",
|
|
395
395
|
);
|
|
396
396
|
if (_pendingReject) _pendingReject(err);
|
|
397
397
|
cleanup();
|
|
@@ -422,9 +422,7 @@
|
|
|
422
422
|
*/
|
|
423
423
|
function send(action, payload) {
|
|
424
424
|
if (!_connected) {
|
|
425
|
-
throw new Error(
|
|
426
|
-
"SuperleapBridge: Not connected. Call connect() first.",
|
|
427
|
-
);
|
|
425
|
+
throw new Error("SuperleapBridge: Not connected. Call connect() first.");
|
|
428
426
|
}
|
|
429
427
|
sendRaw(createEnvelope(action, payload));
|
|
430
428
|
}
|
package/core/crm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Superleap-Flow CRM Bridge Extensions
|
|
3
3
|
*
|
|
4
|
-
* This module extends the existing
|
|
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
|
|
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.
|
|
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
|
-
*
|
|
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
|
|
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
|
|
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();
|
|
@@ -248,18 +248,17 @@
|
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
/**
|
|
251
|
-
*
|
|
252
|
-
* The CRM
|
|
251
|
+
* Notify the CRM that the form was submitted successfully.
|
|
252
|
+
* The CRM listens for 'crm:formSubmitSuccess' and can react
|
|
253
|
+
* (e.g. close the form, refresh data, show a toast).
|
|
253
254
|
*
|
|
254
|
-
* @param {
|
|
255
|
-
* @returns {Function} unsubscribe function
|
|
255
|
+
* @param {Object} [payload] – optional data about the submission
|
|
256
256
|
*/
|
|
257
|
-
function
|
|
257
|
+
function formSubmittedSuccessfully(payload) {
|
|
258
258
|
var bridge = getBridge();
|
|
259
|
-
if (
|
|
260
|
-
|
|
259
|
+
if (bridge && bridge.isConnected()) {
|
|
260
|
+
bridge.send("crm:formSubmitSuccess", payload || {});
|
|
261
261
|
}
|
|
262
|
-
return bridge.onMessage("crm:onFormSubmitSuccess", callback);
|
|
263
262
|
}
|
|
264
263
|
|
|
265
264
|
// ---------------------------------------------------------------------------
|
|
@@ -325,7 +324,7 @@
|
|
|
325
324
|
}
|
|
326
325
|
|
|
327
326
|
// ---------------------------------------------------------------------------
|
|
328
|
-
// Extend the existing superleapClient (which becomes
|
|
327
|
+
// Extend the existing superleapClient (which becomes Superleap)
|
|
329
328
|
// ---------------------------------------------------------------------------
|
|
330
329
|
|
|
331
330
|
// Wait for superleapClient to be defined, then extend it
|
|
@@ -336,7 +335,8 @@
|
|
|
336
335
|
global.superleapClient.disconnect = disconnect;
|
|
337
336
|
global.superleapClient.setLoading = setLoading;
|
|
338
337
|
global.superleapClient.closeForm = closeForm;
|
|
339
|
-
global.superleapClient.
|
|
338
|
+
global.superleapClient.formSubmittedSuccessfully =
|
|
339
|
+
formSubmittedSuccessfully;
|
|
340
340
|
global.superleapClient.toast = toast;
|
|
341
341
|
global.superleapClient.navigate = navigate;
|
|
342
342
|
global.superleapClient.getContext = getContext;
|
|
@@ -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
|
-
"
|
|
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);
|