vanilla-jui 1.5.11 → 1.5.12
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.js +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/style.css +1 -1
- package/package.json +2 -2
- package/src/components/swiper.ts +104 -30
- package/src/css/content.css +1 -0
- package/src/css/menu.css +7 -6
- package/src/css/table.css +1 -0
- package/src/css/themes/default/menu.css +1 -0
- package/src/css/themes/default/table.css +1 -0
- package/src/css/tokens.css +7 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vanilla-jui",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.12",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A lightweight, reactive, and fully customizable vanilla JS UI library.",
|
|
6
6
|
"keywords": [
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
64
|
"vanilla-create-storage": "^1.0.4",
|
|
65
|
-
"vanilla-signal": "^1.1.
|
|
65
|
+
"vanilla-signal": "^1.1.15",
|
|
66
66
|
"vanilla-signal-i18n": "^1.1.2"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
package/src/components/swiper.ts
CHANGED
|
@@ -75,6 +75,12 @@ interface TrackItem {
|
|
|
75
75
|
key: string;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
interface NormalizedItemCacheEntry {
|
|
79
|
+
item: NormalizedSwiperDataItem;
|
|
80
|
+
keys: string[];
|
|
81
|
+
values: unknown[];
|
|
82
|
+
}
|
|
83
|
+
|
|
78
84
|
export interface SwiperSlideContext {
|
|
79
85
|
swiper: Swiper;
|
|
80
86
|
item: NormalizedSwiperDataItem;
|
|
@@ -291,6 +297,8 @@ export function createSwiper(input: SwiperProps = {}): Swiper {
|
|
|
291
297
|
}) as SwiperState;
|
|
292
298
|
const events = createEventManager();
|
|
293
299
|
const itemKeys = new WeakMap<object, string>();
|
|
300
|
+
const normalizedCache = new Map<string, NormalizedItemCacheEntry>();
|
|
301
|
+
const trackItemCache = new Map<string, TrackItem>();
|
|
294
302
|
const imageCleanups = new Set<() => void>();
|
|
295
303
|
let swiper!: Swiper;
|
|
296
304
|
let wrapper: HTMLElement | null = null;
|
|
@@ -311,9 +319,31 @@ export function createSwiper(input: SwiperProps = {}): Swiper {
|
|
|
311
319
|
if (!itemKeys.has(item)) itemKeys.set(item, randomId());
|
|
312
320
|
return itemKeys.get(item) as string;
|
|
313
321
|
};
|
|
322
|
+
const readItemEntries = (
|
|
323
|
+
item: SwiperDataItem
|
|
324
|
+
): { keys: string[]; values: unknown[] } => {
|
|
325
|
+
const keys = Object.keys(item);
|
|
326
|
+
return {
|
|
327
|
+
keys,
|
|
328
|
+
values: keys.map((key) => item[key]),
|
|
329
|
+
};
|
|
330
|
+
};
|
|
331
|
+
const sameItemEntries = (
|
|
332
|
+
entry: NormalizedItemCacheEntry | undefined,
|
|
333
|
+
keys: string[],
|
|
334
|
+
values: unknown[]
|
|
335
|
+
): boolean => {
|
|
336
|
+
if (!entry || entry.keys.length !== keys.length) return false;
|
|
337
|
+
for (let index = 0; index < keys.length; index += 1) {
|
|
338
|
+
if (entry.keys[index] !== keys[index]) return false;
|
|
339
|
+
if (!Object.is(entry.values[index], values[index])) return false;
|
|
340
|
+
}
|
|
341
|
+
return true;
|
|
342
|
+
};
|
|
314
343
|
const normalizeData = (
|
|
315
344
|
data: SwiperDataItem[]
|
|
316
345
|
): NormalizedSwiperDataItem[] => {
|
|
346
|
+
const activeKeys = new Set<string>();
|
|
317
347
|
const items = data.map((item, index) => {
|
|
318
348
|
validateParam(
|
|
319
349
|
String(index),
|
|
@@ -321,13 +351,26 @@ export function createSwiper(input: SwiperProps = {}): Swiper {
|
|
|
321
351
|
SWIPER_DATA_ITEM_RULE,
|
|
322
352
|
'Swiper.state.data'
|
|
323
353
|
);
|
|
324
|
-
|
|
354
|
+
const key = itemKey(item);
|
|
355
|
+
activeKeys.add(key);
|
|
356
|
+
const { keys, values } = readItemEntries(item);
|
|
357
|
+
const cached = normalizedCache.get(key);
|
|
358
|
+
if (cached && sameItemEntries(cached, keys, values)) {
|
|
359
|
+
cached.item.index = index;
|
|
360
|
+
return cached.item;
|
|
361
|
+
}
|
|
362
|
+
const normalized = {
|
|
325
363
|
...item,
|
|
326
364
|
blank: item.blank !== false,
|
|
327
365
|
index,
|
|
328
|
-
key
|
|
366
|
+
key,
|
|
329
367
|
};
|
|
368
|
+
normalizedCache.set(key, { item: normalized, keys, values });
|
|
369
|
+
return normalized;
|
|
330
370
|
});
|
|
371
|
+
for (const key of normalizedCache.keys()) {
|
|
372
|
+
if (!activeKeys.has(key)) normalizedCache.delete(key);
|
|
373
|
+
}
|
|
331
374
|
if (!items.some((item) => item.sort != null)) return items;
|
|
332
375
|
return items.sort((a, b) => {
|
|
333
376
|
if (a.sort == null && b.sort == null) return a.index - b.index;
|
|
@@ -336,31 +379,47 @@ export function createSwiper(input: SwiperProps = {}): Swiper {
|
|
|
336
379
|
return a.sort - b.sort || a.index - b.index;
|
|
337
380
|
});
|
|
338
381
|
};
|
|
382
|
+
const trackItem = (
|
|
383
|
+
item: NormalizedSwiperDataItem,
|
|
384
|
+
index: number,
|
|
385
|
+
clone: TrackItem['clone']
|
|
386
|
+
): TrackItem => {
|
|
387
|
+
const key =
|
|
388
|
+
clone === null
|
|
389
|
+
? `real:${item.key}:${Boolean(item.url)}`
|
|
390
|
+
: `clone:${clone}:${item.key}:${Boolean(item.url)}`;
|
|
391
|
+
const cached = trackItemCache.get(key);
|
|
392
|
+
if (cached && cached.item === item && cached.clone === clone) {
|
|
393
|
+
cached.index = index;
|
|
394
|
+
return cached;
|
|
395
|
+
}
|
|
396
|
+
const next = { item, index, clone, key } satisfies TrackItem;
|
|
397
|
+
trackItemCache.set(key, next);
|
|
398
|
+
return next;
|
|
399
|
+
};
|
|
339
400
|
const createTrackItems = (items: NormalizedSwiperDataItem[]): TrackItem[] => {
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
index,
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
})
|
|
346
|
-
if (!props.loop || items.length <= 1)
|
|
401
|
+
const activeKeys = new Set<string>();
|
|
402
|
+
const real = items.map((item, index) => {
|
|
403
|
+
const current = trackItem(item, index, null);
|
|
404
|
+
activeKeys.add(current.key);
|
|
405
|
+
return current;
|
|
406
|
+
});
|
|
407
|
+
if (!props.loop || items.length <= 1) {
|
|
408
|
+
for (const key of trackItemCache.keys()) {
|
|
409
|
+
if (!activeKeys.has(key)) trackItemCache.delete(key);
|
|
410
|
+
}
|
|
411
|
+
return real;
|
|
412
|
+
}
|
|
347
413
|
const first = items[0];
|
|
348
414
|
const last = items[items.length - 1];
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
{
|
|
358
|
-
item: first,
|
|
359
|
-
index: 0,
|
|
360
|
-
clone: 'first',
|
|
361
|
-
key: `clone:first:${first.key}:${Boolean(first.url)}`,
|
|
362
|
-
},
|
|
363
|
-
];
|
|
415
|
+
const lastClone = trackItem(last, items.length - 1, 'last');
|
|
416
|
+
const firstClone = trackItem(first, 0, 'first');
|
|
417
|
+
activeKeys.add(lastClone.key);
|
|
418
|
+
activeKeys.add(firstClone.key);
|
|
419
|
+
for (const key of trackItemCache.keys()) {
|
|
420
|
+
if (!activeKeys.has(key)) trackItemCache.delete(key);
|
|
421
|
+
}
|
|
422
|
+
return [lastClone, ...real, firstClone];
|
|
364
423
|
};
|
|
365
424
|
const realCount = (): number => normalizedItems().length;
|
|
366
425
|
const trackCount = (): number => trackItems().length;
|
|
@@ -373,6 +432,10 @@ export function createSwiper(input: SwiperProps = {}): Swiper {
|
|
|
373
432
|
if (index === trackCount() - 1) return 0;
|
|
374
433
|
return index - 1;
|
|
375
434
|
};
|
|
435
|
+
const toRealIndexFromTrackPosition = (index: number): number => {
|
|
436
|
+
if (!props.loop) return Math.max(0, index);
|
|
437
|
+
return toRealIndex(index);
|
|
438
|
+
};
|
|
376
439
|
const trackIndexForRealIndex = (index: number): number => {
|
|
377
440
|
const count = realCount();
|
|
378
441
|
if (!count) return 0;
|
|
@@ -710,11 +773,22 @@ export function createSwiper(input: SwiperProps = {}): Swiper {
|
|
|
710
773
|
});
|
|
711
774
|
};
|
|
712
775
|
|
|
713
|
-
const slideView = (
|
|
776
|
+
const slideView = (
|
|
777
|
+
itemAccessor: () => TrackItem,
|
|
778
|
+
trackIndexAccessor: () => number
|
|
779
|
+
): HTMLElement => {
|
|
780
|
+
const realIndex = (): number =>
|
|
781
|
+
toRealIndexFromTrackPosition(trackIndexAccessor());
|
|
714
782
|
const slideContent = () => {
|
|
715
|
-
const { item
|
|
716
|
-
const context = { swiper, item, index };
|
|
783
|
+
const { item } = itemAccessor();
|
|
717
784
|
if (item.children != null) {
|
|
785
|
+
const context = {
|
|
786
|
+
swiper,
|
|
787
|
+
item,
|
|
788
|
+
get index() {
|
|
789
|
+
return realIndex();
|
|
790
|
+
},
|
|
791
|
+
} as SwiperSlideContext;
|
|
718
792
|
return asRenderable(
|
|
719
793
|
typeof item.children === 'function'
|
|
720
794
|
? item.children(context)
|
|
@@ -742,12 +816,12 @@ export function createSwiper(input: SwiperProps = {}): Swiper {
|
|
|
742
816
|
};
|
|
743
817
|
const commonProps = {
|
|
744
818
|
className: props.className.slide,
|
|
745
|
-
'data-swiper-slide': () => String(
|
|
819
|
+
'data-swiper-slide': () => String(realIndex()),
|
|
746
820
|
'data-swiper-index': () =>
|
|
747
|
-
itemAccessor().clone ? null : String(
|
|
821
|
+
itemAccessor().clone ? null : String(realIndex()),
|
|
748
822
|
'data-clone': () => itemAccessor().clone,
|
|
749
823
|
role: 'group',
|
|
750
|
-
'aria-label': () => `Slide ${
|
|
824
|
+
'aria-label': () => `Slide ${realIndex() + 1}`,
|
|
751
825
|
children: slideContent,
|
|
752
826
|
};
|
|
753
827
|
return itemAccessor().item.url
|
package/src/css/content.css
CHANGED
package/src/css/menu.css
CHANGED
|
@@ -363,6 +363,7 @@
|
|
|
363
363
|
overflow-y: auto;
|
|
364
364
|
scrollbar-width: thin;
|
|
365
365
|
scrollbar-color: var(--ui-border) transparent;
|
|
366
|
+
height: 100%;
|
|
366
367
|
}
|
|
367
368
|
|
|
368
369
|
.j-menu[data-menu-type='mobile'] .menu {
|
|
@@ -416,13 +417,13 @@
|
|
|
416
417
|
width: 100%;
|
|
417
418
|
visibility: hidden;
|
|
418
419
|
opacity: 0;
|
|
419
|
-
transform: translateX(80%);
|
|
420
|
+
/* transform: translateX(80%); */
|
|
420
421
|
transition:
|
|
421
|
-
transform 0.3s ease-in-out,
|
|
422
|
-
opacity 0.3s ease-in-out
|
|
423
|
-
visibility 0.3s ease-in-out;
|
|
422
|
+
/* transform 0.3s ease-in-out, */
|
|
423
|
+
/* visibility 0.3s ease-in-out, */ opacity 0.3s ease-in-out;
|
|
424
424
|
max-width: 100%;
|
|
425
425
|
background: var(--ui-bg);
|
|
426
|
+
padding-block: 0;
|
|
426
427
|
}
|
|
427
428
|
|
|
428
429
|
.j-menu[data-menu-type='mobile'] .menu .sub-menu .menu-item:hover a {
|
|
@@ -440,9 +441,9 @@
|
|
|
440
441
|
> .sub-menu {
|
|
441
442
|
visibility: visible;
|
|
442
443
|
opacity: 1;
|
|
443
|
-
transform: translateX(0);
|
|
444
|
-
height: 100%;
|
|
444
|
+
/* transform: translateX(0); */
|
|
445
445
|
z-index: var(--z-submenu);
|
|
446
|
+
height: 100%;
|
|
446
447
|
}
|
|
447
448
|
|
|
448
449
|
/* bottom menu */
|
package/src/css/table.css
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
--table-border-color: var(--ui-border);
|
|
11
11
|
--table-cell-padding: 0.5em 0.75em;
|
|
12
12
|
--table-cell-text-align: left;
|
|
13
|
+
--table-cell-vertical-align: top;
|
|
13
14
|
--table-link-fg: var(--tone-solid);
|
|
14
15
|
--table-striped-bg: var(--tone-soft);
|
|
15
16
|
--table-hover-bg: var(--tone-soft);
|
package/src/css/tokens.css
CHANGED
|
@@ -1162,13 +1162,13 @@
|
|
|
1162
1162
|
}
|
|
1163
1163
|
|
|
1164
1164
|
.j-radius-round {
|
|
1165
|
-
--radius-2xs:
|
|
1166
|
-
--radius-xs:
|
|
1167
|
-
--radius-sm:
|
|
1168
|
-
--radius-md:
|
|
1169
|
-
--radius-lg:
|
|
1170
|
-
--radius-xl:
|
|
1171
|
-
--radius-2xl:
|
|
1165
|
+
--radius-2xs: 0.375rem;
|
|
1166
|
+
--radius-xs: 0.5rem;
|
|
1167
|
+
--radius-sm: 0.75rem;
|
|
1168
|
+
--radius-md: 1rem;
|
|
1169
|
+
--radius-lg: 999px;
|
|
1170
|
+
--radius-xl: 999px;
|
|
1171
|
+
--radius-2xl: 999px;
|
|
1172
1172
|
}
|
|
1173
1173
|
|
|
1174
1174
|
/* ============================================
|