@haiyue/ui 0.1.2 → 0.2.2

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 (110) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/LICENSE +27 -0
  3. package/README.md +643 -2
  4. package/dist/adapters/web/controls.d.ts +19 -0
  5. package/dist/adapters/web/controls.js +307 -0
  6. package/dist/adapters/web/dom.d.ts +10 -0
  7. package/dist/adapters/web/dom.js +98 -0
  8. package/dist/adapters/web/index.d.ts +3 -0
  9. package/dist/adapters/web/index.js +3 -0
  10. package/dist/adapters/web/renderer.d.ts +18 -0
  11. package/dist/adapters/web/renderer.js +553 -0
  12. package/dist/adapters/web/styles.d.ts +3 -0
  13. package/dist/adapters/web/styles.js +83 -0
  14. package/dist/adapters/web/types.d.ts +46 -0
  15. package/dist/adapters/web/types.js +2 -0
  16. package/dist/affix.d.ts +35 -0
  17. package/dist/affix.js +137 -0
  18. package/dist/badge.d.ts +45 -0
  19. package/dist/badge.js +168 -0
  20. package/dist/breadcrumb.d.ts +37 -0
  21. package/dist/breadcrumb.js +210 -0
  22. package/dist/button-group.d.ts +12 -0
  23. package/dist/button-group.js +72 -0
  24. package/dist/button.d.ts +15 -1
  25. package/dist/button.js +101 -12
  26. package/dist/carousel.d.ts +92 -0
  27. package/dist/carousel.js +509 -0
  28. package/dist/cascader.d.ts +65 -0
  29. package/dist/cascader.js +479 -0
  30. package/dist/collapse.d.ts +68 -0
  31. package/dist/collapse.js +348 -0
  32. package/dist/core/actions.d.ts +32 -0
  33. package/dist/core/actions.js +145 -0
  34. package/dist/core/data.d.ts +4 -0
  35. package/dist/core/data.js +27 -0
  36. package/dist/core/index.d.ts +7 -0
  37. package/dist/core/index.js +6 -0
  38. package/dist/core/platform-view.d.ts +17 -0
  39. package/dist/core/platform-view.js +84 -0
  40. package/dist/core/selection.d.ts +14 -0
  41. package/dist/core/selection.js +93 -0
  42. package/dist/core/text.d.ts +31 -0
  43. package/dist/core/text.js +154 -0
  44. package/dist/core/types.d.ts +269 -0
  45. package/dist/core/types.js +2 -0
  46. package/dist/core/validation.d.ts +24 -0
  47. package/dist/core/validation.js +243 -0
  48. package/dist/date-picker.d.ts +60 -0
  49. package/dist/date-picker.js +355 -0
  50. package/dist/dialog.d.ts +4 -0
  51. package/dist/dialog.js +23 -5
  52. package/dist/divider.d.ts +33 -0
  53. package/dist/divider.js +113 -0
  54. package/dist/draggable.d.ts +78 -0
  55. package/dist/draggable.js +255 -0
  56. package/dist/index.d.ts +53 -1
  57. package/dist/index.js +78 -0
  58. package/dist/input.d.ts +30 -1
  59. package/dist/input.js +166 -54
  60. package/dist/internal/qrcodegen.d.ts +94 -0
  61. package/dist/internal/qrcodegen.js +856 -0
  62. package/dist/masonry.d.ts +36 -0
  63. package/dist/masonry.js +171 -0
  64. package/dist/modal.d.ts +73 -0
  65. package/dist/modal.js +361 -0
  66. package/dist/portable/icons.d.ts +5 -0
  67. package/dist/portable/icons.js +24 -0
  68. package/dist/portable/index.d.ts +7 -0
  69. package/dist/portable/index.js +5 -0
  70. package/dist/portable/page.d.ts +38 -0
  71. package/dist/portable/page.js +361 -0
  72. package/dist/portable/responsive.d.ts +20 -0
  73. package/dist/portable/responsive.js +15 -0
  74. package/dist/portable/theme.d.ts +24 -0
  75. package/dist/portable/theme.js +60 -0
  76. package/dist/portable/tree.d.ts +10 -0
  77. package/dist/portable/tree.js +96 -0
  78. package/dist/qr-code.d.ts +62 -0
  79. package/dist/qr-code.js +224 -0
  80. package/dist/range.d.ts +3 -0
  81. package/dist/range.js +16 -5
  82. package/dist/rate.d.ts +46 -0
  83. package/dist/rate.js +193 -0
  84. package/dist/resizable.d.ts +97 -0
  85. package/dist/resizable.js +426 -0
  86. package/dist/skeleton.d.ts +41 -0
  87. package/dist/skeleton.js +141 -0
  88. package/dist/steps.d.ts +45 -0
  89. package/dist/steps.js +203 -0
  90. package/dist/table.d.ts +106 -0
  91. package/dist/table.js +689 -0
  92. package/dist/tabs.d.ts +3 -0
  93. package/dist/tabs.js +11 -1
  94. package/dist/tag.d.ts +55 -0
  95. package/dist/tag.js +225 -0
  96. package/dist/time-picker.d.ts +62 -0
  97. package/dist/time-picker.js +298 -0
  98. package/dist/timeline.d.ts +48 -0
  99. package/dist/timeline.js +201 -0
  100. package/dist/toast.d.ts +55 -0
  101. package/dist/toast.js +224 -0
  102. package/dist/tour.d.ts +89 -0
  103. package/dist/tour.js +306 -0
  104. package/dist/virtual-keyboard.d.ts +95 -0
  105. package/dist/virtual-keyboard.js +432 -0
  106. package/dist/virtual-mouse.d.ts +82 -0
  107. package/dist/virtual-mouse.js +358 -0
  108. package/dist/watermark.d.ts +44 -0
  109. package/dist/watermark.js +148 -0
  110. package/package.json +132 -4
@@ -0,0 +1,509 @@
1
+ const properties = ['--_hy-carousel-transform', '--_hy-carousel-visibility'];
2
+ const attributes = ['role', 'aria-roledescription', 'aria-label', 'aria-hidden', 'inert'];
3
+ function numeric(value, fallback, min, max) {
4
+ if (value === null || value === '')
5
+ return fallback;
6
+ const number = Number(value);
7
+ return Number.isFinite(number) ? Math.min(max, Math.max(min, number)) : fallback;
8
+ }
9
+ /** A slotted, accessible carousel. Panels stay mounted and inactive panels are inert. */
10
+ export class HYCarousel extends HTMLElement {
11
+ _viewport = document.createElement('div');
12
+ _slot = document.createElement('slot');
13
+ _indicators = document.createElement('div');
14
+ _previous = document.createElement('button');
15
+ _next = document.createElement('button');
16
+ _playback = document.createElement('button');
17
+ _motion = window.matchMedia('(prefers-reduced-motion: reduce)');
18
+ _saved = new Map();
19
+ _animations = new Set();
20
+ _hostAttributes = new Map();
21
+ _slides = [];
22
+ _index = 0;
23
+ _reflecting = false;
24
+ _connected = false;
25
+ _timer = 0;
26
+ _paused = false;
27
+ _hovered = false;
28
+ _motionOverride = false;
29
+ _drag = null;
30
+ _blockClickUntil = 0;
31
+ _playbackPointerAction = null;
32
+ _indicatorRenderer = null;
33
+ static get observedAttributes() {
34
+ return ['index', 'direction', 'indicator-position', 'indicator-style', 'show-indicators', 'show-arrows', 'autoplay', 'interval', 'draggable', 'loop'];
35
+ }
36
+ constructor() {
37
+ super();
38
+ const root = this.attachShadow({ mode: 'open' });
39
+ const style = document.createElement('style');
40
+ style.textContent = `
41
+ :host { display: block; position: relative; box-sizing: border-box; width: 100%; height: var(--hy-carousel-height, 240px); min-width: 0; min-height: 0; color: var(--hy-text-color, #eef0ff); font: inherit; }
42
+ :host([hidden]), [hidden] { display: none !important; }
43
+ .viewport { position: relative; width: 100%; height: 100%; overflow: hidden; border-radius: var(--hy-carousel-radius, 10px); background: var(--hy-carousel-bg-color, var(--hy-surface-color, #10132f)); touch-action: pan-y; }
44
+ :host([direction="vertical"]) .viewport { touch-action: pan-x; }
45
+ :host([draggable="false"]) .viewport { touch-action: auto; }
46
+ slot { display: contents; }
47
+ ::slotted(*) { position: absolute; box-sizing: border-box; inset: 0; width: 100%; height: 100%; margin: 0; overflow: auto; touch-action: pan-y; transform: var(--_hy-carousel-transform, translate3d(0,0,0)); visibility: var(--_hy-carousel-visibility, hidden); }
48
+ :host([direction="vertical"]) ::slotted(*) { touch-action: pan-x; }
49
+ :host([draggable="false"]) ::slotted(*) { touch-action: auto; }
50
+ button { box-sizing: border-box; color: inherit; font: inherit; cursor: pointer; border: 0; }
51
+ button:disabled { opacity: .35; cursor: default; }
52
+ button:focus-visible, .viewport:focus-visible { outline: 2px solid var(--hy-focus-border-color, #9c8fff); outline-offset: -3px; }
53
+ .arrow, .playback { position: absolute; z-index: 2; display: grid; place-items: center; width: 32px; height: 32px; border-radius: var(--hy-carousel-control-radius, 50%); background: var(--hy-carousel-control-bg-color, var(--hy-surface-elevated-color, #181a40)); color: var(--hy-carousel-control-color, var(--hy-text-color, #eef0ff)); }
54
+ .arrow:hover, .playback:hover { background: var(--hy-hover-bg-color, #242752); }
55
+ .previous { left: 12px; top: calc(50% - 16px); }
56
+ .next { right: 12px; top: calc(50% - 16px); }
57
+ :host(:dir(rtl)) .previous { left: auto; right: 12px; }
58
+ :host(:dir(rtl)) .next { right: auto; left: 12px; }
59
+ :host([direction="vertical"]) .previous { left: calc(50% - 16px); right: auto; top: 12px; }
60
+ :host([direction="vertical"]) .next { left: calc(50% - 16px); right: auto; top: auto; bottom: 12px; }
61
+ :host(:not([direction="vertical"])[indicator-position="left"]) .arrow,
62
+ :host(:not([direction="vertical"])[indicator-position="right"]) .arrow { top: auto; bottom: 12px; }
63
+ :host([direction="vertical"]:not([indicator-position="left"]):not([indicator-position="right"])) .arrow { left: auto; right: auto; inset-inline-start: 12px; }
64
+ .playback { top: 12px; inset-inline-end: 12px; font-size: 12px; }
65
+ .indicators { position: absolute; z-index: 2; display: flex; align-items: center; max-width: calc(100% - 88px); overflow: auto; gap: var(--hy-carousel-indicator-gap, 4px); bottom: var(--hy-carousel-indicator-offset, 12px); left: 50%; transform: translateX(-50%); }
66
+ :host([indicator-position="top"]) .indicators { top: var(--hy-carousel-indicator-offset, 12px); bottom: auto; }
67
+ :host([indicator-position="left"]) .indicators, :host([indicator-position="right"]) .indicators { flex-direction: column; max-height: calc(100% - 88px); top: 50%; bottom: auto; transform: translateY(-50%); }
68
+ :host([indicator-position="left"]) .indicators { left: var(--hy-carousel-indicator-offset, 12px); }
69
+ :host([indicator-position="right"]) .indicators { left: auto; right: var(--hy-carousel-indicator-offset, 12px); }
70
+ .indicator { display: grid; flex: 0 0 auto; place-items: center; min-width: 24px; min-height: 24px; padding: 4px; background: transparent; border-radius: 4px; }
71
+ .indicator-content { display: grid; place-items: center; width: var(--hy-carousel-indicator-size, 8px); height: var(--hy-carousel-indicator-size, 8px); border-radius: var(--hy-carousel-indicator-radius, 50%); background: var(--hy-carousel-indicator-color, var(--hy-muted-color, #747ba8)); }
72
+ .indicator[aria-current="true"] .indicator-content { background: var(--hy-carousel-indicator-active-color, var(--hy-accent-color, #8177f2)); }
73
+ :host([indicator-style="line"]) .indicator-content { width: var(--hy-carousel-indicator-width, 24px); height: var(--hy-carousel-indicator-thickness, 3px); border-radius: var(--hy-carousel-indicator-radius, 2px); }
74
+ :host([indicator-style="number"]) .indicator-content { width: 24px; height: 24px; font-size: 12px; color: var(--hy-carousel-indicator-text-color, var(--hy-text-color, #eef0ff)); }
75
+ .indicators.custom .indicator-content { width: auto; height: auto; background: transparent; }
76
+ `;
77
+ this._viewport.className = 'viewport';
78
+ this._viewport.part.add('viewport');
79
+ this._viewport.tabIndex = 0;
80
+ this._viewport.append(this._slot);
81
+ this._indicators.className = 'indicators';
82
+ this._indicators.part.add('indicators');
83
+ this._indicators.setAttribute('role', 'group');
84
+ this._indicators.setAttribute('aria-label', 'Choose slide');
85
+ for (const [button, name] of [[this._previous, 'previous'], [this._next, 'next'], [this._playback, 'playback']]) {
86
+ button.type = 'button';
87
+ button.className = name === 'playback' ? name : `arrow ${name}`;
88
+ button.part.add(name);
89
+ }
90
+ this._previous.setAttribute('aria-label', 'Previous slide');
91
+ this._next.setAttribute('aria-label', 'Next slide');
92
+ this._previous.addEventListener('click', () => this._select(this._index - 1, 'arrow'));
93
+ this._next.addEventListener('click', () => this._select(this._index + 1, 'arrow'));
94
+ // Pointer focus pauses rotation before click fires. Preserve the action
95
+ // the user saw on pointerdown so the first click still pauses playback.
96
+ this._playback.addEventListener('pointerdown', () => { this._playbackPointerAction = !this._paused && !(this._motion.matches && !this._motionOverride); });
97
+ this._playback.addEventListener('click', event => {
98
+ const pause = event.detail > 0 && this._playbackPointerAction !== null ? this._playbackPointerAction : !this._paused && !(this._motion.matches && !this._motionOverride);
99
+ this._playbackPointerAction = null;
100
+ if (pause)
101
+ this.pause();
102
+ else
103
+ this.play();
104
+ });
105
+ this._indicators.addEventListener('click', event => {
106
+ const button = event.target.closest('button[data-index]');
107
+ if (button)
108
+ this._select(Number(button.dataset.index), 'indicator');
109
+ });
110
+ root.append(style, this._viewport, this._previous, this._next, this._indicators, this._playback);
111
+ }
112
+ connectedCallback() {
113
+ if (this._connected)
114
+ return;
115
+ this._connected = true;
116
+ for (const [name, value] of [['role', 'region'], ['aria-roledescription', 'carousel'], ['aria-label', 'Carousel']]) {
117
+ this._hostAttributes.set(name, this.getAttribute(name));
118
+ if (!this.hasAttribute(name))
119
+ this.setAttribute(name, value);
120
+ }
121
+ this._slot.addEventListener('slotchange', this._syncSlides);
122
+ this.addEventListener('keydown', this._onKeyDown);
123
+ this.addEventListener('pointerenter', this._onEnter);
124
+ this.addEventListener('pointerleave', this._onLeave);
125
+ this.addEventListener('focusin', this._onFocus);
126
+ this._viewport.addEventListener('pointerdown', this._onPointerDown);
127
+ this._viewport.addEventListener('lostpointercapture', this._onPointerCancel);
128
+ this._viewport.addEventListener('dragstart', this._onNativeDrag);
129
+ this._viewport.addEventListener('click', this._onClick, true);
130
+ document.addEventListener('visibilitychange', this._schedule);
131
+ this._motion.addEventListener('change', this._onMotionChange);
132
+ this._syncSlides();
133
+ }
134
+ disconnectedCallback() {
135
+ this._connected = false;
136
+ this._clearTimer();
137
+ this._cancelDrag();
138
+ this._cancelAnimations();
139
+ this._hovered = false;
140
+ this._playbackPointerAction = null;
141
+ this._slot.removeEventListener('slotchange', this._syncSlides);
142
+ this.removeEventListener('keydown', this._onKeyDown);
143
+ this.removeEventListener('pointerenter', this._onEnter);
144
+ this.removeEventListener('pointerleave', this._onLeave);
145
+ this.removeEventListener('focusin', this._onFocus);
146
+ this._viewport.removeEventListener('pointerdown', this._onPointerDown);
147
+ this._viewport.removeEventListener('lostpointercapture', this._onPointerCancel);
148
+ this._viewport.removeEventListener('dragstart', this._onNativeDrag);
149
+ this._viewport.removeEventListener('click', this._onClick, true);
150
+ document.removeEventListener('visibilitychange', this._schedule);
151
+ this._motion.removeEventListener('change', this._onMotionChange);
152
+ for (const slide of this._saved.keys())
153
+ this._releaseSlide(slide);
154
+ for (const [name, value] of this._hostAttributes) {
155
+ if (value === null)
156
+ this.removeAttribute(name);
157
+ else
158
+ this.setAttribute(name, value);
159
+ }
160
+ this._hostAttributes.clear();
161
+ }
162
+ attributeChangedCallback(name, oldValue, value) {
163
+ if (oldValue === value || this._reflecting)
164
+ return;
165
+ if (name === 'index') {
166
+ const index = Math.floor(numeric(value, 0, 0, Number.MAX_SAFE_INTEGER));
167
+ if (this._connected)
168
+ this._select(index, 'api');
169
+ else
170
+ this._index = index;
171
+ return;
172
+ }
173
+ if (name === 'direction' || name === 'draggable') {
174
+ this._cancelDrag();
175
+ this._cancelAnimations();
176
+ }
177
+ if (name === 'autoplay') {
178
+ this._paused = false;
179
+ this._motionOverride = false;
180
+ }
181
+ if (this._connected) {
182
+ this._render();
183
+ this._schedule();
184
+ }
185
+ }
186
+ get index() { return this._index; }
187
+ set index(value) { this.setAttribute('index', String(Math.floor(numeric(value, 0, 0, Number.MAX_SAFE_INTEGER)))); }
188
+ get direction() { return this.getAttribute('direction') === 'vertical' ? 'vertical' : 'horizontal'; }
189
+ set direction(value) { this.setAttribute('direction', value === 'vertical' ? value : 'horizontal'); }
190
+ get indicatorPosition() {
191
+ const value = this.getAttribute('indicator-position');
192
+ return value === 'top' || value === 'left' || value === 'right' ? value : 'bottom';
193
+ }
194
+ set indicatorPosition(value) { this.setAttribute('indicator-position', value); }
195
+ get indicatorStyle() {
196
+ const value = this.getAttribute('indicator-style');
197
+ return value === 'line' || value === 'number' ? value : 'dot';
198
+ }
199
+ set indicatorStyle(value) { this.setAttribute('indicator-style', value); }
200
+ get indicatorRenderer() { return this._indicatorRenderer; }
201
+ set indicatorRenderer(value) { this._indicatorRenderer = typeof value === 'function' ? value : null; if (this._connected)
202
+ this._render(); }
203
+ get showIndicators() { return this.getAttribute('show-indicators') !== 'false'; }
204
+ set showIndicators(value) { this.setAttribute('show-indicators', String(Boolean(value))); }
205
+ get showArrows() { return this.getAttribute('show-arrows') !== 'false'; }
206
+ set showArrows(value) { this.setAttribute('show-arrows', String(Boolean(value))); }
207
+ get autoplay() { return this.hasAttribute('autoplay') && this.getAttribute('autoplay') !== 'false'; }
208
+ set autoplay(value) { if (value)
209
+ this.setAttribute('autoplay', '');
210
+ else
211
+ this.removeAttribute('autoplay'); }
212
+ get interval() { return numeric(this.getAttribute('interval'), 3000, 100, 86_400_000); }
213
+ set interval(value) { this.setAttribute('interval', String(numeric(value, 3000, 100, 86_400_000))); }
214
+ get draggable() { return this.getAttribute('draggable') !== 'false'; }
215
+ set draggable(value) { this.setAttribute('draggable', String(Boolean(value))); }
216
+ get loop() { return this.getAttribute('loop') !== 'false'; }
217
+ set loop(value) { this.setAttribute('loop', String(Boolean(value))); }
218
+ next() { this._select(this._index + 1, 'api'); }
219
+ previous() { this._select(this._index - 1, 'api'); }
220
+ goTo(index) { this._select(Math.floor(numeric(index, 0, -Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER)), 'api'); }
221
+ play() { this._paused = false; this.autoplay = true; this._motionOverride = true; if (this._connected)
222
+ this._render(); this._schedule(); }
223
+ pause() { this._paused = true; this._clearTimer(); if (this._connected)
224
+ this._render(); }
225
+ _syncSlides = () => {
226
+ const active = this._slides[this._index];
227
+ const slides = this._slot.assignedElements().filter((slide) => slide instanceof HTMLElement);
228
+ this._cancelDrag();
229
+ this._cancelAnimations();
230
+ for (const slide of this._saved.keys())
231
+ if (!slides.includes(slide))
232
+ this._releaseSlide(slide);
233
+ this._slides = slides;
234
+ for (const slide of slides)
235
+ if (!this._saved.has(slide))
236
+ this._saved.set(slide, {
237
+ attributes: attributes.map(name => slide.getAttribute(name)),
238
+ properties: properties.map(name => ({ value: slide.style.getPropertyValue(name), priority: slide.style.getPropertyPriority(name) })),
239
+ });
240
+ this._indicators.replaceChildren(...slides.map((_, index) => {
241
+ const button = document.createElement('button');
242
+ button.type = 'button';
243
+ button.className = 'indicator';
244
+ button.dataset.index = String(index);
245
+ button.part.add('indicator');
246
+ button.setAttribute('aria-label', `Go to slide ${index + 1}`);
247
+ const content = document.createElement('span');
248
+ content.className = 'indicator-content';
249
+ content.part.add('indicator-content');
250
+ content.setAttribute('aria-hidden', 'true');
251
+ button.append(content);
252
+ return button;
253
+ }));
254
+ const index = active && slides.includes(active) ? slides.indexOf(active) : Math.min(this._index, Math.max(0, slides.length - 1));
255
+ this._select(index, 'content', false);
256
+ };
257
+ _releaseSlide(slide) {
258
+ const saved = this._saved.get(slide);
259
+ if (!saved)
260
+ return;
261
+ attributes.forEach((name, index) => { const value = saved.attributes[index]; if (value == null)
262
+ slide.removeAttribute(name);
263
+ else
264
+ slide.setAttribute(name, value); });
265
+ properties.forEach((name, index) => { const entry = saved.properties[index]; if (entry.value)
266
+ slide.style.setProperty(name, entry.value, entry.priority);
267
+ else
268
+ slide.style.removeProperty(name); });
269
+ this._saved.delete(slide);
270
+ }
271
+ _resolve(index) {
272
+ const length = this._slides.length;
273
+ return !length ? 0 : this.loop ? ((index % length) + length) % length : Math.max(0, Math.min(length - 1, index));
274
+ }
275
+ _select(requested, source, animate = true, dragOffset = 0) {
276
+ if (!this._connected) {
277
+ this.index = Math.max(0, requested);
278
+ return;
279
+ }
280
+ if (this._drag)
281
+ this._cancelDrag();
282
+ const index = this._resolve(requested);
283
+ const previousIndex = this._index;
284
+ const previous = this._slides[previousIndex];
285
+ const next = this._slides[index];
286
+ this._cancelAnimations();
287
+ if (previous && index !== previousIndex && previous.matches(':focus-within'))
288
+ this._viewport.focus({ preventScroll: true });
289
+ this._index = index;
290
+ this._reflecting = true;
291
+ this.setAttribute('index', String(index));
292
+ this._reflecting = false;
293
+ this._render();
294
+ if (animate && index !== previousIndex && previous && next) {
295
+ const sign = requested > previousIndex ? 1 : -1;
296
+ this._animate(previous, dragOffset, -sign * 100);
297
+ this._animate(next, dragOffset + sign * 100, 0);
298
+ }
299
+ this._schedule();
300
+ if (index !== previousIndex)
301
+ this.dispatchEvent(new CustomEvent('change', {
302
+ detail: { index, previousIndex, source }, bubbles: true, composed: true,
303
+ }));
304
+ }
305
+ _transform(offset) {
306
+ return this.direction === 'vertical' ? `translate3d(0, ${offset}%, 0)` : `translate3d(${offset * (getComputedStyle(this).direction === 'rtl' ? -1 : 1)}%, 0, 0)`;
307
+ }
308
+ _position(slide, offset, visible) {
309
+ slide.style.setProperty(properties[0], this._transform(offset));
310
+ slide.style.setProperty(properties[1], visible ? 'visible' : 'hidden');
311
+ }
312
+ _paint() { this._slides.forEach((slide, index) => this._position(slide, 0, index === this._index)); }
313
+ _render() {
314
+ this._paint();
315
+ this._slides.forEach((slide, index) => {
316
+ const saved = this._saved.get(slide);
317
+ if (!saved)
318
+ return;
319
+ if (!saved.attributes[0])
320
+ slide.setAttribute('role', 'group');
321
+ if (!saved.attributes[1])
322
+ slide.setAttribute('aria-roledescription', 'slide');
323
+ if (!saved.attributes[2])
324
+ slide.setAttribute('aria-label', `${index + 1} of ${this._slides.length}`);
325
+ for (const name of ['inert', 'aria-hidden']) {
326
+ const value = saved.attributes[attributes.indexOf(name)];
327
+ if (index !== this._index)
328
+ slide.setAttribute(name, name === 'inert' ? '' : 'true');
329
+ else if (value == null)
330
+ slide.removeAttribute(name);
331
+ else
332
+ slide.setAttribute(name, value);
333
+ }
334
+ });
335
+ this._indicators.hidden = !this.showIndicators || this._slides.length < 2;
336
+ this._indicators.classList.toggle('custom', Boolean(this._indicatorRenderer));
337
+ [...this._indicators.children].forEach((element, index) => {
338
+ const button = element;
339
+ const active = index === this._index;
340
+ button.setAttribute('aria-current', String(active));
341
+ button.tabIndex = active ? 0 : -1;
342
+ button.part.toggle('indicator-active', active);
343
+ const content = button.firstElementChild;
344
+ if (this._indicatorRenderer) {
345
+ const rendered = this._indicatorRenderer(index, active);
346
+ content.replaceChildren(...(rendered == null ? [] : [rendered]));
347
+ }
348
+ else
349
+ content.textContent = this.indicatorStyle === 'number' ? String(index + 1) : '';
350
+ });
351
+ const vertical = this.direction === 'vertical';
352
+ const rtl = getComputedStyle(this).direction === 'rtl';
353
+ this._previous.textContent = vertical ? '↑' : rtl ? '→' : '←';
354
+ this._next.textContent = vertical ? '↓' : rtl ? '←' : '→';
355
+ this._previous.hidden = this._next.hidden = !this.showArrows || this._slides.length < 2;
356
+ this._previous.disabled = !this.loop && this._index === 0;
357
+ this._next.disabled = !this.loop && this._index >= this._slides.length - 1;
358
+ this._playback.hidden = !this.autoplay || this._slides.length < 2;
359
+ const paused = this._paused || (this._motion.matches && !this._motionOverride);
360
+ this._playback.textContent = paused ? '▶' : 'Ⅱ';
361
+ this._playback.setAttribute('aria-label', paused ? 'Start automatic slide rotation' : 'Pause automatic slide rotation');
362
+ this._viewport.setAttribute('aria-live', this.autoplay && !paused ? 'off' : 'polite');
363
+ }
364
+ _animate(slide, from, to) {
365
+ if (this._motion.matches)
366
+ return;
367
+ const raw = getComputedStyle(this).getPropertyValue('--hy-carousel-duration').trim() || '320ms';
368
+ const duration = numeric(Number.parseFloat(raw) * (raw.endsWith('ms') ? 1 : 1000), 320, 0, 5000);
369
+ if (!duration)
370
+ return;
371
+ slide.style.setProperty(properties[1], 'visible');
372
+ const animation = slide.animate([{ transform: this._transform(from) }, { transform: this._transform(to) }], { duration, easing: 'ease', fill: 'forwards' });
373
+ this._animations.add(animation);
374
+ void animation.finished.then(() => {
375
+ if (!this._animations.delete(animation))
376
+ return;
377
+ animation.cancel();
378
+ this._position(slide, 0, slide === this._slides[this._index]);
379
+ }, () => { this._animations.delete(animation); });
380
+ }
381
+ _cancelAnimations() { for (const animation of this._animations)
382
+ animation.cancel(); this._animations.clear(); }
383
+ _clearTimer() { window.clearTimeout(this._timer); this._timer = 0; }
384
+ _schedule = () => {
385
+ this._clearTimer();
386
+ if (!this._connected || !this.autoplay || this._paused || this._hovered || this._drag || document.hidden || this._slides.length < 2 ||
387
+ (this._motion.matches && !this._motionOverride) || (!this.loop && this._index === this._slides.length - 1))
388
+ return;
389
+ this._timer = window.setTimeout(() => this._select(this._index + 1, 'autoplay'), this.interval);
390
+ };
391
+ _onEnter = () => { this._hovered = true; this._schedule(); };
392
+ _onLeave = () => { this._hovered = false; this._schedule(); };
393
+ _onMotionChange = () => { this._cancelAnimations(); if (this._connected)
394
+ this._render(); this._schedule(); };
395
+ _onFocus = (event) => { if (!(event.relatedTarget instanceof Node) || !this.contains(event.relatedTarget))
396
+ this.pause(); };
397
+ _onKeyDown = (event) => {
398
+ if (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey || !this._slides.length)
399
+ return;
400
+ const path = event.composedPath();
401
+ const indicator = path.find(node => node instanceof HTMLButtonElement && node.dataset.index != null);
402
+ if (!indicator && path.some(node => node instanceof HTMLElement && /^(INPUT|SELECT|TEXTAREA|BUTTON|A)$/.test(node.tagName) || node instanceof HTMLElement && node.isContentEditable))
403
+ return;
404
+ const backward = this.direction === 'vertical' ? 'ArrowUp' : 'ArrowLeft';
405
+ const forward = this.direction === 'vertical' ? 'ArrowDown' : 'ArrowRight';
406
+ let step = event.key === forward ? 1 : event.key === backward ? -1 : 0;
407
+ if (indicator && !step)
408
+ step = event.key === 'ArrowDown' ? 1 : event.key === 'ArrowUp' ? -1 : 0;
409
+ if (this.direction === 'horizontal' && getComputedStyle(this).direction === 'rtl' && ['ArrowLeft', 'ArrowRight'].includes(event.key))
410
+ step *= -1;
411
+ if (!step && event.key !== 'Home' && event.key !== 'End')
412
+ return;
413
+ event.preventDefault();
414
+ this._select(event.key === 'Home' ? 0 : event.key === 'End' ? this._slides.length - 1 : this._index + step, 'keyboard');
415
+ if (indicator)
416
+ this._indicators.children[this._index]?.focus();
417
+ };
418
+ _onNativeDrag = (event) => { if (this.draggable)
419
+ event.preventDefault(); };
420
+ _onClick = (event) => { if (event.detail > 0 && performance.now() < this._blockClickUntil) {
421
+ event.preventDefault();
422
+ event.stopImmediatePropagation();
423
+ } };
424
+ _onPointerDown = (event) => {
425
+ if (!this.draggable || !event.isPrimary || event.button !== 0 || this._slides.length < 2 ||
426
+ event.composedPath().some(node => node instanceof HTMLElement && (node.matches('a, button, input, textarea, select, [contenteditable]:not([contenteditable="false"])'))))
427
+ return;
428
+ this._cancelAnimations();
429
+ this._paint();
430
+ this._drag = { id: event.pointerId, x: event.clientX, y: event.clientY, offset: 0, moved: false };
431
+ this._clearTimer();
432
+ window.addEventListener('pointermove', this._onPointerMove, { passive: false });
433
+ window.addEventListener('pointerup', this._onPointerUp);
434
+ window.addEventListener('pointercancel', this._onPointerCancel);
435
+ };
436
+ _onPointerMove = (event) => {
437
+ const drag = this._drag;
438
+ if (!drag || drag.id !== event.pointerId)
439
+ return;
440
+ const vertical = this.direction === 'vertical';
441
+ const delta = vertical ? event.clientY - drag.y : event.clientX - drag.x;
442
+ const cross = vertical ? event.clientX - drag.x : event.clientY - drag.y;
443
+ if (!drag.moved && Math.abs(cross) > Math.max(8, Math.abs(delta))) {
444
+ this._cancelDrag();
445
+ this._schedule();
446
+ return;
447
+ }
448
+ if (!drag.moved && Math.abs(delta) < 6)
449
+ return;
450
+ if (!drag.moved) {
451
+ drag.moved = true;
452
+ this._viewport.setPointerCapture(event.pointerId);
453
+ }
454
+ event.preventDefault();
455
+ const rect = this._viewport.getBoundingClientRect();
456
+ const size = vertical ? rect.height : rect.width;
457
+ drag.offset = size > 0 ? delta / size * 100 * (!vertical && getComputedStyle(this).direction === 'rtl' ? -1 : 1) : 0;
458
+ const step = drag.offset < 0 ? 1 : -1;
459
+ const neighbor = this._resolve(this._index + step);
460
+ this._paint();
461
+ const offset = neighbor === this._index ? drag.offset * .25 : drag.offset;
462
+ this._position(this._slides[this._index], offset, true);
463
+ if (neighbor !== this._index)
464
+ this._position(this._slides[neighbor], offset + step * 100, true);
465
+ };
466
+ _onPointerUp = (event) => {
467
+ const drag = this._drag;
468
+ if (!drag || drag.id !== event.pointerId)
469
+ return;
470
+ const offset = drag.offset;
471
+ const step = offset < 0 ? 1 : -1;
472
+ const neighbor = this._resolve(this._index + step);
473
+ this._cancelDrag();
474
+ if (drag.moved) {
475
+ this._blockClickUntil = performance.now() + 400;
476
+ if (Math.abs(offset) >= 18 && neighbor !== this._index)
477
+ this._select(this._index + step, 'drag', true, offset);
478
+ else
479
+ this._animate(this._slides[this._index], neighbor === this._index ? offset * .25 : offset, 0);
480
+ }
481
+ this._schedule();
482
+ };
483
+ _onPointerCancel = (event) => {
484
+ // Touch starts with implicit capture on the slotted content. Moving capture
485
+ // to the viewport emits a bubbling loss from that content, not a cancellation.
486
+ if (event.type === 'lostpointercapture' && event.target !== this._viewport)
487
+ return;
488
+ if (this._drag?.id === event.pointerId) {
489
+ this._cancelDrag();
490
+ this._schedule();
491
+ }
492
+ };
493
+ _cancelDrag() {
494
+ const drag = this._drag;
495
+ this._drag = null;
496
+ window.removeEventListener('pointermove', this._onPointerMove);
497
+ window.removeEventListener('pointerup', this._onPointerUp);
498
+ window.removeEventListener('pointercancel', this._onPointerCancel);
499
+ if (drag && this._viewport.hasPointerCapture(drag.id))
500
+ this._viewport.releasePointerCapture(drag.id);
501
+ if (this._connected)
502
+ this._paint();
503
+ }
504
+ }
505
+ export function defineCarouselComponents() {
506
+ if (!customElements.get('hy-carousel'))
507
+ customElements.define('hy-carousel', HYCarousel);
508
+ }
509
+ //# sourceMappingURL=carousel.js.map
@@ -0,0 +1,65 @@
1
+ export type HYCascaderValue = string | number;
2
+ export interface HYCascaderOption {
3
+ readonly label: string;
4
+ readonly value: HYCascaderValue;
5
+ readonly disabled?: boolean;
6
+ readonly children?: readonly HYCascaderOption[];
7
+ }
8
+ export interface HYCascaderChangeDetail {
9
+ readonly value: readonly HYCascaderValue[];
10
+ readonly options: readonly HYCascaderOption[];
11
+ }
12
+ export interface HYCascaderOpenChangeDetail {
13
+ readonly open: boolean;
14
+ }
15
+ /** Tree-backed cascading dropdown that commits a complete value path. */
16
+ export declare class HYCascader extends HTMLElement {
17
+ private readonly _control;
18
+ private readonly _trigger;
19
+ private readonly _label;
20
+ private readonly _arrow;
21
+ private readonly _clear;
22
+ private readonly _panel;
23
+ private readonly _panelId;
24
+ private _options;
25
+ private _value;
26
+ private _activePath;
27
+ private _reflecting;
28
+ private _outsideAbort;
29
+ static get observedAttributes(): string[];
30
+ constructor();
31
+ connectedCallback(): void;
32
+ disconnectedCallback(): void;
33
+ attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
34
+ get options(): readonly HYCascaderOption[];
35
+ set options(value: readonly HYCascaderOption[]);
36
+ get value(): readonly HYCascaderValue[];
37
+ set value(value: readonly HYCascaderValue[]);
38
+ get open(): boolean;
39
+ set open(value: boolean);
40
+ get disabled(): boolean;
41
+ set disabled(value: boolean);
42
+ get clearable(): boolean;
43
+ set clearable(value: boolean);
44
+ get changeOnSelect(): boolean;
45
+ set changeOnSelect(value: boolean);
46
+ get placeholder(): string;
47
+ set placeholder(value: string);
48
+ get displaySeparator(): string;
49
+ set displaySeparator(value: string);
50
+ private _syncAttributes;
51
+ private _readOptionsAttribute;
52
+ private _readValueAttribute;
53
+ private _reflectValue;
54
+ private _normalizePath;
55
+ private _resolveOptions;
56
+ private _render;
57
+ private _renderPanel;
58
+ private _createOption;
59
+ private _activateOption;
60
+ private _commit;
61
+ private _handleOptionKeydown;
62
+ private _syncOutsideListener;
63
+ private _dispatchOpenChange;
64
+ }
65
+ export declare function defineCascaderComponents(): void;