@delightstack/components 0.1.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/LICENSE +21 -0
- package/README.md +136 -0
- package/SKILL.md +149 -0
- package/bin/agents.js +63 -0
- package/dist/actions/Alert.svelte +202 -0
- package/dist/actions/Alert.svelte.d.ts +36 -0
- package/dist/actions/Alert.svelte.d.ts.map +1 -0
- package/dist/actions/Button.svelte +1450 -0
- package/dist/actions/Button.svelte.d.ts +56 -0
- package/dist/actions/Button.svelte.d.ts.map +1 -0
- package/dist/actions/ButtonGroup.svelte +111 -0
- package/dist/actions/ButtonGroup.svelte.d.ts +41 -0
- package/dist/actions/ButtonGroup.svelte.d.ts.map +1 -0
- package/dist/actions/CommandPalette.svelte +939 -0
- package/dist/actions/CommandPalette.svelte.d.ts +37 -0
- package/dist/actions/CommandPalette.svelte.d.ts.map +1 -0
- package/dist/actions/ContextMenu.svelte +138 -0
- package/dist/actions/ContextMenu.svelte.d.ts +54 -0
- package/dist/actions/ContextMenu.svelte.d.ts.map +1 -0
- package/dist/actions/Modal.svelte +474 -0
- package/dist/actions/Modal.svelte.d.ts +28 -0
- package/dist/actions/Modal.svelte.d.ts.map +1 -0
- package/dist/actions/Popover.svelte +1214 -0
- package/dist/actions/Popover.svelte.d.ts +31 -0
- package/dist/actions/Popover.svelte.d.ts.map +1 -0
- package/dist/actions/Portal.svelte +80 -0
- package/dist/actions/Portal.svelte.d.ts +17 -0
- package/dist/actions/Portal.svelte.d.ts.map +1 -0
- package/dist/actions/ThemeToggle.svelte +345 -0
- package/dist/actions/ThemeToggle.svelte.d.ts +15 -0
- package/dist/actions/ThemeToggle.svelte.d.ts.map +1 -0
- package/dist/actions/index.d.ts +13 -0
- package/dist/actions/index.d.ts.map +1 -0
- package/dist/actions/index.js +10 -0
- package/dist/actions/scrollbar.d.ts +48 -0
- package/dist/actions/scrollbar.d.ts.map +1 -0
- package/dist/actions/scrollbar.js +404 -0
- package/dist/display/Accordion.svelte +586 -0
- package/dist/display/Accordion.svelte.d.ts +41 -0
- package/dist/display/Accordion.svelte.d.ts.map +1 -0
- package/dist/display/Avatar.svelte +527 -0
- package/dist/display/Avatar.svelte.d.ts +22 -0
- package/dist/display/Avatar.svelte.d.ts.map +1 -0
- package/dist/display/AvatarGroup.svelte +298 -0
- package/dist/display/AvatarGroup.svelte.d.ts +31 -0
- package/dist/display/AvatarGroup.svelte.d.ts.map +1 -0
- package/dist/display/Calendar.svelte +1366 -0
- package/dist/display/Calendar.svelte.d.ts +58 -0
- package/dist/display/Calendar.svelte.d.ts.map +1 -0
- package/dist/display/Chart.svelte +1426 -0
- package/dist/display/Chart.svelte.d.ts +35 -0
- package/dist/display/Chart.svelte.d.ts.map +1 -0
- package/dist/display/Code.svelte +780 -0
- package/dist/display/Code.svelte.d.ts +19 -0
- package/dist/display/Code.svelte.d.ts.map +1 -0
- package/dist/display/Comparison.svelte +686 -0
- package/dist/display/Comparison.svelte.d.ts +22 -0
- package/dist/display/Comparison.svelte.d.ts.map +1 -0
- package/dist/display/Counter.svelte +285 -0
- package/dist/display/Counter.svelte.d.ts +21 -0
- package/dist/display/Counter.svelte.d.ts.map +1 -0
- package/dist/display/Expand.svelte +48 -0
- package/dist/display/Expand.svelte.d.ts +9 -0
- package/dist/display/Expand.svelte.d.ts.map +1 -0
- package/dist/display/List.svelte +294 -0
- package/dist/display/List.svelte.d.ts +40 -0
- package/dist/display/List.svelte.d.ts.map +1 -0
- package/dist/display/ListContextReset.svelte +19 -0
- package/dist/display/ListContextReset.svelte.d.ts +7 -0
- package/dist/display/ListContextReset.svelte.d.ts.map +1 -0
- package/dist/display/ListItem.svelte +834 -0
- package/dist/display/ListItem.svelte.d.ts +22 -0
- package/dist/display/ListItem.svelte.d.ts.map +1 -0
- package/dist/display/QR.svelte +1193 -0
- package/dist/display/QR.svelte.d.ts +23 -0
- package/dist/display/QR.svelte.d.ts.map +1 -0
- package/dist/display/SplitPane.svelte +744 -0
- package/dist/display/SplitPane.svelte.d.ts +25 -0
- package/dist/display/SplitPane.svelte.d.ts.map +1 -0
- package/dist/display/Stat.svelte +439 -0
- package/dist/display/Stat.svelte.d.ts +24 -0
- package/dist/display/Stat.svelte.d.ts.map +1 -0
- package/dist/display/Table.svelte +4654 -0
- package/dist/display/Table.svelte.d.ts +249 -0
- package/dist/display/Table.svelte.d.ts.map +1 -0
- package/dist/display/TableCellEditor.svelte +935 -0
- package/dist/display/TableCellEditor.svelte.d.ts +58 -0
- package/dist/display/TableCellEditor.svelte.d.ts.map +1 -0
- package/dist/display/Timeline.svelte +1258 -0
- package/dist/display/Timeline.svelte.d.ts +43 -0
- package/dist/display/Timeline.svelte.d.ts.map +1 -0
- package/dist/display/Tree.svelte +1740 -0
- package/dist/display/Tree.svelte.d.ts +74 -0
- package/dist/display/Tree.svelte.d.ts.map +1 -0
- package/dist/display/Typewriter.svelte +338 -0
- package/dist/display/Typewriter.svelte.d.ts +22 -0
- package/dist/display/Typewriter.svelte.d.ts.map +1 -0
- package/dist/display/index.d.ts +24 -0
- package/dist/display/index.d.ts.map +1 -0
- package/dist/display/index.js +18 -0
- package/dist/feedback/Callout.svelte +529 -0
- package/dist/feedback/Callout.svelte.d.ts +24 -0
- package/dist/feedback/Callout.svelte.d.ts.map +1 -0
- package/dist/feedback/Confetti.svelte +631 -0
- package/dist/feedback/Confetti.svelte.d.ts +90 -0
- package/dist/feedback/Confetti.svelte.d.ts.map +1 -0
- package/dist/feedback/Progress.svelte +382 -0
- package/dist/feedback/Progress.svelte.d.ts +25 -0
- package/dist/feedback/Progress.svelte.d.ts.map +1 -0
- package/dist/feedback/Toast.svelte +967 -0
- package/dist/feedback/Toast.svelte.d.ts +54 -0
- package/dist/feedback/Toast.svelte.d.ts.map +1 -0
- package/dist/feedback/index.d.ts +7 -0
- package/dist/feedback/index.d.ts.map +1 -0
- package/dist/feedback/index.js +4 -0
- package/dist/form/Checkbox.svelte +449 -0
- package/dist/form/Checkbox.svelte.d.ts +27 -0
- package/dist/form/Checkbox.svelte.d.ts.map +1 -0
- package/dist/form/Fieldset.svelte +410 -0
- package/dist/form/Fieldset.svelte.d.ts +22 -0
- package/dist/form/Fieldset.svelte.d.ts.map +1 -0
- package/dist/form/FileUpload.svelte +934 -0
- package/dist/form/FileUpload.svelte.d.ts +41 -0
- package/dist/form/FileUpload.svelte.d.ts.map +1 -0
- package/dist/form/Form.svelte +530 -0
- package/dist/form/Form.svelte.d.ts +120 -0
- package/dist/form/Form.svelte.d.ts.map +1 -0
- package/dist/form/Input.svelte +2858 -0
- package/dist/form/Input.svelte.d.ts +66 -0
- package/dist/form/Input.svelte.d.ts.map +1 -0
- package/dist/form/Radio.svelte +507 -0
- package/dist/form/Radio.svelte.d.ts +39 -0
- package/dist/form/Radio.svelte.d.ts.map +1 -0
- package/dist/form/Range.svelte +912 -0
- package/dist/form/Range.svelte.d.ts +33 -0
- package/dist/form/Range.svelte.d.ts.map +1 -0
- package/dist/form/Rating.svelte +429 -0
- package/dist/form/Rating.svelte.d.ts +28 -0
- package/dist/form/Rating.svelte.d.ts.map +1 -0
- package/dist/form/Select.svelte +1933 -0
- package/dist/form/Select.svelte.d.ts +54 -0
- package/dist/form/Select.svelte.d.ts.map +1 -0
- package/dist/form/Toggle.svelte +645 -0
- package/dist/form/Toggle.svelte.d.ts +50 -0
- package/dist/form/Toggle.svelte.d.ts.map +1 -0
- package/dist/form/index.d.ts +15 -0
- package/dist/form/index.d.ts.map +1 -0
- package/dist/form/index.js +10 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/layout/README.md +172 -0
- package/dist/media/Carousel.svelte +2424 -0
- package/dist/media/Carousel.svelte.d.ts +47 -0
- package/dist/media/Carousel.svelte.d.ts.map +1 -0
- package/dist/media/Gallery.svelte +2881 -0
- package/dist/media/Gallery.svelte.d.ts +82 -0
- package/dist/media/Gallery.svelte.d.ts.map +1 -0
- package/dist/media/Image.svelte +389 -0
- package/dist/media/Image.svelte.d.ts +33 -0
- package/dist/media/Image.svelte.d.ts.map +1 -0
- package/dist/media/PDF.svelte +1793 -0
- package/dist/media/PDF.svelte.d.ts +44 -0
- package/dist/media/PDF.svelte.d.ts.map +1 -0
- package/dist/media/Panorama.svelte +1391 -0
- package/dist/media/Panorama.svelte.d.ts +47 -0
- package/dist/media/Panorama.svelte.d.ts.map +1 -0
- package/dist/media/Video.svelte +2501 -0
- package/dist/media/Video.svelte.d.ts +58 -0
- package/dist/media/Video.svelte.d.ts.map +1 -0
- package/dist/media/carousel.d.ts +211 -0
- package/dist/media/carousel.d.ts.map +1 -0
- package/dist/media/carousel.js +408 -0
- package/dist/media/index.d.ts +11 -0
- package/dist/media/index.d.ts.map +1 -0
- package/dist/media/index.js +5 -0
- package/dist/navigation/BottomSheet.svelte +636 -0
- package/dist/navigation/BottomSheet.svelte.d.ts +27 -0
- package/dist/navigation/BottomSheet.svelte.d.ts.map +1 -0
- package/dist/navigation/Breadcrumbs.svelte +611 -0
- package/dist/navigation/Breadcrumbs.svelte.d.ts +28 -0
- package/dist/navigation/Breadcrumbs.svelte.d.ts.map +1 -0
- package/dist/navigation/Pagination.svelte +641 -0
- package/dist/navigation/Pagination.svelte.d.ts +27 -0
- package/dist/navigation/Pagination.svelte.d.ts.map +1 -0
- package/dist/navigation/Steps.svelte +965 -0
- package/dist/navigation/Steps.svelte.d.ts +43 -0
- package/dist/navigation/Steps.svelte.d.ts.map +1 -0
- package/dist/navigation/Tabs.svelte +698 -0
- package/dist/navigation/Tabs.svelte.d.ts +41 -0
- package/dist/navigation/Tabs.svelte.d.ts.map +1 -0
- package/dist/navigation/index.d.ts +8 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +5 -0
- package/package.json +139 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
import { thumbHashToDataURL } from 'thumbhash';
|
|
2
|
+
// const BACK_OUT_EASTING = 'cubic-bezier(0.34, 1.56, 0.64, 1)';
|
|
3
|
+
const BACK_OUT_EASTING = 'cubic-bezier(0.34, 1.30, 0.55, 1)';
|
|
4
|
+
const DELTA_LINE_MULTIPLIER = 8;
|
|
5
|
+
const DELTA_PAGE_MULTIPLIER = 24;
|
|
6
|
+
const MAX_WHEEL_DELTA = 24;
|
|
7
|
+
/** Returns the centroid center point between all the given points */
|
|
8
|
+
export function center(...points) {
|
|
9
|
+
const x = points.reduce((a, b) => a + b.x, 0) / points.length;
|
|
10
|
+
const y = points.reduce((a, b) => a + b.y, 0) / points.length;
|
|
11
|
+
return { x, y };
|
|
12
|
+
}
|
|
13
|
+
/** Returns the distance between two points. Always a positive number */
|
|
14
|
+
export function distance(pointA, pointB) {
|
|
15
|
+
if (!pointA || !pointB)
|
|
16
|
+
return 0;
|
|
17
|
+
return Math.sqrt((pointA.x - pointB.x) ** 2 + (pointA.y - pointB.y) ** 2);
|
|
18
|
+
}
|
|
19
|
+
/** Calculates the angle between two points (in radians) */
|
|
20
|
+
export function angle(pointA, pointB) {
|
|
21
|
+
if (!pointA || !pointB)
|
|
22
|
+
return 0;
|
|
23
|
+
return (180 / Math.PI) * Math.atan2(pointB.y - pointA.y, pointB.x - pointA.x);
|
|
24
|
+
}
|
|
25
|
+
/** Creates a new DOMMatrix based on the transform string. If force3d, it will ensure the matrix is 3d */
|
|
26
|
+
export function createMatrix(transform, force3d = true) {
|
|
27
|
+
const Matrix = window.WebKitCSSMatrix || window.DOMMatrix;
|
|
28
|
+
if (transform instanceof Matrix)
|
|
29
|
+
return Matrix.fromMatrix(transform);
|
|
30
|
+
if (!force3d)
|
|
31
|
+
return new Matrix(transform || '');
|
|
32
|
+
if (transform) {
|
|
33
|
+
const matrix = new Matrix(transform);
|
|
34
|
+
if (!matrix.is2D)
|
|
35
|
+
return matrix;
|
|
36
|
+
return new Matrix(Array.from(matrix.toFloat32Array()));
|
|
37
|
+
}
|
|
38
|
+
return new Matrix([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
|
|
39
|
+
}
|
|
40
|
+
/** Extracts the x, y, and scale of the given matrix */
|
|
41
|
+
export function extractMatrixTransform(matrix) {
|
|
42
|
+
const scale = Math.hypot(matrix.a, matrix.b);
|
|
43
|
+
return { scale, x: matrix.e / scale, y: matrix.f / scale };
|
|
44
|
+
}
|
|
45
|
+
/** Animates the target element to the given transform matrix. Returns a promise that resolves when complete */
|
|
46
|
+
export async function animateElement(element, options) {
|
|
47
|
+
if (!element)
|
|
48
|
+
return;
|
|
49
|
+
element.getAnimations().forEach((animation) => {
|
|
50
|
+
try {
|
|
51
|
+
animation.commitStyles();
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// ignore
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
const matrix = options?.transform || createMatrix();
|
|
58
|
+
const animation = element.animate([
|
|
59
|
+
{
|
|
60
|
+
transform: typeof matrix === 'string' ? matrix : matrix.toString(),
|
|
61
|
+
...(options?.opacity !== undefined && { opacity: `${options.opacity}` }),
|
|
62
|
+
},
|
|
63
|
+
], {
|
|
64
|
+
direction: 'normal',
|
|
65
|
+
fill: 'both',
|
|
66
|
+
...options,
|
|
67
|
+
duration: options?.duration || 250,
|
|
68
|
+
easing: options?.easing === 'back-out' ? BACK_OUT_EASTING : options?.easing || 'ease-out',
|
|
69
|
+
});
|
|
70
|
+
await animation.finished.catch(() => { });
|
|
71
|
+
try {
|
|
72
|
+
animation.commitStyles();
|
|
73
|
+
animation.finish();
|
|
74
|
+
animation.cancel();
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** Calculates the transform of the pointers based on their relationship to each other */
|
|
81
|
+
export function calcTransform(pointer, pointers, midpoint, prevPointers, prevMidpoint) {
|
|
82
|
+
const prevPointer = prevPointers[pointer.id];
|
|
83
|
+
if (!prevPointer) {
|
|
84
|
+
return {
|
|
85
|
+
scale: 1,
|
|
86
|
+
rotation: 0,
|
|
87
|
+
translateX: 0,
|
|
88
|
+
translateY: 0,
|
|
89
|
+
originX: 0,
|
|
90
|
+
originY: 0,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const prevPointerList = Object.values(prevPointers);
|
|
94
|
+
const pointerList = Object.values(pointers);
|
|
95
|
+
const primary = pointerList.find((p) => p.primary) ||
|
|
96
|
+
[...pointerList].sort((a, b) => a.time - b.time)[0];
|
|
97
|
+
const prevPrimary = prevPointerList.find((p) => p.id === primary.id) ||
|
|
98
|
+
prevPointerList.find((p) => p.primary) ||
|
|
99
|
+
[...prevPointerList].sort((a, b) => a.time - b.time)[0] ||
|
|
100
|
+
primary;
|
|
101
|
+
let scale = 1;
|
|
102
|
+
let rotation = 0;
|
|
103
|
+
if (pointerList.length > 1) {
|
|
104
|
+
const scaleList = pointerList
|
|
105
|
+
.filter((p) => p.id !== primary.id)
|
|
106
|
+
.map((p) => {
|
|
107
|
+
if (!prevPointers[p.id])
|
|
108
|
+
return 1;
|
|
109
|
+
const prevDistance = distance(prevPointers[p.id], prevPrimary);
|
|
110
|
+
if (!prevDistance)
|
|
111
|
+
return 1;
|
|
112
|
+
return distance(p, primary) / prevDistance;
|
|
113
|
+
});
|
|
114
|
+
scale = scaleList.reduce((a, b) => a + b, 0) / (scaleList.length || 1) || 1;
|
|
115
|
+
const rotationList = pointerList.map((p) => !prevPointers[p.id]
|
|
116
|
+
? 1
|
|
117
|
+
: angle(p, primary) - angle(prevPointers[p.id], prevPrimary));
|
|
118
|
+
rotation = rotationList.reduce((a, b) => a + b, 0) / rotationList.length;
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
scale,
|
|
122
|
+
rotation,
|
|
123
|
+
translateX: pointerList.length > 1 && prevMidpoint
|
|
124
|
+
? (midpoint?.x || 0) - (prevMidpoint?.x || 0)
|
|
125
|
+
: prevPointer
|
|
126
|
+
? pointer.x - prevPointer.x
|
|
127
|
+
: 0,
|
|
128
|
+
translateY: pointerList.length > 1 && prevMidpoint
|
|
129
|
+
? (midpoint?.y || 0) - (prevMidpoint?.y || 0)
|
|
130
|
+
: prevPointer
|
|
131
|
+
? pointer.y - prevPointer.y
|
|
132
|
+
: 0,
|
|
133
|
+
originX: prevMidpoint?.x || 0,
|
|
134
|
+
originY: prevMidpoint?.y || 0,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/** Returns the min/max of the x/y position that should be used to ensure the element fits in the bounds */
|
|
138
|
+
export function calcBounds(options) {
|
|
139
|
+
const scale = options?.scale || 1;
|
|
140
|
+
const viewportW = options?.viewportW || window.innerWidth;
|
|
141
|
+
const viewportH = options?.viewportH || window.innerHeight;
|
|
142
|
+
if (scale <= 1) {
|
|
143
|
+
const x = (viewportW * (1 - scale)) / 2;
|
|
144
|
+
const y = (viewportH * (1 - scale)) / 2;
|
|
145
|
+
return { minX: x, maxX: x, minY: y, maxY: y };
|
|
146
|
+
}
|
|
147
|
+
const padding = (options?.padding || 0) / scale;
|
|
148
|
+
const ratio = options?.ratio || 1;
|
|
149
|
+
const viewportRatio = viewportW / (viewportH || 1);
|
|
150
|
+
const imageW = ratio >= viewportRatio ? viewportW : viewportH * ratio;
|
|
151
|
+
const imageH = ratio >= viewportRatio ? viewportW / ratio : viewportH;
|
|
152
|
+
const containerW = viewportW;
|
|
153
|
+
const containerH = viewportH;
|
|
154
|
+
const containerPaddingW = (containerW * scale - imageW * scale) / 2;
|
|
155
|
+
const containerPaddingH = (containerH * scale - imageH * scale) / 2;
|
|
156
|
+
const imagePaddingW = Math.abs(imageW * scale - viewportW);
|
|
157
|
+
const imagePaddingH = Math.abs(imageH * scale - viewportH);
|
|
158
|
+
let minX = (-containerPaddingW - imagePaddingW) / scale - padding;
|
|
159
|
+
let maxX = (imageW - containerW) / 2 + padding;
|
|
160
|
+
let minY = (-containerPaddingH - imagePaddingH) / scale - padding;
|
|
161
|
+
let maxY = (imageH - containerH) / 2 + padding;
|
|
162
|
+
if (imageW * scale < viewportW - padding * 2) {
|
|
163
|
+
minX = (viewportW - containerW * scale) / 2 / scale;
|
|
164
|
+
maxX = minX;
|
|
165
|
+
}
|
|
166
|
+
if (imageH * scale < viewportH - padding * 2) {
|
|
167
|
+
minY = (viewportH - containerH * scale) / 2 / scale;
|
|
168
|
+
maxY = minY;
|
|
169
|
+
}
|
|
170
|
+
return { minX, maxX, minY, maxY };
|
|
171
|
+
}
|
|
172
|
+
/** Calculates the transform matrix that would ensure the image stays in the bounds of the window */
|
|
173
|
+
export function clampMatrix(matrix, options) {
|
|
174
|
+
const { scale, x, y } = extractMatrixTransform(matrix);
|
|
175
|
+
const viewportW = options?.viewportW || window.innerWidth;
|
|
176
|
+
const viewportH = options?.viewportH || window.innerHeight;
|
|
177
|
+
if (scale <= 1) {
|
|
178
|
+
return createMatrix()
|
|
179
|
+
.translate((viewportW * (1 - scale)) / 2, (viewportH * (1 - scale)) / 2)
|
|
180
|
+
.scale(scale);
|
|
181
|
+
}
|
|
182
|
+
const { minX, minY, maxX, maxY } = calcBounds({ ...options, scale });
|
|
183
|
+
const targetX = Math.max(minX, Math.min(maxX, x));
|
|
184
|
+
const targetY = Math.max(minY, Math.min(maxY, y));
|
|
185
|
+
return matrix.translate(targetX - x, targetY - y);
|
|
186
|
+
}
|
|
187
|
+
/** Returns the deltaX/deltaY of the given wheel event - normalized between devices */
|
|
188
|
+
export function normalizeWheel(e) {
|
|
189
|
+
function limit(delta, max_delta) {
|
|
190
|
+
return Math.sign(delta) * Math.min(max_delta, Math.abs(delta));
|
|
191
|
+
}
|
|
192
|
+
let dx = e.deltaX;
|
|
193
|
+
let dy = e.deltaY;
|
|
194
|
+
if (e.shiftKey && dx === 0) {
|
|
195
|
+
[dx, dy] = [dy, dx];
|
|
196
|
+
}
|
|
197
|
+
if (e.deltaMode === WheelEvent.DOM_DELTA_LINE) {
|
|
198
|
+
dx *= DELTA_LINE_MULTIPLIER;
|
|
199
|
+
dy *= DELTA_LINE_MULTIPLIER;
|
|
200
|
+
}
|
|
201
|
+
else if (e.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
|
|
202
|
+
dx *= DELTA_PAGE_MULTIPLIER;
|
|
203
|
+
dy *= DELTA_PAGE_MULTIPLIER;
|
|
204
|
+
}
|
|
205
|
+
return [limit(dx, MAX_WHEEL_DELTA), limit(dy, MAX_WHEEL_DELTA)];
|
|
206
|
+
}
|
|
207
|
+
/** Returns whether the given item can be swiped left/right to change slides */
|
|
208
|
+
export function isSwipeable(item) {
|
|
209
|
+
if (!item)
|
|
210
|
+
return false;
|
|
211
|
+
if (item.disable_swipe)
|
|
212
|
+
return false;
|
|
213
|
+
if (item.type === 'embed')
|
|
214
|
+
return false;
|
|
215
|
+
if (item.type === 'image' && item.panorama)
|
|
216
|
+
return false;
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
/** Returns whether the given item can be pinched/zoomed */
|
|
220
|
+
export function isScalable(item) {
|
|
221
|
+
if (!item)
|
|
222
|
+
return false;
|
|
223
|
+
if (item.disable_zoom)
|
|
224
|
+
return false;
|
|
225
|
+
if (item.type === 'embed' || item.type === 'video')
|
|
226
|
+
return false;
|
|
227
|
+
if (item.type === 'image' && item.panorama)
|
|
228
|
+
return false;
|
|
229
|
+
if (item.type === 'custom')
|
|
230
|
+
return false;
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Normalizes an embed iframe URL: rewrites known providers (YouTube, Vimeo,
|
|
235
|
+
* iplayerhd, Matterport) so autoplay/play params reflect whether the iframe is
|
|
236
|
+
* eagerly loaded. Plain `vimeo.com/<id>` URLs are converted to the canonical
|
|
237
|
+
* `player.vimeo.com/video/<id>` embed form.
|
|
238
|
+
*/
|
|
239
|
+
export function normalizeEmbedSrc(src, eager) {
|
|
240
|
+
if (!src)
|
|
241
|
+
return '';
|
|
242
|
+
let url;
|
|
243
|
+
try {
|
|
244
|
+
url = new URL(src);
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
return src;
|
|
248
|
+
}
|
|
249
|
+
const host = url.hostname.replace(/^www\./, '');
|
|
250
|
+
if (host === 'youtube.com' ||
|
|
251
|
+
host === 'youtu.be' ||
|
|
252
|
+
host === 'youtube-nocookie.com' ||
|
|
253
|
+
host === 'player.vimeo.com') {
|
|
254
|
+
url.searchParams.set('autoplay', eager ? '1' : '0');
|
|
255
|
+
}
|
|
256
|
+
else if (host === 'vimeo.com') {
|
|
257
|
+
// vimeo.com/<id> → player.vimeo.com/video/<id>
|
|
258
|
+
const match = url.pathname.match(/^\/(\d+)(?:\/([0-9a-zA-Z]+))?/);
|
|
259
|
+
if (match) {
|
|
260
|
+
const id = match[1];
|
|
261
|
+
const hash = match[2];
|
|
262
|
+
url = new URL(`https://player.vimeo.com/video/${id}${hash ? `?h=${hash}` : ''}`);
|
|
263
|
+
url.searchParams.set('autoplay', eager ? '1' : '0');
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
else if (host === 'iplayerhd.com') {
|
|
267
|
+
url.searchParams.set('autoplay', eager ? 'true' : 'false');
|
|
268
|
+
}
|
|
269
|
+
else if (host === 'matterport.com' || host === 'my.matterport.com') {
|
|
270
|
+
url.searchParams.set('play', eager ? '1' : '0');
|
|
271
|
+
}
|
|
272
|
+
return url.toString();
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Returns true if the given URL points to an embed provider whose iframe
|
|
276
|
+
* renders video-like 16:9 content (YouTube, Vimeo). Used as a styling hint.
|
|
277
|
+
*/
|
|
278
|
+
export function isVideoEmbed(src) {
|
|
279
|
+
if (!src)
|
|
280
|
+
return false;
|
|
281
|
+
return /^(https?:\/\/)?(www\.)?(youtu\.?be|vimeo|youtube-nocookie)/.test(src);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Returns the best thumbnail URL for an item, in this order:
|
|
285
|
+
* 1. The explicit `item.poster` field.
|
|
286
|
+
* 2. For images, the largest src URL.
|
|
287
|
+
* 3. For known providers, a derived poster (YouTube → img.youtube.com,
|
|
288
|
+
* Vimeo → vumbnail.com, Cloudinary `.mp4` → `.jpg`).
|
|
289
|
+
* 4. Otherwise `undefined` — callers should fall back to a placeholder
|
|
290
|
+
* (the Gallery shows a type icon overlay over a styled placeholder block).
|
|
291
|
+
*/
|
|
292
|
+
export function getItemThumbnailSrc(item) {
|
|
293
|
+
if (item.poster)
|
|
294
|
+
return item.poster;
|
|
295
|
+
const src = item.src;
|
|
296
|
+
if (!src)
|
|
297
|
+
return undefined;
|
|
298
|
+
// Images (including panoramas) just use the source image directly.
|
|
299
|
+
if (!item.type || item.type === 'image')
|
|
300
|
+
return pickLargestSrc(src);
|
|
301
|
+
const single = pickLargestSrc(src);
|
|
302
|
+
// Cloudinary video URL → swap the file extension for `.jpg` to get the
|
|
303
|
+
// first frame as an image with all the same transforms applied.
|
|
304
|
+
if (/^https?:\/\/res\.cloudinary\.com\//.test(single) &&
|
|
305
|
+
/\.(mp4|webm|mov|m3u8)$/i.test(single)) {
|
|
306
|
+
return single.replace(/\.(mp4|webm|mov|m3u8)$/i, '.jpg');
|
|
307
|
+
}
|
|
308
|
+
// YouTube embed → `img.youtube.com` thumbnail.
|
|
309
|
+
const youtubeId = single.match(/^https?:\/\/(?:www\.)?(?:youtube(?:-nocookie)?\.com\/embed\/|youtu\.be\/)([\w-]{6,})/)?.[1];
|
|
310
|
+
if (youtubeId)
|
|
311
|
+
return `https://img.youtube.com/vi/${youtubeId}/hqdefault.jpg`;
|
|
312
|
+
// Vimeo embed → vumbnail.com (free third-party thumbnail mirror).
|
|
313
|
+
const vimeoId = single.match(/^https?:\/\/player\.vimeo\.com\/video\/(\d+)/)?.[1];
|
|
314
|
+
if (vimeoId)
|
|
315
|
+
return `https://vumbnail.com/${vimeoId}.jpg`;
|
|
316
|
+
return undefined;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Normalizes any acceptable carousel input (string src, partial item, or a full item)
|
|
320
|
+
* into a guaranteed CarouselItem. Returns `undefined` for inputs that can't be coerced.
|
|
321
|
+
*/
|
|
322
|
+
export function normalizeCarouselItem(input) {
|
|
323
|
+
if (!input)
|
|
324
|
+
return undefined;
|
|
325
|
+
if (typeof input === 'string') {
|
|
326
|
+
return { src: input, type: 'image' };
|
|
327
|
+
}
|
|
328
|
+
if (!input.src)
|
|
329
|
+
return undefined;
|
|
330
|
+
return {
|
|
331
|
+
type: input.type || 'image',
|
|
332
|
+
...input,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Returns true if `src` is an actual srcset (multiple URLs with width descriptors),
|
|
337
|
+
* not just a single URL that happens to contain a comma in its path.
|
|
338
|
+
*/
|
|
339
|
+
export function isResponsiveSrcset(src) {
|
|
340
|
+
if (!src)
|
|
341
|
+
return false;
|
|
342
|
+
if (!src.includes(',') && !src.includes(' '))
|
|
343
|
+
return false;
|
|
344
|
+
return /\s\d+w(?:\s*,|\s*$)/.test(src);
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Returns the highest-width URL from a srcset-style string, or the URL as-is if it's
|
|
348
|
+
* already a single URL. Used to extract a single `src` for elements that don't accept
|
|
349
|
+
* srcset (video, iframe, pdf consumers, download links).
|
|
350
|
+
*/
|
|
351
|
+
export function pickLargestSrc(src) {
|
|
352
|
+
if (!src)
|
|
353
|
+
return '';
|
|
354
|
+
if (!src.includes(',') && !src.includes(' '))
|
|
355
|
+
return src;
|
|
356
|
+
if (!isResponsiveSrcset(src))
|
|
357
|
+
return src;
|
|
358
|
+
let bestUrl = '';
|
|
359
|
+
let bestWidth = -1;
|
|
360
|
+
for (const entry of src.split(',')) {
|
|
361
|
+
const trimmed = entry.trim();
|
|
362
|
+
if (!trimmed)
|
|
363
|
+
continue;
|
|
364
|
+
const parts = trimmed.split(/\s+/);
|
|
365
|
+
const url = parts[0];
|
|
366
|
+
if (!url)
|
|
367
|
+
continue;
|
|
368
|
+
const widthMatch = parts[1]?.match(/^(\d+)w$/);
|
|
369
|
+
const width = widthMatch ? parseInt(widthMatch[1], 10) : 0;
|
|
370
|
+
if (width > bestWidth) {
|
|
371
|
+
bestWidth = width;
|
|
372
|
+
bestUrl = url;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return bestUrl || src;
|
|
376
|
+
}
|
|
377
|
+
/** Module-level cache of "best resolution already loaded" per item id, so cross-mount renders */
|
|
378
|
+
/** of the same image avoid downgrading to a smaller resolution. */
|
|
379
|
+
const loadedResolutions = new Map();
|
|
380
|
+
export function getLoadedResolutions(id) {
|
|
381
|
+
return Array.from(loadedResolutions.get(id) || []);
|
|
382
|
+
}
|
|
383
|
+
export function addLoadedResolution(id, resolution) {
|
|
384
|
+
if (!id || !resolution || !Number.isFinite(resolution))
|
|
385
|
+
return;
|
|
386
|
+
const set = loadedResolutions.get(id) || new Set();
|
|
387
|
+
set.add(resolution);
|
|
388
|
+
loadedResolutions.set(id, set);
|
|
389
|
+
}
|
|
390
|
+
/** Memoized base64-thumbhash → data:image/png URL conversions. */
|
|
391
|
+
const thumbhashDecodeCache = new Map();
|
|
392
|
+
/**
|
|
393
|
+
* Decode a base64-encoded ThumbHash into a `data:image/png` URL suitable for
|
|
394
|
+
* use as an `<img src>` value. Decoded URLs are memoized so repeated renders
|
|
395
|
+
* of the same item don't pay the decode cost more than once.
|
|
396
|
+
*/
|
|
397
|
+
export function decodeThumbHash(base64) {
|
|
398
|
+
const cached = thumbhashDecodeCache.get(base64);
|
|
399
|
+
if (cached)
|
|
400
|
+
return cached;
|
|
401
|
+
const binary = atob(base64);
|
|
402
|
+
const bytes = new Uint8Array(binary.length);
|
|
403
|
+
for (let i = 0; i < binary.length; i++)
|
|
404
|
+
bytes[i] = binary.charCodeAt(i);
|
|
405
|
+
const url = thumbHashToDataURL(bytes);
|
|
406
|
+
thumbhashDecodeCache.set(base64, url);
|
|
407
|
+
return url;
|
|
408
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { default as Carousel } from './Carousel.svelte';
|
|
2
|
+
export type { CarouselItem, CarouselItemType, GalleryGesture } from './Carousel.svelte';
|
|
3
|
+
export { decodeThumbHash, getItemThumbnailSrc, isResponsiveSrcset, isScalable, isSwipeable, isVideoEmbed, normalizeCarouselItem, normalizeEmbedSrc, pickLargestSrc, } from './carousel';
|
|
4
|
+
export { default as Gallery } from './Gallery.svelte';
|
|
5
|
+
export type { GalleryDisplay, GalleryItem, GalleryItemAction, GalleryRadius, GallerySize, GallerySpacing, } from './Gallery.svelte';
|
|
6
|
+
export { default as Image } from './Image.svelte';
|
|
7
|
+
export type { Hotspot as PanoramaHotspot } from './Panorama.svelte';
|
|
8
|
+
export type { PDFAnnotation } from './PDF.svelte';
|
|
9
|
+
export { default as Video } from './Video.svelte';
|
|
10
|
+
export type { Source as VideoSource, Track as VideoTrack } from './Video.svelte';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/media/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxF,OAAO,EACN,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,YAAY,EACZ,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACtD,YAAY,EACX,cAAc,EACd,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,cAAc,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAGlD,YAAY,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGpE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAClD,YAAY,EAAE,MAAM,IAAI,WAAW,EAAE,KAAK,IAAI,UAAU,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { default as Carousel } from './Carousel.svelte';
|
|
2
|
+
export { decodeThumbHash, getItemThumbnailSrc, isResponsiveSrcset, isScalable, isSwipeable, isVideoEmbed, normalizeCarouselItem, normalizeEmbedSrc, pickLargestSrc, } from './carousel';
|
|
3
|
+
export { default as Gallery } from './Gallery.svelte';
|
|
4
|
+
export { default as Image } from './Image.svelte';
|
|
5
|
+
export { default as Video } from './Video.svelte';
|