@superleapai/flow-ui 2.3.7 → 2.3.9
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/steps.js +245 -0
- package/components/tabs.js +191 -0
- package/core/flow.js +34 -0
- package/dist/output.css +1 -1
- package/dist/superleap-flow.js +383 -681
- package/dist/superleap-flow.js.map +1 -1
- package/dist/superleap-flow.min.js +2 -2
- package/index.d.ts +36 -0
- package/index.js +4 -0
- package/package.json +1 -1
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Steps Component (vanilla JS)
|
|
3
|
+
* Multi-step flow with numbered step triggers and optional content panels.
|
|
4
|
+
* Use for wizards / step-by-step forms (e.g. "1 Step One", "2 Step Two").
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
(function (global) {
|
|
8
|
+
"use strict";
|
|
9
|
+
|
|
10
|
+
function getComponent(name) {
|
|
11
|
+
if (typeof global.FlowUI !== "undefined" && typeof global.FlowUI._getComponent === "function") {
|
|
12
|
+
var c = global.FlowUI._getComponent(name);
|
|
13
|
+
if (c) return c;
|
|
14
|
+
}
|
|
15
|
+
return global[name];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
var LIST_BASE_CLASS =
|
|
19
|
+
"flex items-center flex-wrap gap-0 rounded-4 border border-border-primary bg-fill-quarternary-fill-white p-4";
|
|
20
|
+
|
|
21
|
+
/** Inactive step: muted label color only (button stays ghost large) */
|
|
22
|
+
var INACTIVE_LABEL_CLASS = "!text-typography-quaternary-text";
|
|
23
|
+
|
|
24
|
+
/** Box around step number: active = dark fill + invert text, inactive = dark gray fill + tertiary text */
|
|
25
|
+
var NUMBER_BOX_ACTIVE =
|
|
26
|
+
"flex h-16 w-16 items-center justify-center rounded-4 bg-typography-primary-text text-typography-invert-text shrink-0";
|
|
27
|
+
var NUMBER_BOX_INACTIVE =
|
|
28
|
+
"flex h-16 w-16 items-center justify-center rounded-4 bg-fill-primary-fill-dark-gray text-typography-tertiary-text shrink-0";
|
|
29
|
+
|
|
30
|
+
/** Horizontal line between steps (step1 ——— step2) */
|
|
31
|
+
var CONNECTOR_CLASS = "flex-1 min-w-12 max-w-32 h-0 border-t border-border-primary shrink-0 mx-2 self-center";
|
|
32
|
+
|
|
33
|
+
var CONTENT_BASE_CLASS =
|
|
34
|
+
"ring-offset-background focus-visible:ring-2 focus-visible:ring-offset-2 h-full";
|
|
35
|
+
|
|
36
|
+
function join() {
|
|
37
|
+
return Array.prototype.filter.call(arguments, Boolean).join(" ");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Create a Steps component (numbered step triggers + optional content)
|
|
42
|
+
* Design: ghost large Button for all steps; inactive steps use muted label color. Connectors between steps. Optional title/description above.
|
|
43
|
+
* @param {Object} config
|
|
44
|
+
* @param {Array<{id: string, label: string, content?: HTMLElement|string}>} config.steps - step definitions
|
|
45
|
+
* @param {string} [config.defaultValue] - initial active step id
|
|
46
|
+
* @param {string} [config.value] - controlled active step id
|
|
47
|
+
* @param {Function} [config.onChange] - (stepId) => void when step changes
|
|
48
|
+
* @param {string} [config.title] - optional title above steps
|
|
49
|
+
* @param {string} [config.description] - optional description above steps
|
|
50
|
+
* @param {string} [config.listClassName] - extra class on step list
|
|
51
|
+
* @param {string} [config.contentClassName] - extra class on content wrapper
|
|
52
|
+
* @param {boolean} [config.showContent=true] - whether to render content panels (if steps have content)
|
|
53
|
+
* @returns {HTMLElement} root element
|
|
54
|
+
*/
|
|
55
|
+
function create(config) {
|
|
56
|
+
var opts = config || {};
|
|
57
|
+
var steps = opts.steps || [];
|
|
58
|
+
var defaultValue = opts.defaultValue;
|
|
59
|
+
var controlledValue = opts.value;
|
|
60
|
+
var onChange = opts.onChange;
|
|
61
|
+
var title = opts.title;
|
|
62
|
+
var description = opts.description;
|
|
63
|
+
var listClassName = opts.listClassName || "";
|
|
64
|
+
var contentClassName = opts.contentClassName || "";
|
|
65
|
+
var showContent = opts.showContent !== false;
|
|
66
|
+
|
|
67
|
+
var root = document.createElement("div");
|
|
68
|
+
root.className = "steps-root w-full";
|
|
69
|
+
|
|
70
|
+
var activeId =
|
|
71
|
+
controlledValue !== undefined
|
|
72
|
+
? controlledValue
|
|
73
|
+
: defaultValue !== undefined
|
|
74
|
+
? defaultValue
|
|
75
|
+
: (steps[0] && steps[0].id) || "";
|
|
76
|
+
|
|
77
|
+
if (title != null && title !== "") {
|
|
78
|
+
var titleEl = document.createElement("h3");
|
|
79
|
+
titleEl.className = "text-typography-primary-text";
|
|
80
|
+
titleEl.textContent = title;
|
|
81
|
+
root.appendChild(titleEl);
|
|
82
|
+
}
|
|
83
|
+
if (description != null && description !== "") {
|
|
84
|
+
var descEl = document.createElement("p");
|
|
85
|
+
descEl.className = "text-typography-secondary-text";
|
|
86
|
+
descEl.textContent = description;
|
|
87
|
+
root.appendChild(descEl);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Step list (horizontal: step, connector, step, connector, ...)
|
|
91
|
+
var list = document.createElement("div");
|
|
92
|
+
list.setAttribute("role", "tablist");
|
|
93
|
+
list.setAttribute("aria-label", "Steps");
|
|
94
|
+
list.className = join(LIST_BASE_CLASS, listClassName);
|
|
95
|
+
|
|
96
|
+
var triggerEls = [];
|
|
97
|
+
var numberBoxEls = [];
|
|
98
|
+
var contentPanels = [];
|
|
99
|
+
var contentWrapper = null;
|
|
100
|
+
|
|
101
|
+
if (showContent && steps.some(function (s) { return s.content != null; })) {
|
|
102
|
+
contentWrapper = document.createElement("div");
|
|
103
|
+
contentWrapper.className = join("steps-content-wrapper mt-4", contentClassName);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
var Button = getComponent("Button");
|
|
107
|
+
|
|
108
|
+
steps.forEach(function (step, index) {
|
|
109
|
+
var stepId = step.id;
|
|
110
|
+
var label = step.label != null ? step.label : stepId;
|
|
111
|
+
var content = step.content;
|
|
112
|
+
var stepNumber = index + 1;
|
|
113
|
+
var isActive = stepId === activeId;
|
|
114
|
+
|
|
115
|
+
var trigger = Button.create({
|
|
116
|
+
variant: "ghost",
|
|
117
|
+
size: "large",
|
|
118
|
+
text: "\u00A0",
|
|
119
|
+
type: "button",
|
|
120
|
+
className: isActive ? "" : INACTIVE_LABEL_CLASS,
|
|
121
|
+
onClick: function () {
|
|
122
|
+
if (activeId === stepId) return;
|
|
123
|
+
if (controlledValue === undefined) {
|
|
124
|
+
activeId = stepId;
|
|
125
|
+
updateActiveState();
|
|
126
|
+
}
|
|
127
|
+
if (typeof onChange === "function") {
|
|
128
|
+
onChange(stepId);
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
var numberBox = document.createElement("span");
|
|
134
|
+
numberBox.setAttribute("aria-hidden", "true");
|
|
135
|
+
numberBox.className = isActive ? NUMBER_BOX_ACTIVE : NUMBER_BOX_INACTIVE;
|
|
136
|
+
numberBox.textContent = String(stepNumber);
|
|
137
|
+
|
|
138
|
+
trigger.innerHTML = "";
|
|
139
|
+
trigger.appendChild(numberBox);
|
|
140
|
+
trigger.appendChild(document.createTextNode(" " + label));
|
|
141
|
+
|
|
142
|
+
trigger.setAttribute("role", "tab");
|
|
143
|
+
trigger.setAttribute("aria-selected", isActive ? "true" : "false");
|
|
144
|
+
trigger.setAttribute("data-state", isActive ? "active" : "inactive");
|
|
145
|
+
trigger.setAttribute("data-step-id", stepId);
|
|
146
|
+
trigger.tabIndex = isActive ? 0 : -1;
|
|
147
|
+
|
|
148
|
+
numberBoxEls.push(numberBox);
|
|
149
|
+
|
|
150
|
+
trigger.addEventListener("keydown", function (e) {
|
|
151
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
152
|
+
e.preventDefault();
|
|
153
|
+
trigger.click();
|
|
154
|
+
}
|
|
155
|
+
if (e.key === "ArrowRight" || e.key === "ArrowLeft") {
|
|
156
|
+
e.preventDefault();
|
|
157
|
+
var nextIndex = e.key === "ArrowRight" ? index + 1 : index - 1;
|
|
158
|
+
if (nextIndex >= 0 && nextIndex < steps.length) {
|
|
159
|
+
var nextTrigger = triggerEls[nextIndex];
|
|
160
|
+
if (nextTrigger) {
|
|
161
|
+
nextTrigger.focus();
|
|
162
|
+
nextTrigger.click();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
list.appendChild(trigger);
|
|
169
|
+
triggerEls.push(trigger);
|
|
170
|
+
|
|
171
|
+
if (index < steps.length - 1) {
|
|
172
|
+
var connector = document.createElement("span");
|
|
173
|
+
connector.className = CONNECTOR_CLASS;
|
|
174
|
+
connector.setAttribute("aria-hidden", "true");
|
|
175
|
+
list.appendChild(connector);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (contentWrapper && content != null) {
|
|
179
|
+
var panel = document.createElement("div");
|
|
180
|
+
panel.setAttribute("role", "tabpanel");
|
|
181
|
+
panel.setAttribute("aria-hidden", stepId !== activeId ? "true" : "false");
|
|
182
|
+
panel.setAttribute("data-step-id", stepId);
|
|
183
|
+
panel.className = join(CONTENT_BASE_CLASS, stepId !== activeId ? "hidden" : "");
|
|
184
|
+
if (typeof content === "string") {
|
|
185
|
+
panel.innerHTML = content;
|
|
186
|
+
} else if (content && content.nodeType === 1) {
|
|
187
|
+
panel.appendChild(content);
|
|
188
|
+
}
|
|
189
|
+
contentWrapper.appendChild(panel);
|
|
190
|
+
contentPanels.push(panel);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
function updateActiveState() {
|
|
195
|
+
triggerEls.forEach(function (t, i) {
|
|
196
|
+
var step = steps[i];
|
|
197
|
+
var id = step && step.id;
|
|
198
|
+
var isActive = id === activeId;
|
|
199
|
+
t.setAttribute("aria-selected", isActive ? "true" : "false");
|
|
200
|
+
t.setAttribute("data-state", isActive ? "active" : "inactive");
|
|
201
|
+
t.tabIndex = isActive ? 0 : -1;
|
|
202
|
+
if (isActive) {
|
|
203
|
+
t.classList.remove(INACTIVE_LABEL_CLASS);
|
|
204
|
+
} else {
|
|
205
|
+
t.classList.add(INACTIVE_LABEL_CLASS);
|
|
206
|
+
}
|
|
207
|
+
numberBoxEls[i].className = isActive ? NUMBER_BOX_ACTIVE : NUMBER_BOX_INACTIVE;
|
|
208
|
+
});
|
|
209
|
+
contentPanels.forEach(function (p, i) {
|
|
210
|
+
var step = steps[i];
|
|
211
|
+
var id = step && step.id;
|
|
212
|
+
var isActive = id === activeId;
|
|
213
|
+
p.setAttribute("aria-hidden", isActive ? "false" : "true");
|
|
214
|
+
p.classList.toggle("hidden", !isActive);
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
root.appendChild(list);
|
|
219
|
+
if (contentWrapper) {
|
|
220
|
+
root.appendChild(contentWrapper);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
root.getValue = function () {
|
|
224
|
+
return activeId;
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
root.setValue = function (newId) {
|
|
228
|
+
if (newId === activeId) return;
|
|
229
|
+
activeId = newId;
|
|
230
|
+
updateActiveState();
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
return root;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
var Steps = {
|
|
237
|
+
create: create,
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
if (typeof module !== "undefined" && module.exports) {
|
|
241
|
+
module.exports = Steps;
|
|
242
|
+
} else {
|
|
243
|
+
global.Steps = Steps;
|
|
244
|
+
}
|
|
245
|
+
})(typeof window !== "undefined" ? window : this);
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tabs Component (vanilla JS)
|
|
3
|
+
* Tabbed interface with list, triggers, and content panels.
|
|
4
|
+
* Ref: Radix-style Tabs; design tokens match design system.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
(function (global) {
|
|
8
|
+
"use strict";
|
|
9
|
+
|
|
10
|
+
function getComponent(name) {
|
|
11
|
+
if (typeof global.FlowUI !== "undefined" && typeof global.FlowUI._getComponent === "function") {
|
|
12
|
+
var c = global.FlowUI._getComponent(name);
|
|
13
|
+
if (c) return c;
|
|
14
|
+
}
|
|
15
|
+
return global[name];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
var LIST_BASE_CLASS =
|
|
19
|
+
"inline-flex items-center justify-center gap-2 rounded-4 bg-fill-tertiary-fill-light-gray p-4";
|
|
20
|
+
|
|
21
|
+
/** Button variant classes for active (outline) vs inactive (ghost) */
|
|
22
|
+
var BUTTON_OUTLINE =
|
|
23
|
+
"shadow-soft-extra-small group bg-fill-quarternary-fill-white border-1/2 border-border-primary text-typography-primary-text hover:bg-fill-tertiary-fill-light-gray active:bg-fill-secondary-fill-gray disabled:opacity-50 disabled:border-fill-secondary-fill-gray";
|
|
24
|
+
var BUTTON_GHOST =
|
|
25
|
+
"group text-typography-primary-text hover:bg-fill-tertiary-fill-light-gray active:bg-fill-secondary-fill-gray disabled:text-typography-quaternary-text";
|
|
26
|
+
var BUTTON_BASE =
|
|
27
|
+
"inline-flex items-center justify-center whitespace-nowrap !text-med-12 transition-colors disabled:pointer-events-none hover:cursor-pointer h-fit";
|
|
28
|
+
var BUTTON_SIZES = {
|
|
29
|
+
default: "px-8 py-4 gap-4 rounded-4",
|
|
30
|
+
small: "px-8 py-4 gap-4 rounded-4",
|
|
31
|
+
large: "px-16 py-8 gap-4 rounded-4",
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
var CONTENT_BASE_CLASS =
|
|
35
|
+
"ring-offset-background focus-visible:ring-ring h-full focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2";
|
|
36
|
+
|
|
37
|
+
function join() {
|
|
38
|
+
return Array.prototype.filter.call(arguments, Boolean).join(" ");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Create a full Tabs component (list + triggers + content panels)
|
|
43
|
+
* @param {Object} config
|
|
44
|
+
* @param {string} [config.defaultValue] - initial active tab value
|
|
45
|
+
* @param {string} [config.value] - controlled active value
|
|
46
|
+
* @param {Function} [config.onChange] - (value) => void when tab changes
|
|
47
|
+
* @param {Array<{value: string, label: string, content: HTMLElement|string}>} config.tabs - tab definitions
|
|
48
|
+
* @param {string} [config.size] - 'default' | 'small' | 'large'
|
|
49
|
+
* @param {string} [config.listClassName] - extra class on list
|
|
50
|
+
* @param {string} [config.contentClassName] - extra class on content wrapper
|
|
51
|
+
* @returns {HTMLElement} root element (wrapper containing list + content area)
|
|
52
|
+
*/
|
|
53
|
+
function create(config) {
|
|
54
|
+
var opts = config || {};
|
|
55
|
+
var defaultValue = opts.defaultValue;
|
|
56
|
+
var controlledValue = opts.value;
|
|
57
|
+
var onChange = opts.onChange;
|
|
58
|
+
var tabs = opts.tabs || [];
|
|
59
|
+
var size = opts.size || "default";
|
|
60
|
+
var listClassName = opts.listClassName || "";
|
|
61
|
+
var contentClassName = opts.contentClassName || "";
|
|
62
|
+
|
|
63
|
+
var sizeClass = BUTTON_SIZES[size] || BUTTON_SIZES.default;
|
|
64
|
+
|
|
65
|
+
var root = document.createElement("div");
|
|
66
|
+
root.className = "tabs-root w-full";
|
|
67
|
+
|
|
68
|
+
var activeValue = controlledValue !== undefined ? controlledValue : defaultValue !== undefined ? defaultValue : (tabs[0] && tabs[0].value) || "";
|
|
69
|
+
|
|
70
|
+
// List container
|
|
71
|
+
var list = document.createElement("div");
|
|
72
|
+
list.setAttribute("role", "tablist");
|
|
73
|
+
list.className = join(LIST_BASE_CLASS, listClassName);
|
|
74
|
+
|
|
75
|
+
// Content container (holds all panels; we show/hide by value)
|
|
76
|
+
var contentWrapper = document.createElement("div");
|
|
77
|
+
contentWrapper.className = join("tabs-content-wrapper mt-4", contentClassName);
|
|
78
|
+
|
|
79
|
+
var triggerEls = [];
|
|
80
|
+
var contentPanels = [];
|
|
81
|
+
|
|
82
|
+
var Button = getComponent("Button");
|
|
83
|
+
|
|
84
|
+
tabs.forEach(function (tab, index) {
|
|
85
|
+
var value = tab.value;
|
|
86
|
+
var label = tab.label != null ? tab.label : value;
|
|
87
|
+
var content = tab.content;
|
|
88
|
+
|
|
89
|
+
var isActive = value === activeValue;
|
|
90
|
+
var trigger = Button.create({
|
|
91
|
+
variant: isActive ? "outline" : "ghost",
|
|
92
|
+
size: size === "small" ? "small" : size === "large" ? "large" : "default",
|
|
93
|
+
text: label,
|
|
94
|
+
type: "button",
|
|
95
|
+
className: "mx-2",
|
|
96
|
+
onClick: function () {
|
|
97
|
+
if (activeValue === value) return;
|
|
98
|
+
if (controlledValue === undefined) {
|
|
99
|
+
activeValue = value;
|
|
100
|
+
updateActiveState();
|
|
101
|
+
}
|
|
102
|
+
if (typeof onChange === "function") {
|
|
103
|
+
onChange(value);
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
trigger.setAttribute("role", "tab");
|
|
109
|
+
trigger.setAttribute("aria-selected", value === activeValue ? "true" : "false");
|
|
110
|
+
trigger.setAttribute("data-state", value === activeValue ? "active" : "inactive");
|
|
111
|
+
trigger.setAttribute("data-value", value);
|
|
112
|
+
trigger.tabIndex = value === activeValue ? 0 : -1;
|
|
113
|
+
|
|
114
|
+
trigger.addEventListener("keydown", function (e) {
|
|
115
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
116
|
+
e.preventDefault();
|
|
117
|
+
trigger.click();
|
|
118
|
+
}
|
|
119
|
+
if (e.key === "ArrowRight" || e.key === "ArrowLeft") {
|
|
120
|
+
e.preventDefault();
|
|
121
|
+
var nextIndex = e.key === "ArrowRight" ? index + 1 : index - 1;
|
|
122
|
+
if (nextIndex >= 0 && nextIndex < tabs.length) {
|
|
123
|
+
var nextTrigger = triggerEls[nextIndex];
|
|
124
|
+
if (nextTrigger) {
|
|
125
|
+
nextTrigger.focus();
|
|
126
|
+
nextTrigger.click();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
list.appendChild(trigger);
|
|
133
|
+
triggerEls.push(trigger);
|
|
134
|
+
|
|
135
|
+
var panel = document.createElement("div");
|
|
136
|
+
panel.setAttribute("role", "tabpanel");
|
|
137
|
+
panel.setAttribute("aria-hidden", value !== activeValue ? "true" : "false");
|
|
138
|
+
panel.setAttribute("data-value", value);
|
|
139
|
+
panel.className = join(CONTENT_BASE_CLASS, value !== activeValue ? "hidden" : "");
|
|
140
|
+
if (typeof content === "string") {
|
|
141
|
+
panel.innerHTML = content;
|
|
142
|
+
} else if (content && content.nodeType === 1) {
|
|
143
|
+
panel.appendChild(content);
|
|
144
|
+
}
|
|
145
|
+
contentWrapper.appendChild(panel);
|
|
146
|
+
contentPanels.push(panel);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
function updateActiveState() {
|
|
150
|
+
triggerEls.forEach(function (t, i) {
|
|
151
|
+
var val = tabs[i] && tabs[i].value;
|
|
152
|
+
var isActive = val === activeValue;
|
|
153
|
+
t.setAttribute("aria-selected", isActive ? "true" : "false");
|
|
154
|
+
t.setAttribute("data-state", isActive ? "active" : "inactive");
|
|
155
|
+
t.tabIndex = isActive ? 0 : -1;
|
|
156
|
+
t.className = join(BUTTON_BASE, isActive ? BUTTON_OUTLINE : BUTTON_GHOST, sizeClass, "mx-2");
|
|
157
|
+
});
|
|
158
|
+
contentPanels.forEach(function (p, i) {
|
|
159
|
+
var val = tabs[i] && tabs[i].value;
|
|
160
|
+
var isActive = val === activeValue;
|
|
161
|
+
p.setAttribute("aria-hidden", isActive ? "false" : "true");
|
|
162
|
+
p.classList.toggle("hidden", !isActive);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
root.appendChild(list);
|
|
167
|
+
root.appendChild(contentWrapper);
|
|
168
|
+
|
|
169
|
+
root.getValue = function () {
|
|
170
|
+
return activeValue;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
root.setValue = function (newValue) {
|
|
174
|
+
if (newValue === activeValue) return;
|
|
175
|
+
activeValue = newValue;
|
|
176
|
+
updateActiveState();
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
return root;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
var Tabs = {
|
|
183
|
+
create: create,
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
if (typeof module !== "undefined" && module.exports) {
|
|
187
|
+
module.exports = Tabs;
|
|
188
|
+
} else {
|
|
189
|
+
global.Tabs = Tabs;
|
|
190
|
+
}
|
|
191
|
+
})(typeof window !== "undefined" ? window : this);
|
package/core/flow.js
CHANGED
|
@@ -1374,6 +1374,38 @@
|
|
|
1374
1374
|
});
|
|
1375
1375
|
}
|
|
1376
1376
|
|
|
1377
|
+
/**
|
|
1378
|
+
* Create a Tabs component (list + triggers + content panels)
|
|
1379
|
+
* @param {Object} config - { defaultValue?, value?, onChange?, tabs: [{ value, label, content }], size?, variant?, listClassName?, contentClassName? }
|
|
1380
|
+
* @returns {HTMLElement} Tabs root element
|
|
1381
|
+
*/
|
|
1382
|
+
function createTabs(config) {
|
|
1383
|
+
const Tabs = getComponent("Tabs");
|
|
1384
|
+
if (Tabs && typeof Tabs.create === "function") {
|
|
1385
|
+
return Tabs.create(config);
|
|
1386
|
+
}
|
|
1387
|
+
const fallback = document.createElement("div");
|
|
1388
|
+
fallback.className = "tabs-root";
|
|
1389
|
+
fallback.textContent = "Tabs component not loaded.";
|
|
1390
|
+
return fallback;
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
/**
|
|
1394
|
+
* Create a Steps component (numbered step triggers + optional content panels)
|
|
1395
|
+
* @param {Object} config - { steps: [{ id, label, content? }], defaultValue?, value?, onChange?, size?, variant?, listClassName?, contentClassName?, showContent? }
|
|
1396
|
+
* @returns {HTMLElement} Steps root element
|
|
1397
|
+
*/
|
|
1398
|
+
function createSteps(config) {
|
|
1399
|
+
const Steps = getComponent("Steps");
|
|
1400
|
+
if (Steps && typeof Steps.create === "function") {
|
|
1401
|
+
return Steps.create(config);
|
|
1402
|
+
}
|
|
1403
|
+
const fallback = document.createElement("div");
|
|
1404
|
+
fallback.className = "steps-root";
|
|
1405
|
+
fallback.textContent = "Steps component not loaded.";
|
|
1406
|
+
return fallback;
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1377
1409
|
// ============================================================================
|
|
1378
1410
|
// TABLE COMPONENT
|
|
1379
1411
|
// ============================================================================
|
|
@@ -1736,6 +1768,8 @@
|
|
|
1736
1768
|
|
|
1737
1769
|
// Stepper
|
|
1738
1770
|
renderStepper,
|
|
1771
|
+
createTabs,
|
|
1772
|
+
createSteps,
|
|
1739
1773
|
|
|
1740
1774
|
// Alerts
|
|
1741
1775
|
renderAlerts,
|