@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/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
+ }