@superleapai/flow-ui 2.3.4 → 2.3.6
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/components/checkbox.js +21 -8
- package/components/currency.js +7 -2
- package/components/date-time-picker/date-time-picker.js +10 -9
- package/components/duration/duration.js +8 -3
- package/components/enumeration.js +29 -10
- package/components/file-input.js +101 -9
- package/components/input.js +13 -17
- package/components/popover.js +59 -3
- package/components/textarea.js +1 -1
- package/core/flow.js +29 -0
- package/dist/output.css +1 -1
- package/dist/superleap-flow.js +993 -1893
- package/dist/superleap-flow.js.map +1 -1
- package/dist/superleap-flow.min.js +2 -2
- package/package.json +1 -1
package/components/checkbox.js
CHANGED
|
@@ -35,10 +35,18 @@
|
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
var CHECKBOX_BASE_CLASS =
|
|
38
|
-
"flex items-center justify-center rounded-2 border-1/2 border-borderColor-border-primary bg-fill-quarternary-fill-white p-4 transition-all
|
|
38
|
+
"flex items-center justify-center rounded-2 border-1/2 border-borderColor-border-primary bg-fill-quarternary-fill-white p-4 transition-all";
|
|
39
|
+
|
|
40
|
+
var CHECKBOX_ACTIVE_CLASS =
|
|
41
|
+
"hover:border-primary-base hover:shadow-primary-focused cursor-pointer";
|
|
42
|
+
|
|
43
|
+
var CHECKBOX_DISABLED_CLASS =
|
|
44
|
+
"cursor-not-allowed opacity-50";
|
|
39
45
|
|
|
40
46
|
var CHECKBOX_CHECKED_CLASS =
|
|
41
|
-
"data-checked:border-transparent data-checked:bg-primary-base
|
|
47
|
+
"data-checked:border-transparent data-checked:bg-primary-base";
|
|
48
|
+
var CHECKBOX_CHECKED_ACTIVE_CLASS =
|
|
49
|
+
"data-checked:hover:border-primary-base data-checked:hover:shadow-primary-focused";
|
|
42
50
|
|
|
43
51
|
var LABEL_BASE_CLASS =
|
|
44
52
|
"cursor-pointer pb-0 text-reg-12 leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70";
|
|
@@ -102,12 +110,16 @@
|
|
|
102
110
|
|
|
103
111
|
// Custom checkbox visual
|
|
104
112
|
var checkboxBox = document.createElement("div");
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
function applyCheckboxBoxClasses() {
|
|
114
|
+
var sizeClass = CHECKBOX_SIZES[size] || CHECKBOX_SIZES.default;
|
|
115
|
+
checkboxBox.className = join(
|
|
116
|
+
CHECKBOX_BASE_CLASS,
|
|
117
|
+
disabled ? CHECKBOX_DISABLED_CLASS : join(CHECKBOX_ACTIVE_CLASS, CHECKBOX_CHECKED_ACTIVE_CLASS),
|
|
118
|
+
CHECKBOX_CHECKED_CLASS,
|
|
119
|
+
sizeClass
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
applyCheckboxBoxClasses();
|
|
111
123
|
checkboxBox.setAttribute("role", "checkbox");
|
|
112
124
|
checkboxBox.setAttribute("tabindex", disabled ? "-1" : "0");
|
|
113
125
|
checkboxBox.setAttribute("aria-checked", indeterminate ? "mixed" : checked ? "true" : "false");
|
|
@@ -224,6 +236,7 @@
|
|
|
224
236
|
} else {
|
|
225
237
|
checkboxBox.removeAttribute("aria-disabled");
|
|
226
238
|
}
|
|
239
|
+
applyCheckboxBoxClasses();
|
|
227
240
|
updateCheckedState();
|
|
228
241
|
};
|
|
229
242
|
|
package/components/currency.js
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
sizeLarge: "",
|
|
27
27
|
sizeSmall: "",
|
|
28
28
|
disabled:
|
|
29
|
-
"cursor-not-allowed border-border-primary bg-fill-tertiary-fill-light-gray text-typography-quaternary-text hover:border-border-primary",
|
|
29
|
+
"pointer-events-none cursor-not-allowed border-border-primary bg-fill-tertiary-fill-light-gray text-typography-quaternary-text hover:border-border-primary",
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
// Currency type label: fit-content, separator (border-r) on type only, full height
|
|
@@ -213,7 +213,12 @@
|
|
|
213
213
|
wrapper.setDisabled = function (d) {
|
|
214
214
|
disabled = !!d;
|
|
215
215
|
input.disabled = disabled;
|
|
216
|
-
wrapper.
|
|
216
|
+
wrapper.className = join(
|
|
217
|
+
WRAPPER_CLASS.base,
|
|
218
|
+
WRAPPER_CLASS[variant] != null ? WRAPPER_CLASS[variant] : WRAPPER_CLASS.default,
|
|
219
|
+
disabled ? WRAPPER_CLASS.disabled : "",
|
|
220
|
+
config.className || ""
|
|
221
|
+
);
|
|
217
222
|
};
|
|
218
223
|
|
|
219
224
|
return wrapper;
|
|
@@ -243,13 +243,15 @@
|
|
|
243
243
|
var displayMonth = validDate ? new Date(validDate.getTime()) : new Date();
|
|
244
244
|
|
|
245
245
|
var triggerWrapper = document.createElement("div");
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
246
|
+
function getTriggerClassName(disabledState) {
|
|
247
|
+
return join(
|
|
248
|
+
"group flex items-center border-1/2 border-border-primary rounded-4 text-typography-primary-text gap-x-8 w-full transition-all ease-in-out",
|
|
249
|
+
"bg-fill-quarternary-fill-white hover:border-primary-base focus-within:border-primary-base",
|
|
250
|
+
size === "large" ? "px-12 py-8" : size === "small" ? "px-12 py-4" : "px-12 py-6",
|
|
251
|
+
disabledState ? "pointer-events-none cursor-not-allowed border-border-primary bg-fill-tertiary-fill-light-gray text-typography-quaternary-text hover:border-border-primary" : "cursor-pointer"
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
triggerWrapper.className = getTriggerClassName(disabled);
|
|
253
255
|
triggerWrapper.setAttribute("role", "button");
|
|
254
256
|
triggerWrapper.setAttribute("tabindex", disabled ? "-1" : "0");
|
|
255
257
|
triggerWrapper.setAttribute("aria-haspopup", "dialog");
|
|
@@ -517,8 +519,7 @@
|
|
|
517
519
|
};
|
|
518
520
|
container.setDisabled = function (d) {
|
|
519
521
|
disabled = !!d;
|
|
520
|
-
triggerWrapper.
|
|
521
|
-
triggerWrapper.classList.toggle("opacity-60", disabled);
|
|
522
|
+
triggerWrapper.className = getTriggerClassName(disabled);
|
|
522
523
|
triggerWrapper.setAttribute("tabindex", disabled ? "-1" : "0");
|
|
523
524
|
if (disabled) popoverApi.hide();
|
|
524
525
|
};
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
sizeLarge: "px-12 py-8",
|
|
41
41
|
sizeSmall: "px-12 py-4",
|
|
42
42
|
disabled:
|
|
43
|
-
"cursor-not-allowed border-border-primary bg-fill-tertiary-fill-light-gray text-typography-quaternary-text hover:border-border-primary
|
|
43
|
+
"pointer-events-none cursor-not-allowed border-border-primary bg-fill-tertiary-fill-light-gray text-typography-quaternary-text hover:border-border-primary",
|
|
44
44
|
};
|
|
45
45
|
|
|
46
46
|
function join() {
|
|
@@ -433,8 +433,13 @@
|
|
|
433
433
|
};
|
|
434
434
|
container.setDisabled = function (d) {
|
|
435
435
|
disabled = !!d;
|
|
436
|
-
triggerWrapper.
|
|
437
|
-
|
|
436
|
+
triggerWrapper.className = join(
|
|
437
|
+
TRIGGER_CLASS.base,
|
|
438
|
+
TRIGGER_CLASS[variant] != null ? TRIGGER_CLASS[variant] : TRIGGER_CLASS.default,
|
|
439
|
+
size === "large" ? TRIGGER_CLASS.sizeLarge : size === "small" ? TRIGGER_CLASS.sizeSmall : TRIGGER_CLASS.sizeDefault,
|
|
440
|
+
disabled ? TRIGGER_CLASS.disabled : "",
|
|
441
|
+
className
|
|
442
|
+
);
|
|
438
443
|
triggerWrapper.setAttribute("tabindex", disabled ? "-1" : "0");
|
|
439
444
|
if (disabled) popoverApi.hide();
|
|
440
445
|
};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"use strict";
|
|
9
9
|
|
|
10
10
|
var BASE_CLASS =
|
|
11
|
-
"flex items-center border rounded-4 text-typography-primary-text gap-4 !text-reg-13";
|
|
11
|
+
"flex items-center border-1/2 rounded-4 text-typography-primary-text gap-4 !text-reg-13";
|
|
12
12
|
|
|
13
13
|
var VARIANTS = {
|
|
14
14
|
default:
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
var DISABLED_CLASS =
|
|
35
|
-
"pointer-events-none !cursor-not-allowed opacity-50";
|
|
35
|
+
"pointer-events-none !cursor-not-allowed opacity-50 bg-fill-tertiary-fill-light-gray";
|
|
36
36
|
var READONLY_CLASS = "pointer-events-none";
|
|
37
37
|
|
|
38
38
|
var ITEM_BASE_CLASS =
|
|
@@ -97,14 +97,17 @@
|
|
|
97
97
|
var children = opts.children;
|
|
98
98
|
|
|
99
99
|
var wrapper = document.createElement("div");
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
100
|
+
function applyWrapperClasses() {
|
|
101
|
+
wrapper.className = join(
|
|
102
|
+
BASE_CLASS,
|
|
103
|
+
VARIANTS[variant] != null ? VARIANTS[variant] : VARIANTS.default,
|
|
104
|
+
SIZES[size] != null ? SIZES[size] : SIZES.default,
|
|
105
|
+
disabled ? DISABLED_CLASS : "",
|
|
106
|
+
readOnly ? READONLY_CLASS : "",
|
|
107
|
+
className
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
applyWrapperClasses();
|
|
108
111
|
wrapper.setAttribute("data-enumeration-variant", variant);
|
|
109
112
|
|
|
110
113
|
var count =
|
|
@@ -174,6 +177,22 @@
|
|
|
174
177
|
}
|
|
175
178
|
}
|
|
176
179
|
|
|
180
|
+
wrapper.setDisabled = function (d) {
|
|
181
|
+
disabled = d === true;
|
|
182
|
+
for (var j = 0; j < itemElements.length; j++) {
|
|
183
|
+
itemElements[j].setAttribute("tabindex", disabled || readOnly ? "-1" : "0");
|
|
184
|
+
}
|
|
185
|
+
applyWrapperClasses();
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
wrapper.setReadOnly = function (r) {
|
|
189
|
+
readOnly = r === true;
|
|
190
|
+
for (var j = 0; j < itemElements.length; j++) {
|
|
191
|
+
itemElements[j].setAttribute("tabindex", disabled || readOnly ? "-1" : "0");
|
|
192
|
+
}
|
|
193
|
+
applyWrapperClasses();
|
|
194
|
+
};
|
|
195
|
+
|
|
177
196
|
return wrapper;
|
|
178
197
|
}
|
|
179
198
|
|
package/components/file-input.js
CHANGED
|
@@ -114,8 +114,36 @@
|
|
|
114
114
|
* @param {boolean} config.isPrivate - Whether files should be private
|
|
115
115
|
* @param {number} config.maxFiles - Maximum number of files (for multiple mode)
|
|
116
116
|
* @param {number} config.maxFileSize - Maximum file size in bytes
|
|
117
|
+
* @param {boolean} [config.disabled] - Whether the file upload is disabled
|
|
118
|
+
* @param {string} [config.variant] - 'default' | 'error' | 'warning' | 'success' | 'borderless' | 'inline'
|
|
119
|
+
* @param {string} [config.inputSize] - 'default' | 'large' | 'small'
|
|
120
|
+
* @param {string} [config.className] - Extra class on upload wrapper
|
|
117
121
|
* @returns {HTMLElement} Field element
|
|
118
122
|
*/
|
|
123
|
+
var UPLOAD_WRAPPER_CLASS = {
|
|
124
|
+
base:
|
|
125
|
+
"group relative flex w-full items-center justify-between border-1/2 rounded-4 text-typography-primary-text w-full transition-all ease-in-out focus-within:outline-none group-has-[:disabled]:cursor-not-allowed group-has-[:disabled]:border-border-primary group-has-[:disabled]:bg-fill-tertiary-fill-light-gray group-has-[:disabled]:text-typography-quaternary-text group-has-[:disabled]:hover:border-border-primary",
|
|
126
|
+
default:
|
|
127
|
+
"border-border-primary bg-fill-quarternary-fill-white hover:border-primary-base focus-within:border-primary-base",
|
|
128
|
+
error:
|
|
129
|
+
"border-error-base bg-fill-quarternary-fill-white hover:border-error-base focus-within:border-error-base",
|
|
130
|
+
warning:
|
|
131
|
+
"border-warning-base bg-fill-quarternary-fill-white hover:border-warning-base focus-within:border-warning-base",
|
|
132
|
+
success:
|
|
133
|
+
"border-success-base bg-fill-quarternary-fill-white hover:border-success-base focus-within:border-success-base",
|
|
134
|
+
borderless:
|
|
135
|
+
"border-none shadow-none rounded-0 bg-fill-quarternary-fill-white",
|
|
136
|
+
inline:
|
|
137
|
+
"border-transparent shadow-none rounded-0 bg-fill-quarternary-fill-white hover:bg-fill-tertiary-fill-light-gray focus-within:border-transparent focus-within:bg-fill-tertiary-fill-light-gray",
|
|
138
|
+
sizeDefault: "px-12 py-4",
|
|
139
|
+
sizeLarge: "px-12 py-6",
|
|
140
|
+
sizeSmall: "px-12 py-2",
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
function joinClasses() {
|
|
144
|
+
return Array.prototype.filter.call(arguments, Boolean).join(" ");
|
|
145
|
+
}
|
|
146
|
+
|
|
119
147
|
function create(config) {
|
|
120
148
|
const {
|
|
121
149
|
label,
|
|
@@ -127,7 +155,14 @@
|
|
|
127
155
|
isPrivate = false,
|
|
128
156
|
maxFiles = null,
|
|
129
157
|
maxFileSize = 10 * 1024 * 1024, // 10MB default
|
|
158
|
+
disabled = false,
|
|
159
|
+
variant = "default",
|
|
160
|
+
inputSize = "default",
|
|
161
|
+
className = "",
|
|
130
162
|
} = config;
|
|
163
|
+
let disabledState = !!disabled;
|
|
164
|
+
let currentVariant = variant;
|
|
165
|
+
let currentInputSize = inputSize;
|
|
131
166
|
|
|
132
167
|
if (!global.FlowUI) {
|
|
133
168
|
throw new Error("FlowUI not available");
|
|
@@ -145,12 +180,33 @@
|
|
|
145
180
|
|
|
146
181
|
// Upload row: button + status + optional end spinner (match Select/MultiSelect trigger)
|
|
147
182
|
const uploadWrapper = document.createElement("div");
|
|
148
|
-
|
|
183
|
+
var sizeClass =
|
|
184
|
+
currentInputSize === "large"
|
|
185
|
+
? UPLOAD_WRAPPER_CLASS.sizeLarge
|
|
186
|
+
: currentInputSize === "small"
|
|
187
|
+
? UPLOAD_WRAPPER_CLASS.sizeSmall
|
|
188
|
+
: UPLOAD_WRAPPER_CLASS.sizeDefault;
|
|
189
|
+
function applyWrapperClasses() {
|
|
190
|
+
uploadWrapper.className = joinClasses(
|
|
191
|
+
UPLOAD_WRAPPER_CLASS.base,
|
|
192
|
+
UPLOAD_WRAPPER_CLASS[currentVariant] || UPLOAD_WRAPPER_CLASS.default,
|
|
193
|
+
sizeClass,
|
|
194
|
+
className
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
applyWrapperClasses();
|
|
198
|
+
uploadWrapper.setAttribute("data-file-input-variant", currentVariant);
|
|
199
|
+
uploadWrapper.setAttribute("data-file-input-size", currentInputSize);
|
|
200
|
+
uploadWrapper.setAttribute("data-disabled", disabledState ? "true" : "false");
|
|
149
201
|
|
|
150
202
|
// Left content (button + status) – pointer-events-none so overlay input receives clicks
|
|
151
203
|
const leftContent = document.createElement("div");
|
|
152
204
|
leftContent.className = "pointer-events-none flex min-w-0 flex-1 items-center gap-8 truncate";
|
|
153
205
|
|
|
206
|
+
var disabledChildClasses =
|
|
207
|
+
"group-has-[:disabled]:text-typography-quaternary-text group-has-[:disabled]:bg-fill-tertiary-fill-light-gray group-has-[:disabled]:hover:bg-fill-tertiary-fill-light-gray";
|
|
208
|
+
var statusTextBaseClass = "text-reg-13 min-w-0 flex-1 truncate";
|
|
209
|
+
var statusTextDisabledClass = " group-has-[:disabled]:text-typography-quaternary-text";
|
|
154
210
|
const useButtonComponent = global.Button && typeof global.Button.create === "function";
|
|
155
211
|
const initialButtonText = multiple ? "Choose files" : "Choose a file";
|
|
156
212
|
const btn = useButtonComponent
|
|
@@ -158,31 +214,41 @@
|
|
|
158
214
|
variant: "outline",
|
|
159
215
|
size: "small",
|
|
160
216
|
text: initialButtonText,
|
|
161
|
-
className: "shrink-0 truncate",
|
|
217
|
+
className: "shrink-0 truncate " + disabledChildClasses,
|
|
162
218
|
})
|
|
163
219
|
: (function () {
|
|
164
220
|
const el = document.createElement("div");
|
|
165
|
-
el.className =
|
|
221
|
+
el.className =
|
|
222
|
+
"shrink-0 truncate rounded-2 border-1/2 border-border-primary bg-fill-tertiary-fill-light-gray px-8 py-1 text-reg-13 text-typography-primary-text transition-colors duration-150 hover:bg-fill-secondary-fill-gray " +
|
|
223
|
+
disabledChildClasses;
|
|
166
224
|
el.textContent = initialButtonText;
|
|
167
225
|
return el;
|
|
168
226
|
})();
|
|
169
227
|
|
|
170
228
|
// Status text: "No files chosen" (quaternary) or "X file(s) selected"
|
|
171
229
|
const statusText = document.createElement("p");
|
|
172
|
-
statusText.className =
|
|
230
|
+
statusText.className = statusTextBaseClass + " text-typography-quaternary-text" + statusTextDisabledClass;
|
|
173
231
|
|
|
174
232
|
// Hidden file input – overlays row, high z-index so it receives clicks
|
|
175
233
|
const input = document.createElement("input");
|
|
176
234
|
input.type = "file";
|
|
177
|
-
|
|
235
|
+
const inputBaseClass = "absolute inset-0 z-10 w-full opacity-0";
|
|
236
|
+
function applyInputClasses() {
|
|
237
|
+
input.className =
|
|
238
|
+
inputBaseClass +
|
|
239
|
+
(disabledState ? " !pointer-events-none !cursor-not-allowed" : " cursor-pointer");
|
|
240
|
+
}
|
|
241
|
+
applyInputClasses();
|
|
178
242
|
input.multiple = multiple;
|
|
243
|
+
input.disabled = disabledState;
|
|
179
244
|
if (accept !== "*") {
|
|
180
245
|
input.accept = accept;
|
|
181
246
|
}
|
|
182
247
|
|
|
183
248
|
// End icon slot: spinner when uploading (match Select chevron position)
|
|
184
249
|
const endIconSlot = document.createElement("div");
|
|
185
|
-
endIconSlot.className =
|
|
250
|
+
endIconSlot.className =
|
|
251
|
+
"ml-4 flex size-16 items-center justify-center shrink-0 text-typography-quaternary-text group-has-[:disabled]:text-typography-quaternary-text";
|
|
186
252
|
endIconSlot.style.display = "none";
|
|
187
253
|
|
|
188
254
|
// Uploaded files: badge list (match UploadedFilePreviewer – flex-wrap gap-2)
|
|
@@ -363,13 +429,13 @@
|
|
|
363
429
|
|
|
364
430
|
if (!filesChosen) {
|
|
365
431
|
statusText.textContent = "No files chosen";
|
|
366
|
-
statusText.className =
|
|
432
|
+
statusText.className = statusTextBaseClass + " text-typography-quaternary-text" + statusTextDisabledClass;
|
|
367
433
|
} else if (uploadingCount > 0) {
|
|
368
434
|
statusText.textContent = "Uploading…";
|
|
369
|
-
statusText.className =
|
|
435
|
+
statusText.className = statusTextBaseClass + " text-typography-quaternary-text" + statusTextDisabledClass;
|
|
370
436
|
} else {
|
|
371
437
|
statusText.textContent = `${uploadedCount} file${uploadedCount !== 1 ? "s" : ""} selected`;
|
|
372
|
-
statusText.className =
|
|
438
|
+
statusText.className = statusTextBaseClass + " text-typography-primary-text" + statusTextDisabledClass;
|
|
373
439
|
}
|
|
374
440
|
|
|
375
441
|
endIconSlot.style.display = uploadingCount > 0 ? "flex" : "none";
|
|
@@ -506,6 +572,32 @@
|
|
|
506
572
|
loadExistingFiles();
|
|
507
573
|
updateStatus();
|
|
508
574
|
|
|
575
|
+
field.setDisabled = function (d) {
|
|
576
|
+
disabledState = !!d;
|
|
577
|
+
input.disabled = disabledState;
|
|
578
|
+
applyInputClasses();
|
|
579
|
+
applyWrapperClasses();
|
|
580
|
+
uploadWrapper.setAttribute("data-disabled", disabledState ? "true" : "false");
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
field.setVariant = function (v) {
|
|
584
|
+
currentVariant = v || "default";
|
|
585
|
+
uploadWrapper.setAttribute("data-file-input-variant", currentVariant);
|
|
586
|
+
applyWrapperClasses();
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
field.setInputSize = function (s) {
|
|
590
|
+
currentInputSize = s || "default";
|
|
591
|
+
sizeClass =
|
|
592
|
+
currentInputSize === "large"
|
|
593
|
+
? UPLOAD_WRAPPER_CLASS.sizeLarge
|
|
594
|
+
: currentInputSize === "small"
|
|
595
|
+
? UPLOAD_WRAPPER_CLASS.sizeSmall
|
|
596
|
+
: UPLOAD_WRAPPER_CLASS.sizeDefault;
|
|
597
|
+
uploadWrapper.setAttribute("data-file-input-size", currentInputSize);
|
|
598
|
+
applyWrapperClasses();
|
|
599
|
+
};
|
|
600
|
+
|
|
509
601
|
return field;
|
|
510
602
|
}
|
|
511
603
|
|
package/components/input.js
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
var WRAPPER_CLASS = {
|
|
25
25
|
base:
|
|
26
|
-
"group flex items-center border-1/2 border-border-primary rounded-4 text-typography-primary-text gap-x-8 w-full transition-all ease-in-out",
|
|
26
|
+
"group flex items-center border-1/2 border-border-primary rounded-4 text-typography-primary-text gap-x-8 w-full transition-all ease-in-out group-has-[:disabled]:cursor-not-allowed group-has-[:disabled]:border-border-primary group-has-[:disabled]:bg-fill-tertiary-fill-light-gray group-has-[:disabled]:text-typography-quaternary-text group-has-[:disabled]:hover:border-border-primary group-has-[:disabled]:[&_input]:cursor-not-allowed group-has-[:disabled]:[&_input]:text-typography-quaternary-text",
|
|
27
27
|
default:
|
|
28
28
|
"bg-fill-quarternary-fill-white hover:border-primary-base focus-within:border-primary-base",
|
|
29
29
|
error:
|
|
@@ -98,13 +98,16 @@
|
|
|
98
98
|
var isPassword = type === "password";
|
|
99
99
|
|
|
100
100
|
var wrapper = document.createElement("div");
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
101
|
+
var sizeClass = inputSize === "large" ? WRAPPER_CLASS.sizeLarge : inputSize === "small" ? WRAPPER_CLASS.sizeSmall : WRAPPER_CLASS.sizeDefault;
|
|
102
|
+
function applyWrapperClasses() {
|
|
103
|
+
wrapper.className = join(
|
|
104
|
+
WRAPPER_CLASS.base,
|
|
105
|
+
disabled ? WRAPPER_CLASS.disabled : (WRAPPER_CLASS[variant] || WRAPPER_CLASS.default),
|
|
106
|
+
sizeClass,
|
|
107
|
+
config.className || ""
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
applyWrapperClasses();
|
|
108
111
|
wrapper.setAttribute("data-input-variant", variant);
|
|
109
112
|
|
|
110
113
|
if (config.prefixNode) {
|
|
@@ -234,19 +237,12 @@
|
|
|
234
237
|
wrapper.setVariant = function (v) {
|
|
235
238
|
variant = v;
|
|
236
239
|
wrapper.setAttribute("data-input-variant", v);
|
|
237
|
-
|
|
238
|
-
WRAPPER_CLASS.base,
|
|
239
|
-
WRAPPER_CLASS[variant] || WRAPPER_CLASS.default,
|
|
240
|
-
inputSize === "large" ? WRAPPER_CLASS.sizeLarge : inputSize === "small" ? WRAPPER_CLASS.sizeSmall : WRAPPER_CLASS.sizeDefault,
|
|
241
|
-
disabled ? WRAPPER_CLASS.disabled : "",
|
|
242
|
-
config.className || ""
|
|
243
|
-
);
|
|
240
|
+
applyWrapperClasses();
|
|
244
241
|
};
|
|
245
242
|
wrapper.setDisabled = function (d) {
|
|
246
243
|
disabled = !!d;
|
|
247
244
|
input.disabled = disabled;
|
|
248
|
-
|
|
249
|
-
wrapper.classList.toggle("opacity-60", disabled);
|
|
245
|
+
applyWrapperClasses();
|
|
250
246
|
};
|
|
251
247
|
|
|
252
248
|
return wrapper;
|
package/components/popover.js
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
* @param {Function} [config.onOpen] - Called when popover opens (before positioning)
|
|
20
20
|
* @param {string} [config.bodyClassName] - Optional class for body wrapper (overrides default padding)
|
|
21
21
|
* @param {string} [config.panelClassName] - Optional class to add to panel (e.g. for width)
|
|
22
|
+
* @param {boolean} [config.modal=false] - If true, lock body scroll and show backdrop; only popover and trigger are interactive
|
|
22
23
|
* @returns {Object} Popover API {show, hide, destroy, element}
|
|
23
24
|
*/
|
|
24
25
|
function create(config = {}) {
|
|
@@ -33,6 +34,7 @@
|
|
|
33
34
|
onOpen = null,
|
|
34
35
|
bodyClassName = "",
|
|
35
36
|
panelClassName = "",
|
|
37
|
+
modal = true,
|
|
36
38
|
} = config;
|
|
37
39
|
|
|
38
40
|
const triggerEl =
|
|
@@ -91,20 +93,68 @@
|
|
|
91
93
|
wrapper.appendChild(panel);
|
|
92
94
|
container.appendChild(wrapper);
|
|
93
95
|
|
|
96
|
+
var backdropEl = null;
|
|
97
|
+
|
|
98
|
+
function onBackdropWheel(e) {
|
|
99
|
+
e.preventDefault();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function applyModalOpen() {
|
|
103
|
+
if (!modal) return;
|
|
104
|
+
if (!backdropEl) {
|
|
105
|
+
backdropEl = document.createElement("div");
|
|
106
|
+
backdropEl.className = "fixed inset-0 z-[9998] bg-transparent pointer-events-auto";
|
|
107
|
+
backdropEl.setAttribute("aria-hidden", "true");
|
|
108
|
+
backdropEl.addEventListener("click", function () {
|
|
109
|
+
hide();
|
|
110
|
+
});
|
|
111
|
+
backdropEl.addEventListener("wheel", onBackdropWheel, { passive: false });
|
|
112
|
+
}
|
|
113
|
+
document.body.appendChild(backdropEl);
|
|
114
|
+
container.style.zIndex = "9999";
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function applyModalClose() {
|
|
118
|
+
if (!modal) return;
|
|
119
|
+
if (backdropEl && backdropEl.parentNode) {
|
|
120
|
+
backdropEl.parentNode.removeChild(backdropEl);
|
|
121
|
+
}
|
|
122
|
+
container.style.zIndex = "";
|
|
123
|
+
}
|
|
124
|
+
|
|
94
125
|
function noop() {}
|
|
95
126
|
|
|
96
127
|
function position() {
|
|
97
128
|
const triggerRect = triggerEl.getBoundingClientRect();
|
|
98
129
|
const panelRect = panel.getBoundingClientRect();
|
|
99
130
|
const gap = 8;
|
|
131
|
+
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
|
|
132
|
+
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
|
|
133
|
+
const spaceBelow = viewportHeight - triggerRect.bottom;
|
|
134
|
+
const spaceAbove = triggerRect.top;
|
|
135
|
+
const spaceRight = viewportWidth - triggerRect.right;
|
|
136
|
+
const spaceLeft = triggerRect.left;
|
|
137
|
+
|
|
138
|
+
// Flip placement when there is not enough space (prefer requested side, flip only when needed)
|
|
139
|
+
let effectivePlacement = placement;
|
|
140
|
+
if (placement === "bottom" && spaceBelow < panelRect.height + gap && spaceAbove >= panelRect.height + gap) {
|
|
141
|
+
effectivePlacement = "top";
|
|
142
|
+
} else if (placement === "top" && spaceAbove < panelRect.height + gap && spaceBelow >= panelRect.height + gap) {
|
|
143
|
+
effectivePlacement = "bottom";
|
|
144
|
+
} else if (placement === "right" && spaceRight < panelRect.width + gap && spaceLeft >= panelRect.width + gap) {
|
|
145
|
+
effectivePlacement = "left";
|
|
146
|
+
} else if (placement === "left" && spaceLeft < panelRect.width + gap && spaceRight >= panelRect.width + gap) {
|
|
147
|
+
effectivePlacement = "right";
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
panel.setAttribute("data-side", effectivePlacement);
|
|
151
|
+
|
|
100
152
|
let top = 0;
|
|
101
153
|
let left = 0;
|
|
102
|
-
|
|
103
|
-
// Alignment offset: start = 0, center = half diff, end = full diff
|
|
104
154
|
const alignLeft = (align === "center" ? (triggerRect.width - panelRect.width) / 2 : align === "end" ? triggerRect.width - panelRect.width : 0);
|
|
105
155
|
const alignTop = (align === "center" ? (triggerRect.height - panelRect.height) / 2 : align === "end" ? triggerRect.height - panelRect.height : 0);
|
|
106
156
|
|
|
107
|
-
switch (
|
|
157
|
+
switch (effectivePlacement) {
|
|
108
158
|
case "bottom":
|
|
109
159
|
top = triggerRect.height + gap;
|
|
110
160
|
left = alignLeft;
|
|
@@ -137,11 +187,13 @@
|
|
|
137
187
|
wrapper.classList.add("invisible", "opacity-0", "pointer-events-none");
|
|
138
188
|
wrapper.classList.remove("visible", "opacity-100", "pointer-events-auto");
|
|
139
189
|
wrapper.setAttribute("aria-hidden", "true");
|
|
190
|
+
applyModalClose();
|
|
140
191
|
if (onClose) onClose();
|
|
141
192
|
}
|
|
142
193
|
|
|
143
194
|
function show() {
|
|
144
195
|
if (onOpen) onOpen();
|
|
196
|
+
applyModalOpen();
|
|
145
197
|
requestAnimationFrame(function () {
|
|
146
198
|
position();
|
|
147
199
|
wrapper.classList.remove("invisible", "opacity-0", "pointer-events-none");
|
|
@@ -157,6 +209,10 @@
|
|
|
157
209
|
|
|
158
210
|
function destroy() {
|
|
159
211
|
hide();
|
|
212
|
+
applyModalClose();
|
|
213
|
+
if (backdropEl && backdropEl.parentNode) {
|
|
214
|
+
backdropEl.parentNode.removeChild(backdropEl);
|
|
215
|
+
}
|
|
160
216
|
if (wrapper.parentNode) {
|
|
161
217
|
wrapper.parentNode.removeChild(wrapper);
|
|
162
218
|
}
|
package/components/textarea.js
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
warning:
|
|
22
22
|
"min-h-[80px] border-warning-base hover:border-warning-base focus:border-warning-base",
|
|
23
23
|
disabled:
|
|
24
|
-
"cursor-not-allowed border-border-primary bg-fill-tertiary-fill-light-gray text-typography-quaternary-text hover:border-border-primary",
|
|
24
|
+
"pointer-events-none cursor-not-allowed border-border-primary bg-fill-tertiary-fill-light-gray text-typography-quaternary-text hover:border-border-primary",
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
function join() {
|
package/core/flow.js
CHANGED
|
@@ -1494,6 +1494,34 @@
|
|
|
1494
1494
|
return field;
|
|
1495
1495
|
}
|
|
1496
1496
|
|
|
1497
|
+
// ============================================================================
|
|
1498
|
+
// ALERTS
|
|
1499
|
+
// ============================================================================
|
|
1500
|
+
|
|
1501
|
+
/**
|
|
1502
|
+
* Render multiple alert messages into a container
|
|
1503
|
+
* @param {HTMLElement} container - Container to append alerts to
|
|
1504
|
+
* @param {string[]} messages - Array of message strings
|
|
1505
|
+
* @param {string} [variant='default'] - 'default' | 'error' | 'warning' | 'success' | 'info' | 'destructive'
|
|
1506
|
+
*/
|
|
1507
|
+
function renderAlerts(container, messages, variant = "default") {
|
|
1508
|
+
if (!container || !Array.isArray(messages)) return;
|
|
1509
|
+
const Alert = getComponent("Alert");
|
|
1510
|
+
if (Alert && typeof Alert.simple === "function") {
|
|
1511
|
+
messages.forEach((msg) => {
|
|
1512
|
+
const el = Alert.simple(msg, variant);
|
|
1513
|
+
if (el) container.appendChild(el);
|
|
1514
|
+
});
|
|
1515
|
+
} else {
|
|
1516
|
+
messages.forEach((msg) => {
|
|
1517
|
+
const div = document.createElement("div");
|
|
1518
|
+
div.className = "rounded border p-2 text-sm " + (variant === "error" ? "bg-red-50 border-red-200 text-red-800" : "bg-gray-50 border-gray-200");
|
|
1519
|
+
div.textContent = msg;
|
|
1520
|
+
container.appendChild(div);
|
|
1521
|
+
});
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1497
1525
|
// ============================================================================
|
|
1498
1526
|
// TOAST NOTIFICATIONS
|
|
1499
1527
|
// ============================================================================
|
|
@@ -1667,6 +1695,7 @@
|
|
|
1667
1695
|
renderStepper,
|
|
1668
1696
|
|
|
1669
1697
|
// Alerts
|
|
1698
|
+
renderAlerts,
|
|
1670
1699
|
showToast,
|
|
1671
1700
|
|
|
1672
1701
|
// Table
|