tyrell-components 1.0.0-RC14 → 1.0.0-RC15

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.
Files changed (113) hide show
  1. package/README.md +9 -1
  2. package/css/tyrell-theme.css +25 -2
  3. package/css/tyrell.css +4 -0
  4. package/dist/tyrell-colors-static.css +1 -316
  5. package/dist/tyrell-theme.css +1 -1443
  6. package/dist/tyrell.css +1 -1390
  7. package/dist/tyrell.js +1 -1
  8. package/lib/base/ty-component.js +196 -196
  9. package/lib/components/button.d.ts +1 -1
  10. package/lib/components/button.js +261 -259
  11. package/lib/components/calendar-month.d.ts +2 -2
  12. package/lib/components/calendar-month.js +439 -416
  13. package/lib/components/calendar-navigation.js +238 -238
  14. package/lib/components/calendar.d.ts +5 -3
  15. package/lib/components/calendar.js +611 -602
  16. package/lib/components/checkbox.d.ts +1 -1
  17. package/lib/components/checkbox.js +273 -272
  18. package/lib/components/copy.d.ts +1 -1
  19. package/lib/components/copy.js +280 -278
  20. package/lib/components/date-picker.d.ts +8 -1
  21. package/lib/components/date-picker.js +1128 -1108
  22. package/lib/components/file-upload.js +404 -404
  23. package/lib/components/icon.js +141 -141
  24. package/lib/components/input.d.ts +1 -1
  25. package/lib/components/input.js +593 -596
  26. package/lib/components/modal.js +319 -319
  27. package/lib/components/option.js +167 -167
  28. package/lib/components/popup.js +233 -233
  29. package/lib/components/radio.d.ts +2 -2
  30. package/lib/components/radio.js +407 -406
  31. package/lib/components/resize-observer.js +67 -67
  32. package/lib/components/scroll-container.js +292 -294
  33. package/lib/components/select.d.ts +71 -12
  34. package/lib/components/select.js +1605 -1529
  35. package/lib/components/selected-tags.d.ts +1 -1
  36. package/lib/components/selected-tags.js +188 -182
  37. package/lib/components/step.js +62 -62
  38. package/lib/components/switch.d.ts +1 -1
  39. package/lib/components/switch.js +214 -213
  40. package/lib/components/tab.js +62 -62
  41. package/lib/components/tabs.d.ts +1 -0
  42. package/lib/components/tabs.js +523 -492
  43. package/lib/components/tag.d.ts +1 -1
  44. package/lib/components/tag.js +236 -235
  45. package/lib/components/textarea.d.ts +1 -1
  46. package/lib/components/textarea.js +457 -456
  47. package/lib/components/tooltip.js +283 -283
  48. package/lib/components/wizard.js +384 -384
  49. package/lib/icons/heroicons/micro.js +392 -392
  50. package/lib/icons/heroicons/mini.js +382 -382
  51. package/lib/icons/heroicons/outline.js +337 -337
  52. package/lib/icons/heroicons/solid.js +407 -407
  53. package/lib/icons/lucide.js +22843 -22843
  54. package/lib/icons/material/filled.js +9653 -9653
  55. package/lib/icons/material/outlined.js +10271 -10271
  56. package/lib/icons/material/round.js +10495 -10495
  57. package/lib/icons/material/sharp.js +9905 -9905
  58. package/lib/icons/material/two-tone.js +12792 -12792
  59. package/lib/index.js +21 -21
  60. package/lib/styles/button.js +200 -302
  61. package/lib/styles/calendar-month.js +123 -183
  62. package/lib/styles/calendar-navigation.d.ts +1 -1
  63. package/lib/styles/calendar-navigation.js +64 -79
  64. package/lib/styles/calendar.d.ts +1 -1
  65. package/lib/styles/calendar.js +9 -9
  66. package/lib/styles/checkbox.js +45 -72
  67. package/lib/styles/copy.js +67 -91
  68. package/lib/styles/custom-scrollbar.js +80 -100
  69. package/lib/styles/date-picker.js +261 -331
  70. package/lib/styles/field-size.d.ts +6 -0
  71. package/lib/styles/field-size.js +91 -0
  72. package/lib/styles/file-upload.js +139 -169
  73. package/lib/styles/icon.js +92 -156
  74. package/lib/styles/input.js +125 -241
  75. package/lib/styles/modal.js +67 -102
  76. package/lib/styles/option.d.ts +1 -1
  77. package/lib/styles/option.js +47 -67
  78. package/lib/styles/popup.js +34 -65
  79. package/lib/styles/radio.js +69 -96
  80. package/lib/styles/resize-observer.js +2 -5
  81. package/lib/styles/scroll-container.js +100 -130
  82. package/lib/styles/select-base.js +596 -773
  83. package/lib/styles/select.js +140 -228
  84. package/lib/styles/step.js +22 -29
  85. package/lib/styles/switch.js +34 -55
  86. package/lib/styles/tab.d.ts +1 -1
  87. package/lib/styles/tab.js +22 -29
  88. package/lib/styles/tabs.d.ts +1 -1
  89. package/lib/styles/tabs.js +186 -180
  90. package/lib/styles/tag.js +135 -188
  91. package/lib/styles/textarea.d.ts +1 -1
  92. package/lib/styles/textarea.js +205 -271
  93. package/lib/styles/tooltip.js +3 -3
  94. package/lib/styles/wizard.js +170 -226
  95. package/lib/types/common.d.ts +2 -0
  96. package/lib/types/common.js +6 -5
  97. package/lib/utils/calendar-utils.js +100 -100
  98. package/lib/utils/custom-scrollbar.js +272 -272
  99. package/lib/utils/flavor-sheet.js +14 -14
  100. package/lib/utils/icon-registry.js +127 -127
  101. package/lib/utils/loader-registry.js +3 -3
  102. package/lib/utils/locale.js +34 -34
  103. package/lib/utils/mobile.js +1 -1
  104. package/lib/utils/number-format.js +54 -54
  105. package/lib/utils/positioning.js +212 -212
  106. package/lib/utils/property-capture.js +36 -36
  107. package/lib/utils/property-manager.js +125 -125
  108. package/lib/utils/resize-observer.js +23 -23
  109. package/lib/utils/scroll-lock.js +57 -57
  110. package/lib/utils/styles.js +17 -17
  111. package/lib/version.d.ts +1 -1
  112. package/lib/version.js +1 -1
  113. package/package.json +4 -4
@@ -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
- 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
- };
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
- return Array.from(el.querySelectorAll('ty-step'));
15
+ return Array.from(el.querySelectorAll('ty-step'));
16
16
  }
17
17
  function getStepId(step) {
18
- return step.getAttribute('id');
18
+ return step.getAttribute('id');
19
19
  }
20
20
  function getCompletedStepIds(el) {
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));
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
- return wizardEl.querySelector(`[slot='indicator-${stepId}']`) !== null;
27
+ return wizardEl.querySelector(`[slot='indicator-${stepId}']`) !== null;
28
28
  }
29
29
  function isStepDisabled(step) {
30
- return step.hasAttribute('disabled');
30
+ return step.hasAttribute('disabled');
31
31
  }
32
32
  function findStepIndex(steps, stepId) {
33
- const index = steps.findIndex(step => getStepId(step) === stepId);
34
- return index >= 0 ? index : undefined;
33
+ const index = steps.findIndex(step => getStepId(step) === stepId);
34
+ return index >= 0 ? index : undefined;
35
35
  }
36
36
  function getActiveStepId(el, steps) {
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;
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
- el.setAttribute('active', stepId);
47
+ el.setAttribute('active', stepId);
48
48
  }
49
49
  function calculateProgressPercent(steps, activeId, completedIds) {
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;
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
- 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);
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
- 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);
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
- 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();
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
- 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);
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
- 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)`;
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
- 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}%`;
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
- 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
- });
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
- 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
- });
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
- 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);
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
- 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
- }
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
- const observer = resizeObservers.get(el);
245
- if (observer) {
246
- observer.disconnect();
247
- resizeObservers.delete(el);
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
- 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';
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
- 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
- `;
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
- 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
- }
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
- cleanupEventListeners(el);
394
- cleanupResizeObserver(el);
393
+ cleanupEventListeners(el);
394
+ cleanupResizeObserver(el);
395
395
  }
396
396
  export class TyWizard extends HTMLElement {
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
- }
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
- customElements.define('ty-wizard', TyWizard);
441
+ customElements.define('ty-wizard', TyWizard);
442
442
  }