@thangdevalone/meet-layout-grid-react 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 ADDED
@@ -0,0 +1,114 @@
1
+ # @meet-layout-grid/react
2
+
3
+ React integration for meet-layout-grid with Motion animations.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @meet-layout-grid/react
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```tsx
14
+ import { GridContainer, GridItem } from '@meet-layout-grid/react'
15
+
16
+ function MeetingGrid({ participants }) {
17
+ return (
18
+ <GridContainer
19
+ aspectRatio="16:9"
20
+ gap={8}
21
+ layoutMode="gallery"
22
+ count={participants.length}
23
+ >
24
+ {participants.map((p, index) => (
25
+ <GridItem key={p.id} index={index}>
26
+ <VideoTile participant={p} />
27
+ </GridItem>
28
+ ))}
29
+ </GridContainer>
30
+ )
31
+ }
32
+ ```
33
+
34
+ ## Components
35
+
36
+ ### `<GridContainer>`
37
+
38
+ Container component that calculates grid layout and provides context.
39
+
40
+ ```tsx
41
+ <GridContainer
42
+ aspectRatio="16:9" // Item aspect ratio
43
+ gap={8} // Gap between items (px)
44
+ count={6} // Number of items
45
+ layoutMode="gallery" // Layout mode
46
+ speakerIndex={0} // Active speaker
47
+ pinnedIndex={0} // Pinned item
48
+ sidebarPosition="right" // Sidebar position
49
+ sidebarRatio={0.25} // Sidebar width ratio
50
+ springPreset="smooth" // Animation preset
51
+ >
52
+ {children}
53
+ </GridContainer>
54
+ ```
55
+
56
+ ### `<GridItem>`
57
+
58
+ Animated grid item with Motion spring animations.
59
+
60
+ ```tsx
61
+ <GridItem
62
+ index={0} // Item index (required)
63
+ disableAnimation={false} // Disable animations
64
+ >
65
+ {content}
66
+ </GridItem>
67
+ ```
68
+
69
+ ## Hooks
70
+
71
+ ### `useGridDimensions(ref)`
72
+
73
+ Track element dimensions with ResizeObserver.
74
+
75
+ ```tsx
76
+ const ref = useRef<HTMLDivElement>(null)
77
+ const dimensions = useGridDimensions(ref)
78
+ // { width: number, height: number }
79
+ ```
80
+
81
+ ### `useMeetGrid(options)`
82
+
83
+ Calculate grid layout manually.
84
+
85
+ ```tsx
86
+ const grid = useMeetGrid({
87
+ dimensions: { width: 800, height: 600 },
88
+ count: 6,
89
+ aspectRatio: '16:9',
90
+ gap: 8,
91
+ layoutMode: 'speaker',
92
+ })
93
+
94
+ const { top, left } = grid.getPosition(index)
95
+ const { width, height } = grid.getItemDimensions(index)
96
+ ```
97
+
98
+ ## Layout Modes
99
+
100
+ - **gallery** - Equal-sized tiles
101
+ - **speaker** - Active speaker larger
102
+ - **spotlight** - Single participant focus
103
+ - **sidebar** - Main view + thumbnails
104
+
105
+ ## Animation Presets
106
+
107
+ - `snappy` - Quick UI interactions
108
+ - `smooth` - Layout changes (default)
109
+ - `gentle` - Subtle effects
110
+ - `bouncy` - Playful effects
111
+
112
+ ## License
113
+
114
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,213 @@
1
+ 'use strict';
2
+
3
+ const React = require('react');
4
+ const core = require('@meet-layout-grid/core');
5
+ const react = require('motion/react');
6
+
7
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
8
+
9
+ const React__default = /*#__PURE__*/_interopDefaultCompat(React);
10
+
11
+ const GridContext = React.createContext(null);
12
+ function useGridContext() {
13
+ const context = React.useContext(GridContext);
14
+ if (!context) {
15
+ throw new Error("useGridContext must be used within a GridContainer");
16
+ }
17
+ return context;
18
+ }
19
+ function useGridDimensions(ref) {
20
+ const [dimensions, setDimensions] = React.useState({ width: 0, height: 0 });
21
+ React.useEffect(() => {
22
+ const element = ref.current;
23
+ if (!element) {
24
+ return;
25
+ }
26
+ const observer = new ResizeObserver((entries) => {
27
+ for (const entry of entries) {
28
+ const { clientWidth: width, clientHeight: height } = entry.target;
29
+ setDimensions((prev) => {
30
+ if (prev.width === width && prev.height === height) {
31
+ return prev;
32
+ }
33
+ return { width, height };
34
+ });
35
+ }
36
+ });
37
+ observer.observe(element);
38
+ setDimensions({
39
+ width: element.clientWidth,
40
+ height: element.clientHeight
41
+ });
42
+ return () => {
43
+ observer.disconnect();
44
+ };
45
+ }, [ref]);
46
+ return dimensions;
47
+ }
48
+ function useMeetGrid(options) {
49
+ return React.useMemo(() => {
50
+ return core.createMeetGrid(options);
51
+ }, [
52
+ options.dimensions.width,
53
+ options.dimensions.height,
54
+ options.count,
55
+ options.aspectRatio,
56
+ options.gap,
57
+ options.layoutMode,
58
+ options.pinnedIndex,
59
+ options.speakerIndex,
60
+ options.sidebarPosition,
61
+ options.sidebarRatio
62
+ ]);
63
+ }
64
+ function useGridAnimation(preset = "smooth") {
65
+ return React.useMemo(() => core.getSpringConfig(preset), [preset]);
66
+ }
67
+
68
+ const GridContainer = React.forwardRef(
69
+ function GridContainer2({
70
+ children,
71
+ aspectRatio = "16:9",
72
+ gap = 8,
73
+ count,
74
+ layoutMode = "gallery",
75
+ pinnedIndex,
76
+ speakerIndex,
77
+ sidebarPosition,
78
+ sidebarRatio,
79
+ springPreset = "smooth",
80
+ style,
81
+ className,
82
+ ...props
83
+ }, forwardedRef) {
84
+ const internalRef = React.useRef(null);
85
+ const ref = forwardedRef || internalRef;
86
+ const dimensions = useGridDimensions(ref);
87
+ const childCount = count ?? React__default.Children.count(children);
88
+ const gridOptions = {
89
+ dimensions,
90
+ count: childCount,
91
+ aspectRatio,
92
+ gap,
93
+ layoutMode,
94
+ pinnedIndex,
95
+ speakerIndex,
96
+ sidebarPosition,
97
+ sidebarRatio
98
+ };
99
+ const grid = useMeetGrid(gridOptions);
100
+ const containerStyle = {
101
+ position: "relative",
102
+ width: "100%",
103
+ height: "100%",
104
+ overflow: "hidden",
105
+ ...style
106
+ };
107
+ return /* @__PURE__ */ React__default.createElement(GridContext.Provider, { value: { dimensions, grid, springPreset } }, /* @__PURE__ */ React__default.createElement("div", { ref, style: containerStyle, className, ...props }, children));
108
+ }
109
+ );
110
+ const GridItem = React.forwardRef(
111
+ function GridItem2({
112
+ index,
113
+ children,
114
+ transition: customTransition,
115
+ disableAnimation = false,
116
+ className,
117
+ style,
118
+ ...props
119
+ }, ref) {
120
+ const { grid, springPreset } = useGridContext();
121
+ if (!grid) {
122
+ return null;
123
+ }
124
+ const { top, left } = grid.getPosition(index);
125
+ const { width, height } = grid.getItemDimensions(index);
126
+ const isMain = grid.isMainItem(index);
127
+ if (grid.layoutMode === "spotlight" && !isMain) {
128
+ return null;
129
+ }
130
+ const springConfig = core.getSpringConfig(springPreset);
131
+ const transition = customTransition ?? {
132
+ type: springConfig.type,
133
+ stiffness: springConfig.stiffness,
134
+ damping: springConfig.damping
135
+ };
136
+ const animatedStyle = {
137
+ position: "absolute",
138
+ width,
139
+ height,
140
+ top,
141
+ left
142
+ };
143
+ if (disableAnimation) {
144
+ return /* @__PURE__ */ React__default.createElement(
145
+ "div",
146
+ {
147
+ ref,
148
+ style: { ...animatedStyle, ...style },
149
+ className,
150
+ "data-grid-index": index,
151
+ "data-grid-main": isMain,
152
+ ...props
153
+ },
154
+ children
155
+ );
156
+ }
157
+ return /* @__PURE__ */ React__default.createElement(
158
+ react.motion.div,
159
+ {
160
+ ref,
161
+ layout: true,
162
+ initial: false,
163
+ animate: animatedStyle,
164
+ transition,
165
+ style,
166
+ className,
167
+ "data-grid-index": index,
168
+ "data-grid-main": isMain,
169
+ ...props
170
+ },
171
+ children
172
+ );
173
+ }
174
+ );
175
+ const GridOverlay = React.forwardRef(
176
+ function GridOverlay2({ visible = true, backgroundColor = "rgba(0,0,0,0.5)", children, style, ...props }, ref) {
177
+ if (!visible)
178
+ return null;
179
+ return /* @__PURE__ */ React__default.createElement(
180
+ "div",
181
+ {
182
+ ref,
183
+ style: {
184
+ position: "absolute",
185
+ inset: 0,
186
+ display: "flex",
187
+ alignItems: "center",
188
+ justifyContent: "center",
189
+ backgroundColor,
190
+ ...style
191
+ },
192
+ ...props
193
+ },
194
+ children
195
+ );
196
+ }
197
+ );
198
+
199
+ exports.createGrid = core.createGrid;
200
+ exports.createGridItemPositioner = core.createGridItemPositioner;
201
+ exports.createMeetGrid = core.createMeetGrid;
202
+ exports.getAspectRatio = core.getAspectRatio;
203
+ exports.getGridItemDimensions = core.getGridItemDimensions;
204
+ exports.getSpringConfig = core.getSpringConfig;
205
+ exports.springPresets = core.springPresets;
206
+ exports.GridContainer = GridContainer;
207
+ exports.GridContext = GridContext;
208
+ exports.GridItem = GridItem;
209
+ exports.GridOverlay = GridOverlay;
210
+ exports.useGridAnimation = useGridAnimation;
211
+ exports.useGridContext = useGridContext;
212
+ exports.useGridDimensions = useGridDimensions;
213
+ exports.useMeetGrid = useMeetGrid;
@@ -0,0 +1,113 @@
1
+ import * as React from 'react';
2
+ import React__default, { RefObject, HTMLAttributes, ReactNode, CSSProperties } from 'react';
3
+ import { GridDimensions, MeetGridOptions, MeetGridResult, SpringPreset, LayoutMode } from '@meet-layout-grid/core';
4
+ export { GridDimensions, GridOptions, LayoutMode, MeetGridOptions, MeetGridResult, Position, SpringPreset, createGrid, createGridItemPositioner, createMeetGrid, getAspectRatio, getGridItemDimensions, getSpringConfig, springPresets } from '@meet-layout-grid/core';
5
+ import { HTMLMotionProps, Transition } from 'motion/react';
6
+
7
+ interface GridContextValue {
8
+ dimensions: GridDimensions;
9
+ grid: MeetGridResult | null;
10
+ springPreset: SpringPreset;
11
+ }
12
+ declare const GridContext: React.Context<GridContextValue | null>;
13
+ /**
14
+ * Hook to access the grid context
15
+ */
16
+ declare function useGridContext(): GridContextValue;
17
+
18
+ /**
19
+ * A React hook to calculate dimensions of an element using ResizeObserver.
20
+ * @param ref An element ref
21
+ * @returns Dimensions of the element
22
+ */
23
+ declare function useGridDimensions(ref: RefObject<HTMLElement | null>): GridDimensions;
24
+ /**
25
+ * React hook for creating a meet-style responsive grid.
26
+ * @param options Grid options including dimensions, count, aspectRatio, gap, and layoutMode
27
+ * @returns Grid result with width, height, and position getter
28
+ */
29
+ declare function useMeetGrid(options: MeetGridOptions): MeetGridResult;
30
+ /**
31
+ * Hook to get animation configuration for Motion
32
+ */
33
+ declare function useGridAnimation(preset?: SpringPreset): {
34
+ stiffness: 400;
35
+ damping: 30;
36
+ type: "spring";
37
+ } | {
38
+ stiffness: 300;
39
+ damping: 30;
40
+ type: "spring";
41
+ } | {
42
+ stiffness: 200;
43
+ damping: 25;
44
+ type: "spring";
45
+ } | {
46
+ stiffness: 400;
47
+ damping: 15;
48
+ type: "spring";
49
+ };
50
+
51
+ interface GridContainerProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
52
+ /** Children to render inside the grid */
53
+ children: ReactNode;
54
+ /** Aspect ratio in format "width:height" (e.g., "16:9") */
55
+ aspectRatio?: string;
56
+ /** Gap between items in pixels */
57
+ gap?: number;
58
+ /** Number of items (if not using GridItem children) */
59
+ count?: number;
60
+ /** Layout mode */
61
+ layoutMode?: LayoutMode;
62
+ /** Index of pinned item */
63
+ pinnedIndex?: number;
64
+ /** Index of active speaker */
65
+ speakerIndex?: number;
66
+ /** Sidebar position */
67
+ sidebarPosition?: 'left' | 'right' | 'bottom';
68
+ /** Sidebar ratio (0-1) */
69
+ sidebarRatio?: number;
70
+ /** Spring animation preset */
71
+ springPreset?: SpringPreset;
72
+ /** Custom container style */
73
+ style?: CSSProperties;
74
+ /** Additional class name */
75
+ className?: string;
76
+ }
77
+ /**
78
+ * Container component for the meet grid.
79
+ * Provides grid context to child GridItem components.
80
+ */
81
+ declare const GridContainer: React__default.ForwardRefExoticComponent<GridContainerProps & React__default.RefAttributes<HTMLDivElement>>;
82
+ interface GridItemProps extends Omit<HTMLMotionProps<'div'>, 'animate' | 'initial' | 'transition'> {
83
+ /** Index of this item in the grid */
84
+ index: number;
85
+ /** Children to render inside the item */
86
+ children: ReactNode;
87
+ /** Custom transition override */
88
+ transition?: Transition;
89
+ /** Whether to disable animations */
90
+ disableAnimation?: boolean;
91
+ /** Additional class name */
92
+ className?: string;
93
+ /** Custom style (merged with animated styles) */
94
+ style?: CSSProperties;
95
+ }
96
+ /**
97
+ * Grid item component with Motion animations.
98
+ * Automatically positions itself based on index in the grid.
99
+ */
100
+ declare const GridItem: React__default.ForwardRefExoticComponent<Omit<GridItemProps, "ref"> & React__default.RefAttributes<HTMLDivElement>>;
101
+ interface GridOverlayProps extends HTMLAttributes<HTMLDivElement> {
102
+ /** Whether to show the overlay */
103
+ visible?: boolean;
104
+ /** Overlay background color */
105
+ backgroundColor?: string;
106
+ }
107
+ /**
108
+ * Overlay component for grid items (e.g., for muted indicator, name label)
109
+ */
110
+ declare const GridOverlay: React__default.ForwardRefExoticComponent<GridOverlayProps & React__default.RefAttributes<HTMLDivElement>>;
111
+
112
+ export { GridContainer, GridContext, GridItem, GridOverlay, useGridAnimation, useGridContext, useGridDimensions, useMeetGrid };
113
+ export type { GridContainerProps, GridItemProps, GridOverlayProps };
@@ -0,0 +1,113 @@
1
+ import * as React from 'react';
2
+ import React__default, { RefObject, HTMLAttributes, ReactNode, CSSProperties } from 'react';
3
+ import { GridDimensions, MeetGridOptions, MeetGridResult, SpringPreset, LayoutMode } from '@meet-layout-grid/core';
4
+ export { GridDimensions, GridOptions, LayoutMode, MeetGridOptions, MeetGridResult, Position, SpringPreset, createGrid, createGridItemPositioner, createMeetGrid, getAspectRatio, getGridItemDimensions, getSpringConfig, springPresets } from '@meet-layout-grid/core';
5
+ import { HTMLMotionProps, Transition } from 'motion/react';
6
+
7
+ interface GridContextValue {
8
+ dimensions: GridDimensions;
9
+ grid: MeetGridResult | null;
10
+ springPreset: SpringPreset;
11
+ }
12
+ declare const GridContext: React.Context<GridContextValue | null>;
13
+ /**
14
+ * Hook to access the grid context
15
+ */
16
+ declare function useGridContext(): GridContextValue;
17
+
18
+ /**
19
+ * A React hook to calculate dimensions of an element using ResizeObserver.
20
+ * @param ref An element ref
21
+ * @returns Dimensions of the element
22
+ */
23
+ declare function useGridDimensions(ref: RefObject<HTMLElement | null>): GridDimensions;
24
+ /**
25
+ * React hook for creating a meet-style responsive grid.
26
+ * @param options Grid options including dimensions, count, aspectRatio, gap, and layoutMode
27
+ * @returns Grid result with width, height, and position getter
28
+ */
29
+ declare function useMeetGrid(options: MeetGridOptions): MeetGridResult;
30
+ /**
31
+ * Hook to get animation configuration for Motion
32
+ */
33
+ declare function useGridAnimation(preset?: SpringPreset): {
34
+ stiffness: 400;
35
+ damping: 30;
36
+ type: "spring";
37
+ } | {
38
+ stiffness: 300;
39
+ damping: 30;
40
+ type: "spring";
41
+ } | {
42
+ stiffness: 200;
43
+ damping: 25;
44
+ type: "spring";
45
+ } | {
46
+ stiffness: 400;
47
+ damping: 15;
48
+ type: "spring";
49
+ };
50
+
51
+ interface GridContainerProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
52
+ /** Children to render inside the grid */
53
+ children: ReactNode;
54
+ /** Aspect ratio in format "width:height" (e.g., "16:9") */
55
+ aspectRatio?: string;
56
+ /** Gap between items in pixels */
57
+ gap?: number;
58
+ /** Number of items (if not using GridItem children) */
59
+ count?: number;
60
+ /** Layout mode */
61
+ layoutMode?: LayoutMode;
62
+ /** Index of pinned item */
63
+ pinnedIndex?: number;
64
+ /** Index of active speaker */
65
+ speakerIndex?: number;
66
+ /** Sidebar position */
67
+ sidebarPosition?: 'left' | 'right' | 'bottom';
68
+ /** Sidebar ratio (0-1) */
69
+ sidebarRatio?: number;
70
+ /** Spring animation preset */
71
+ springPreset?: SpringPreset;
72
+ /** Custom container style */
73
+ style?: CSSProperties;
74
+ /** Additional class name */
75
+ className?: string;
76
+ }
77
+ /**
78
+ * Container component for the meet grid.
79
+ * Provides grid context to child GridItem components.
80
+ */
81
+ declare const GridContainer: React__default.ForwardRefExoticComponent<GridContainerProps & React__default.RefAttributes<HTMLDivElement>>;
82
+ interface GridItemProps extends Omit<HTMLMotionProps<'div'>, 'animate' | 'initial' | 'transition'> {
83
+ /** Index of this item in the grid */
84
+ index: number;
85
+ /** Children to render inside the item */
86
+ children: ReactNode;
87
+ /** Custom transition override */
88
+ transition?: Transition;
89
+ /** Whether to disable animations */
90
+ disableAnimation?: boolean;
91
+ /** Additional class name */
92
+ className?: string;
93
+ /** Custom style (merged with animated styles) */
94
+ style?: CSSProperties;
95
+ }
96
+ /**
97
+ * Grid item component with Motion animations.
98
+ * Automatically positions itself based on index in the grid.
99
+ */
100
+ declare const GridItem: React__default.ForwardRefExoticComponent<Omit<GridItemProps, "ref"> & React__default.RefAttributes<HTMLDivElement>>;
101
+ interface GridOverlayProps extends HTMLAttributes<HTMLDivElement> {
102
+ /** Whether to show the overlay */
103
+ visible?: boolean;
104
+ /** Overlay background color */
105
+ backgroundColor?: string;
106
+ }
107
+ /**
108
+ * Overlay component for grid items (e.g., for muted indicator, name label)
109
+ */
110
+ declare const GridOverlay: React__default.ForwardRefExoticComponent<GridOverlayProps & React__default.RefAttributes<HTMLDivElement>>;
111
+
112
+ export { GridContainer, GridContext, GridItem, GridOverlay, useGridAnimation, useGridContext, useGridDimensions, useMeetGrid };
113
+ export type { GridContainerProps, GridItemProps, GridOverlayProps };
@@ -0,0 +1,113 @@
1
+ import * as React from 'react';
2
+ import React__default, { RefObject, HTMLAttributes, ReactNode, CSSProperties } from 'react';
3
+ import { GridDimensions, MeetGridOptions, MeetGridResult, SpringPreset, LayoutMode } from '@thangdevalone/meet-layout-grid-core';
4
+ export { GridDimensions, GridOptions, LayoutMode, MeetGridOptions, MeetGridResult, Position, SpringPreset, createGrid, createGridItemPositioner, createMeetGrid, getAspectRatio, getGridItemDimensions, getSpringConfig, springPresets } from '@thangdevalone/meet-layout-grid-core';
5
+ import { HTMLMotionProps, Transition } from 'motion/react';
6
+
7
+ interface GridContextValue {
8
+ dimensions: GridDimensions;
9
+ grid: MeetGridResult | null;
10
+ springPreset: SpringPreset;
11
+ }
12
+ declare const GridContext: React.Context<GridContextValue | null>;
13
+ /**
14
+ * Hook to access the grid context
15
+ */
16
+ declare function useGridContext(): GridContextValue;
17
+
18
+ /**
19
+ * A React hook to calculate dimensions of an element using ResizeObserver.
20
+ * @param ref An element ref
21
+ * @returns Dimensions of the element
22
+ */
23
+ declare function useGridDimensions(ref: RefObject<HTMLElement | null>): GridDimensions;
24
+ /**
25
+ * React hook for creating a meet-style responsive grid.
26
+ * @param options Grid options including dimensions, count, aspectRatio, gap, and layoutMode
27
+ * @returns Grid result with width, height, and position getter
28
+ */
29
+ declare function useMeetGrid(options: MeetGridOptions): MeetGridResult;
30
+ /**
31
+ * Hook to get animation configuration for Motion
32
+ */
33
+ declare function useGridAnimation(preset?: SpringPreset): {
34
+ stiffness: 400;
35
+ damping: 30;
36
+ type: "spring";
37
+ } | {
38
+ stiffness: 300;
39
+ damping: 30;
40
+ type: "spring";
41
+ } | {
42
+ stiffness: 200;
43
+ damping: 25;
44
+ type: "spring";
45
+ } | {
46
+ stiffness: 400;
47
+ damping: 15;
48
+ type: "spring";
49
+ };
50
+
51
+ interface GridContainerProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
52
+ /** Children to render inside the grid */
53
+ children: ReactNode;
54
+ /** Aspect ratio in format "width:height" (e.g., "16:9") */
55
+ aspectRatio?: string;
56
+ /** Gap between items in pixels */
57
+ gap?: number;
58
+ /** Number of items (if not using GridItem children) */
59
+ count?: number;
60
+ /** Layout mode */
61
+ layoutMode?: LayoutMode;
62
+ /** Index of pinned item */
63
+ pinnedIndex?: number;
64
+ /** Index of active speaker */
65
+ speakerIndex?: number;
66
+ /** Sidebar position */
67
+ sidebarPosition?: 'left' | 'right' | 'bottom';
68
+ /** Sidebar ratio (0-1) */
69
+ sidebarRatio?: number;
70
+ /** Spring animation preset */
71
+ springPreset?: SpringPreset;
72
+ /** Custom container style */
73
+ style?: CSSProperties;
74
+ /** Additional class name */
75
+ className?: string;
76
+ }
77
+ /**
78
+ * Container component for the meet grid.
79
+ * Provides grid context to child GridItem components.
80
+ */
81
+ declare const GridContainer: React__default.ForwardRefExoticComponent<GridContainerProps & React__default.RefAttributes<HTMLDivElement>>;
82
+ interface GridItemProps extends Omit<HTMLMotionProps<'div'>, 'animate' | 'initial' | 'transition'> {
83
+ /** Index of this item in the grid */
84
+ index: number;
85
+ /** Children to render inside the item */
86
+ children: ReactNode;
87
+ /** Custom transition override */
88
+ transition?: Transition;
89
+ /** Whether to disable animations */
90
+ disableAnimation?: boolean;
91
+ /** Additional class name */
92
+ className?: string;
93
+ /** Custom style (merged with animated styles) */
94
+ style?: CSSProperties;
95
+ }
96
+ /**
97
+ * Grid item component with Motion animations.
98
+ * Automatically positions itself based on index in the grid.
99
+ */
100
+ declare const GridItem: React__default.ForwardRefExoticComponent<Omit<GridItemProps, "ref"> & React__default.RefAttributes<HTMLDivElement>>;
101
+ interface GridOverlayProps extends HTMLAttributes<HTMLDivElement> {
102
+ /** Whether to show the overlay */
103
+ visible?: boolean;
104
+ /** Overlay background color */
105
+ backgroundColor?: string;
106
+ }
107
+ /**
108
+ * Overlay component for grid items (e.g., for muted indicator, name label)
109
+ */
110
+ declare const GridOverlay: React__default.ForwardRefExoticComponent<GridOverlayProps & React__default.RefAttributes<HTMLDivElement>>;
111
+
112
+ export { GridContainer, GridContext, GridItem, GridOverlay, useGridAnimation, useGridContext, useGridDimensions, useMeetGrid };
113
+ export type { GridContainerProps, GridItemProps, GridOverlayProps };
package/dist/index.mjs ADDED
@@ -0,0 +1,194 @@
1
+ import React, { createContext, useContext, useState, useEffect, useMemo, forwardRef, useRef } from 'react';
2
+ import { createMeetGrid, getSpringConfig } from '@meet-layout-grid/core';
3
+ export { createGrid, createGridItemPositioner, createMeetGrid, getAspectRatio, getGridItemDimensions, getSpringConfig, springPresets } from '@meet-layout-grid/core';
4
+ import { motion } from 'motion/react';
5
+
6
+ const GridContext = createContext(null);
7
+ function useGridContext() {
8
+ const context = useContext(GridContext);
9
+ if (!context) {
10
+ throw new Error("useGridContext must be used within a GridContainer");
11
+ }
12
+ return context;
13
+ }
14
+ function useGridDimensions(ref) {
15
+ const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
16
+ useEffect(() => {
17
+ const element = ref.current;
18
+ if (!element) {
19
+ return;
20
+ }
21
+ const observer = new ResizeObserver((entries) => {
22
+ for (const entry of entries) {
23
+ const { clientWidth: width, clientHeight: height } = entry.target;
24
+ setDimensions((prev) => {
25
+ if (prev.width === width && prev.height === height) {
26
+ return prev;
27
+ }
28
+ return { width, height };
29
+ });
30
+ }
31
+ });
32
+ observer.observe(element);
33
+ setDimensions({
34
+ width: element.clientWidth,
35
+ height: element.clientHeight
36
+ });
37
+ return () => {
38
+ observer.disconnect();
39
+ };
40
+ }, [ref]);
41
+ return dimensions;
42
+ }
43
+ function useMeetGrid(options) {
44
+ return useMemo(() => {
45
+ return createMeetGrid(options);
46
+ }, [
47
+ options.dimensions.width,
48
+ options.dimensions.height,
49
+ options.count,
50
+ options.aspectRatio,
51
+ options.gap,
52
+ options.layoutMode,
53
+ options.pinnedIndex,
54
+ options.speakerIndex,
55
+ options.sidebarPosition,
56
+ options.sidebarRatio
57
+ ]);
58
+ }
59
+ function useGridAnimation(preset = "smooth") {
60
+ return useMemo(() => getSpringConfig(preset), [preset]);
61
+ }
62
+
63
+ const GridContainer = forwardRef(
64
+ function GridContainer2({
65
+ children,
66
+ aspectRatio = "16:9",
67
+ gap = 8,
68
+ count,
69
+ layoutMode = "gallery",
70
+ pinnedIndex,
71
+ speakerIndex,
72
+ sidebarPosition,
73
+ sidebarRatio,
74
+ springPreset = "smooth",
75
+ style,
76
+ className,
77
+ ...props
78
+ }, forwardedRef) {
79
+ const internalRef = useRef(null);
80
+ const ref = forwardedRef || internalRef;
81
+ const dimensions = useGridDimensions(ref);
82
+ const childCount = count ?? React.Children.count(children);
83
+ const gridOptions = {
84
+ dimensions,
85
+ count: childCount,
86
+ aspectRatio,
87
+ gap,
88
+ layoutMode,
89
+ pinnedIndex,
90
+ speakerIndex,
91
+ sidebarPosition,
92
+ sidebarRatio
93
+ };
94
+ const grid = useMeetGrid(gridOptions);
95
+ const containerStyle = {
96
+ position: "relative",
97
+ width: "100%",
98
+ height: "100%",
99
+ overflow: "hidden",
100
+ ...style
101
+ };
102
+ return /* @__PURE__ */ React.createElement(GridContext.Provider, { value: { dimensions, grid, springPreset } }, /* @__PURE__ */ React.createElement("div", { ref, style: containerStyle, className, ...props }, children));
103
+ }
104
+ );
105
+ const GridItem = forwardRef(
106
+ function GridItem2({
107
+ index,
108
+ children,
109
+ transition: customTransition,
110
+ disableAnimation = false,
111
+ className,
112
+ style,
113
+ ...props
114
+ }, ref) {
115
+ const { grid, springPreset } = useGridContext();
116
+ if (!grid) {
117
+ return null;
118
+ }
119
+ const { top, left } = grid.getPosition(index);
120
+ const { width, height } = grid.getItemDimensions(index);
121
+ const isMain = grid.isMainItem(index);
122
+ if (grid.layoutMode === "spotlight" && !isMain) {
123
+ return null;
124
+ }
125
+ const springConfig = getSpringConfig(springPreset);
126
+ const transition = customTransition ?? {
127
+ type: springConfig.type,
128
+ stiffness: springConfig.stiffness,
129
+ damping: springConfig.damping
130
+ };
131
+ const animatedStyle = {
132
+ position: "absolute",
133
+ width,
134
+ height,
135
+ top,
136
+ left
137
+ };
138
+ if (disableAnimation) {
139
+ return /* @__PURE__ */ React.createElement(
140
+ "div",
141
+ {
142
+ ref,
143
+ style: { ...animatedStyle, ...style },
144
+ className,
145
+ "data-grid-index": index,
146
+ "data-grid-main": isMain,
147
+ ...props
148
+ },
149
+ children
150
+ );
151
+ }
152
+ return /* @__PURE__ */ React.createElement(
153
+ motion.div,
154
+ {
155
+ ref,
156
+ layout: true,
157
+ initial: false,
158
+ animate: animatedStyle,
159
+ transition,
160
+ style,
161
+ className,
162
+ "data-grid-index": index,
163
+ "data-grid-main": isMain,
164
+ ...props
165
+ },
166
+ children
167
+ );
168
+ }
169
+ );
170
+ const GridOverlay = forwardRef(
171
+ function GridOverlay2({ visible = true, backgroundColor = "rgba(0,0,0,0.5)", children, style, ...props }, ref) {
172
+ if (!visible)
173
+ return null;
174
+ return /* @__PURE__ */ React.createElement(
175
+ "div",
176
+ {
177
+ ref,
178
+ style: {
179
+ position: "absolute",
180
+ inset: 0,
181
+ display: "flex",
182
+ alignItems: "center",
183
+ justifyContent: "center",
184
+ backgroundColor,
185
+ ...style
186
+ },
187
+ ...props
188
+ },
189
+ children
190
+ );
191
+ }
192
+ );
193
+
194
+ export { GridContainer, GridContext, GridItem, GridOverlay, useGridAnimation, useGridContext, useGridDimensions, useMeetGrid };
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@thangdevalone/meet-layout-grid-react",
3
+ "version": "1.0.0",
4
+ "description": "React 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
+ "react",
33
+ "grid",
34
+ "meeting",
35
+ "video",
36
+ "motion",
37
+ "animation"
38
+ ],
39
+ "author": "ThangDevAlone",
40
+ "license": "MIT",
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/thangdevalone/meet-layout-grid"
44
+ },
45
+ "peerDependencies": {
46
+ "react": ">=18.0.0",
47
+ "react-dom": ">=18.0.0"
48
+ },
49
+ "dependencies": {
50
+ "@thangdevalone/meet-layout-grid-core": "workspace:*",
51
+ "motion": "^11.15.0"
52
+ },
53
+ "devDependencies": {
54
+ "@types/react": "^18.2.0",
55
+ "@types/react-dom": "^18.2.0",
56
+ "react": "^18.2.0",
57
+ "react-dom": "^18.2.0",
58
+ "unbuild": "^2.0.0",
59
+ "vitest": "^1.0.0",
60
+ "rimraf": "^5.0.0"
61
+ }
62
+ }