@thangdevalone/meet-layout-grid-vue 1.3.0 → 1.3.2

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.cjs CHANGED
@@ -198,7 +198,7 @@ const GridItem = vue.defineComponent({
198
198
  console.warn("GridItem must be used inside a GridContainer");
199
199
  return () => null;
200
200
  }
201
- const { grid, springPreset } = context;
201
+ const { grid, springPreset, dimensions: containerDimensions } = context;
202
202
  const position = vue.computed(() => grid.value.getPosition(props.index));
203
203
  const dimensions = vue.computed(() => grid.value.getItemDimensions(props.index));
204
204
  const contentDimensions = vue.computed(
@@ -213,6 +213,77 @@ const GridItem = vue.defineComponent({
213
213
  return true;
214
214
  return false;
215
215
  });
216
+ const isFloat = vue.computed(() => grid.value.floatIndex === props.index);
217
+ const floatDims = vue.computed(() => grid.value.floatDimensions ?? { width: 120, height: 160 });
218
+ const floatAnchor = vue.ref("bottom-right");
219
+ const floatDragging = vue.ref(false);
220
+ const floatDragOffset = vue.ref({ x: 0, y: 0 });
221
+ const floatStartPos = vue.ref({ x: 0, y: 0 });
222
+ const floatDisplayPos = vue.ref({ x: 0, y: 0 });
223
+ const floatInitialized = vue.ref(false);
224
+ const getFloatCornerPos = (corner) => {
225
+ const padding = 12;
226
+ const dims = containerDimensions.value;
227
+ const fw = floatDims.value.width;
228
+ const fh = floatDims.value.height;
229
+ switch (corner) {
230
+ case "top-left":
231
+ return { x: padding, y: padding };
232
+ case "top-right":
233
+ return { x: dims.width - fw - padding, y: padding };
234
+ case "bottom-left":
235
+ return { x: padding, y: dims.height - fh - padding };
236
+ case "bottom-right":
237
+ default:
238
+ return { x: dims.width - fw - padding, y: dims.height - fh - padding };
239
+ }
240
+ };
241
+ const findFloatNearestCorner = (x, y) => {
242
+ const fw = floatDims.value.width;
243
+ const fh = floatDims.value.height;
244
+ const centerX = x + fw / 2;
245
+ const centerY = y + fh / 2;
246
+ const dims = containerDimensions.value;
247
+ const isLeft = centerX < dims.width / 2;
248
+ const isTop = centerY < dims.height / 2;
249
+ if (isTop && isLeft)
250
+ return "top-left";
251
+ if (isTop && !isLeft)
252
+ return "top-right";
253
+ if (!isTop && isLeft)
254
+ return "bottom-left";
255
+ return "bottom-right";
256
+ };
257
+ const floatCornerPos = vue.computed(() => getFloatCornerPos(floatAnchor.value));
258
+ const handleFloatDragStart = (e) => {
259
+ floatDragging.value = true;
260
+ const pos = "touches" in e ? e.touches[0] : e;
261
+ floatStartPos.value = { x: pos.clientX, y: pos.clientY };
262
+ floatDragOffset.value = { x: 0, y: 0 };
263
+ };
264
+ const handleFloatDragMove = (e) => {
265
+ if (!floatDragging.value)
266
+ return;
267
+ e.preventDefault();
268
+ const pos = "touches" in e ? e.touches[0] : e;
269
+ floatDragOffset.value = {
270
+ x: pos.clientX - floatStartPos.value.x,
271
+ y: pos.clientY - floatStartPos.value.y
272
+ };
273
+ floatDisplayPos.value = {
274
+ x: floatCornerPos.value.x + floatDragOffset.value.x,
275
+ y: floatCornerPos.value.y + floatDragOffset.value.y
276
+ };
277
+ };
278
+ const handleFloatDragEnd = () => {
279
+ if (!floatDragging.value)
280
+ return;
281
+ floatDragging.value = false;
282
+ const nearest = findFloatNearestCorner(floatDisplayPos.value.x, floatDisplayPos.value.y);
283
+ floatAnchor.value = nearest;
284
+ floatDisplayPos.value = getFloatCornerPos(nearest);
285
+ floatDragOffset.value = { x: 0, y: 0 };
286
+ };
216
287
  const isLastVisibleOther = vue.computed(() => {
217
288
  const lastVisibleOthersIndex = grid.value.getLastVisibleOthersIndex();
218
289
  return props.index === lastVisibleOthersIndex;
@@ -228,6 +299,50 @@ const GridItem = vue.defineComponent({
228
299
  if (isHidden.value) {
229
300
  return null;
230
301
  }
302
+ if (isFloat.value) {
303
+ const dims = containerDimensions.value;
304
+ if (dims.width === 0 || dims.height === 0)
305
+ return null;
306
+ if (!floatInitialized.value) {
307
+ floatDisplayPos.value = floatCornerPos.value;
308
+ floatInitialized.value = true;
309
+ }
310
+ return vue.h(
311
+ motionV.motion.div,
312
+ {
313
+ animate: {
314
+ x: floatDisplayPos.value.x,
315
+ y: floatDisplayPos.value.y,
316
+ opacity: 1,
317
+ scale: floatDragging.value ? 1.05 : 1
318
+ },
319
+ transition: floatDragging.value ? { duration: 0 } : { type: "spring", stiffness: 400, damping: 30 },
320
+ style: {
321
+ position: "absolute",
322
+ width: `${floatDims.value.width}px`,
323
+ height: `${floatDims.value.height}px`,
324
+ borderRadius: "12px",
325
+ boxShadow: floatDragging.value ? "0 8px 32px rgba(0,0,0,0.4)" : "0 4px 20px rgba(0,0,0,0.3)",
326
+ overflow: "hidden",
327
+ cursor: floatDragging.value ? "grabbing" : "grab",
328
+ zIndex: 100,
329
+ touchAction: "none",
330
+ left: 0,
331
+ top: 0
332
+ },
333
+ "data-grid-index": props.index,
334
+ "data-grid-float": true,
335
+ onMousedown: handleFloatDragStart,
336
+ onMousemove: handleFloatDragMove,
337
+ onMouseup: handleFloatDragEnd,
338
+ onMouseleave: handleFloatDragEnd,
339
+ onTouchstart: handleFloatDragStart,
340
+ onTouchmove: handleFloatDragMove,
341
+ onTouchend: handleFloatDragEnd
342
+ },
343
+ () => slots.default?.(slotProps.value)
344
+ );
345
+ }
231
346
  const animateProps = {
232
347
  width: dimensions.value.width,
233
348
  height: dimensions.value.height,
package/dist/index.mjs CHANGED
@@ -197,7 +197,7 @@ const GridItem = defineComponent({
197
197
  console.warn("GridItem must be used inside a GridContainer");
198
198
  return () => null;
199
199
  }
200
- const { grid, springPreset } = context;
200
+ const { grid, springPreset, dimensions: containerDimensions } = context;
201
201
  const position = computed(() => grid.value.getPosition(props.index));
202
202
  const dimensions = computed(() => grid.value.getItemDimensions(props.index));
203
203
  const contentDimensions = computed(
@@ -212,6 +212,77 @@ const GridItem = defineComponent({
212
212
  return true;
213
213
  return false;
214
214
  });
215
+ const isFloat = computed(() => grid.value.floatIndex === props.index);
216
+ const floatDims = computed(() => grid.value.floatDimensions ?? { width: 120, height: 160 });
217
+ const floatAnchor = ref("bottom-right");
218
+ const floatDragging = ref(false);
219
+ const floatDragOffset = ref({ x: 0, y: 0 });
220
+ const floatStartPos = ref({ x: 0, y: 0 });
221
+ const floatDisplayPos = ref({ x: 0, y: 0 });
222
+ const floatInitialized = ref(false);
223
+ const getFloatCornerPos = (corner) => {
224
+ const padding = 12;
225
+ const dims = containerDimensions.value;
226
+ const fw = floatDims.value.width;
227
+ const fh = floatDims.value.height;
228
+ switch (corner) {
229
+ case "top-left":
230
+ return { x: padding, y: padding };
231
+ case "top-right":
232
+ return { x: dims.width - fw - padding, y: padding };
233
+ case "bottom-left":
234
+ return { x: padding, y: dims.height - fh - padding };
235
+ case "bottom-right":
236
+ default:
237
+ return { x: dims.width - fw - padding, y: dims.height - fh - padding };
238
+ }
239
+ };
240
+ const findFloatNearestCorner = (x, y) => {
241
+ const fw = floatDims.value.width;
242
+ const fh = floatDims.value.height;
243
+ const centerX = x + fw / 2;
244
+ const centerY = y + fh / 2;
245
+ const dims = containerDimensions.value;
246
+ const isLeft = centerX < dims.width / 2;
247
+ const isTop = centerY < dims.height / 2;
248
+ if (isTop && isLeft)
249
+ return "top-left";
250
+ if (isTop && !isLeft)
251
+ return "top-right";
252
+ if (!isTop && isLeft)
253
+ return "bottom-left";
254
+ return "bottom-right";
255
+ };
256
+ const floatCornerPos = computed(() => getFloatCornerPos(floatAnchor.value));
257
+ const handleFloatDragStart = (e) => {
258
+ floatDragging.value = true;
259
+ const pos = "touches" in e ? e.touches[0] : e;
260
+ floatStartPos.value = { x: pos.clientX, y: pos.clientY };
261
+ floatDragOffset.value = { x: 0, y: 0 };
262
+ };
263
+ const handleFloatDragMove = (e) => {
264
+ if (!floatDragging.value)
265
+ return;
266
+ e.preventDefault();
267
+ const pos = "touches" in e ? e.touches[0] : e;
268
+ floatDragOffset.value = {
269
+ x: pos.clientX - floatStartPos.value.x,
270
+ y: pos.clientY - floatStartPos.value.y
271
+ };
272
+ floatDisplayPos.value = {
273
+ x: floatCornerPos.value.x + floatDragOffset.value.x,
274
+ y: floatCornerPos.value.y + floatDragOffset.value.y
275
+ };
276
+ };
277
+ const handleFloatDragEnd = () => {
278
+ if (!floatDragging.value)
279
+ return;
280
+ floatDragging.value = false;
281
+ const nearest = findFloatNearestCorner(floatDisplayPos.value.x, floatDisplayPos.value.y);
282
+ floatAnchor.value = nearest;
283
+ floatDisplayPos.value = getFloatCornerPos(nearest);
284
+ floatDragOffset.value = { x: 0, y: 0 };
285
+ };
215
286
  const isLastVisibleOther = computed(() => {
216
287
  const lastVisibleOthersIndex = grid.value.getLastVisibleOthersIndex();
217
288
  return props.index === lastVisibleOthersIndex;
@@ -227,6 +298,50 @@ const GridItem = defineComponent({
227
298
  if (isHidden.value) {
228
299
  return null;
229
300
  }
301
+ if (isFloat.value) {
302
+ const dims = containerDimensions.value;
303
+ if (dims.width === 0 || dims.height === 0)
304
+ return null;
305
+ if (!floatInitialized.value) {
306
+ floatDisplayPos.value = floatCornerPos.value;
307
+ floatInitialized.value = true;
308
+ }
309
+ return h(
310
+ motion.div,
311
+ {
312
+ animate: {
313
+ x: floatDisplayPos.value.x,
314
+ y: floatDisplayPos.value.y,
315
+ opacity: 1,
316
+ scale: floatDragging.value ? 1.05 : 1
317
+ },
318
+ transition: floatDragging.value ? { duration: 0 } : { type: "spring", stiffness: 400, damping: 30 },
319
+ style: {
320
+ position: "absolute",
321
+ width: `${floatDims.value.width}px`,
322
+ height: `${floatDims.value.height}px`,
323
+ borderRadius: "12px",
324
+ boxShadow: floatDragging.value ? "0 8px 32px rgba(0,0,0,0.4)" : "0 4px 20px rgba(0,0,0,0.3)",
325
+ overflow: "hidden",
326
+ cursor: floatDragging.value ? "grabbing" : "grab",
327
+ zIndex: 100,
328
+ touchAction: "none",
329
+ left: 0,
330
+ top: 0
331
+ },
332
+ "data-grid-index": props.index,
333
+ "data-grid-float": true,
334
+ onMousedown: handleFloatDragStart,
335
+ onMousemove: handleFloatDragMove,
336
+ onMouseup: handleFloatDragEnd,
337
+ onMouseleave: handleFloatDragEnd,
338
+ onTouchstart: handleFloatDragStart,
339
+ onTouchmove: handleFloatDragMove,
340
+ onTouchend: handleFloatDragEnd
341
+ },
342
+ () => slots.default?.(slotProps.value)
343
+ );
344
+ }
230
345
  const animateProps = {
231
346
  width: dimensions.value.width,
232
347
  height: dimensions.value.height,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thangdevalone/meet-layout-grid-vue",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "Vue 3 integration for meet-layout-grid with Motion animations",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -43,7 +43,7 @@
43
43
  "dependencies": {
44
44
  "@vueuse/core": "^10.7.0",
45
45
  "motion-v": "^1.0.0",
46
- "@thangdevalone/meet-layout-grid-core": "1.3.0"
46
+ "@thangdevalone/meet-layout-grid-core": "1.3.2"
47
47
  },
48
48
  "devDependencies": {
49
49
  "vue": "^3.4.0",