@dodlhuat/basix 1.3.3 → 1.3.5
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/README.md +78 -12
- package/css/badge.scss +8 -0
- package/css/button.scss +61 -15
- package/css/chips.scss +10 -0
- package/css/colors.scss +4 -0
- package/css/docs.scss +0 -4
- package/css/dropdown.scss +14 -0
- package/css/modal.scss +21 -0
- package/css/sidebar-nav.scss +25 -0
- package/css/style.css +224 -21
- package/css/style.css.map +1 -1
- package/css/style.min.css +1 -1
- package/css/style.min.css.map +1 -1
- package/css/tabs.scss +49 -0
- package/css/typography.scss +36 -7
- package/js/dropdown.d.ts +1 -0
- package/js/dropdown.js +11 -0
- package/js/editor.d.ts +6 -1
- package/js/editor.js +48 -31
- package/js/gallery.d.ts +2 -0
- package/js/gallery.js +22 -2
- package/js/modal.js +1 -1
- package/js/sidebar-nav.d.ts +11 -1
- package/js/sidebar-nav.js +40 -1
- package/package.json +1 -1
package/js/gallery.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { escapeHtml } from './utils.js';
|
|
2
|
+
import { Lightbox } from './lightbox.js';
|
|
2
3
|
/** Infinite-scroll masonry gallery that distributes images across dynamically sized columns. */
|
|
3
4
|
class MasonryGallery {
|
|
4
5
|
container;
|
|
5
6
|
loader;
|
|
6
7
|
options;
|
|
7
8
|
columns = [];
|
|
9
|
+
allImages = [];
|
|
8
10
|
isFetching = false;
|
|
9
11
|
resizeObserver = null;
|
|
10
12
|
abortController = null;
|
|
@@ -21,6 +23,7 @@ class MasonryGallery {
|
|
|
21
23
|
scrollThreshold: options.scrollThreshold ?? 100,
|
|
22
24
|
reload: 2,
|
|
23
25
|
fetchFunction: options.fetchFunction,
|
|
26
|
+
enableLightbox: options.enableLightbox ?? true,
|
|
24
27
|
};
|
|
25
28
|
this.init();
|
|
26
29
|
}
|
|
@@ -38,6 +41,7 @@ class MasonryGallery {
|
|
|
38
41
|
}
|
|
39
42
|
buildColumns(count) {
|
|
40
43
|
this.container.innerHTML = '';
|
|
44
|
+
this.container.classList.add('masonry-container');
|
|
41
45
|
this.columns = [];
|
|
42
46
|
for (let i = 0; i < count; i++) {
|
|
43
47
|
const col = document.createElement('div');
|
|
@@ -111,14 +115,29 @@ class MasonryGallery {
|
|
|
111
115
|
}
|
|
112
116
|
}
|
|
113
117
|
renderImages(imageDataList) {
|
|
118
|
+
const startIndex = this.allImages.length;
|
|
119
|
+
this.allImages.push(...imageDataList);
|
|
114
120
|
// Sort columns by current height so we start filling from the shortest.
|
|
115
121
|
// Then round-robin across them — this avoids the problem where unloaded
|
|
116
122
|
// images (0 height) cause offsetHeight-based distribution to pile all
|
|
117
123
|
// new items into a single column.
|
|
118
124
|
const sorted = [...this.columns].sort((a, b) => a.offsetHeight - b.offsetHeight);
|
|
119
|
-
imageDataList.forEach((data,
|
|
125
|
+
imageDataList.forEach((data, i) => {
|
|
120
126
|
const item = this.createCard(data);
|
|
121
|
-
|
|
127
|
+
if (this.options.enableLightbox) {
|
|
128
|
+
const index = startIndex + i;
|
|
129
|
+
item.addEventListener('click', () => {
|
|
130
|
+
new Lightbox({
|
|
131
|
+
images: this.allImages.map(img => ({
|
|
132
|
+
src: img.src,
|
|
133
|
+
alt: img.title,
|
|
134
|
+
caption: img.desc,
|
|
135
|
+
})),
|
|
136
|
+
startIndex: index,
|
|
137
|
+
}).show();
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
const col = sorted[i % sorted.length];
|
|
122
141
|
col.appendChild(item);
|
|
123
142
|
requestAnimationFrame(() => {
|
|
124
143
|
const img = item.querySelector("img");
|
|
@@ -168,6 +187,7 @@ class MasonryGallery {
|
|
|
168
187
|
this.abortController.abort();
|
|
169
188
|
this.abortController = null;
|
|
170
189
|
}
|
|
190
|
+
this.allImages = [];
|
|
171
191
|
}
|
|
172
192
|
}
|
|
173
193
|
export { MasonryGallery };
|
package/js/modal.js
CHANGED
package/js/sidebar-nav.d.ts
CHANGED
|
@@ -4,16 +4,26 @@ interface SidebarNavOptions {
|
|
|
4
4
|
toggleSelector?: string;
|
|
5
5
|
/** Breakpoint (px) above which the sidebar is always visible. Default: 768 */
|
|
6
6
|
breakpoint?: number;
|
|
7
|
+
/** Minimum horizontal swipe distance (px) to trigger open/close. Default: 60 */
|
|
8
|
+
swipeThreshold?: number;
|
|
9
|
+
/** Width of the left-edge zone (px) that triggers open on swipe-right. Default: 20 */
|
|
10
|
+
swipeEdge?: number;
|
|
7
11
|
}
|
|
8
|
-
/** Collapsible sidebar navigation with backdrop and responsive breakpoint support. */
|
|
12
|
+
/** Collapsible sidebar navigation with backdrop, swipe gestures, and responsive breakpoint support. */
|
|
9
13
|
declare class SidebarNav {
|
|
10
14
|
private nav;
|
|
11
15
|
private backdrop;
|
|
12
16
|
private toggleBtn;
|
|
17
|
+
private closeBtn;
|
|
13
18
|
private opts;
|
|
19
|
+
private _touchStartX;
|
|
20
|
+
private _touchStartY;
|
|
14
21
|
private _onToggle;
|
|
15
22
|
private _onBackdrop;
|
|
16
23
|
private _onResize;
|
|
24
|
+
private _onClose;
|
|
25
|
+
private _onTouchStart;
|
|
26
|
+
private _onTouchEnd;
|
|
17
27
|
constructor(containerOrSelector: string | HTMLElement, options?: SidebarNavOptions);
|
|
18
28
|
open(): void;
|
|
19
29
|
close(): void;
|
package/js/sidebar-nav.js
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
/** Collapsible sidebar navigation with backdrop and responsive breakpoint support. */
|
|
1
|
+
/** Collapsible sidebar navigation with backdrop, swipe gestures, and responsive breakpoint support. */
|
|
2
2
|
class SidebarNav {
|
|
3
3
|
nav;
|
|
4
4
|
backdrop;
|
|
5
5
|
toggleBtn;
|
|
6
|
+
closeBtn = null;
|
|
6
7
|
opts;
|
|
8
|
+
_touchStartX = 0;
|
|
9
|
+
_touchStartY = 0;
|
|
7
10
|
_onToggle;
|
|
8
11
|
_onBackdrop;
|
|
9
12
|
_onResize;
|
|
13
|
+
_onClose;
|
|
14
|
+
_onTouchStart;
|
|
15
|
+
_onTouchEnd;
|
|
10
16
|
constructor(containerOrSelector, options = {}) {
|
|
11
17
|
const container = typeof containerOrSelector === 'string'
|
|
12
18
|
? document.querySelector(containerOrSelector)
|
|
@@ -14,6 +20,8 @@ class SidebarNav {
|
|
|
14
20
|
this.opts = {
|
|
15
21
|
toggleSelector: options.toggleSelector ?? '.sidebar-toggle',
|
|
16
22
|
breakpoint: options.breakpoint ?? 768,
|
|
23
|
+
swipeThreshold: options.swipeThreshold ?? 60,
|
|
24
|
+
swipeEdge: options.swipeEdge ?? 20,
|
|
17
25
|
};
|
|
18
26
|
this.nav = container?.querySelector('.sidebar-nav') ?? null;
|
|
19
27
|
this.backdrop = container?.querySelector('.sidebar-backdrop') ?? null;
|
|
@@ -22,9 +30,36 @@ class SidebarNav {
|
|
|
22
30
|
this._onBackdrop = () => this.close();
|
|
23
31
|
this._onResize = () => { if (window.innerWidth > this.opts.breakpoint)
|
|
24
32
|
this.close(); };
|
|
33
|
+
this._onClose = () => this.close();
|
|
34
|
+
this._onTouchStart = (e) => {
|
|
35
|
+
this._touchStartX = e.touches[0].clientX;
|
|
36
|
+
this._touchStartY = e.touches[0].clientY;
|
|
37
|
+
};
|
|
38
|
+
this._onTouchEnd = (e) => {
|
|
39
|
+
if (window.innerWidth > this.opts.breakpoint)
|
|
40
|
+
return;
|
|
41
|
+
const dx = e.changedTouches[0].clientX - this._touchStartX;
|
|
42
|
+
const dy = e.changedTouches[0].clientY - this._touchStartY;
|
|
43
|
+
if (Math.abs(dx) < Math.abs(dy))
|
|
44
|
+
return;
|
|
45
|
+
if (!this.isOpen() && this._touchStartX <= this.opts.swipeEdge && dx >= this.opts.swipeThreshold) {
|
|
46
|
+
this.open();
|
|
47
|
+
}
|
|
48
|
+
else if (this.isOpen() && dx <= -this.opts.swipeThreshold) {
|
|
49
|
+
this.close();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
25
52
|
this.toggleBtn?.addEventListener('click', this._onToggle);
|
|
26
53
|
this.backdrop?.addEventListener('click', this._onBackdrop);
|
|
27
54
|
window.addEventListener('resize', this._onResize);
|
|
55
|
+
document.addEventListener('touchstart', this._onTouchStart, { passive: true });
|
|
56
|
+
document.addEventListener('touchend', this._onTouchEnd, { passive: true });
|
|
57
|
+
this.closeBtn = document.createElement('button');
|
|
58
|
+
this.closeBtn.className = 'sidebar-close';
|
|
59
|
+
this.closeBtn.setAttribute('aria-label', 'Close navigation');
|
|
60
|
+
this.closeBtn.innerHTML = '<div class="icon icon-close"></div>';
|
|
61
|
+
this.closeBtn.addEventListener('click', this._onClose);
|
|
62
|
+
this.nav?.append(this.closeBtn);
|
|
28
63
|
}
|
|
29
64
|
open() {
|
|
30
65
|
this.nav?.classList.add('is-open');
|
|
@@ -44,6 +79,10 @@ class SidebarNav {
|
|
|
44
79
|
this.toggleBtn?.removeEventListener('click', this._onToggle);
|
|
45
80
|
this.backdrop?.removeEventListener('click', this._onBackdrop);
|
|
46
81
|
window.removeEventListener('resize', this._onResize);
|
|
82
|
+
this.closeBtn?.removeEventListener('click', this._onClose);
|
|
83
|
+
this.closeBtn?.remove();
|
|
84
|
+
document.removeEventListener('touchstart', this._onTouchStart);
|
|
85
|
+
document.removeEventListener('touchend', this._onTouchEnd);
|
|
47
86
|
}
|
|
48
87
|
}
|
|
49
88
|
export { SidebarNav };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dodlhuat/basix",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.5",
|
|
4
4
|
"description": "Basix is intended as a starter for the rapid development of a design. Each design element can be added individually to include only the data required. It is using plain javascript / typescript and therefore is not dependent on any plugin.",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./css/*": "./css/*",
|