react-motion-gallery 2.0.23 → 2.0.25
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 +249 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -169,6 +169,179 @@ Subpaths give bundlers a smaller graph than the root. Less JS to transfer, parse
|
|
|
169
169
|
| `react-motion-gallery/video` | `Video` and optional Plyr-backed video types |
|
|
170
170
|
| `react-motion-gallery/zoomPan` | `ZoomPanImage` and zoom/pan types |
|
|
171
171
|
|
|
172
|
+
## MCP server
|
|
173
|
+
|
|
174
|
+
This repository includes `react-motion-gallery-mcp`, a local Model Context Protocol server for AI-assisted gallery design and integration. It runs over stdio and gives MCP-capable clients a structured way to inspect React Motion Gallery patterns, generate starter components, audit installs, and scaffold skeleton text measurement manifests.
|
|
175
|
+
|
|
176
|
+
From a local checkout, build the server first:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
npm install
|
|
180
|
+
npm run build --workspace packages/react-motion-gallery-mcp
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Then add it to your MCP client config. Replace the path with the absolute path to your checkout:
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"mcpServers": {
|
|
188
|
+
"react-motion-gallery": {
|
|
189
|
+
"command": "node",
|
|
190
|
+
"args": [
|
|
191
|
+
"/absolute/path/to/react-motion-gallery/packages/react-motion-gallery-mcp/dist/server.js"
|
|
192
|
+
]
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Once connected, start with workflow classification. The MCP server treats requests as **layout intent plus loading fidelity**, so agents can avoid unnecessary skeleton work when the user only asked for a layout.
|
|
199
|
+
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"goal": "Build a pricing card grid with simple skeleton loading",
|
|
203
|
+
"hasExistingLayout": false,
|
|
204
|
+
"layoutHint": "grid",
|
|
205
|
+
"framework": "next"
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The classifier returns one of these modes:
|
|
210
|
+
|
|
211
|
+
```text
|
|
212
|
+
User goal: "Build a responsive gallery slider."
|
|
213
|
+
Workflow: layoutOnly
|
|
214
|
+
Use: recommend_pattern -> get_demo -> generate_gallery_component
|
|
215
|
+
Skip: skeleton tools
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
```text
|
|
219
|
+
User goal: "Build a product grid with image placeholders while loading."
|
|
220
|
+
Workflow: layoutWithNonTextSkeleton
|
|
221
|
+
Use: Skeleton rect/media nodes or gallery skeleton wrappers
|
|
222
|
+
Skip: browser text measurement
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
```text
|
|
226
|
+
User goal: "Build a card layout with simple text skeleton lines."
|
|
227
|
+
Workflow: layoutWithHandAuthoredTextSkeleton
|
|
228
|
+
Use: text skeleton nodes with hand-authored lines/barWidth values
|
|
229
|
+
Skip: generated sidecar
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
```text
|
|
233
|
+
User goal: "Build a masonry layout where skeleton text matches real responsive copy."
|
|
234
|
+
Workflow: layoutWithBrowserMeasuredTextSkeleton
|
|
235
|
+
Use: stable selectors -> scaffold_skeleton_text -> generate:skeleton-text-module --analysis-output -> import sidecar
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
When a connected agent needs context, it should read `rmg://context/agent-brief`, then use targeted resources such as `rmg://guides/layout-selection`, `rmg://guides/loading-fidelity`, `rmg://guides/browser-measured-skeletons`, `rmg://docs`, `rmg://catalog/demos`, and `rmg://examples/{demoId}`.
|
|
239
|
+
|
|
240
|
+
Read a specific example:
|
|
241
|
+
|
|
242
|
+
```text
|
|
243
|
+
rmg://examples/slider-video-html5
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Call `recommend_pattern` with your UI goal to choose the right layout, imports, demos, and gotchas.
|
|
247
|
+
|
|
248
|
+
```json
|
|
249
|
+
{
|
|
250
|
+
"goal": "Responsive masonry gallery with lazy-loaded images and fullscreen preview",
|
|
251
|
+
"layout": "masonry",
|
|
252
|
+
"features": ["lazy-load", "fullscreen"],
|
|
253
|
+
"mediaKinds": ["image"],
|
|
254
|
+
"framework": "next"
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Call `classify_gallery_workflow` when the user goal is ambiguous about loading fidelity.
|
|
259
|
+
|
|
260
|
+
```json
|
|
261
|
+
{
|
|
262
|
+
"goal": "Add a skeleton that matches the real responsive card copy",
|
|
263
|
+
"hasExistingLayout": true,
|
|
264
|
+
"layoutHint": "custom",
|
|
265
|
+
"framework": "next"
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Call `search_demos` to find matching examples by category, tags, component, media kind, or query.
|
|
270
|
+
|
|
271
|
+
```json
|
|
272
|
+
{
|
|
273
|
+
"category": "slider",
|
|
274
|
+
"mediaKind": "video",
|
|
275
|
+
"query": "html5",
|
|
276
|
+
"limit": 3
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Call `get_demo` to retrieve consumer-ready TSX/CSS for a specific demo.
|
|
281
|
+
|
|
282
|
+
```json
|
|
283
|
+
{
|
|
284
|
+
"demoId": "slider-video-html5",
|
|
285
|
+
"includeExtraFiles": true
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Call `audit_project` with a `projectRoot` to check installs, stylesheet imports, optional video peers, and common Next.js client-component issues.
|
|
290
|
+
|
|
291
|
+
```json
|
|
292
|
+
{
|
|
293
|
+
"projectRoot": "/absolute/path/to/your-app"
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Call `generate_gallery_component` to turn a selected demo into renamed TSX/CSS output for your app.
|
|
298
|
+
|
|
299
|
+
```json
|
|
300
|
+
{
|
|
301
|
+
"demoId": "masonry-balanced",
|
|
302
|
+
"componentName": "ProjectGallery",
|
|
303
|
+
"cssModuleName": "ProjectGallery.module.css"
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Call `write_gallery_files` after reviewing generated output. Pass `apply: true` only when you want the server to write files under `projectRoot`.
|
|
308
|
+
|
|
309
|
+
```json
|
|
310
|
+
{
|
|
311
|
+
"projectRoot": "/absolute/path/to/your-app",
|
|
312
|
+
"demoId": "masonry-balanced",
|
|
313
|
+
"componentName": "ProjectGallery",
|
|
314
|
+
"componentPath": "src/components/ProjectGallery.tsx",
|
|
315
|
+
"cssPath": "src/components/ProjectGallery.module.css",
|
|
316
|
+
"apply": true
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Call `scaffold_skeleton_text` to create a browser-measurement manifest for the skeleton text workflow.
|
|
321
|
+
|
|
322
|
+
```json
|
|
323
|
+
{
|
|
324
|
+
"projectRoot": "/absolute/path/to/app",
|
|
325
|
+
"manifestPath": "src/components/pricing.skeleton-text.browser.manifest.json",
|
|
326
|
+
"url": "http://127.0.0.1:3000/pricing?skeletonMeasure=content",
|
|
327
|
+
"outputFile": "src/components/pricing.skeleton-text.generated.ts",
|
|
328
|
+
"moduleExportName": "pricingSkeletonText",
|
|
329
|
+
"barWidthUnit": "px",
|
|
330
|
+
"includeTextMetrics": true,
|
|
331
|
+
"targets": [
|
|
332
|
+
{
|
|
333
|
+
"exportName": "pricingCardTitle",
|
|
334
|
+
"selector": "[data-skeleton-text-id='pricingCardTitle']"
|
|
335
|
+
}
|
|
336
|
+
],
|
|
337
|
+
"apply": true
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
Use flat `targets` for ordinary DOM text in any layout: sliders, grids, masonry cards, entries, thumbnails, flex layouts, app shells, pricing cards, and custom UI. Add the optional `slider`, `masonry`, or `entries` manifest blocks only when those specialized layouts need canonical item measurement, geometry readiness, or row readiness.
|
|
342
|
+
|
|
343
|
+
The file-writing tools default to dry runs unless `apply: true` is passed, and they refuse to write outside the provided `projectRoot`.
|
|
344
|
+
|
|
172
345
|
## Acknowledgements
|
|
173
346
|
|
|
174
347
|
React Motion Gallery's slider engine includes portions of code derived from [Embla Carousel](https://github.com/davidjerleke/embla-carousel), which is MIT licensed. Those portions have been substantially adapted for React Motion Gallery's React architecture, public API, transition system, fullscreen integration, loading layers, and media workflows.
|
|
@@ -1551,9 +1724,9 @@ The hook returns additional refs and setters for the internal fullscreen runtime
|
|
|
1551
1724
|
| `controls.counter.render` | `({ index, count }) => ReactNode` | `—` | Custom counter renderer. |
|
|
1552
1725
|
| `caption.className` | `string` | `—` | Caption root class. |
|
|
1553
1726
|
| `caption.style` | `React.CSSProperties` | `—` | Caption root style. |
|
|
1554
|
-
| `caption.placement` | `
|
|
1555
|
-
| `caption.width` | `number
|
|
1556
|
-
| `caption.height` | `number
|
|
1727
|
+
| `caption.placement` | `FsCaptionPlacement \| FsCaptionPlacement[] \| Record<string, FsCaptionPlacement>` | `—` | Preferred caption placement. Responsive maps use the `GalleryCore.breakpoints` keys such as `xs`, `md`, and `lg`. |
|
|
1728
|
+
| `caption.width` | `number \| string \| Record<string, number \| string>` | `—` | Caption area width. Strings can use `px` or `%`; percentages are viewport-relative in fullscreen. Responsive maps use breakpoint keys. |
|
|
1729
|
+
| `caption.height` | `number \| string \| Record<string, number \| string>` | `—` | Caption area height. Strings can use `px` or `%`; percentages are viewport-relative in fullscreen. Responsive maps use breakpoint keys. |
|
|
1557
1730
|
| `caption.breakpoint` | `number` | `—` | Viewport cutoff for switching placement logic. |
|
|
1558
1731
|
| `caption.render` | `({ item, index, isZoomed }) => ReactNode` | `—` | Custom caption renderer. |
|
|
1559
1732
|
| `caption.layout` | `"overlay" \| "slide"` | `—` | Chooses whether the caption overlays the media or lives in the slide layout. |
|
|
@@ -1597,6 +1770,79 @@ The hook returns additional refs and setters for the internal fullscreen runtime
|
|
|
1597
1770
|
|
|
1598
1771
|
Fullscreen `effects.crossfade.wheel` uses the same `true`, `false`, or object form as slider wheel crossfade. Its `durationMs` default follows fullscreen `effects.crossfade.durationMs`, which defaults to `120`.
|
|
1599
1772
|
|
|
1773
|
+
### Responsive fullscreen captions
|
|
1774
|
+
|
|
1775
|
+
Use `fullscreenCaptions()` with `fullscreenSlider()` when fullscreen slides need captions. Caption placement and size accept responsive values. This example places captions on the right at desktop widths, reserves 50% of the fullscreen viewport for the caption area, and moves captions to the bottom on mobile:
|
|
1776
|
+
|
|
1777
|
+
```typescript
|
|
1778
|
+
import { useFullscreenController } from "react-motion-gallery/fullscreen";
|
|
1779
|
+
import { fullscreenSlider } from "react-motion-gallery/fullscreen/slider";
|
|
1780
|
+
import { fullscreenCaptions } from "react-motion-gallery/fullscreen/captions";
|
|
1781
|
+
|
|
1782
|
+
const slides = [
|
|
1783
|
+
{
|
|
1784
|
+
title: "Lorem ipsum dolor sit amet",
|
|
1785
|
+
description: "Consectetur adipiscing elit, sed do eiusmod tempor.",
|
|
1786
|
+
},
|
|
1787
|
+
];
|
|
1788
|
+
|
|
1789
|
+
function FullscreenAddon() {
|
|
1790
|
+
const { fullscreenNode } = useFullscreenController({
|
|
1791
|
+
plugins: [fullscreenSlider(), fullscreenCaptions()],
|
|
1792
|
+
fullscreen: {
|
|
1793
|
+
enabled: true,
|
|
1794
|
+
caption: {
|
|
1795
|
+
layout: "overlay",
|
|
1796
|
+
placement: {
|
|
1797
|
+
xs: "bottom",
|
|
1798
|
+
lg: "right",
|
|
1799
|
+
},
|
|
1800
|
+
width: {
|
|
1801
|
+
lg: "50%",
|
|
1802
|
+
},
|
|
1803
|
+
style: {
|
|
1804
|
+
padding: 0,
|
|
1805
|
+
},
|
|
1806
|
+
render: ({ index }) => {
|
|
1807
|
+
const slide = slides[index];
|
|
1808
|
+
if (!slide) return null;
|
|
1809
|
+
|
|
1810
|
+
return (
|
|
1811
|
+
<div className="fullscreenCaption">
|
|
1812
|
+
<p>{slide.title}</p>
|
|
1813
|
+
<p>{slide.description}</p>
|
|
1814
|
+
</div>
|
|
1815
|
+
);
|
|
1816
|
+
},
|
|
1817
|
+
},
|
|
1818
|
+
},
|
|
1819
|
+
});
|
|
1820
|
+
|
|
1821
|
+
return <>{fullscreenNode}</>;
|
|
1822
|
+
}
|
|
1823
|
+
```
|
|
1824
|
+
|
|
1825
|
+
For overlay captions, style the rendered caption content to fill the reserved caption surface when needed:
|
|
1826
|
+
|
|
1827
|
+
```css
|
|
1828
|
+
.fullscreenCaption {
|
|
1829
|
+
box-sizing: border-box;
|
|
1830
|
+
width: 100%;
|
|
1831
|
+
height: 100%;
|
|
1832
|
+
display: flex;
|
|
1833
|
+
flex-direction: column;
|
|
1834
|
+
justify-content: center;
|
|
1835
|
+
padding: clamp(18px, 3vw, 34px);
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
@media (max-width: 1199px) {
|
|
1839
|
+
.fullscreenCaption {
|
|
1840
|
+
justify-content: flex-end;
|
|
1841
|
+
padding-bottom: 30px;
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
```
|
|
1845
|
+
|
|
1600
1846
|
### Fullscreen callback and helper types
|
|
1601
1847
|
|
|
1602
1848
|
#### `FsCounterArgs`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-motion-gallery",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.25",
|
|
4
4
|
"description": "Composable React media gallery primitives for sliders, grids, masonry, fullscreen, video, zoom/pan, and stable skeleton loading",
|
|
5
5
|
"license": "PolyForm-Noncommercial-1.0.0",
|
|
6
6
|
"author": "React Motion Gallery",
|