@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.
- package/CHANGELOG.md +43 -0
- package/LICENSE +27 -0
- package/README.md +643 -2
- package/dist/adapters/web/controls.d.ts +19 -0
- package/dist/adapters/web/controls.js +307 -0
- package/dist/adapters/web/dom.d.ts +10 -0
- package/dist/adapters/web/dom.js +98 -0
- package/dist/adapters/web/index.d.ts +3 -0
- package/dist/adapters/web/index.js +3 -0
- package/dist/adapters/web/renderer.d.ts +18 -0
- package/dist/adapters/web/renderer.js +553 -0
- package/dist/adapters/web/styles.d.ts +3 -0
- package/dist/adapters/web/styles.js +83 -0
- package/dist/adapters/web/types.d.ts +46 -0
- package/dist/adapters/web/types.js +2 -0
- package/dist/affix.d.ts +35 -0
- package/dist/affix.js +137 -0
- package/dist/badge.d.ts +45 -0
- package/dist/badge.js +168 -0
- package/dist/breadcrumb.d.ts +37 -0
- package/dist/breadcrumb.js +210 -0
- package/dist/button-group.d.ts +12 -0
- package/dist/button-group.js +72 -0
- package/dist/button.d.ts +15 -1
- package/dist/button.js +101 -12
- package/dist/carousel.d.ts +92 -0
- package/dist/carousel.js +509 -0
- package/dist/cascader.d.ts +65 -0
- package/dist/cascader.js +479 -0
- package/dist/collapse.d.ts +68 -0
- package/dist/collapse.js +348 -0
- package/dist/core/actions.d.ts +32 -0
- package/dist/core/actions.js +145 -0
- package/dist/core/data.d.ts +4 -0
- package/dist/core/data.js +27 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.js +6 -0
- package/dist/core/platform-view.d.ts +17 -0
- package/dist/core/platform-view.js +84 -0
- package/dist/core/selection.d.ts +14 -0
- package/dist/core/selection.js +93 -0
- package/dist/core/text.d.ts +31 -0
- package/dist/core/text.js +154 -0
- package/dist/core/types.d.ts +269 -0
- package/dist/core/types.js +2 -0
- package/dist/core/validation.d.ts +24 -0
- package/dist/core/validation.js +243 -0
- package/dist/date-picker.d.ts +60 -0
- package/dist/date-picker.js +355 -0
- package/dist/dialog.d.ts +4 -0
- package/dist/dialog.js +23 -5
- package/dist/divider.d.ts +33 -0
- package/dist/divider.js +113 -0
- package/dist/draggable.d.ts +78 -0
- package/dist/draggable.js +255 -0
- package/dist/index.d.ts +53 -1
- package/dist/index.js +78 -0
- package/dist/input.d.ts +30 -1
- package/dist/input.js +166 -54
- package/dist/internal/qrcodegen.d.ts +94 -0
- package/dist/internal/qrcodegen.js +856 -0
- package/dist/masonry.d.ts +36 -0
- package/dist/masonry.js +171 -0
- package/dist/modal.d.ts +73 -0
- package/dist/modal.js +361 -0
- package/dist/portable/icons.d.ts +5 -0
- package/dist/portable/icons.js +24 -0
- package/dist/portable/index.d.ts +7 -0
- package/dist/portable/index.js +5 -0
- package/dist/portable/page.d.ts +38 -0
- package/dist/portable/page.js +361 -0
- package/dist/portable/responsive.d.ts +20 -0
- package/dist/portable/responsive.js +15 -0
- package/dist/portable/theme.d.ts +24 -0
- package/dist/portable/theme.js +60 -0
- package/dist/portable/tree.d.ts +10 -0
- package/dist/portable/tree.js +96 -0
- package/dist/qr-code.d.ts +62 -0
- package/dist/qr-code.js +224 -0
- package/dist/range.d.ts +3 -0
- package/dist/range.js +16 -5
- package/dist/rate.d.ts +46 -0
- package/dist/rate.js +193 -0
- package/dist/resizable.d.ts +97 -0
- package/dist/resizable.js +426 -0
- package/dist/skeleton.d.ts +41 -0
- package/dist/skeleton.js +141 -0
- package/dist/steps.d.ts +45 -0
- package/dist/steps.js +203 -0
- package/dist/table.d.ts +106 -0
- package/dist/table.js +689 -0
- package/dist/tabs.d.ts +3 -0
- package/dist/tabs.js +11 -1
- package/dist/tag.d.ts +55 -0
- package/dist/tag.js +225 -0
- package/dist/time-picker.d.ts +62 -0
- package/dist/time-picker.js +298 -0
- package/dist/timeline.d.ts +48 -0
- package/dist/timeline.js +201 -0
- package/dist/toast.d.ts +55 -0
- package/dist/toast.js +224 -0
- package/dist/tour.d.ts +89 -0
- package/dist/tour.js +306 -0
- package/dist/virtual-keyboard.d.ts +95 -0
- package/dist/virtual-keyboard.js +432 -0
- package/dist/virtual-mouse.d.ts +82 -0
- package/dist/virtual-mouse.js +358 -0
- package/dist/watermark.d.ts +44 -0
- package/dist/watermark.js +148 -0
- package/package.json +132 -4
package/dist/carousel.js
ADDED
|
@@ -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;
|