tyrell-components 1.0.0-TC52 → 1.0.0-TC53
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/css/tyrell-theme.css +25 -2
- package/css/tyrell.css +4 -0
- package/dist/tyrell-colors-static.css +1 -316
- package/dist/tyrell-theme.css +1 -1443
- package/dist/tyrell.css +1 -1390
- package/dist/tyrell.js +1 -1
- package/lib/base/ty-component.js +196 -196
- package/lib/components/button.d.ts +1 -1
- package/lib/components/button.js +260 -259
- package/lib/components/calendar-month.d.ts +2 -2
- package/lib/components/calendar-month.js +426 -416
- package/lib/components/calendar-navigation.js +238 -238
- package/lib/components/calendar.js +605 -602
- package/lib/components/checkbox.d.ts +1 -1
- package/lib/components/checkbox.js +273 -272
- package/lib/components/copy.d.ts +1 -1
- package/lib/components/copy.js +279 -278
- package/lib/components/date-picker.d.ts +1 -1
- package/lib/components/date-picker.js +1103 -1108
- package/lib/components/file-upload.js +404 -404
- package/lib/components/icon.js +141 -141
- package/lib/components/input.d.ts +1 -1
- package/lib/components/input.js +593 -596
- package/lib/components/modal.js +319 -319
- package/lib/components/option.js +167 -167
- package/lib/components/popup.js +233 -233
- package/lib/components/radio.d.ts +2 -2
- package/lib/components/radio.js +407 -406
- package/lib/components/resize-observer.js +67 -67
- package/lib/components/scroll-container.js +294 -294
- package/lib/components/select.d.ts +1 -1
- package/lib/components/select.js +1524 -1532
- package/lib/components/selected-tags.js +184 -184
- package/lib/components/step.js +62 -62
- package/lib/components/switch.d.ts +1 -1
- package/lib/components/switch.js +214 -213
- package/lib/components/tab.js +62 -62
- package/lib/components/tabs.js +507 -507
- package/lib/components/tag.d.ts +1 -1
- package/lib/components/tag.js +236 -235
- package/lib/components/textarea.d.ts +1 -1
- package/lib/components/textarea.js +457 -456
- package/lib/components/tooltip.js +283 -283
- package/lib/components/wizard.js +384 -384
- package/lib/icons/heroicons/micro.js +392 -392
- package/lib/icons/heroicons/mini.js +382 -382
- package/lib/icons/heroicons/outline.js +337 -337
- package/lib/icons/heroicons/solid.js +407 -407
- package/lib/icons/lucide.js +22843 -22843
- package/lib/icons/material/filled.js +9653 -9653
- package/lib/icons/material/outlined.js +10271 -10271
- package/lib/icons/material/round.js +10495 -10495
- package/lib/icons/material/sharp.js +9905 -9905
- package/lib/icons/material/two-tone.js +12792 -12792
- package/lib/index.js +21 -21
- package/lib/styles/button.js +176 -288
- package/lib/styles/calendar-month.js +123 -183
- package/lib/styles/calendar-navigation.js +60 -79
- package/lib/styles/calendar.js +8 -9
- package/lib/styles/checkbox.js +45 -72
- package/lib/styles/copy.js +67 -91
- package/lib/styles/custom-scrollbar.js +80 -100
- package/lib/styles/date-picker.js +261 -331
- package/lib/styles/field-size.d.ts +6 -0
- package/lib/styles/field-size.js +91 -0
- package/lib/styles/file-upload.js +139 -169
- package/lib/styles/icon.js +92 -156
- package/lib/styles/input.js +125 -241
- package/lib/styles/modal.js +67 -102
- package/lib/styles/option.d.ts +1 -1
- package/lib/styles/option.js +47 -67
- package/lib/styles/popup.js +34 -65
- package/lib/styles/radio.js +69 -96
- package/lib/styles/resize-observer.js +2 -5
- package/lib/styles/scroll-container.js +100 -130
- package/lib/styles/select-base.js +525 -778
- package/lib/styles/select.js +140 -228
- package/lib/styles/step.js +22 -29
- package/lib/styles/switch.js +34 -55
- package/lib/styles/tab.js +22 -29
- package/lib/styles/tabs.js +171 -252
- package/lib/styles/tag.js +135 -188
- package/lib/styles/textarea.d.ts +1 -1
- package/lib/styles/textarea.js +205 -271
- package/lib/styles/tooltip.js +3 -3
- package/lib/styles/wizard.js +170 -226
- package/lib/types/common.d.ts +2 -0
- package/lib/types/common.js +6 -5
- package/lib/utils/calendar-utils.js +100 -100
- package/lib/utils/custom-scrollbar.js +272 -272
- package/lib/utils/flavor-sheet.js +14 -14
- package/lib/utils/icon-registry.js +127 -127
- package/lib/utils/loader-registry.js +3 -3
- package/lib/utils/locale.js +34 -34
- package/lib/utils/mobile.js +1 -1
- package/lib/utils/number-format.js +54 -54
- package/lib/utils/positioning.js +212 -212
- package/lib/utils/property-capture.js +36 -36
- package/lib/utils/property-manager.js +125 -125
- package/lib/utils/resize-observer.js +23 -23
- package/lib/utils/scroll-lock.js +57 -57
- package/lib/utils/styles.js +17 -17
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +4 -4
package/lib/components/wizard.js
CHANGED
|
@@ -3,440 +3,440 @@ import { wizardStyles } from '../styles/wizard.js';
|
|
|
3
3
|
const eventHandlers = new WeakMap();
|
|
4
4
|
const resizeObservers = new WeakMap();
|
|
5
5
|
function getWizardAttributes(el) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
return {
|
|
7
|
+
width: el.getAttribute('width') || '100%',
|
|
8
|
+
height: el.getAttribute('height') || '700px',
|
|
9
|
+
active: el.getAttribute('active'),
|
|
10
|
+
completed: el.getAttribute('completed') || '',
|
|
11
|
+
orientation: (el.getAttribute('orientation') || 'horizontal'),
|
|
12
|
+
};
|
|
13
13
|
}
|
|
14
14
|
function getChildSteps(el) {
|
|
15
|
-
|
|
15
|
+
return Array.from(el.querySelectorAll('ty-step'));
|
|
16
16
|
}
|
|
17
17
|
function getStepId(step) {
|
|
18
|
-
|
|
18
|
+
return step.getAttribute('id');
|
|
19
19
|
}
|
|
20
20
|
function getCompletedStepIds(el) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
const completedAttr = el.getAttribute('completed') || '';
|
|
22
|
+
if (!completedAttr.trim())
|
|
23
|
+
return new Set();
|
|
24
|
+
return new Set(completedAttr.split(',').map(id => id.trim()).filter(Boolean));
|
|
25
25
|
}
|
|
26
26
|
function hasCustomIndicator(wizardEl, stepId) {
|
|
27
|
-
|
|
27
|
+
return wizardEl.querySelector(`[slot='indicator-${stepId}']`) !== null;
|
|
28
28
|
}
|
|
29
29
|
function isStepDisabled(step) {
|
|
30
|
-
|
|
30
|
+
return step.hasAttribute('disabled');
|
|
31
31
|
}
|
|
32
32
|
function findStepIndex(steps, stepId) {
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
const index = steps.findIndex(step => getStepId(step) === stepId);
|
|
34
|
+
return index >= 0 ? index : undefined;
|
|
35
35
|
}
|
|
36
36
|
function getActiveStepId(el, steps) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
const activeAttr = el.getAttribute('active');
|
|
38
|
+
if (activeAttr && findStepIndex(steps, activeAttr) !== undefined) {
|
|
39
|
+
return activeAttr;
|
|
40
|
+
}
|
|
41
|
+
if (steps.length > 0) {
|
|
42
|
+
return getStepId(steps[0]);
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
45
|
}
|
|
46
46
|
function setActiveStep(el, stepId) {
|
|
47
|
-
|
|
47
|
+
el.setAttribute('active', stepId);
|
|
48
48
|
}
|
|
49
49
|
function calculateProgressPercent(steps, activeId, completedIds) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
if (steps.length <= 1 || !activeId)
|
|
51
|
+
return 0;
|
|
52
|
+
const activeIndex = steps.findIndex(s => getStepId(s) === activeId);
|
|
53
|
+
return (activeIndex / (steps.length - 1)) * 100;
|
|
54
54
|
}
|
|
55
55
|
function dispatchStepChangeEvent(el, activeId, activeIndex, previousId, previousIndex) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
56
|
+
const direction = previousIndex === null ? 'none'
|
|
57
|
+
: activeIndex > previousIndex ? 'forward'
|
|
58
|
+
: activeIndex < previousIndex ? 'backward'
|
|
59
|
+
: 'none';
|
|
60
|
+
const event = new CustomEvent('ty-wizard-step-change', {
|
|
61
|
+
detail: {
|
|
62
|
+
activeId,
|
|
63
|
+
activeIndex,
|
|
64
|
+
previousId,
|
|
65
|
+
previousIndex,
|
|
66
|
+
direction,
|
|
67
|
+
},
|
|
68
|
+
bubbles: true,
|
|
69
|
+
cancelable: false,
|
|
70
|
+
});
|
|
71
|
+
el.dispatchEvent(event);
|
|
72
72
|
}
|
|
73
73
|
function handleStepClick(el, stepId, event) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
74
|
+
event.preventDefault();
|
|
75
|
+
event.stopPropagation();
|
|
76
|
+
const steps = getChildSteps(el);
|
|
77
|
+
const targetIndex = steps.findIndex(s => getStepId(s) === stepId);
|
|
78
|
+
if (targetIndex < 0)
|
|
79
|
+
return;
|
|
80
|
+
const currentActive = getActiveStepId(el, steps);
|
|
81
|
+
const currentIndex = currentActive ? findStepIndex(steps, currentActive) ?? null : null;
|
|
82
|
+
const direction = currentIndex === null ? 'none'
|
|
83
|
+
: targetIndex > currentIndex ? 'forward'
|
|
84
|
+
: targetIndex < currentIndex ? 'backward'
|
|
85
|
+
: 'none';
|
|
86
|
+
const event2 = new CustomEvent('ty-wizard-step-change', {
|
|
87
|
+
detail: {
|
|
88
|
+
activeId: stepId,
|
|
89
|
+
activeIndex: targetIndex,
|
|
90
|
+
previousId: currentActive,
|
|
91
|
+
previousIndex: currentIndex,
|
|
92
|
+
direction,
|
|
93
|
+
},
|
|
94
|
+
bubbles: true,
|
|
95
|
+
cancelable: false,
|
|
96
|
+
});
|
|
97
|
+
el.dispatchEvent(event2);
|
|
98
98
|
}
|
|
99
99
|
function cleanupEventListeners(el) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
100
|
+
const handlers = eventHandlers.get(el);
|
|
101
|
+
if (!handlers)
|
|
102
|
+
return;
|
|
103
|
+
const shadowRoot = el.shadowRoot;
|
|
104
|
+
if (!shadowRoot)
|
|
105
|
+
return;
|
|
106
|
+
handlers.stepClickHandlers.forEach((handler, stepId) => {
|
|
107
|
+
const button = shadowRoot.querySelector(`[data-step-id='${stepId}']`);
|
|
108
|
+
if (button) {
|
|
109
|
+
button.removeEventListener('pointerdown', handler);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
handlers.stepClickHandlers.clear();
|
|
113
113
|
}
|
|
114
114
|
function setupEventListeners(el, shadowRoot, steps) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
115
|
+
cleanupEventListeners(el);
|
|
116
|
+
const handlers = {
|
|
117
|
+
stepClickHandlers: new Map(),
|
|
118
|
+
};
|
|
119
|
+
steps.forEach((step) => {
|
|
120
|
+
const stepId = getStepId(step);
|
|
121
|
+
if (!stepId)
|
|
122
|
+
return;
|
|
123
|
+
const button = shadowRoot.querySelector(`[data-step-id='${stepId}']`);
|
|
124
|
+
if (button) {
|
|
125
|
+
const handler = (e) => handleStepClick(el, stepId, e);
|
|
126
|
+
button.addEventListener('pointerdown', handler);
|
|
127
|
+
handlers.stepClickHandlers.set(stepId, handler);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
eventHandlers.set(el, handlers);
|
|
131
131
|
}
|
|
132
132
|
function updateTransform(el, activeIndex) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
133
|
+
const shadowRoot = el.shadowRoot;
|
|
134
|
+
if (!shadowRoot)
|
|
135
|
+
return;
|
|
136
|
+
const panelsWrapper = shadowRoot.querySelector('.panels-wrapper');
|
|
137
|
+
if (!panelsWrapper)
|
|
138
|
+
return;
|
|
139
|
+
const containerWidth = el.offsetWidth;
|
|
140
|
+
const offsetPx = activeIndex * containerWidth;
|
|
141
|
+
panelsWrapper.style.transform = `translateX(-${offsetPx}px)`;
|
|
142
142
|
}
|
|
143
143
|
function updateProgressLine(el) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
144
|
+
const shadowRoot = el.shadowRoot;
|
|
145
|
+
if (!shadowRoot)
|
|
146
|
+
return;
|
|
147
|
+
const progressOverlay = shadowRoot.querySelector('.progress-overlay');
|
|
148
|
+
if (!progressOverlay)
|
|
149
|
+
return;
|
|
150
|
+
const steps = getChildSteps(el);
|
|
151
|
+
const activeId = getActiveStepId(el, steps);
|
|
152
|
+
const completedIds = getCompletedStepIds(el);
|
|
153
|
+
const progressPercent = calculateProgressPercent(steps, activeId, completedIds);
|
|
154
|
+
progressOverlay.style.width = `${progressPercent}%`;
|
|
155
155
|
}
|
|
156
156
|
function updateStepIndicators(el, shadowRoot, activeId) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
157
|
+
const steps = getChildSteps(el);
|
|
158
|
+
const completedIds = getCompletedStepIds(el);
|
|
159
|
+
const activeIndex = activeId ? steps.findIndex(s => getStepId(s) === activeId) : 0;
|
|
160
|
+
steps.forEach((step, index) => {
|
|
161
|
+
const stepId = getStepId(step);
|
|
162
|
+
if (!stepId)
|
|
163
|
+
return;
|
|
164
|
+
const button = shadowRoot.querySelector(`[data-step-id='${stepId}']`);
|
|
165
|
+
const circle = shadowRoot.querySelector(`[data-step-id='${stepId}'] .step-circle`);
|
|
166
|
+
const isActive = stepId === activeId;
|
|
167
|
+
if (button) {
|
|
168
|
+
button.setAttribute('aria-selected', String(isActive));
|
|
169
|
+
button.setAttribute('tabindex', isActive ? '0' : '-1');
|
|
170
|
+
button.setAttribute('data-active', String(isActive));
|
|
171
|
+
}
|
|
172
|
+
if (circle) {
|
|
173
|
+
const state = getStepStatus(step, stepId, activeId, completedIds);
|
|
174
|
+
circle.setAttribute('data-state', state);
|
|
175
|
+
}
|
|
176
|
+
const slottedIndicator = el.querySelector(`[slot='indicator-${stepId}']`);
|
|
177
|
+
if (slottedIndicator) {
|
|
178
|
+
slottedIndicator.setAttribute('data-active', String(isActive));
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
181
|
}
|
|
182
182
|
function updatePanelInteraction(el, activeId) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
183
|
+
const steps = getChildSteps(el);
|
|
184
|
+
steps.forEach((step) => {
|
|
185
|
+
const stepId = getStepId(step);
|
|
186
|
+
if (!stepId)
|
|
187
|
+
return;
|
|
188
|
+
const isActive = stepId === activeId;
|
|
189
|
+
step.setAttribute('data-active', String(isActive));
|
|
190
|
+
if (isActive) {
|
|
191
|
+
step.style.pointerEvents = 'auto';
|
|
192
|
+
step.style.opacity = '1';
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
step.style.pointerEvents = 'none';
|
|
196
|
+
step.style.opacity = '0';
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
199
|
}
|
|
200
200
|
function updateActiveStepState(el, stepId) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
201
|
+
const steps = getChildSteps(el);
|
|
202
|
+
const shadowRoot = el.shadowRoot;
|
|
203
|
+
if (!shadowRoot)
|
|
204
|
+
return;
|
|
205
|
+
const currentActive = getActiveStepId(el, steps);
|
|
206
|
+
const currentIndex = currentActive ? findStepIndex(steps, currentActive) : undefined;
|
|
207
|
+
const newIndex = findStepIndex(steps, stepId);
|
|
208
|
+
if (currentActive === stepId || newIndex === undefined)
|
|
209
|
+
return;
|
|
210
|
+
el.style.setProperty('--ty-wizard-active-index', String(newIndex));
|
|
211
|
+
updateTransform(el, newIndex);
|
|
212
|
+
updateStepIndicators(el, shadowRoot, stepId);
|
|
213
|
+
updateProgressLine(el);
|
|
214
|
+
updatePanelInteraction(el, stepId);
|
|
215
|
+
const newPanel = steps[newIndex];
|
|
216
|
+
if (newPanel?.resetScroll) {
|
|
217
|
+
newPanel.resetScroll();
|
|
218
|
+
}
|
|
219
|
+
dispatchStepChangeEvent(el, stepId, newIndex, currentActive, currentIndex ?? null);
|
|
220
220
|
}
|
|
221
221
|
function setupResizeObserver(el) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
222
|
+
const oldObserver = resizeObservers.get(el);
|
|
223
|
+
if (oldObserver) {
|
|
224
|
+
oldObserver.disconnect();
|
|
225
|
+
}
|
|
226
|
+
const { width } = getWizardAttributes(el);
|
|
227
|
+
if (width.includes('%')) {
|
|
228
|
+
const observer = new ResizeObserver((entries) => {
|
|
229
|
+
const entry = entries[0];
|
|
230
|
+
const measuredWidth = entry.contentRect.width;
|
|
231
|
+
const steps = getChildSteps(el);
|
|
232
|
+
const activeId = getActiveStepId(el, steps);
|
|
233
|
+
const activeIndex = activeId ? findStepIndex(steps, activeId) : 0;
|
|
234
|
+
el.style.setProperty('--ty-wizard-width', `${measuredWidth}px`);
|
|
235
|
+
if (activeIndex !== undefined) {
|
|
236
|
+
updateTransform(el, activeIndex);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
observer.observe(el);
|
|
240
|
+
resizeObservers.set(el, observer);
|
|
241
|
+
}
|
|
242
242
|
}
|
|
243
243
|
function cleanupResizeObserver(el) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
244
|
+
const observer = resizeObservers.get(el);
|
|
245
|
+
if (observer) {
|
|
246
|
+
observer.disconnect();
|
|
247
|
+
resizeObservers.delete(el);
|
|
248
|
+
}
|
|
249
249
|
}
|
|
250
250
|
function getStepStatus(step, stepId, activeId, completedIds) {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
251
|
+
const explicitStatus = step.getAttribute('status');
|
|
252
|
+
if (explicitStatus && ['completed', 'active', 'pending', 'error'].includes(explicitStatus)) {
|
|
253
|
+
return explicitStatus;
|
|
254
|
+
}
|
|
255
|
+
const isActive = stepId === activeId;
|
|
256
|
+
const isCompleted = completedIds.has(stepId);
|
|
257
|
+
return isCompleted ? 'completed' : isActive ? 'active' : 'pending';
|
|
258
258
|
}
|
|
259
259
|
function renderStepIndicators(wizardEl, steps, activeId, completedIds) {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
260
|
+
const activeIndex = activeId ? steps.findIndex(s => getStepId(s) === activeId) : 0;
|
|
261
|
+
const indicators = steps.map((step, index) => {
|
|
262
|
+
const stepId = getStepId(step);
|
|
263
|
+
if (!stepId)
|
|
264
|
+
return '';
|
|
265
|
+
const label = step.getAttribute('label') || `Step ${index + 1}`;
|
|
266
|
+
const description = step.getAttribute('description') || '';
|
|
267
|
+
const disabled = isStepDisabled(step);
|
|
268
|
+
const isActive = stepId === activeId;
|
|
269
|
+
const hasCustom = hasCustomIndicator(wizardEl, stepId);
|
|
270
|
+
const state = getStepStatus(step, stepId, activeId, completedIds);
|
|
271
|
+
let circleContent = '';
|
|
272
|
+
if (hasCustom) {
|
|
273
|
+
circleContent = `<slot name="indicator-${stepId}"></slot>`;
|
|
274
|
+
}
|
|
275
|
+
else if (state === 'completed') {
|
|
276
|
+
circleContent = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>`;
|
|
277
|
+
}
|
|
278
|
+
else if (state === 'error') {
|
|
279
|
+
circleContent = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>`;
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
circleContent = `<span style="font-size: 12px; font-weight: 700;">${index + 1}</span>`;
|
|
283
|
+
}
|
|
284
|
+
return `<button
|
|
285
|
+
class="step-indicator"
|
|
286
|
+
role="tab"
|
|
287
|
+
data-step-id="${stepId}"
|
|
288
|
+
id="step-${stepId}"
|
|
289
|
+
aria-selected="${isActive}"
|
|
290
|
+
tabindex="${isActive ? '0' : '-1'}"
|
|
291
|
+
data-active="${isActive}"
|
|
292
|
+
${disabled ? 'disabled aria-disabled="true"' : ''}
|
|
293
|
+
>
|
|
294
|
+
<div class="step-circle" data-state="${state}" part="step-circle">
|
|
295
|
+
${circleContent}
|
|
296
|
+
</div>
|
|
297
|
+
<div class="step-text">
|
|
298
|
+
<span class="step-label">${label}</span>
|
|
299
|
+
${description ? `<span class="step-description">${description}</span>` : ''}
|
|
300
|
+
</div>
|
|
301
|
+
</button>`;
|
|
302
|
+
}).join('');
|
|
303
|
+
const progressPercent = calculateProgressPercent(steps, activeId, completedIds);
|
|
304
|
+
const stepCount = steps.length;
|
|
305
|
+
return `
|
|
306
|
+
<div class="step-indicators-wrapper" part="indicators-wrapper">
|
|
307
|
+
<div class="step-indicators" style="--ty-wizard-step-count: ${stepCount}">
|
|
308
|
+
<div class="progress-line" part="progress-line" role="progressbar" aria-label="Wizard progress" aria-valuenow="${Math.round(progressPercent)}" aria-valuemin="0" aria-valuemax="100">
|
|
309
|
+
<div class="progress-overlay" style="width: ${progressPercent}%"></div>
|
|
310
|
+
</div>
|
|
311
|
+
<div class="step-tablist" role="tablist" style="display: contents;">
|
|
312
|
+
${indicators}
|
|
313
|
+
</div>
|
|
314
|
+
</div>
|
|
315
|
+
</div>
|
|
316
|
+
`;
|
|
317
317
|
}
|
|
318
318
|
function render(el) {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
319
|
+
const shadowRoot = el.shadowRoot;
|
|
320
|
+
if (!shadowRoot)
|
|
321
|
+
return;
|
|
322
|
+
const { width, height } = getWizardAttributes(el);
|
|
323
|
+
const steps = getChildSteps(el);
|
|
324
|
+
const activeId = getActiveStepId(el, steps);
|
|
325
|
+
const activeIndex = activeId ? (findStepIndex(steps, activeId) ?? 0) : 0;
|
|
326
|
+
const completedIds = getCompletedStepIds(el);
|
|
327
|
+
steps.forEach((step) => {
|
|
328
|
+
const stepId = getStepId(step);
|
|
329
|
+
if (!stepId)
|
|
330
|
+
return;
|
|
331
|
+
step.setAttribute('role', 'tabpanel');
|
|
332
|
+
step.setAttribute('aria-labelledby', `step-${stepId}`);
|
|
333
|
+
step.setAttribute('tabindex', '0');
|
|
334
|
+
});
|
|
335
|
+
const existingContainer = shadowRoot.querySelector('.wizard-container');
|
|
336
|
+
const existingIndicators = shadowRoot.querySelector('.step-indicators-wrapper');
|
|
337
|
+
const existingViewport = shadowRoot.querySelector('.panels-viewport');
|
|
338
|
+
ensureStyles(shadowRoot, { css: wizardStyles, id: 'ty-wizard' });
|
|
339
|
+
el.style.setProperty('--ty-wizard-width', width.includes('%') ? '100%' : width);
|
|
340
|
+
el.style.setProperty('--ty-wizard-height', height);
|
|
341
|
+
el.style.setProperty('--ty-wizard-active-index', String(activeIndex));
|
|
342
|
+
el.style.setProperty('--ty-wizard-step-count', String(steps.length));
|
|
343
|
+
if (existingContainer && existingIndicators && existingViewport) {
|
|
344
|
+
existingIndicators.remove();
|
|
345
|
+
const newIndicatorsHtml = renderStepIndicators(el, steps, activeId, completedIds);
|
|
346
|
+
const tempDiv = document.createElement('div');
|
|
347
|
+
tempDiv.innerHTML = newIndicatorsHtml;
|
|
348
|
+
existingContainer.insertBefore(tempDiv.firstElementChild, existingViewport);
|
|
349
|
+
setupEventListeners(el, shadowRoot, steps);
|
|
350
|
+
updateStepIndicators(el, shadowRoot, activeId || '');
|
|
351
|
+
requestAnimationFrame(() => {
|
|
352
|
+
const indicators = shadowRoot.querySelector('.step-indicators-wrapper');
|
|
353
|
+
if (indicators) {
|
|
354
|
+
const indicatorsHeight = indicators.offsetHeight;
|
|
355
|
+
el.style.setProperty('--ty-wizard-indicators-height', `${indicatorsHeight}px`);
|
|
356
|
+
}
|
|
357
|
+
updateTransform(el, activeIndex);
|
|
358
|
+
updateProgressLine(el);
|
|
359
|
+
});
|
|
360
|
+
if (activeId) {
|
|
361
|
+
updatePanelInteraction(el, activeId);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
shadowRoot.innerHTML = `
|
|
366
|
+
<div class="wizard-container">
|
|
367
|
+
${renderStepIndicators(el, steps, activeId, completedIds)}
|
|
368
|
+
<div class="panels-viewport" part="panels-container">
|
|
369
|
+
<div class="panels-wrapper">
|
|
370
|
+
<slot></slot>
|
|
371
|
+
</div>
|
|
372
|
+
</div>
|
|
373
|
+
</div>
|
|
374
|
+
`;
|
|
375
|
+
requestAnimationFrame(() => {
|
|
376
|
+
const indicators = shadowRoot.querySelector('.step-indicators-wrapper');
|
|
377
|
+
if (indicators) {
|
|
378
|
+
const indicatorsHeight = indicators.offsetHeight;
|
|
379
|
+
el.style.setProperty('--ty-wizard-indicators-height', `${indicatorsHeight}px`);
|
|
380
|
+
}
|
|
381
|
+
updateTransform(el, activeIndex);
|
|
382
|
+
updateProgressLine(el);
|
|
383
|
+
});
|
|
384
|
+
setupEventListeners(el, shadowRoot, steps);
|
|
385
|
+
updateStepIndicators(el, shadowRoot, activeId || '');
|
|
386
|
+
setupResizeObserver(el);
|
|
387
|
+
if (activeId) {
|
|
388
|
+
updatePanelInteraction(el, activeId);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
391
|
}
|
|
392
392
|
function cleanup(el) {
|
|
393
|
-
|
|
394
|
-
|
|
393
|
+
cleanupEventListeners(el);
|
|
394
|
+
cleanupResizeObserver(el);
|
|
395
395
|
}
|
|
396
396
|
export class TyWizard extends HTMLElement {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
397
|
+
static get observedAttributes() {
|
|
398
|
+
return ['width', 'height', 'active', 'completed', 'orientation'];
|
|
399
|
+
}
|
|
400
|
+
constructor() {
|
|
401
|
+
super();
|
|
402
|
+
this._childObserver = null;
|
|
403
|
+
this._childRenderQueued = false;
|
|
404
|
+
this.attachShadow({ mode: 'open' });
|
|
405
|
+
}
|
|
406
|
+
connectedCallback() {
|
|
407
|
+
render(this);
|
|
408
|
+
this._childObserver = new MutationObserver(() => {
|
|
409
|
+
if (this._childRenderQueued)
|
|
410
|
+
return;
|
|
411
|
+
this._childRenderQueued = true;
|
|
412
|
+
queueMicrotask(() => {
|
|
413
|
+
this._childRenderQueued = false;
|
|
414
|
+
if (this.isConnected)
|
|
415
|
+
render(this);
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
this._childObserver.observe(this, { childList: true });
|
|
419
|
+
}
|
|
420
|
+
disconnectedCallback() {
|
|
421
|
+
this._childObserver?.disconnect();
|
|
422
|
+
this._childObserver = null;
|
|
423
|
+
cleanup(this);
|
|
424
|
+
}
|
|
425
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
426
|
+
if (name === 'active') {
|
|
427
|
+
if (newValue) {
|
|
428
|
+
updateActiveStepState(this, newValue);
|
|
429
|
+
}
|
|
430
|
+
render(this);
|
|
431
|
+
}
|
|
432
|
+
else if (name === 'completed') {
|
|
433
|
+
render(this);
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
render(this);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
439
|
}
|
|
440
440
|
if (!customElements.get('ty-wizard')) {
|
|
441
|
-
|
|
441
|
+
customElements.define('ty-wizard', TyWizard);
|
|
442
442
|
}
|