@superleapai/flow-ui 2.5.6 → 2.5.8

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.
@@ -30,8 +30,11 @@
30
30
  return parts.join(" ");
31
31
  }
32
32
 
33
+ var INFO_ICON_SVG =
34
+ '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0" /><path d="M12 9h.01" /><path d="M11 12h1v4h1" /></svg>';
35
+
33
36
  /**
34
- * Create a label element matching the Radix Label API (size, requiredPosition, optional, icon).
37
+ * Create a label element matching the Radix Label API (size, requiredPosition, optional, icon, helpText).
35
38
  * @param {Object} config
36
39
  * @param {string} config.label - Label text
37
40
  * @param {boolean} [config.required=false] - Show required asterisk
@@ -39,6 +42,7 @@
39
42
  * @param {boolean} [config.optional=false] - Show "(optional)" after label
40
43
  * @param {string} [config.size='default'] - 'default' | 'small' | 'large'
41
44
  * @param {HTMLElement} [config.icon] - Optional icon node
45
+ * @param {string} [config.helpText] - Optional help text; when set, shows info icon after required with Tooltip
42
46
  * @param {string} [config.className] - Extra classes
43
47
  * @param {string} [config.htmlFor] - For attribute
44
48
  * @param {HTMLElement} [config.suffix] - Optional node appended after content (e.g. tooltip)
@@ -51,6 +55,7 @@
51
55
  var optional = !!config.optional;
52
56
  var size = config.size || "default";
53
57
  var icon = config.icon;
58
+ var helpText = config.helpText != null ? String(config.helpText) : "";
54
59
  var className = config.className || "";
55
60
  var htmlFor = config.htmlFor;
56
61
  var suffix = config.suffix;
@@ -95,6 +100,23 @@
95
100
  labelEl.appendChild(rightAsterisk);
96
101
  }
97
102
 
103
+ if (helpText) {
104
+ var infoWrap = document.createElement("span");
105
+ infoWrap.className = "box-content flex ml-4 size-16 items-center justify-center shrink-0 text-typography-tertiary-text cursor-pointer";
106
+ infoWrap.innerHTML = INFO_ICON_SVG;
107
+ var Tooltip =
108
+ (global.FlowUI && typeof global.FlowUI._getComponent === "function" && global.FlowUI._getComponent("Tooltip")) ||
109
+ global.Tooltip ||
110
+ (typeof window !== "undefined" && window.Tooltip);
111
+ if (Tooltip && typeof Tooltip.create === "function") {
112
+ var tooltipEl = Tooltip.create({ content: helpText, trigger: infoWrap, placement: "top" });
113
+ labelEl.appendChild(tooltipEl);
114
+ } else {
115
+ infoWrap.setAttribute("title", helpText);
116
+ labelEl.appendChild(infoWrap);
117
+ }
118
+ }
119
+
98
120
  if (optional) {
99
121
  var optionalSpan = document.createElement("span");
100
122
  optionalSpan.className = "optional-label text-typography-tertiary-text";
@@ -43,6 +43,8 @@
43
43
  var CHECK_SVG =
44
44
  '<svg width="14" height="14" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M11.4669 3.72684C11.7558 3.41574 12.2442 3.41574 12.5331 3.72684C12.822 4.03795 12.822 4.53753 12.5331 4.84863L6.81767 10.6736C6.52329 10.9901 6.05308 10.9901 5.7587 10.6736L2.46685 7.3463C2.17795 7.03519 2.17795 6.53561 2.46685 6.2245C2.75575 5.9134 3.24395 5.9134 3.53285 6.2245L6.28822 9.05351L11.4669 3.72684Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"/></svg>';
45
45
 
46
+ var SEARCH_FIELD = "search_field";
47
+
46
48
  var SEARCH_ICON =
47
49
  '<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>';
48
50
 
@@ -473,10 +475,9 @@
473
475
  }
474
476
  if (search && search.trim()) {
475
477
  filters.push({
476
- or: [
477
- { field: "name", operator: "contains", value: search.trim() },
478
- { field: "id", operator: "eq", value: search.trim() },
479
- ],
478
+ field: SEARCH_FIELD,
479
+ operator: "contains",
480
+ value: search.trim(),
480
481
  });
481
482
  }
482
483
  if (filters.length > 0) {
@@ -46,6 +46,8 @@
46
46
  var X_SVG =
47
47
  '<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>';
48
48
 
49
+ var SEARCH_FIELD = "search_field";
50
+
49
51
  var SEARCH_ICON =
50
52
  '<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>';
51
53
 
@@ -552,10 +554,9 @@
552
554
  }
553
555
  if (search && search.trim()) {
554
556
  filters.push({
555
- or: [
556
- { field: "name", operator: "contains", value: search.trim() },
557
- { field: "id", operator: "eq", value: search.trim() },
558
- ],
557
+ field: SEARCH_FIELD,
558
+ operator: "contains",
559
+ value: search.trim(),
559
560
  });
560
561
  }
561
562
  if (filters.length > 0) {
@@ -76,7 +76,6 @@
76
76
  * @param {Object} config
77
77
  * @param {string} [config.value] - Initial HTML content
78
78
  * @param {string} [config.placeholder] - Placeholder when empty
79
- * @param {number} [config.minHeightPx] - Min height of editor area (default 400)
80
79
  * @param {boolean} [config.disabled]
81
80
  * @param {Function} [config.onChange] - (html: string) => void
82
81
  * @returns {HTMLElement} Wrapper element with getValue/setValue/setDisabled/getInput
@@ -84,7 +83,6 @@
84
83
  function create(config) {
85
84
  var value = config.value != null ? String(config.value) : "";
86
85
  var placeholder = config.placeholder != null ? config.placeholder : "";
87
- var minHeightPx = config.minHeightPx != null ? config.minHeightPx : 400;
88
86
  var disabled = !!config.disabled;
89
87
  var onChange = config.onChange;
90
88
 
@@ -103,9 +101,10 @@
103
101
  var editorEl = document.createElement("div");
104
102
  editorEl.contentEditable = !disabled;
105
103
  editorEl.className = join(
106
- "rich-text-editor-content max-w-none rounded-b-12 border-t border-borderColor-border-primary p-8 text-reg-14 text-typography-primary-text"
104
+ "rich-text-editor-content max-w-none rounded-b-12 border-t border-borderColor-border-primary p-8 text-reg-14 text-typography-primary-text overflow-y-auto"
107
105
  );
108
- editorEl.style.minHeight = minHeightPx + "px";
106
+ editorEl.style.minHeight = "15vh";
107
+ editorEl.style.maxHeight = "20vh";
109
108
  if (value) editorEl.innerHTML = value;
110
109
  editorEl.setAttribute("data-placeholder", placeholder);
111
110
 
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Tooltip Component (vanilla JS)
3
+ * Shows a short label on hover/focus of a trigger element.
4
+ * Uses same styling conventions as Badge/Label (border-border-primary, typography, etc.).
5
+ */
6
+
7
+ (function (global) {
8
+ "use strict";
9
+
10
+ var TOOLTIP_BASE =
11
+ "absolute z-50 rounded-4 border-1/2 border-black text-typography-invert-text shadow-default-medium px-8 py-6 text-reg-10 leading-5 max-w-[80vw] whitespace-normal break-words pointer-events-none";
12
+
13
+ var ARROW_SIZE = 6;
14
+ var TOOLTIP_BG = "var(--color-neutral-900)";
15
+
16
+ function join() {
17
+ return Array.prototype.filter.call(arguments, Boolean).join(" ");
18
+ }
19
+
20
+ function positionTooltip(triggerRect, tooltipEl, placement) {
21
+ var style = tooltipEl.style;
22
+ style.position = "fixed";
23
+ var cx = triggerRect.left + triggerRect.width / 2;
24
+ var cy = triggerRect.top + triggerRect.height / 2;
25
+ var gap = 4;
26
+ if (placement === "top") {
27
+ style.left = cx + "px";
28
+ style.top = triggerRect.top + "px";
29
+ style.transform = "translate(-50%, -100%) translateY(-" + gap + "px)";
30
+ } else if (placement === "bottom") {
31
+ style.left = cx + "px";
32
+ style.top = triggerRect.bottom + "px";
33
+ style.transform = "translate(-50%, " + gap + "px)";
34
+ } else if (placement === "left") {
35
+ style.left = triggerRect.left + "px";
36
+ style.top = cy + "px";
37
+ style.transform = "translate(-100%, -50%) translateX(-" + gap + "px)";
38
+ } else {
39
+ style.left = triggerRect.right + "px";
40
+ style.top = cy + "px";
41
+ style.transform = "translate(" + gap + "px, -50%)";
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Create a tooltip wrapper: trigger element + tooltip that shows on hover/focus.
47
+ * @param {Object} config
48
+ * @param {string} config.content - Tooltip text
49
+ * @param {HTMLElement} [config.trigger] - Trigger element (if omitted, a span with label is created)
50
+ * @param {string} [config.label='Hover me'] - Label for default trigger when config.trigger is not provided
51
+ * @param {'top'|'bottom'|'left'|'right'} [config.placement='top'] - Where tooltip appears
52
+ * @param {string} [config.className] - Extra class for wrapper
53
+ * @param {string} [config.triggerClassName] - Extra class for default trigger span
54
+ * @returns {HTMLElement} Wrapper element (contains trigger; tooltip is portaled to body)
55
+ */
56
+ function create(config) {
57
+ var content = config && (config.content != null ? String(config.content) : "");
58
+ var placement = (config && config.placement) || "top";
59
+ var className = (config && config.className) || "";
60
+ var triggerClassName = (config && config.triggerClassName) || "";
61
+
62
+ var triggerEl = config && config.trigger;
63
+ if (!triggerEl || !triggerEl.nodeType) {
64
+ var span = document.createElement("span");
65
+ span.className = join(
66
+ "inline-flex items-center cursor-pointer text-typography-secondary-text underline decoration-dotted underline-offset-2",
67
+ triggerClassName
68
+ );
69
+ span.setAttribute("tabindex", "0");
70
+ span.setAttribute("role", "button");
71
+ span.textContent = (config && config.label) || "Hover me";
72
+ triggerEl = span;
73
+ }
74
+
75
+ var wrapper = document.createElement("div");
76
+ wrapper.className = join("relative inline-flex", className);
77
+ wrapper.appendChild(triggerEl);
78
+
79
+ var tooltipEl = document.createElement("div");
80
+ tooltipEl.className = join(TOOLTIP_BASE, "opacity-0 invisible transition-opacity duration-150");
81
+ tooltipEl.style.backgroundColor = TOOLTIP_BG;
82
+ tooltipEl.setAttribute("role", "tooltip");
83
+ tooltipEl.setAttribute("data-placement", placement);
84
+
85
+ var contentWrap = document.createElement("div");
86
+ contentWrap.textContent = content;
87
+ tooltipEl.appendChild(contentWrap);
88
+
89
+ var arrow = document.createElement("div");
90
+ arrow.setAttribute("data-tooltip-arrow", placement);
91
+ arrow.style.position = "absolute";
92
+ arrow.style.width = "0";
93
+ arrow.style.height = "0";
94
+ arrow.style.borderStyle = "solid";
95
+ arrow.style.pointerEvents = "none";
96
+ var s = ARROW_SIZE;
97
+ if (placement === "top") {
98
+ arrow.style.left = "50%";
99
+ arrow.style.bottom = "-" + s + "px";
100
+ arrow.style.marginLeft = "-" + s + "px";
101
+ arrow.style.borderWidth = s + "px " + s + "px 0 " + s + "px";
102
+ arrow.style.borderColor = TOOLTIP_BG + " transparent transparent transparent";
103
+ } else if (placement === "bottom") {
104
+ arrow.style.left = "50%";
105
+ arrow.style.top = "-" + s + "px";
106
+ arrow.style.marginLeft = "-" + s + "px";
107
+ arrow.style.borderWidth = "0 " + s + "px " + s + "px " + s + "px";
108
+ arrow.style.borderColor = "transparent transparent " + TOOLTIP_BG + " transparent";
109
+ } else if (placement === "left") {
110
+ arrow.style.top = "50%";
111
+ arrow.style.right = "-" + s + "px";
112
+ arrow.style.marginTop = "-" + s + "px";
113
+ arrow.style.borderWidth = s + "px 0 " + s + "px " + s + "px";
114
+ arrow.style.borderColor = "transparent transparent transparent " + TOOLTIP_BG;
115
+ } else {
116
+ arrow.style.top = "50%";
117
+ arrow.style.left = "-" + s + "px";
118
+ arrow.style.marginTop = "-" + s + "px";
119
+ arrow.style.borderWidth = s + "px " + s + "px " + s + "px 0";
120
+ arrow.style.borderColor = "transparent " + TOOLTIP_BG + " transparent transparent";
121
+ }
122
+ tooltipEl.appendChild(arrow);
123
+
124
+ document.body.appendChild(tooltipEl);
125
+
126
+ var showTimer;
127
+ var hideTimer;
128
+ var delay = 120;
129
+
130
+ function show() {
131
+ if (hideTimer) {
132
+ clearTimeout(hideTimer);
133
+ hideTimer = null;
134
+ }
135
+ showTimer = setTimeout(function () {
136
+ showTimer = null;
137
+ var rect = triggerEl.getBoundingClientRect();
138
+ positionTooltip(rect, tooltipEl, placement);
139
+ tooltipEl.style.opacity = "1";
140
+ tooltipEl.classList.remove("invisible");
141
+ }, delay);
142
+ }
143
+
144
+ function hide() {
145
+ if (showTimer) {
146
+ clearTimeout(showTimer);
147
+ showTimer = null;
148
+ }
149
+ hideTimer = setTimeout(function () {
150
+ hideTimer = null;
151
+ tooltipEl.style.opacity = "0";
152
+ tooltipEl.classList.add("invisible");
153
+ }, 80);
154
+ }
155
+
156
+ function handleShow() {
157
+ show();
158
+ }
159
+ function handleHide() {
160
+ hide();
161
+ }
162
+
163
+ triggerEl.addEventListener("mouseenter", handleShow);
164
+ triggerEl.addEventListener("mouseleave", handleHide);
165
+ triggerEl.addEventListener("focus", handleShow);
166
+ triggerEl.addEventListener("blur", handleHide);
167
+
168
+ wrapper._tooltipDestroy = function () {
169
+ triggerEl.removeEventListener("mouseenter", handleShow);
170
+ triggerEl.removeEventListener("mouseleave", handleHide);
171
+ triggerEl.removeEventListener("focus", handleShow);
172
+ triggerEl.removeEventListener("blur", handleHide);
173
+ if (showTimer) clearTimeout(showTimer);
174
+ if (hideTimer) clearTimeout(hideTimer);
175
+ if (tooltipEl.parentNode) tooltipEl.parentNode.removeChild(tooltipEl);
176
+ };
177
+
178
+ return wrapper;
179
+ }
180
+
181
+ global.Tooltip = {
182
+ create: create,
183
+ };
184
+
185
+ console.log("[Tooltip] Module loaded successfully");
186
+ })(typeof window !== "undefined" ? window : this);
package/core/flow.js CHANGED
@@ -126,14 +126,13 @@
126
126
  let labelEl;
127
127
  const LabelComponent = getComponent("Label");
128
128
  if (LabelComponent && typeof LabelComponent.create === "function") {
129
- const suffix = helpText && getComponent("Tooltip") ? getComponent("Tooltip").create(helpText) : null;
130
129
  labelEl = LabelComponent.create({
131
130
  label: label,
132
131
  required: required,
133
132
  requiredPosition: "right",
134
133
  optional: false,
135
134
  size: "default",
136
- suffix: suffix || undefined,
135
+ helpText: helpText || undefined,
137
136
  });
138
137
  } else {
139
138
  // Fallback: inline label (no Label component)
@@ -153,7 +152,7 @@
153
152
  labelContentWrapper.appendChild(document.createTextNode(label));
154
153
  }
155
154
  if (helpText && getComponent("Tooltip")) {
156
- const tooltip = getComponent("Tooltip").create(helpText);
155
+ const tooltip = getComponent("Tooltip").create({ content: helpText, label: "?" });
157
156
  if (tooltip) labelContentWrapper.appendChild(tooltip);
158
157
  }
159
158
  labelEl.appendChild(labelContentWrapper);
@@ -256,12 +255,11 @@
256
255
  * @param {string} [config.placeholder] - Placeholder when empty
257
256
  * @param {boolean} [config.required] - Whether field is required
258
257
  * @param {string} [config.helpText] - Optional help text for tooltip
259
- * @param {number} [config.minHeightPx] - Min height of editor area in pixels (default 400)
260
258
  * @param {boolean} [config.disabled] - Whether editor is disabled
261
259
  * @returns {HTMLElement} Field element
262
260
  */
263
261
  function createRichTextEditor(config) {
264
- const { label, fieldId, placeholder, required = false, helpText = null, minHeightPx = 400, disabled = false } = config;
262
+ const { label, fieldId, placeholder, required = false, helpText = null, disabled = false } = config;
265
263
 
266
264
  const field = createFieldWrapper(label, required, helpText);
267
265
  field.setAttribute("data-field-id", fieldId);
@@ -271,7 +269,6 @@
271
269
  const editorEl = getComponent("RichTextEditorComponent").create({
272
270
  value: currentValue,
273
271
  placeholder: placeholder || "",
274
- minHeightPx,
275
272
  disabled,
276
273
  onChange: (html) => set(fieldId, html),
277
274
  });
@@ -281,7 +278,7 @@
281
278
  }
282
279
 
283
280
  const fallback = document.createElement("textarea");
284
- fallback.className = "textarea min-h-[400px]";
281
+ fallback.className = "textarea min-h-[15vh]";
285
282
  fallback.placeholder = placeholder || `Enter ${label.toLowerCase()}`;
286
283
  fallback.value = get(fieldId) || "";
287
284
  fallback.disabled = disabled;
@@ -1766,6 +1763,23 @@
1766
1763
  return createAvatar(config);
1767
1764
  }
1768
1765
 
1766
+ /**
1767
+ * Create a tooltip wrapper (trigger + tooltip on hover/focus)
1768
+ * @param {Object} config - { content, trigger?, label?, placement?, className?, triggerClassName? }
1769
+ * @returns {HTMLElement} Wrapper element containing trigger
1770
+ */
1771
+ function createTooltip(config) {
1772
+ const Tooltip = getComponent("Tooltip");
1773
+ if (Tooltip && typeof Tooltip.create === "function") {
1774
+ return Tooltip.create(config);
1775
+ }
1776
+ const span = document.createElement("span");
1777
+ span.className = "text-typography-tertiary-text";
1778
+ span.title = config && config.content ? config.content : "";
1779
+ span.textContent = (config && config.label) || (config && config.content) || "Hover me";
1780
+ return span;
1781
+ }
1782
+
1769
1783
  /**
1770
1784
  * Create an avatar group (overlapping avatars, max 3 + remainder)
1771
1785
  * @param {Object} config - { users: [{ id, name, image? }], size?, className? }
@@ -1910,6 +1924,9 @@
1910
1924
  createBadge,
1911
1925
  createLoader,
1912
1926
 
1927
+ // Tooltip
1928
+ createTooltip,
1929
+
1913
1930
  // Avatar
1914
1931
  createAvatar,
1915
1932
  createVividAvatar,