@thangdevalone/meet-layout-grid-vue 1.0.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/README.md +126 -0
- package/dist/index.cjs +277 -0
- package/dist/index.d.cts +237 -0
- package/dist/index.d.mts +237 -0
- package/dist/index.d.ts +237 -0
- package/dist/index.mjs +262 -0
- package/package.json +60 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { ref, onMounted, computed, defineComponent, provide, h, inject } from 'vue';
|
|
2
|
+
import { useResizeObserver } from '@vueuse/core';
|
|
3
|
+
import { createMeetGrid, getSpringConfig } from '@meet-layout-grid/core';
|
|
4
|
+
export { createGrid, createGridItemPositioner, createMeetGrid, getAspectRatio, getGridItemDimensions, getSpringConfig, springPresets } from '@meet-layout-grid/core';
|
|
5
|
+
import { Motion } from 'motion-v';
|
|
6
|
+
|
|
7
|
+
function useGridDimensions(elementRef) {
|
|
8
|
+
const width = ref(0);
|
|
9
|
+
const height = ref(0);
|
|
10
|
+
useResizeObserver(elementRef, (entries) => {
|
|
11
|
+
const entry = entries[0];
|
|
12
|
+
if (entry) {
|
|
13
|
+
width.value = entry.contentRect.width;
|
|
14
|
+
height.value = entry.contentRect.height;
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
onMounted(() => {
|
|
18
|
+
if (elementRef.value) {
|
|
19
|
+
width.value = elementRef.value.clientWidth;
|
|
20
|
+
height.value = elementRef.value.clientHeight;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
return computed(() => ({
|
|
24
|
+
width: width.value,
|
|
25
|
+
height: height.value
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
function useMeetGrid(options) {
|
|
29
|
+
const getOptions = typeof options === "function" ? options : () => options.value;
|
|
30
|
+
return computed(() => {
|
|
31
|
+
const opts = getOptions();
|
|
32
|
+
return createMeetGrid(opts);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function useGridAnimation(preset = "smooth") {
|
|
36
|
+
return computed(() => getSpringConfig(preset));
|
|
37
|
+
}
|
|
38
|
+
function useGridItemPosition(grid, index) {
|
|
39
|
+
const getIndex = () => typeof index === "number" ? index : index.value;
|
|
40
|
+
const position = computed(() => grid.value.getPosition(getIndex()));
|
|
41
|
+
const dimensions = computed(() => grid.value.getItemDimensions(getIndex()));
|
|
42
|
+
const isMain = computed(() => grid.value.isMainItem(getIndex()));
|
|
43
|
+
const isHidden = computed(() => {
|
|
44
|
+
return grid.value.layoutMode === "spotlight" && !isMain.value;
|
|
45
|
+
});
|
|
46
|
+
return {
|
|
47
|
+
position,
|
|
48
|
+
dimensions,
|
|
49
|
+
isMain,
|
|
50
|
+
isHidden
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const GridContextKey = Symbol("MeetGridContext");
|
|
55
|
+
const GridContainer = defineComponent({
|
|
56
|
+
name: "GridContainer",
|
|
57
|
+
props: {
|
|
58
|
+
/** Aspect ratio in format "width:height" */
|
|
59
|
+
aspectRatio: {
|
|
60
|
+
type: String,
|
|
61
|
+
default: "16:9"
|
|
62
|
+
},
|
|
63
|
+
/** Gap between items in pixels */
|
|
64
|
+
gap: {
|
|
65
|
+
type: Number,
|
|
66
|
+
default: 8
|
|
67
|
+
},
|
|
68
|
+
/** Number of items */
|
|
69
|
+
count: {
|
|
70
|
+
type: Number,
|
|
71
|
+
required: true
|
|
72
|
+
},
|
|
73
|
+
/** Layout mode */
|
|
74
|
+
layoutMode: {
|
|
75
|
+
type: String,
|
|
76
|
+
default: "gallery"
|
|
77
|
+
},
|
|
78
|
+
/** Index of pinned item */
|
|
79
|
+
pinnedIndex: {
|
|
80
|
+
type: Number,
|
|
81
|
+
default: void 0
|
|
82
|
+
},
|
|
83
|
+
/** Index of active speaker */
|
|
84
|
+
speakerIndex: {
|
|
85
|
+
type: Number,
|
|
86
|
+
default: void 0
|
|
87
|
+
},
|
|
88
|
+
/** Sidebar position */
|
|
89
|
+
sidebarPosition: {
|
|
90
|
+
type: String,
|
|
91
|
+
default: "right"
|
|
92
|
+
},
|
|
93
|
+
/** Sidebar ratio (0-1) */
|
|
94
|
+
sidebarRatio: {
|
|
95
|
+
type: Number,
|
|
96
|
+
default: 0.25
|
|
97
|
+
},
|
|
98
|
+
/** Spring animation preset */
|
|
99
|
+
springPreset: {
|
|
100
|
+
type: String,
|
|
101
|
+
default: "smooth"
|
|
102
|
+
},
|
|
103
|
+
/** HTML tag to render */
|
|
104
|
+
tag: {
|
|
105
|
+
type: String,
|
|
106
|
+
default: "div"
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
setup(props, { slots }) {
|
|
110
|
+
const containerRef = ref(null);
|
|
111
|
+
const dimensions = useGridDimensions(containerRef);
|
|
112
|
+
const gridOptions = computed(() => ({
|
|
113
|
+
dimensions: dimensions.value,
|
|
114
|
+
count: props.count,
|
|
115
|
+
aspectRatio: props.aspectRatio,
|
|
116
|
+
gap: props.gap,
|
|
117
|
+
layoutMode: props.layoutMode,
|
|
118
|
+
pinnedIndex: props.pinnedIndex,
|
|
119
|
+
speakerIndex: props.speakerIndex,
|
|
120
|
+
sidebarPosition: props.sidebarPosition,
|
|
121
|
+
sidebarRatio: props.sidebarRatio
|
|
122
|
+
}));
|
|
123
|
+
const grid = useMeetGrid(gridOptions);
|
|
124
|
+
provide(GridContextKey, {
|
|
125
|
+
grid,
|
|
126
|
+
springPreset: props.springPreset
|
|
127
|
+
});
|
|
128
|
+
return () => h(
|
|
129
|
+
props.tag,
|
|
130
|
+
{
|
|
131
|
+
ref: containerRef,
|
|
132
|
+
style: {
|
|
133
|
+
position: "relative",
|
|
134
|
+
width: "100%",
|
|
135
|
+
height: "100%",
|
|
136
|
+
overflow: "hidden"
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
slots.default?.()
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
const GridItem = defineComponent({
|
|
144
|
+
name: "GridItem",
|
|
145
|
+
props: {
|
|
146
|
+
/** Index of this item in the grid */
|
|
147
|
+
index: {
|
|
148
|
+
type: Number,
|
|
149
|
+
required: true
|
|
150
|
+
},
|
|
151
|
+
/** Whether to disable animations */
|
|
152
|
+
disableAnimation: {
|
|
153
|
+
type: Boolean,
|
|
154
|
+
default: false
|
|
155
|
+
},
|
|
156
|
+
/** HTML tag to render */
|
|
157
|
+
tag: {
|
|
158
|
+
type: String,
|
|
159
|
+
default: "div"
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
setup(props, { slots }) {
|
|
163
|
+
const context = inject(GridContextKey);
|
|
164
|
+
if (!context) {
|
|
165
|
+
console.warn("GridItem must be used inside a GridContainer");
|
|
166
|
+
return () => null;
|
|
167
|
+
}
|
|
168
|
+
const { grid, springPreset } = context;
|
|
169
|
+
const position = computed(() => grid.value.getPosition(props.index));
|
|
170
|
+
const dimensions = computed(() => grid.value.getItemDimensions(props.index));
|
|
171
|
+
const isMain = computed(() => grid.value.isMainItem(props.index));
|
|
172
|
+
const isHidden = computed(() => {
|
|
173
|
+
return grid.value.layoutMode === "spotlight" && !isMain.value;
|
|
174
|
+
});
|
|
175
|
+
const springConfig = getSpringConfig(springPreset);
|
|
176
|
+
return () => {
|
|
177
|
+
if (isHidden.value) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
const animateProps = {
|
|
181
|
+
width: dimensions.value.width,
|
|
182
|
+
height: dimensions.value.height,
|
|
183
|
+
top: position.value.top,
|
|
184
|
+
left: position.value.left
|
|
185
|
+
};
|
|
186
|
+
if (props.disableAnimation) {
|
|
187
|
+
return h(
|
|
188
|
+
props.tag,
|
|
189
|
+
{
|
|
190
|
+
style: {
|
|
191
|
+
position: "absolute",
|
|
192
|
+
...animateProps,
|
|
193
|
+
width: `${animateProps.width}px`,
|
|
194
|
+
height: `${animateProps.height}px`,
|
|
195
|
+
top: `${animateProps.top}px`,
|
|
196
|
+
left: `${animateProps.left}px`
|
|
197
|
+
},
|
|
198
|
+
"data-grid-index": props.index,
|
|
199
|
+
"data-grid-main": isMain.value
|
|
200
|
+
},
|
|
201
|
+
slots.default?.()
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
return h(
|
|
205
|
+
Motion,
|
|
206
|
+
{
|
|
207
|
+
tag: props.tag,
|
|
208
|
+
animate: animateProps,
|
|
209
|
+
transition: {
|
|
210
|
+
type: springConfig.type,
|
|
211
|
+
stiffness: springConfig.stiffness,
|
|
212
|
+
damping: springConfig.damping
|
|
213
|
+
},
|
|
214
|
+
style: {
|
|
215
|
+
position: "absolute"
|
|
216
|
+
},
|
|
217
|
+
"data-grid-index": props.index,
|
|
218
|
+
"data-grid-main": isMain.value
|
|
219
|
+
},
|
|
220
|
+
slots.default
|
|
221
|
+
);
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
const GridOverlay = defineComponent({
|
|
226
|
+
name: "GridOverlay",
|
|
227
|
+
props: {
|
|
228
|
+
/** Whether to show the overlay */
|
|
229
|
+
visible: {
|
|
230
|
+
type: Boolean,
|
|
231
|
+
default: true
|
|
232
|
+
},
|
|
233
|
+
/** Background color */
|
|
234
|
+
backgroundColor: {
|
|
235
|
+
type: String,
|
|
236
|
+
default: "rgba(0,0,0,0.5)"
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
setup(props, { slots }) {
|
|
240
|
+
return () => {
|
|
241
|
+
if (!props.visible) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
return h(
|
|
245
|
+
"div",
|
|
246
|
+
{
|
|
247
|
+
style: {
|
|
248
|
+
position: "absolute",
|
|
249
|
+
inset: 0,
|
|
250
|
+
display: "flex",
|
|
251
|
+
alignItems: "center",
|
|
252
|
+
justifyContent: "center",
|
|
253
|
+
backgroundColor: props.backgroundColor
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
slots.default?.()
|
|
257
|
+
);
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
export { GridContainer, GridContextKey, GridItem, GridOverlay, useGridAnimation, useGridDimensions, useGridItemPosition, useMeetGrid };
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@thangdevalone/meet-layout-grid-vue",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Vue 3 integration for meet-layout-grid with Motion animations",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.mts",
|
|
13
|
+
"default": "./dist/index.mjs"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "unbuild",
|
|
26
|
+
"dev": "unbuild --watch",
|
|
27
|
+
"clean": "rimraf dist",
|
|
28
|
+
"test": "vitest run",
|
|
29
|
+
"test:watch": "vitest"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"vue",
|
|
33
|
+
"vue3",
|
|
34
|
+
"grid",
|
|
35
|
+
"meeting",
|
|
36
|
+
"video",
|
|
37
|
+
"motion",
|
|
38
|
+
"animation"
|
|
39
|
+
],
|
|
40
|
+
"author": "ThangDevAlone",
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "https://github.com/thangdevalone/meet-layout-grid"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"vue": ">=3.3.0"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@thangdevalone/meet-layout-grid-core": "workspace:*",
|
|
51
|
+
"@vueuse/core": "^10.7.0",
|
|
52
|
+
"motion-v": "^1.0.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"vue": "^3.4.0",
|
|
56
|
+
"unbuild": "^2.0.0",
|
|
57
|
+
"vitest": "^1.0.0",
|
|
58
|
+
"rimraf": "^5.0.0"
|
|
59
|
+
}
|
|
60
|
+
}
|