vanilla-jui 1.3.10 → 1.4.0
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/dist/index.d.ts +2927 -0
- package/dist/index.js +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/style.css +1 -1
- package/package.json +4 -3
- package/src/components/accordion.ts +522 -0
- package/src/components/drop.ts +497 -0
- package/src/components/flow.ts +1579 -0
- package/src/components/form.ts +953 -0
- package/src/components/{icons.js → icons.ts} +24 -11
- package/src/components/menu.ts +615 -0
- package/src/components/{modal.js → modal.ts} +560 -237
- package/src/components/offcanvas.ts +496 -0
- package/src/components/{pagination.js → pagination.ts} +251 -76
- package/src/components/parabola.ts +335 -0
- package/src/components/{sticky.js → sticky.ts} +123 -98
- package/src/components/{swiper.js → swiper.ts} +510 -232
- package/src/components/tabs.ts +984 -0
- package/src/components/theme.ts +437 -0
- package/src/components/toast.ts +371 -0
- package/src/components/toc.ts +385 -0
- package/src/components/tooltip.ts +179 -0
- package/src/components/validator.ts +596 -0
- package/src/core/{Component.js → Component.ts} +134 -27
- package/src/css/accordion.css +2 -2
- package/src/css/animation.css +31 -1
- package/src/css/breadcrumb.css +1 -1
- package/src/css/button.css +5 -5
- package/src/css/card.css +7 -7
- package/src/css/color.css +865 -1028
- package/src/css/color_p3.css +871 -1036
- package/src/css/components.css +1 -0
- package/src/css/drop.css +1 -1
- package/src/css/flow.css +1 -1
- package/src/css/form.css +21 -21
- package/src/css/gradient.css +17 -4
- package/src/css/icon.css +17 -1
- package/src/css/index.css +3 -3
- package/src/css/layout.css +1 -1
- package/src/css/menu.css +27 -27
- package/src/css/modal.css +10 -27
- package/src/css/offcanvas.css +2 -2
- package/src/css/pagination.css +1 -1
- package/src/css/popup.css +2 -2
- package/src/css/swiper.css +12 -12
- package/src/css/tabs.css +3 -2
- package/src/css/tag.css +3 -4
- package/src/css/theme-palette.css +6 -6
- package/src/css/tip.css +1 -1
- package/src/css/toast.css +8 -8
- package/src/css/tokens.css +197 -226
- package/src/css/toolbar.css +3 -3
- package/src/css/tooltip.css +1 -1
- package/src/index.ts +37 -0
- package/src/locales/{index.js → index.ts} +1 -2
- package/src/types.d.ts +1 -0
- package/src/utilities/browser.ts +131 -0
- package/src/utilities/cache.ts +57 -0
- package/src/utilities/core.ts +614 -0
- package/src/utilities/dom.ts +468 -0
- package/src/utilities/events.ts +106 -0
- package/src/utilities/http.ts +35 -0
- package/src/utilities/storage.ts +46 -0
- package/src/components/accordion.js +0 -373
- package/src/components/drop.js +0 -437
- package/src/components/flow.js +0 -1133
- package/src/components/form.js +0 -585
- package/src/components/menu.js +0 -422
- package/src/components/offcanvas.js +0 -332
- package/src/components/parabola.js +0 -295
- package/src/components/tabs.js +0 -746
- package/src/components/theme.js +0 -353
- package/src/components/toast.js +0 -329
- package/src/components/toc.js +0 -226
- package/src/components/tooltip.js +0 -86
- package/src/components/validator.js +0 -586
- package/src/css/toast.min.css +0 -1
- package/src/index.js +0 -45
- package/src/locales/index.min.js +0 -1
- package/src/utilities/browser.js +0 -111
- package/src/utilities/cache.js +0 -159
- package/src/utilities/core.js +0 -502
- package/src/utilities/debug.js +0 -103
- package/src/utilities/dom.js +0 -313
- package/src/utilities/events.js +0 -69
- package/src/utilities/http.js +0 -30
- package/src/utilities/legacy-dom.js +0 -179
- package/src/utilities/storage.js +0 -46
- /package/src/{components/components.js → css/themes/index.css} +0 -0
- /package/src/icons/{index.js → index.ts} +0 -0
|
@@ -6,26 +6,195 @@ import {
|
|
|
6
6
|
h,
|
|
7
7
|
} from 'vanilla-signal';
|
|
8
8
|
|
|
9
|
-
import Component
|
|
10
|
-
|
|
9
|
+
import Component, {
|
|
10
|
+
type ComponentDOM,
|
|
11
|
+
type ComponentRuntime,
|
|
12
|
+
type ComponentUpdateOptions,
|
|
13
|
+
} from '../core/Component.ts';
|
|
14
|
+
import {
|
|
15
|
+
type ResolveSchema,
|
|
16
|
+
isPlainObject,
|
|
17
|
+
resolveProps,
|
|
18
|
+
validateParam,
|
|
19
|
+
} from '../utilities/core.ts';
|
|
11
20
|
import {
|
|
12
21
|
all,
|
|
22
|
+
type DOMReference,
|
|
13
23
|
isElement,
|
|
14
24
|
isRenderableContent,
|
|
15
25
|
normalizeContentNodes,
|
|
16
26
|
q,
|
|
27
|
+
type RenderableContent,
|
|
17
28
|
requireContainer,
|
|
18
|
-
|
|
19
|
-
} from '
|
|
20
|
-
import { icon } from './icons.js';
|
|
29
|
+
} from '../utilities/dom.ts';
|
|
30
|
+
import { icon } from './icons.ts';
|
|
21
31
|
|
|
22
32
|
const SWIPE_THRESHOLD = 6;
|
|
23
33
|
const AUTOPLAY_DELAY_FLOOR = 16;
|
|
24
34
|
|
|
35
|
+
export interface SwiperClassNames {
|
|
36
|
+
root: string;
|
|
37
|
+
wrapper: string;
|
|
38
|
+
slide: string;
|
|
39
|
+
image: string;
|
|
40
|
+
title: string;
|
|
41
|
+
pagination: string;
|
|
42
|
+
paginationHorizontal: string;
|
|
43
|
+
paginationClickable: string;
|
|
44
|
+
paginationBulletGroup: string;
|
|
45
|
+
indicator: string;
|
|
46
|
+
bullet: string;
|
|
47
|
+
navigation: string;
|
|
48
|
+
prev: string;
|
|
49
|
+
next: string;
|
|
50
|
+
active: string;
|
|
51
|
+
disabled: string;
|
|
52
|
+
loading: string;
|
|
53
|
+
loaded: string;
|
|
54
|
+
error: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type SwiperClassNameConfig = Partial<SwiperClassNames>;
|
|
58
|
+
|
|
59
|
+
export interface SwiperDataItem extends Record<string, unknown> {
|
|
60
|
+
image?: string | null;
|
|
61
|
+
url?: string | null;
|
|
62
|
+
title?: string | null;
|
|
63
|
+
sort?: number | null;
|
|
64
|
+
blank?: boolean | null;
|
|
65
|
+
children?: RenderableContent<SwiperSlideContext> | null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface NormalizedSwiperDataItem extends SwiperDataItem {
|
|
69
|
+
blank: boolean;
|
|
70
|
+
index: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface SwiperSlideContext {
|
|
74
|
+
swiper: Swiper;
|
|
75
|
+
item: NormalizedSwiperDataItem;
|
|
76
|
+
index: number;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface SwiperOptions extends Record<string, unknown> {
|
|
80
|
+
data?: SwiperDataItem[] | null;
|
|
81
|
+
loop?: boolean;
|
|
82
|
+
autoplay?: boolean;
|
|
83
|
+
delay?: number;
|
|
84
|
+
lazyload?: boolean;
|
|
85
|
+
pagination?: boolean;
|
|
86
|
+
navigation?: boolean;
|
|
87
|
+
speed?: number;
|
|
88
|
+
touchRatio?: number;
|
|
89
|
+
touchAngle?: number;
|
|
90
|
+
longSwipesMs?: number;
|
|
91
|
+
longSwipesRatio?: number;
|
|
92
|
+
preventClick?: boolean;
|
|
93
|
+
className?: SwiperClassNameConfig;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface ResolvedSwiperOptions extends Record<string, unknown> {
|
|
97
|
+
data: SwiperDataItem[] | null;
|
|
98
|
+
loop: boolean;
|
|
99
|
+
autoplay: boolean;
|
|
100
|
+
delay: number;
|
|
101
|
+
lazyload: boolean;
|
|
102
|
+
pagination: boolean;
|
|
103
|
+
navigation: boolean;
|
|
104
|
+
speed: number;
|
|
105
|
+
touchRatio: number;
|
|
106
|
+
touchAngle: number;
|
|
107
|
+
longSwipesMs: number;
|
|
108
|
+
longSwipesRatio: number;
|
|
109
|
+
preventClick: boolean;
|
|
110
|
+
className: SwiperClassNames;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
interface SwiperState extends Record<string, unknown> {
|
|
114
|
+
index: number;
|
|
115
|
+
trackIndex: number;
|
|
116
|
+
transform: number;
|
|
117
|
+
animating: boolean;
|
|
118
|
+
width: number;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
interface SwiperDOM extends ComponentDOM {
|
|
122
|
+
root: HTMLElement | null;
|
|
123
|
+
container: DOMReference;
|
|
124
|
+
mountTarget: Element | null;
|
|
125
|
+
createdRoot: boolean;
|
|
126
|
+
createdSlides: boolean;
|
|
127
|
+
wrapper: HTMLElement | null;
|
|
128
|
+
slides: HTMLElement[];
|
|
129
|
+
pagination: HTMLElement | null;
|
|
130
|
+
prevButton: HTMLButtonElement | null;
|
|
131
|
+
nextButton: HTMLButtonElement | null;
|
|
132
|
+
bullets: HTMLButtonElement[];
|
|
133
|
+
createdPagination: boolean;
|
|
134
|
+
createdPrevButton: boolean;
|
|
135
|
+
createdNextButton: boolean;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
interface SwipeLog {
|
|
139
|
+
x: number;
|
|
140
|
+
y: number;
|
|
141
|
+
time: number;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
interface SwipePoint {
|
|
145
|
+
pageX?: number;
|
|
146
|
+
pageY?: number;
|
|
147
|
+
clientX?: number;
|
|
148
|
+
clientY?: number;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
interface SwiperRuntime extends ComponentRuntime {
|
|
152
|
+
logs: SwipeLog[];
|
|
153
|
+
startTarget: EventTarget | null;
|
|
154
|
+
touching: boolean;
|
|
155
|
+
scrolling: boolean;
|
|
156
|
+
swiping: boolean;
|
|
157
|
+
clickPrevented: boolean;
|
|
158
|
+
timer: ReturnType<typeof setInterval> | null;
|
|
159
|
+
imageCleanups: Set<() => void>;
|
|
160
|
+
realCount: number;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
interface SwiperCleanupExtras {
|
|
164
|
+
bindings?: (() => void) | null;
|
|
165
|
+
navBindings?: (() => void) | null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
type SwiperUpdateOptions = Partial<ComponentUpdateOptions>;
|
|
169
|
+
type SwiperDirection = 'prev' | 'next';
|
|
170
|
+
type CreatedNavigationKey = 'createdPrevButton' | 'createdNextButton';
|
|
171
|
+
|
|
172
|
+
const DEFAULT_CLASS_NAMES: SwiperClassNames = {
|
|
173
|
+
root: 'j-swiper',
|
|
174
|
+
wrapper: 'swiper-wrapper',
|
|
175
|
+
slide: 'swiper-slide',
|
|
176
|
+
image: 'swiper-image',
|
|
177
|
+
title: 'swiper-slide-title',
|
|
178
|
+
pagination: 'swiper-pagination',
|
|
179
|
+
paginationHorizontal: 'is-horizontal',
|
|
180
|
+
paginationClickable: 'is-clickable',
|
|
181
|
+
paginationBulletGroup: 'is-bullet',
|
|
182
|
+
indicator: 'swiper-pagination-indicator',
|
|
183
|
+
bullet: 'swiper-pagination-bullet',
|
|
184
|
+
navigation: 'swiper-navigation',
|
|
185
|
+
prev: 'is-prev',
|
|
186
|
+
next: 'is-next',
|
|
187
|
+
active: 'is-active',
|
|
188
|
+
disabled: 'is-disabled',
|
|
189
|
+
loading: 'loading',
|
|
190
|
+
loaded: 'loaded',
|
|
191
|
+
error: 'error',
|
|
192
|
+
};
|
|
193
|
+
|
|
25
194
|
const SWIPER_OPTIONS_SCHEMA = {
|
|
26
195
|
data: {
|
|
27
196
|
default: null,
|
|
28
|
-
validate: (value) => value == null || Array.isArray(value),
|
|
197
|
+
validate: (value: unknown) => value == null || Array.isArray(value),
|
|
29
198
|
message: 'expects an array or null.',
|
|
30
199
|
},
|
|
31
200
|
loop: { default: true, type: 'boolean' },
|
|
@@ -33,7 +202,7 @@ const SWIPER_OPTIONS_SCHEMA = {
|
|
|
33
202
|
delay: {
|
|
34
203
|
default: 3000,
|
|
35
204
|
type: 'number',
|
|
36
|
-
validate: (value) => value >= 0,
|
|
205
|
+
validate: (value: unknown) => Number(value) >= 0,
|
|
37
206
|
message: 'expects a positive number or 0.',
|
|
38
207
|
},
|
|
39
208
|
lazyload: { default: true, type: 'boolean' },
|
|
@@ -42,82 +211,121 @@ const SWIPER_OPTIONS_SCHEMA = {
|
|
|
42
211
|
speed: {
|
|
43
212
|
default: 300,
|
|
44
213
|
type: 'number',
|
|
45
|
-
validate: (value) => value >= 0,
|
|
214
|
+
validate: (value: unknown) => Number(value) >= 0,
|
|
46
215
|
message: 'expects a positive number or 0.',
|
|
47
216
|
},
|
|
48
217
|
touchRatio: {
|
|
49
218
|
default: 1,
|
|
50
219
|
type: 'number',
|
|
51
|
-
validate: (value) => value > 0,
|
|
220
|
+
validate: (value: unknown) => Number(value) > 0,
|
|
52
221
|
message: 'expects a number greater than 0.',
|
|
53
222
|
},
|
|
54
223
|
touchAngle: {
|
|
55
224
|
default: 45,
|
|
56
225
|
type: 'number',
|
|
57
|
-
validate: (value) => value >= 0 && value <= 90,
|
|
226
|
+
validate: (value: unknown) => Number(value) >= 0 && Number(value) <= 90,
|
|
58
227
|
message: 'expects a number between 0 and 90.',
|
|
59
228
|
},
|
|
60
229
|
longSwipesMs: {
|
|
61
230
|
default: 300,
|
|
62
231
|
type: 'number',
|
|
63
|
-
validate: (value) => value >= 0,
|
|
232
|
+
validate: (value: unknown) => Number(value) >= 0,
|
|
64
233
|
message: 'expects a positive number or 0.',
|
|
65
234
|
},
|
|
66
235
|
longSwipesRatio: {
|
|
67
236
|
default: 0.05,
|
|
68
237
|
type: 'number',
|
|
69
|
-
validate: (value) => value >= 0 && value <= 1,
|
|
238
|
+
validate: (value: unknown) => Number(value) >= 0 && Number(value) <= 1,
|
|
70
239
|
message: 'expects a number between 0 and 1.',
|
|
71
240
|
},
|
|
72
241
|
preventClick: { default: true, type: 'boolean' },
|
|
73
|
-
|
|
242
|
+
className: {
|
|
243
|
+
default: DEFAULT_CLASS_NAMES,
|
|
244
|
+
type: 'object',
|
|
245
|
+
normalize: (value: unknown) => ({
|
|
246
|
+
...DEFAULT_CLASS_NAMES,
|
|
247
|
+
...(value && typeof value === 'object' ? value : {}),
|
|
248
|
+
}),
|
|
249
|
+
},
|
|
250
|
+
} satisfies ResolveSchema<SwiperOptions>;
|
|
74
251
|
|
|
75
252
|
const SWIPER_DATA_ITEM_RULE = {
|
|
76
|
-
validate: (value) => {
|
|
253
|
+
validate: (value: unknown) => {
|
|
77
254
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
78
255
|
return false;
|
|
79
256
|
}
|
|
257
|
+
const item = value as SwiperDataItem;
|
|
80
258
|
|
|
81
259
|
return (
|
|
82
|
-
(
|
|
83
|
-
(
|
|
84
|
-
(
|
|
85
|
-
(
|
|
86
|
-
(
|
|
87
|
-
(
|
|
260
|
+
(item.image == null || typeof item.image === 'string') &&
|
|
261
|
+
(item.url == null || typeof item.url === 'string') &&
|
|
262
|
+
(item.title == null || typeof item.title === 'string') &&
|
|
263
|
+
(item.sort == null || typeof item.sort === 'number') &&
|
|
264
|
+
(item.blank == null || typeof item.blank === 'boolean') &&
|
|
265
|
+
(item.children == null || isRenderableContent(item.children))
|
|
88
266
|
);
|
|
89
267
|
},
|
|
90
268
|
message:
|
|
91
269
|
'expects items with optional image, url, title, sort, blank and children fields.',
|
|
92
270
|
};
|
|
93
271
|
|
|
94
|
-
function isInteractiveTarget(target) {
|
|
95
|
-
return
|
|
96
|
-
|
|
272
|
+
function isInteractiveTarget(target: EventTarget | null): boolean {
|
|
273
|
+
return (
|
|
274
|
+
target instanceof Element &&
|
|
275
|
+
!!target.closest(
|
|
276
|
+
'a, button, input, textarea, select, label, [data-swiper-ignore]'
|
|
277
|
+
)
|
|
97
278
|
);
|
|
98
279
|
}
|
|
99
280
|
|
|
100
|
-
function normalizeNumber(value, fallback = 0) {
|
|
281
|
+
function normalizeNumber(value: unknown, fallback = 0): number {
|
|
101
282
|
const number = Number(value);
|
|
102
283
|
return Number.isFinite(number) ? number : fallback;
|
|
103
284
|
}
|
|
104
285
|
|
|
105
|
-
function getRenderableNodes(
|
|
286
|
+
function getRenderableNodes(
|
|
287
|
+
content: RenderableContent<SwiperSlideContext>,
|
|
288
|
+
context: SwiperSlideContext
|
|
289
|
+
): Node[] {
|
|
106
290
|
return normalizeContentNodes(content, context);
|
|
107
291
|
}
|
|
108
292
|
|
|
109
|
-
function
|
|
110
|
-
const
|
|
293
|
+
function normalizeOptions(options: SwiperOptions = {}): ResolvedSwiperOptions {
|
|
294
|
+
const props = resolveProps(
|
|
295
|
+
options,
|
|
296
|
+
SWIPER_OPTIONS_SCHEMA,
|
|
297
|
+
'Swiper.options'
|
|
298
|
+
) as ResolvedSwiperOptions;
|
|
299
|
+
return {
|
|
300
|
+
...props,
|
|
301
|
+
className: { ...props.className },
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function resolveSwiperRoot(container: Element): HTMLElement {
|
|
306
|
+
const roots = all<HTMLElement>('[data-swiper="root"]', container);
|
|
111
307
|
validateParam(
|
|
112
308
|
'container',
|
|
113
309
|
roots,
|
|
114
310
|
{
|
|
115
|
-
validate: (value) => value.length === 1,
|
|
116
|
-
message: 'expects exactly one
|
|
311
|
+
validate: (value: unknown) => Array.isArray(value) && value.length === 1,
|
|
312
|
+
message: 'expects exactly one [data-swiper="root"] descendant.',
|
|
117
313
|
},
|
|
118
314
|
'Swiper'
|
|
119
315
|
);
|
|
120
|
-
return roots[0];
|
|
316
|
+
return roots[0] as HTMLElement;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function classList(...tokens: Array<string | null | undefined>): string {
|
|
320
|
+
return tokens.filter(Boolean).join(' ');
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function setDataMarker(element: Element, name: string, value = ''): void {
|
|
324
|
+
element.setAttribute(name, value);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function isObjectPatch(value: unknown): value is SwiperOptions {
|
|
328
|
+
return isPlainObject(value);
|
|
121
329
|
}
|
|
122
330
|
|
|
123
331
|
/**
|
|
@@ -126,18 +334,26 @@ function resolveSwiperRoot(container) {
|
|
|
126
334
|
* 支持链接 slide、图片 lazyload、分页、导航、loop 和桌面/移动端拖拽滑动。
|
|
127
335
|
* 使用 vanilla-signal 响应式管理 pagination 和 navigation 状态。
|
|
128
336
|
*/
|
|
129
|
-
export class Swiper extends Component
|
|
337
|
+
export class Swiper extends Component<
|
|
338
|
+
ResolvedSwiperOptions,
|
|
339
|
+
SwiperState,
|
|
340
|
+
SwiperDOM
|
|
341
|
+
> {
|
|
342
|
+
declare props: ResolvedSwiperOptions;
|
|
343
|
+
declare state: SwiperState;
|
|
344
|
+
declare dom: SwiperDOM;
|
|
345
|
+
declare runtime: SwiperRuntime;
|
|
346
|
+
declare cleanup: Component['cleanup'] & SwiperCleanupExtras;
|
|
347
|
+
|
|
348
|
+
private _built: boolean;
|
|
349
|
+
|
|
130
350
|
/**
|
|
131
351
|
* 创建轮播实例。
|
|
132
352
|
* @param {Element|Node|string|Array} container 挂载容器、选择器或 JSX/h 返回节点。
|
|
133
353
|
* @param {object} [options={}] Swiper 配置。
|
|
134
354
|
*/
|
|
135
|
-
constructor(container, options = {}) {
|
|
136
|
-
const resolvedOptions =
|
|
137
|
-
options,
|
|
138
|
-
SWIPER_OPTIONS_SCHEMA,
|
|
139
|
-
'Swiper.options'
|
|
140
|
-
);
|
|
355
|
+
constructor(container: DOMReference, options: SwiperOptions = {}) {
|
|
356
|
+
const resolvedOptions = normalizeOptions(options);
|
|
141
357
|
|
|
142
358
|
super(resolvedOptions);
|
|
143
359
|
|
|
@@ -181,13 +397,11 @@ export class Swiper extends Component {
|
|
|
181
397
|
* 构建或绑定 Swiper DOM。
|
|
182
398
|
* @returns {Swiper} 当前实例。
|
|
183
399
|
*/
|
|
184
|
-
build() {
|
|
400
|
+
build(): this {
|
|
185
401
|
if (this.runtime.destroyed)
|
|
186
402
|
throw new Error('Swiper.build: instance destroyed');
|
|
187
403
|
if (this._built) return this;
|
|
188
404
|
|
|
189
|
-
requireRenderDOM('Swiper');
|
|
190
|
-
|
|
191
405
|
const hasData = Array.isArray(this.props.data);
|
|
192
406
|
const root = requireContainer(this.dom.container, 'Swiper');
|
|
193
407
|
|
|
@@ -196,7 +410,10 @@ export class Swiper extends Component {
|
|
|
196
410
|
|
|
197
411
|
if (hasData) {
|
|
198
412
|
mountTarget = root;
|
|
199
|
-
mountRoot = h('div', {
|
|
413
|
+
mountRoot = h('div', {
|
|
414
|
+
className: this.props.className.root,
|
|
415
|
+
'data-swiper': 'root',
|
|
416
|
+
}) as HTMLElement;
|
|
200
417
|
mountTarget.appendChild(mountRoot);
|
|
201
418
|
} else {
|
|
202
419
|
mountRoot = resolveSwiperRoot(root);
|
|
@@ -210,22 +427,34 @@ export class Swiper extends Component {
|
|
|
210
427
|
|
|
211
428
|
const wrapper = hasData
|
|
212
429
|
? this.createDataView(mountRoot, this.props.data)
|
|
213
|
-
: q('
|
|
430
|
+
: q<HTMLElement>('[data-swiper-wrapper]', mountRoot);
|
|
214
431
|
validateParam(
|
|
215
432
|
'wrapper',
|
|
216
433
|
wrapper,
|
|
217
434
|
{
|
|
218
435
|
validate: isElement,
|
|
219
|
-
message: 'expects
|
|
436
|
+
message: 'expects [data-swiper-wrapper] in the root element.',
|
|
220
437
|
},
|
|
221
438
|
'Swiper'
|
|
222
439
|
);
|
|
223
440
|
|
|
224
|
-
this.dom.wrapper = wrapper;
|
|
225
|
-
this.dom.slides = all(
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
441
|
+
this.dom.wrapper = wrapper as HTMLElement;
|
|
442
|
+
this.dom.slides = all<HTMLElement>(
|
|
443
|
+
'[data-swiper-slide]',
|
|
444
|
+
this.dom.wrapper
|
|
445
|
+
);
|
|
446
|
+
this.dom.pagination = q<HTMLElement>(
|
|
447
|
+
'[data-swiper-pagination]',
|
|
448
|
+
mountRoot
|
|
449
|
+
);
|
|
450
|
+
this.dom.prevButton = q<HTMLButtonElement>(
|
|
451
|
+
'[data-action="prev"]',
|
|
452
|
+
mountRoot
|
|
453
|
+
);
|
|
454
|
+
this.dom.nextButton = q<HTMLButtonElement>(
|
|
455
|
+
'[data-action="next"]',
|
|
456
|
+
mountRoot
|
|
457
|
+
);
|
|
229
458
|
this.dom.bullets = [];
|
|
230
459
|
this.dom.createdPagination = false;
|
|
231
460
|
this.dom.createdPrevButton = false;
|
|
@@ -244,47 +473,51 @@ export class Swiper extends Component {
|
|
|
244
473
|
return this;
|
|
245
474
|
}
|
|
246
475
|
|
|
247
|
-
set index(v) {
|
|
476
|
+
set index(v: unknown) {
|
|
248
477
|
this.setState({ index: normalizeNumber(v) });
|
|
249
478
|
}
|
|
250
479
|
|
|
251
|
-
set trackIndex(v) {
|
|
480
|
+
set trackIndex(v: unknown) {
|
|
252
481
|
this.setState({ trackIndex: normalizeNumber(v) });
|
|
253
482
|
}
|
|
254
483
|
|
|
255
|
-
set transform(v) {
|
|
484
|
+
set transform(v: unknown) {
|
|
256
485
|
this.setState({ transform: normalizeNumber(v) });
|
|
257
486
|
}
|
|
258
487
|
|
|
259
|
-
set animating(v) {
|
|
488
|
+
set animating(v: unknown) {
|
|
260
489
|
this.setState({ animating: !!v });
|
|
261
490
|
}
|
|
262
491
|
|
|
263
|
-
set width(v) {
|
|
492
|
+
set width(v: unknown) {
|
|
264
493
|
this.setState({ width: normalizeNumber(v) });
|
|
265
494
|
}
|
|
266
495
|
|
|
267
|
-
get realCount() {
|
|
496
|
+
get realCount(): number {
|
|
268
497
|
if (this.runtime?.destroyed) return 0;
|
|
269
498
|
return this.runtime?.realCount || 0;
|
|
270
499
|
}
|
|
271
500
|
|
|
272
|
-
get realIndex() {
|
|
501
|
+
get realIndex(): number {
|
|
273
502
|
return this.toRealIndex();
|
|
274
503
|
}
|
|
275
504
|
|
|
276
|
-
assertBuilt(method) {
|
|
505
|
+
assertBuilt(method: string): void {
|
|
277
506
|
if (!this._built) {
|
|
278
507
|
throw new Error(`Swiper.${method}: call build() first.`);
|
|
279
508
|
}
|
|
280
509
|
}
|
|
281
510
|
|
|
282
|
-
createDataView(
|
|
511
|
+
createDataView(
|
|
512
|
+
root: HTMLElement,
|
|
513
|
+
data: SwiperDataItem[] | null
|
|
514
|
+
): HTMLElement {
|
|
283
515
|
const items = this.normalizeData(data);
|
|
284
516
|
const wrapper = h('div', {
|
|
285
|
-
className:
|
|
517
|
+
className: this.props.className.wrapper,
|
|
518
|
+
'data-swiper-wrapper': '',
|
|
286
519
|
'aria-live': 'polite',
|
|
287
|
-
});
|
|
520
|
+
}) as HTMLElement;
|
|
288
521
|
root.textContent = '';
|
|
289
522
|
|
|
290
523
|
items.forEach((item, index) => {
|
|
@@ -295,7 +528,9 @@ export class Swiper extends Component {
|
|
|
295
528
|
return wrapper;
|
|
296
529
|
}
|
|
297
530
|
|
|
298
|
-
normalizeData(data) {
|
|
531
|
+
normalizeData(data: SwiperDataItem[] | null): NormalizedSwiperDataItem[] {
|
|
532
|
+
if (!Array.isArray(data)) return [];
|
|
533
|
+
|
|
299
534
|
data.forEach((item, index) => {
|
|
300
535
|
validateParam(
|
|
301
536
|
String(index),
|
|
@@ -305,7 +540,7 @@ export class Swiper extends Component {
|
|
|
305
540
|
);
|
|
306
541
|
});
|
|
307
542
|
|
|
308
|
-
const items = data.map((item, index) => ({
|
|
543
|
+
const items: NormalizedSwiperDataItem[] = data.map((item, index) => ({
|
|
309
544
|
...item,
|
|
310
545
|
blank: item.blank !== false,
|
|
311
546
|
index,
|
|
@@ -320,15 +555,16 @@ export class Swiper extends Component {
|
|
|
320
555
|
});
|
|
321
556
|
}
|
|
322
557
|
|
|
323
|
-
createDataSlide(item, index) {
|
|
558
|
+
createDataSlide(item: NormalizedSwiperDataItem, index: number): HTMLElement {
|
|
324
559
|
const slide = h(item.url ? 'a' : 'div', {
|
|
325
|
-
className:
|
|
560
|
+
className: this.props.className.slide,
|
|
326
561
|
href: item.url || undefined,
|
|
327
562
|
target: item.url ? (item.blank ? '_blank' : '_self') : undefined,
|
|
563
|
+
'data-swiper-slide': String(index),
|
|
328
564
|
'data-swiper-index': String(index),
|
|
329
565
|
role: 'group',
|
|
330
566
|
'aria-label': `Slide ${index + 1}`,
|
|
331
|
-
});
|
|
567
|
+
}) as HTMLElement;
|
|
332
568
|
|
|
333
569
|
if (item.children != null) {
|
|
334
570
|
slide.append(
|
|
@@ -339,10 +575,10 @@ export class Swiper extends Component {
|
|
|
339
575
|
|
|
340
576
|
if (item.image) {
|
|
341
577
|
const img = h('img', {
|
|
342
|
-
className:
|
|
578
|
+
className: this.props.className.image,
|
|
343
579
|
alt: item.title || '',
|
|
344
580
|
loading: 'lazy',
|
|
345
|
-
});
|
|
581
|
+
}) as HTMLImageElement;
|
|
346
582
|
if (this.props.lazyload) img.dataset.lazy = item.image;
|
|
347
583
|
else img.src = item.image;
|
|
348
584
|
slide.appendChild(img);
|
|
@@ -351,16 +587,17 @@ export class Swiper extends Component {
|
|
|
351
587
|
if (item.title) {
|
|
352
588
|
slide.appendChild(
|
|
353
589
|
h('span', {
|
|
354
|
-
className:
|
|
590
|
+
className: this.props.className.title,
|
|
355
591
|
children: item.title,
|
|
356
|
-
})
|
|
592
|
+
}) as HTMLElement
|
|
357
593
|
);
|
|
358
594
|
}
|
|
359
595
|
|
|
360
596
|
return slide;
|
|
361
597
|
}
|
|
362
598
|
|
|
363
|
-
onInit() {
|
|
599
|
+
protected onInit(): void {
|
|
600
|
+
if (!this.dom.root || !this.dom.wrapper) return;
|
|
364
601
|
this.dom.wrapper.setAttribute('aria-live', 'polite');
|
|
365
602
|
this.updateSize();
|
|
366
603
|
|
|
@@ -380,7 +617,7 @@ export class Swiper extends Component {
|
|
|
380
617
|
if (this.props.autoplay) this.play();
|
|
381
618
|
}
|
|
382
619
|
|
|
383
|
-
onDestroy() {
|
|
620
|
+
protected onDestroy(): void {
|
|
384
621
|
this.pause();
|
|
385
622
|
this.clearImageCleanups();
|
|
386
623
|
this.cleanup.events.clear();
|
|
@@ -399,21 +636,27 @@ export class Swiper extends Component {
|
|
|
399
636
|
this._built = false;
|
|
400
637
|
}
|
|
401
638
|
|
|
402
|
-
updateSize() {
|
|
639
|
+
updateSize(): void {
|
|
403
640
|
this.assertBuilt('updateSize');
|
|
641
|
+
if (!this.dom.root) return;
|
|
404
642
|
this.width = this.dom.root.clientWidth || this.dom.root.offsetWidth;
|
|
405
643
|
}
|
|
406
644
|
|
|
407
|
-
refreshSlides() {
|
|
408
|
-
|
|
645
|
+
refreshSlides(): void {
|
|
646
|
+
if (!this.dom.wrapper) return;
|
|
647
|
+
this.dom.slides = all<HTMLElement>('[data-swiper-slide]', this.dom.wrapper);
|
|
409
648
|
this.runtime.realCount = this.dom.slides.filter(
|
|
410
649
|
(slide) => !slide.hasAttribute('data-clone')
|
|
411
650
|
).length;
|
|
412
651
|
}
|
|
413
652
|
|
|
414
|
-
initLoop() {
|
|
415
|
-
|
|
416
|
-
|
|
653
|
+
initLoop(): void {
|
|
654
|
+
if (!this.dom.wrapper || this.dom.slides.length === 0) return;
|
|
655
|
+
|
|
656
|
+
const first = this.dom.slides[0].cloneNode(true) as HTMLElement;
|
|
657
|
+
const last = this.dom.slides[this.dom.slides.length - 1].cloneNode(
|
|
658
|
+
true
|
|
659
|
+
) as HTMLElement;
|
|
417
660
|
|
|
418
661
|
first.setAttribute('data-clone', '');
|
|
419
662
|
last.setAttribute('data-clone', '');
|
|
@@ -425,14 +668,16 @@ export class Swiper extends Component {
|
|
|
425
668
|
this.refreshSlides();
|
|
426
669
|
}
|
|
427
670
|
|
|
428
|
-
setupStyles() {
|
|
671
|
+
setupStyles(): void {
|
|
672
|
+
if (!this.dom.root) return;
|
|
429
673
|
this.dom.root.style.setProperty(
|
|
430
674
|
'--swiper-slide-width',
|
|
431
675
|
`${this.state.width}px`
|
|
432
676
|
);
|
|
433
677
|
}
|
|
434
678
|
|
|
435
|
-
reInitView() {
|
|
679
|
+
reInitView(): void {
|
|
680
|
+
if (!this.dom.wrapper) return;
|
|
436
681
|
this.pause();
|
|
437
682
|
this.clearImageCleanups();
|
|
438
683
|
this.cleanup.bindings?.();
|
|
@@ -465,7 +710,7 @@ export class Swiper extends Component {
|
|
|
465
710
|
if (this.props.autoplay) this.play();
|
|
466
711
|
}
|
|
467
712
|
|
|
468
|
-
clearPagination() {
|
|
713
|
+
clearPagination(): void {
|
|
469
714
|
this.cleanup.bindings?.();
|
|
470
715
|
this.cleanup.bindings = null;
|
|
471
716
|
this.dom.bullets.forEach((_, index) => {
|
|
@@ -482,7 +727,7 @@ export class Swiper extends Component {
|
|
|
482
727
|
}
|
|
483
728
|
}
|
|
484
729
|
|
|
485
|
-
clearNavigation() {
|
|
730
|
+
clearNavigation(): void {
|
|
486
731
|
this.cleanup.navBindings?.();
|
|
487
732
|
this.cleanup.navBindings = null;
|
|
488
733
|
this.cleanup.events.off('nav:prev');
|
|
@@ -499,89 +744,76 @@ export class Swiper extends Component {
|
|
|
499
744
|
}
|
|
500
745
|
}
|
|
501
746
|
|
|
502
|
-
bindEvents() {
|
|
747
|
+
bindEvents(): void {
|
|
748
|
+
const root = this.dom.root;
|
|
749
|
+
const wrapper = this.dom.wrapper;
|
|
750
|
+
if (!root || !wrapper) return;
|
|
751
|
+
|
|
503
752
|
this.cleanup.events.on(
|
|
504
753
|
'touchstart',
|
|
505
|
-
|
|
754
|
+
wrapper,
|
|
506
755
|
'touchstart',
|
|
507
756
|
(event) => {
|
|
508
|
-
|
|
757
|
+
const touchEvent = event as TouchEvent;
|
|
758
|
+
if (touchEvent.touches[0])
|
|
759
|
+
this.onStart(touchEvent.touches[0], touchEvent.target);
|
|
509
760
|
},
|
|
510
761
|
{ passive: true }
|
|
511
762
|
);
|
|
512
763
|
this.cleanup.events.on(
|
|
513
764
|
'touchmove',
|
|
514
|
-
|
|
765
|
+
wrapper,
|
|
515
766
|
'touchmove',
|
|
516
767
|
(event) => {
|
|
517
|
-
|
|
768
|
+
const touchEvent = event as TouchEvent;
|
|
769
|
+
if (touchEvent.touches[0]) this.onMove(touchEvent.touches[0], event);
|
|
518
770
|
},
|
|
519
771
|
{ passive: false }
|
|
520
772
|
);
|
|
521
|
-
this.cleanup.events.on(
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
(
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
);
|
|
530
|
-
this.cleanup.events.on(
|
|
531
|
-
'touchcancel',
|
|
532
|
-
this.dom.wrapper,
|
|
533
|
-
'touchcancel',
|
|
534
|
-
() => {
|
|
535
|
-
this.resetDrag(true);
|
|
536
|
-
}
|
|
537
|
-
);
|
|
773
|
+
this.cleanup.events.on('touchend', wrapper, 'touchend', (event) => {
|
|
774
|
+
const touchEvent = event as TouchEvent;
|
|
775
|
+
if (touchEvent.changedTouches[0])
|
|
776
|
+
this.pushLog(touchEvent.changedTouches[0]);
|
|
777
|
+
this.onEnd();
|
|
778
|
+
});
|
|
779
|
+
this.cleanup.events.on('touchcancel', wrapper, 'touchcancel', () => {
|
|
780
|
+
this.resetDrag(true);
|
|
781
|
+
});
|
|
538
782
|
this.cleanup.events.on('window:touchcancel', window, 'touchcancel', () => {
|
|
539
783
|
this.resetDrag(true);
|
|
540
784
|
});
|
|
541
|
-
this.cleanup.events.on(
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
);
|
|
551
|
-
this.cleanup.events.on(
|
|
552
|
-
'mousemove',
|
|
553
|
-
this.dom.wrapper,
|
|
554
|
-
'mousemove',
|
|
555
|
-
(event) => {
|
|
556
|
-
if (event.buttons === 1) this.onMove(event, event);
|
|
557
|
-
}
|
|
558
|
-
);
|
|
785
|
+
this.cleanup.events.on('mousedown', wrapper, 'mousedown', (event) => {
|
|
786
|
+
const mouseEvent = event as MouseEvent;
|
|
787
|
+
if (mouseEvent.button !== 0) return;
|
|
788
|
+
this.onStart(mouseEvent, mouseEvent.target);
|
|
789
|
+
wrapper.style.cursor = 'grabbing';
|
|
790
|
+
});
|
|
791
|
+
this.cleanup.events.on('mousemove', wrapper, 'mousemove', (event) => {
|
|
792
|
+
const mouseEvent = event as MouseEvent;
|
|
793
|
+
if (mouseEvent.buttons === 1) this.onMove(mouseEvent, event);
|
|
794
|
+
});
|
|
559
795
|
this.cleanup.events.on('window:mousemove', window, 'mousemove', (event) => {
|
|
560
|
-
|
|
561
|
-
|
|
796
|
+
const mouseEvent = event as MouseEvent;
|
|
797
|
+
if (this.runtime.touching && mouseEvent.buttons === 1)
|
|
798
|
+
this.onMove(mouseEvent, event);
|
|
562
799
|
});
|
|
563
|
-
this.cleanup.events.on('mouseup',
|
|
564
|
-
|
|
565
|
-
this.pushLog(event);
|
|
800
|
+
this.cleanup.events.on('mouseup', wrapper, 'mouseup', (event) => {
|
|
801
|
+
wrapper.style.cursor = 'grab';
|
|
802
|
+
this.pushLog(event as MouseEvent);
|
|
566
803
|
this.onEnd();
|
|
567
804
|
});
|
|
568
805
|
this.cleanup.events.on('window:mouseup', window, 'mouseup', (event) => {
|
|
569
806
|
if (!this.runtime.touching) return;
|
|
570
|
-
|
|
571
|
-
this.pushLog(event);
|
|
807
|
+
wrapper.style.cursor = 'grab';
|
|
808
|
+
this.pushLog(event as MouseEvent);
|
|
572
809
|
this.onEnd();
|
|
573
810
|
});
|
|
574
|
-
this.cleanup.events.on(
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
'mouseleave',
|
|
578
|
-
() => {
|
|
579
|
-
this.dom.wrapper.style.cursor = 'grab';
|
|
580
|
-
}
|
|
581
|
-
);
|
|
811
|
+
this.cleanup.events.on('wrapper:mouseleave', wrapper, 'mouseleave', () => {
|
|
812
|
+
wrapper.style.cursor = 'grab';
|
|
813
|
+
});
|
|
582
814
|
this.cleanup.events.on(
|
|
583
815
|
'click',
|
|
584
|
-
|
|
816
|
+
wrapper,
|
|
585
817
|
'click',
|
|
586
818
|
(event) => {
|
|
587
819
|
if (!this.runtime.clickPrevented || !this.props.preventClick) return;
|
|
@@ -591,30 +823,24 @@ export class Swiper extends Component {
|
|
|
591
823
|
},
|
|
592
824
|
{ capture: true }
|
|
593
825
|
);
|
|
594
|
-
this.cleanup.events.on(
|
|
595
|
-
|
|
596
|
-
this.dom.wrapper,
|
|
597
|
-
'dragstart',
|
|
598
|
-
(event) => event.preventDefault()
|
|
826
|
+
this.cleanup.events.on('dragstart', wrapper, 'dragstart', (event) =>
|
|
827
|
+
event.preventDefault()
|
|
599
828
|
);
|
|
600
|
-
this.cleanup.events.on(
|
|
601
|
-
|
|
602
|
-
this.dom.wrapper,
|
|
603
|
-
'transitionend',
|
|
604
|
-
(event) => this.onTransitionEnd(event)
|
|
829
|
+
this.cleanup.events.on('transitionend', wrapper, 'transitionend', (event) =>
|
|
830
|
+
this.onTransitionEnd(event)
|
|
605
831
|
);
|
|
606
832
|
this.cleanup.events.on('window:resize', window, 'resize', () =>
|
|
607
833
|
this.update(null, { force: true })
|
|
608
834
|
);
|
|
609
|
-
this.cleanup.events.on('root:mouseenter',
|
|
835
|
+
this.cleanup.events.on('root:mouseenter', root, 'mouseenter', () =>
|
|
610
836
|
this.pause()
|
|
611
837
|
);
|
|
612
|
-
this.cleanup.events.on('root:mouseleave',
|
|
838
|
+
this.cleanup.events.on('root:mouseleave', root, 'mouseleave', () =>
|
|
613
839
|
this.resume()
|
|
614
840
|
);
|
|
615
841
|
}
|
|
616
842
|
|
|
617
|
-
onStart(point, target = null) {
|
|
843
|
+
onStart(point: SwipePoint, target: EventTarget | null = null): void {
|
|
618
844
|
if (this.state.animating) return;
|
|
619
845
|
|
|
620
846
|
this.runtime.logs = [];
|
|
@@ -626,10 +852,10 @@ export class Swiper extends Component {
|
|
|
626
852
|
this.runtime.clickPrevented = false;
|
|
627
853
|
|
|
628
854
|
this.pause();
|
|
629
|
-
this.dom.wrapper.style.transition = 'none';
|
|
855
|
+
if (this.dom.wrapper) this.dom.wrapper.style.transition = 'none';
|
|
630
856
|
}
|
|
631
857
|
|
|
632
|
-
onMove(point, event) {
|
|
858
|
+
onMove(point: SwipePoint, event: Event): void {
|
|
633
859
|
if (
|
|
634
860
|
!this.runtime.touching ||
|
|
635
861
|
this.runtime.scrolling ||
|
|
@@ -668,7 +894,7 @@ export class Swiper extends Component {
|
|
|
668
894
|
}
|
|
669
895
|
}
|
|
670
896
|
|
|
671
|
-
onEnd() {
|
|
897
|
+
onEnd(): void {
|
|
672
898
|
if (!this.runtime.touching) return;
|
|
673
899
|
|
|
674
900
|
this.runtime.touching = false;
|
|
@@ -706,7 +932,7 @@ export class Swiper extends Component {
|
|
|
706
932
|
this.resume();
|
|
707
933
|
}
|
|
708
934
|
|
|
709
|
-
resetDrag(animate = true) {
|
|
935
|
+
resetDrag(animate = true): void {
|
|
710
936
|
const target =
|
|
711
937
|
this.state.trackIndex === 0
|
|
712
938
|
? 0
|
|
@@ -723,10 +949,12 @@ export class Swiper extends Component {
|
|
|
723
949
|
this.resume();
|
|
724
950
|
}
|
|
725
951
|
|
|
726
|
-
onTransitionEnd(event) {
|
|
952
|
+
onTransitionEnd(event?: Event): void {
|
|
727
953
|
if (
|
|
728
954
|
event &&
|
|
729
|
-
(event.target !== this.dom.wrapper ||
|
|
955
|
+
(event.target !== this.dom.wrapper ||
|
|
956
|
+
!('propertyName' in event) ||
|
|
957
|
+
event.propertyName !== 'transform')
|
|
730
958
|
)
|
|
731
959
|
return;
|
|
732
960
|
|
|
@@ -743,7 +971,7 @@ export class Swiper extends Component {
|
|
|
743
971
|
}
|
|
744
972
|
}
|
|
745
973
|
|
|
746
|
-
pushLog(point) {
|
|
974
|
+
pushLog(point: SwipePoint): void {
|
|
747
975
|
this.runtime.logs.push({
|
|
748
976
|
x: point.pageX ?? point.clientX ?? 0,
|
|
749
977
|
y: point.pageY ?? point.clientY ?? 0,
|
|
@@ -752,7 +980,7 @@ export class Swiper extends Component {
|
|
|
752
980
|
if (this.runtime.logs.length > 5) this.runtime.logs.shift();
|
|
753
981
|
}
|
|
754
982
|
|
|
755
|
-
getDuration() {
|
|
983
|
+
getDuration(): number {
|
|
756
984
|
if (this.runtime.logs.length === 0) return 0;
|
|
757
985
|
return (
|
|
758
986
|
this.runtime.logs[this.runtime.logs.length - 1].time -
|
|
@@ -760,14 +988,14 @@ export class Swiper extends Component {
|
|
|
760
988
|
);
|
|
761
989
|
}
|
|
762
990
|
|
|
763
|
-
getOffset() {
|
|
991
|
+
getOffset(): { x: number; y: number } {
|
|
764
992
|
if (this.runtime.logs.length === 0) return { x: 0, y: 0 };
|
|
765
993
|
const first = this.runtime.logs[0];
|
|
766
994
|
const last = this.runtime.logs[this.runtime.logs.length - 1];
|
|
767
995
|
return { x: last.x - first.x, y: last.y - first.y };
|
|
768
996
|
}
|
|
769
997
|
|
|
770
|
-
toRealIndex(index = this.state.trackIndex) {
|
|
998
|
+
toRealIndex(index = this.state.trackIndex): number {
|
|
771
999
|
if (!this.realCount) return 0;
|
|
772
1000
|
if (!this.props.loop) return index;
|
|
773
1001
|
if (index === 0) return this.realCount - 1;
|
|
@@ -775,13 +1003,13 @@ export class Swiper extends Component {
|
|
|
775
1003
|
return index - 1;
|
|
776
1004
|
}
|
|
777
1005
|
|
|
778
|
-
trackIndexForRealIndex(index) {
|
|
1006
|
+
trackIndexForRealIndex(index: number): number {
|
|
779
1007
|
if (!this.realCount) return 0;
|
|
780
1008
|
const target = Math.max(0, Math.min(index, this.realCount - 1));
|
|
781
1009
|
return this.props.loop && this.realCount > 1 ? target + 1 : target;
|
|
782
1010
|
}
|
|
783
1011
|
|
|
784
|
-
setTrackIndex(trackIndex, animate = true) {
|
|
1012
|
+
setTrackIndex(trackIndex: number, animate: boolean | null = true): void {
|
|
785
1013
|
const target = normalizeNumber(trackIndex);
|
|
786
1014
|
this.setState({
|
|
787
1015
|
trackIndex: target,
|
|
@@ -791,11 +1019,11 @@ export class Swiper extends Component {
|
|
|
791
1019
|
if (animate != null) this.render(animate);
|
|
792
1020
|
}
|
|
793
1021
|
|
|
794
|
-
slideTo(index) {
|
|
1022
|
+
slideTo(index: number): void {
|
|
795
1023
|
return this.slideToTrack(this.trackIndexForRealIndex(index));
|
|
796
1024
|
}
|
|
797
1025
|
|
|
798
|
-
slideToTrack(idx) {
|
|
1026
|
+
slideToTrack(idx: number): void {
|
|
799
1027
|
this.assertBuilt('slideToTrack');
|
|
800
1028
|
if (this.state.animating) return;
|
|
801
1029
|
if (this.dom.slides.length === 0) return;
|
|
@@ -815,20 +1043,21 @@ export class Swiper extends Component {
|
|
|
815
1043
|
if (this.props.lazyload) this.loadImages();
|
|
816
1044
|
}
|
|
817
1045
|
|
|
818
|
-
next() {
|
|
1046
|
+
next(): void {
|
|
819
1047
|
this.assertBuilt('next');
|
|
820
1048
|
if (this.state.animating) return;
|
|
821
1049
|
this.slideToTrack(this.state.trackIndex + 1);
|
|
822
1050
|
}
|
|
823
1051
|
|
|
824
|
-
prev() {
|
|
1052
|
+
prev(): void {
|
|
825
1053
|
this.assertBuilt('prev');
|
|
826
1054
|
if (this.state.animating) return;
|
|
827
1055
|
this.slideToTrack(this.state.trackIndex - 1);
|
|
828
1056
|
}
|
|
829
1057
|
|
|
830
|
-
render(animate) {
|
|
1058
|
+
render(animate: boolean): void {
|
|
831
1059
|
this.assertBuilt('render');
|
|
1060
|
+
if (!this.dom.wrapper) return;
|
|
832
1061
|
if (animate) {
|
|
833
1062
|
this.dom.wrapper.style.transition = `transform ${this.props.speed}ms cubic-bezier(0.25, 0.46, 0.45, 0.94)`;
|
|
834
1063
|
this.animating = true;
|
|
@@ -840,7 +1069,7 @@ export class Swiper extends Component {
|
|
|
840
1069
|
this.dom.wrapper.style.transform = `translate3d(${this.state.transform}px, 0, 0)`;
|
|
841
1070
|
}
|
|
842
1071
|
|
|
843
|
-
loadImages() {
|
|
1072
|
+
loadImages(): void {
|
|
844
1073
|
this.assertBuilt('loadImages');
|
|
845
1074
|
const indices = [this.state.trackIndex];
|
|
846
1075
|
if (this.state.trackIndex > 0) indices.push(this.state.trackIndex - 1);
|
|
@@ -851,11 +1080,11 @@ export class Swiper extends Component {
|
|
|
851
1080
|
const slide = this.dom.slides[index];
|
|
852
1081
|
if (!slide) return;
|
|
853
1082
|
|
|
854
|
-
const img = q('img[data-lazy]', slide);
|
|
1083
|
+
const img = q<HTMLImageElement>('img[data-lazy]', slide);
|
|
855
1084
|
if (!img || img.src) return;
|
|
856
1085
|
|
|
857
|
-
img.classList.add(
|
|
858
|
-
img.src = img.dataset.lazy;
|
|
1086
|
+
img.classList.add(this.props.className.loading);
|
|
1087
|
+
img.src = img.dataset.lazy || '';
|
|
859
1088
|
const cleanup = () => {
|
|
860
1089
|
img.onload = null;
|
|
861
1090
|
img.onerror = null;
|
|
@@ -863,47 +1092,63 @@ export class Swiper extends Component {
|
|
|
863
1092
|
};
|
|
864
1093
|
this.runtime.imageCleanups.add(cleanup);
|
|
865
1094
|
img.onload = () => {
|
|
866
|
-
img.classList.remove(
|
|
867
|
-
img.classList.add(
|
|
1095
|
+
img.classList.remove(this.props.className.loading);
|
|
1096
|
+
img.classList.add(this.props.className.loaded);
|
|
868
1097
|
cleanup();
|
|
869
1098
|
};
|
|
870
1099
|
img.onerror = () => {
|
|
871
|
-
img.classList.remove(
|
|
872
|
-
img.classList.add(
|
|
1100
|
+
img.classList.remove(this.props.className.loading);
|
|
1101
|
+
img.classList.add(this.props.className.error);
|
|
873
1102
|
cleanup();
|
|
874
1103
|
};
|
|
875
1104
|
});
|
|
876
1105
|
}
|
|
877
1106
|
|
|
878
|
-
clearImageCleanups() {
|
|
1107
|
+
clearImageCleanups(): void {
|
|
879
1108
|
this.runtime.imageCleanups?.forEach((cleanup) => cleanup());
|
|
880
1109
|
this.runtime.imageCleanups?.clear();
|
|
881
1110
|
}
|
|
882
1111
|
|
|
883
|
-
initPagination() {
|
|
1112
|
+
initPagination(): void {
|
|
1113
|
+
if (!this.dom.root) return;
|
|
1114
|
+
|
|
884
1115
|
if (!this.dom.pagination) {
|
|
885
1116
|
this.dom.pagination = h('div', {
|
|
886
|
-
className:
|
|
887
|
-
|
|
1117
|
+
className: classList(
|
|
1118
|
+
this.props.className.pagination,
|
|
1119
|
+
this.props.className.paginationHorizontal,
|
|
1120
|
+
this.props.className.paginationClickable,
|
|
1121
|
+
this.props.className.paginationBulletGroup
|
|
1122
|
+
),
|
|
1123
|
+
'data-swiper-pagination': '',
|
|
1124
|
+
}) as HTMLElement;
|
|
888
1125
|
this.dom.root.appendChild(this.dom.pagination);
|
|
889
1126
|
this.dom.createdPagination = true;
|
|
890
1127
|
} else {
|
|
891
1128
|
this.dom.pagination.classList.add(
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
1129
|
+
this.props.className.paginationHorizontal,
|
|
1130
|
+
this.props.className.paginationClickable,
|
|
1131
|
+
this.props.className.paginationBulletGroup
|
|
895
1132
|
);
|
|
1133
|
+
setDataMarker(this.dom.pagination, 'data-swiper-pagination');
|
|
896
1134
|
}
|
|
897
1135
|
|
|
898
|
-
this.dom.pagination
|
|
1136
|
+
const pagination = this.dom.pagination;
|
|
1137
|
+
if (!pagination) return;
|
|
1138
|
+
|
|
1139
|
+
pagination.textContent = '';
|
|
899
1140
|
this.dom.bullets = [];
|
|
900
1141
|
|
|
901
1142
|
for (let index = 0; index < this.realCount; index++) {
|
|
902
1143
|
const bullet = h('button', {
|
|
903
1144
|
type: 'button',
|
|
904
|
-
className:
|
|
1145
|
+
className: classList(
|
|
1146
|
+
this.props.className.indicator,
|
|
1147
|
+
this.props.className.bullet
|
|
1148
|
+
),
|
|
1149
|
+
'data-swiper-bullet': String(index),
|
|
905
1150
|
'aria-label': `Go to slide ${index + 1}`,
|
|
906
|
-
});
|
|
1151
|
+
}) as HTMLButtonElement;
|
|
907
1152
|
this.cleanup.events.on(`bullet:${index}:click`, bullet, 'click', () => {
|
|
908
1153
|
this.slideTo(index);
|
|
909
1154
|
});
|
|
@@ -912,18 +1157,22 @@ export class Swiper extends Component {
|
|
|
912
1157
|
bullet,
|
|
913
1158
|
'keydown',
|
|
914
1159
|
(event) => {
|
|
915
|
-
|
|
1160
|
+
const keyboardEvent = event as KeyboardEvent;
|
|
1161
|
+
if (keyboardEvent.key !== 'Enter' && keyboardEvent.key !== ' ')
|
|
1162
|
+
return;
|
|
916
1163
|
event.preventDefault();
|
|
917
1164
|
this.slideTo(index);
|
|
918
1165
|
}
|
|
919
1166
|
);
|
|
920
1167
|
this.dom.bullets.push(bullet);
|
|
921
|
-
|
|
1168
|
+
pagination.appendChild(bullet);
|
|
922
1169
|
}
|
|
923
1170
|
|
|
924
1171
|
this.cleanup.bindings = createRoot((dispose) => {
|
|
925
1172
|
this.dom.bullets.forEach((bullet, i) => {
|
|
926
|
-
bindClass(bullet,
|
|
1173
|
+
bindClass(bullet, this.props.className.active, () => {
|
|
1174
|
+
return this.state.index === i;
|
|
1175
|
+
});
|
|
927
1176
|
bindAttr(bullet, 'aria-current', () =>
|
|
928
1177
|
this.state.index === i ? 'true' : null
|
|
929
1178
|
);
|
|
@@ -932,33 +1181,31 @@ export class Swiper extends Component {
|
|
|
932
1181
|
});
|
|
933
1182
|
}
|
|
934
1183
|
|
|
935
|
-
initNavigation() {
|
|
936
|
-
|
|
937
|
-
|
|
1184
|
+
initNavigation(): void {
|
|
1185
|
+
const prevButton = this.ensureNavigation('prev', 'arrow-left');
|
|
1186
|
+
const nextButton = this.ensureNavigation('next', 'arrow-right');
|
|
1187
|
+
this.dom.prevButton = prevButton;
|
|
1188
|
+
this.dom.nextButton = nextButton;
|
|
938
1189
|
|
|
939
|
-
this.cleanup.events.on('nav:prev',
|
|
940
|
-
|
|
941
|
-
);
|
|
942
|
-
this.cleanup.events.on('nav:next', this.dom.nextButton, 'click', () =>
|
|
943
|
-
this.next()
|
|
944
|
-
);
|
|
1190
|
+
this.cleanup.events.on('nav:prev', prevButton, 'click', () => this.prev());
|
|
1191
|
+
this.cleanup.events.on('nav:next', nextButton, 'click', () => this.next());
|
|
945
1192
|
|
|
946
1193
|
if (!this.props.loop) {
|
|
947
1194
|
this.cleanup.navBindings = createRoot((dispose) => {
|
|
948
1195
|
bindClass(
|
|
949
|
-
|
|
950
|
-
|
|
1196
|
+
prevButton,
|
|
1197
|
+
this.props.className.disabled,
|
|
951
1198
|
() => this.state.trackIndex <= 0
|
|
952
1199
|
);
|
|
953
|
-
bindAttr(
|
|
1200
|
+
bindAttr(prevButton, 'disabled', () =>
|
|
954
1201
|
this.state.trackIndex <= 0 ? '' : null
|
|
955
1202
|
);
|
|
956
1203
|
bindClass(
|
|
957
|
-
|
|
958
|
-
|
|
1204
|
+
nextButton,
|
|
1205
|
+
this.props.className.disabled,
|
|
959
1206
|
() => this.state.trackIndex >= this.dom.slides.length - 1
|
|
960
1207
|
);
|
|
961
|
-
bindAttr(
|
|
1208
|
+
bindAttr(nextButton, 'disabled', () =>
|
|
962
1209
|
this.state.trackIndex >= this.dom.slides.length - 1 ? '' : null
|
|
963
1210
|
);
|
|
964
1211
|
return dispose;
|
|
@@ -966,27 +1213,53 @@ export class Swiper extends Component {
|
|
|
966
1213
|
}
|
|
967
1214
|
}
|
|
968
1215
|
|
|
969
|
-
ensureNavigation(
|
|
970
|
-
|
|
1216
|
+
ensureNavigation(
|
|
1217
|
+
direction: SwiperDirection,
|
|
1218
|
+
iconName: 'arrow-left' | 'arrow-right'
|
|
1219
|
+
): HTMLButtonElement {
|
|
1220
|
+
if (!this.dom.root) {
|
|
1221
|
+
throw new Error('Swiper.ensureNavigation: root not found.');
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
const key: CreatedNavigationKey =
|
|
971
1225
|
direction === 'prev' ? 'createdPrevButton' : 'createdNextButton';
|
|
972
|
-
const
|
|
973
|
-
|
|
1226
|
+
const directionClass =
|
|
1227
|
+
direction === 'prev'
|
|
1228
|
+
? this.props.className.prev
|
|
1229
|
+
: this.props.className.next;
|
|
1230
|
+
const className = classList(
|
|
1231
|
+
this.props.className.navigation,
|
|
1232
|
+
directionClass
|
|
1233
|
+
);
|
|
1234
|
+
let button = q<HTMLButtonElement>(
|
|
1235
|
+
`[data-action="${direction}"]`,
|
|
1236
|
+
this.dom.root
|
|
1237
|
+
);
|
|
974
1238
|
|
|
975
1239
|
if (!button) {
|
|
976
|
-
button = h('button', {
|
|
1240
|
+
button = h('button', {
|
|
1241
|
+
type: 'button',
|
|
1242
|
+
className,
|
|
1243
|
+
'data-action': direction,
|
|
1244
|
+
'data-swiper-navigation': direction,
|
|
1245
|
+
}) as HTMLButtonElement;
|
|
977
1246
|
this.dom.root.appendChild(button);
|
|
978
1247
|
this.dom[key] = true;
|
|
979
|
-
} else if (
|
|
1248
|
+
} else if (button.tagName.toLowerCase() !== 'button') {
|
|
980
1249
|
button.setAttribute('role', 'button');
|
|
981
1250
|
button.setAttribute('tabindex', '0');
|
|
982
|
-
button.classList.add(
|
|
1251
|
+
button.classList.add(this.props.className.navigation, directionClass);
|
|
1252
|
+
setDataMarker(button, 'data-swiper-navigation', direction);
|
|
1253
|
+
} else {
|
|
1254
|
+
button.classList.add(this.props.className.navigation, directionClass);
|
|
1255
|
+
setDataMarker(button, 'data-swiper-navigation', direction);
|
|
983
1256
|
}
|
|
984
1257
|
|
|
985
1258
|
button.setAttribute(
|
|
986
1259
|
'aria-label',
|
|
987
1260
|
direction === 'prev' ? 'Previous slide' : 'Next slide'
|
|
988
1261
|
);
|
|
989
|
-
if (!
|
|
1262
|
+
if (!q('svg', button)) {
|
|
990
1263
|
button.textContent = '';
|
|
991
1264
|
button.appendChild(icon(iconName));
|
|
992
1265
|
}
|
|
@@ -994,7 +1267,7 @@ export class Swiper extends Component {
|
|
|
994
1267
|
return button;
|
|
995
1268
|
}
|
|
996
1269
|
|
|
997
|
-
play() {
|
|
1270
|
+
play(): void {
|
|
998
1271
|
this.assertBuilt('play');
|
|
999
1272
|
if (this.runtime.destroyed || this.runtime.timer) return;
|
|
1000
1273
|
if (this.realCount <= 1) return;
|
|
@@ -1002,40 +1275,37 @@ export class Swiper extends Component {
|
|
|
1002
1275
|
this.runtime.timer = setInterval(() => this.next(), delay);
|
|
1003
1276
|
}
|
|
1004
1277
|
|
|
1005
|
-
pause() {
|
|
1278
|
+
pause(): void {
|
|
1006
1279
|
if (!this.runtime.timer) return;
|
|
1007
1280
|
clearInterval(this.runtime.timer);
|
|
1008
1281
|
this.runtime.timer = null;
|
|
1009
1282
|
}
|
|
1010
1283
|
|
|
1011
|
-
resume() {
|
|
1284
|
+
resume(): void {
|
|
1012
1285
|
if (this.runtime.destroyed) return;
|
|
1013
1286
|
if (this.props.autoplay && !this.runtime.timer) this.play();
|
|
1014
1287
|
}
|
|
1015
1288
|
|
|
1016
|
-
restartAutoplay() {
|
|
1289
|
+
restartAutoplay(): void {
|
|
1017
1290
|
this.pause();
|
|
1018
1291
|
if (this.props.autoplay) this.play();
|
|
1019
1292
|
}
|
|
1020
1293
|
|
|
1021
|
-
update(
|
|
1294
|
+
update(
|
|
1295
|
+
propsPatch: SwiperOptions | null | undefined = {},
|
|
1296
|
+
{ force = false }: SwiperUpdateOptions = {}
|
|
1297
|
+
): this {
|
|
1022
1298
|
if (this.runtime.destroyed)
|
|
1023
1299
|
throw new Error('Component.update: instance destroyed');
|
|
1024
1300
|
this.assertBuilt('update');
|
|
1025
1301
|
|
|
1026
|
-
const patch =
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
: {};
|
|
1030
|
-
const nextProps = resolveProps(
|
|
1031
|
-
Object.assign({}, this.props, patch),
|
|
1032
|
-
SWIPER_OPTIONS_SCHEMA,
|
|
1033
|
-
'Swiper.options'
|
|
1034
|
-
);
|
|
1035
|
-
const normalizedPatch = {};
|
|
1302
|
+
const patch = isObjectPatch(propsPatch) ? propsPatch : {};
|
|
1303
|
+
const nextProps = normalizeOptions(Object.assign({}, this.props, patch));
|
|
1304
|
+
const normalizedPatch: Partial<ResolvedSwiperOptions> = {};
|
|
1036
1305
|
|
|
1037
1306
|
Object.keys(patch).forEach((key) => {
|
|
1038
|
-
|
|
1307
|
+
const propKey = key as keyof ResolvedSwiperOptions;
|
|
1308
|
+
normalizedPatch[propKey] = nextProps[propKey];
|
|
1039
1309
|
});
|
|
1040
1310
|
|
|
1041
1311
|
this.props = nextProps;
|
|
@@ -1045,7 +1315,10 @@ export class Swiper extends Component {
|
|
|
1045
1315
|
return this;
|
|
1046
1316
|
}
|
|
1047
1317
|
|
|
1048
|
-
onUpdate(
|
|
1318
|
+
protected onUpdate(
|
|
1319
|
+
propsPatch: Partial<ResolvedSwiperOptions> | null | undefined = {},
|
|
1320
|
+
_options: Required<ComponentUpdateOptions> = { force: false }
|
|
1321
|
+
): void {
|
|
1049
1322
|
if (
|
|
1050
1323
|
propsPatch &&
|
|
1051
1324
|
Object.prototype.hasOwnProperty.call(propsPatch, 'data')
|
|
@@ -1076,7 +1349,7 @@ export class Swiper extends Component {
|
|
|
1076
1349
|
else this.pause();
|
|
1077
1350
|
}
|
|
1078
1351
|
|
|
1079
|
-
updateData(data = this.props.data) {
|
|
1352
|
+
updateData(data: SwiperDataItem[] | null = this.props.data): this {
|
|
1080
1353
|
if (this.runtime.destroyed)
|
|
1081
1354
|
throw new Error('Swiper.updateData: instance destroyed');
|
|
1082
1355
|
this.assertBuilt('updateData');
|
|
@@ -1094,6 +1367,8 @@ export class Swiper extends Component {
|
|
|
1094
1367
|
|
|
1095
1368
|
this.props.data = data;
|
|
1096
1369
|
const realIndex = this.state.index;
|
|
1370
|
+
const wrapper = this.dom.wrapper;
|
|
1371
|
+
if (!wrapper) return this;
|
|
1097
1372
|
|
|
1098
1373
|
this.pause();
|
|
1099
1374
|
this.clearImageCleanups();
|
|
@@ -1104,9 +1379,9 @@ export class Swiper extends Component {
|
|
|
1104
1379
|
this.cleanup.events.clear();
|
|
1105
1380
|
|
|
1106
1381
|
const items = this.normalizeData(data);
|
|
1107
|
-
|
|
1382
|
+
wrapper.textContent = '';
|
|
1108
1383
|
items.forEach((item, index) => {
|
|
1109
|
-
|
|
1384
|
+
wrapper.appendChild(this.createDataSlide(item, index));
|
|
1110
1385
|
});
|
|
1111
1386
|
this.refreshSlides();
|
|
1112
1387
|
this.runtime.realCount = this.dom.slides.length;
|
|
@@ -1118,6 +1393,9 @@ export class Swiper extends Component {
|
|
|
1118
1393
|
}
|
|
1119
1394
|
}
|
|
1120
1395
|
|
|
1121
|
-
export function createSwiper(
|
|
1122
|
-
|
|
1396
|
+
export function createSwiper(
|
|
1397
|
+
container: DOMReference,
|
|
1398
|
+
input: SwiperOptions = {}
|
|
1399
|
+
): Swiper {
|
|
1400
|
+
return new Swiper(container, input);
|
|
1123
1401
|
}
|