@patternmode/aperto 0.1.4 → 0.2.1
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 +34 -0
- package/dist/index.d.ts +164 -45
- package/dist/index.js +634 -736
- package/dist/index.js.map +1 -1
- package/package.json +14 -13
package/README.md
CHANGED
|
@@ -35,6 +35,40 @@ export function MediaGroupExample() {
|
|
|
35
35
|
}
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
## Optimized images
|
|
39
|
+
|
|
40
|
+
Aperto's built-in image renderer uses a plain `img` so the package stays
|
|
41
|
+
framework agnostic. If your app uses Next.js, pass `renderImage` and return
|
|
42
|
+
your own `next/image` `Image` component:
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import Image from "next/image";
|
|
46
|
+
|
|
47
|
+
const leadSrc = media[0]?.src;
|
|
48
|
+
|
|
49
|
+
<Aperto.Group
|
|
50
|
+
media={media}
|
|
51
|
+
renderImage={({ alt, item, src, variant }) => {
|
|
52
|
+
const isLeadImage = variant === "expanded" || item.src === leadSrc;
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<Image
|
|
56
|
+
alt={alt ?? ""}
|
|
57
|
+
fetchPriority={isLeadImage ? "high" : "auto"}
|
|
58
|
+
fill
|
|
59
|
+
loading={isLeadImage || variant === "thumbnail" ? "eager" : "lazy"}
|
|
60
|
+
sizes={variant === "thumbnail" ? "(max-width: 640px) 50vw, 320px" : "90vw"}
|
|
61
|
+
src={String(src)}
|
|
62
|
+
/>
|
|
63
|
+
);
|
|
64
|
+
}}
|
|
65
|
+
>
|
|
66
|
+
{media.map((item, index) => (
|
|
67
|
+
<Aperto.Thumbnail key={item.id ?? item.src} index={index} />
|
|
68
|
+
))}
|
|
69
|
+
</Aperto.Group>;
|
|
70
|
+
```
|
|
71
|
+
|
|
38
72
|
## Install
|
|
39
73
|
|
|
40
74
|
```bash
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ImgHTMLAttributes, ReactNode, VideoHTMLAttributes, ComponentPropsWithoutRef } from 'react';
|
|
2
|
+
import { ImgHTMLAttributes, ReactNode, VideoHTMLAttributes, ComponentPropsWithRef, Ref, CSSProperties, ComponentPropsWithoutRef } from 'react';
|
|
3
3
|
import * as Dialog from '@radix-ui/react-dialog';
|
|
4
|
-
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
4
|
import { Transition } from 'motion/react';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
|
-
* @patternmode/aperto
|
|
7
|
+
* Package: @patternmode/aperto
|
|
9
8
|
*
|
|
10
9
|
* Shared element transitions with physics-based drag dismissal.
|
|
11
10
|
* Built on Radix Dialog + Motion.
|
|
@@ -23,22 +22,42 @@ interface BaseMediaItem {
|
|
|
23
22
|
title?: string;
|
|
24
23
|
width?: number;
|
|
25
24
|
}
|
|
25
|
+
/** Image media item rendered as a thumbnail and expanded image. */
|
|
26
26
|
interface ApertoImageItem extends BaseMediaItem {
|
|
27
|
+
/** Required alt text for the image renderer. */
|
|
27
28
|
alt: string;
|
|
28
29
|
type: "image";
|
|
29
30
|
}
|
|
31
|
+
/** Video media item rendered with a thumbnail and expanded player. */
|
|
30
32
|
interface ApertoVideoItem extends BaseMediaItem {
|
|
31
33
|
alt?: string;
|
|
34
|
+
/** Optional captions track URL for the expanded video. */
|
|
32
35
|
captionsSrc?: string;
|
|
33
36
|
poster?: string;
|
|
37
|
+
/** Required thumbnail image shown before expansion. */
|
|
34
38
|
thumbnailSrc: string;
|
|
35
39
|
type: "video";
|
|
36
40
|
}
|
|
41
|
+
/** Media item supported by Aperto's grouped media API. */
|
|
37
42
|
type ApertoMediaItem = ApertoImageItem | ApertoVideoItem;
|
|
43
|
+
/**
|
|
44
|
+
* Custom image renderer for image media.
|
|
45
|
+
*
|
|
46
|
+
* Aperto's default renderer is a plain `img` so the package stays framework
|
|
47
|
+
* agnostic. Next.js consumers should return their own `next/image` `Image`
|
|
48
|
+
* component here, using `variant` to choose thumbnail vs expanded sizing,
|
|
49
|
+
* loading, or fetch priority behavior.
|
|
50
|
+
*/
|
|
38
51
|
type RenderImage = (props: ImgHTMLAttributes<HTMLImageElement> & {
|
|
39
52
|
item: ApertoImageItem;
|
|
40
53
|
variant: "expanded" | "thumbnail";
|
|
41
54
|
}) => ReactNode;
|
|
55
|
+
/**
|
|
56
|
+
* Custom video renderer for video media.
|
|
57
|
+
*
|
|
58
|
+
* Use this to replace the default `video` element while preserving the supplied
|
|
59
|
+
* accessibility, poster, and control props.
|
|
60
|
+
*/
|
|
42
61
|
type RenderVideo = (props: VideoHTMLAttributes<HTMLVideoElement> & {
|
|
43
62
|
item: ApertoVideoItem;
|
|
44
63
|
variant: "expanded" | "thumbnail";
|
|
@@ -77,50 +96,98 @@ interface MotionPreset {
|
|
|
77
96
|
}
|
|
78
97
|
/** Dismissal behaviour config */
|
|
79
98
|
interface DismissibleConfig {
|
|
80
|
-
/**
|
|
99
|
+
/**
|
|
100
|
+
* Distance in px to trigger dismissal.
|
|
101
|
+
*
|
|
102
|
+
* Default `100`.
|
|
103
|
+
*/
|
|
81
104
|
threshold?: number;
|
|
82
|
-
/**
|
|
105
|
+
/**
|
|
106
|
+
* Velocity in px/s to trigger dismissal.
|
|
107
|
+
*
|
|
108
|
+
* Default `500`.
|
|
109
|
+
*/
|
|
83
110
|
velocity?: number;
|
|
84
111
|
}
|
|
85
112
|
|
|
86
113
|
interface ApertoProps {
|
|
87
114
|
classNames?: ApertoClassNames;
|
|
88
|
-
/**
|
|
115
|
+
/**
|
|
116
|
+
* Whether dragging can dismiss the expanded media.
|
|
117
|
+
*
|
|
118
|
+
* Default `true`.
|
|
119
|
+
*/
|
|
89
120
|
dismissible?: boolean | DismissibleConfig;
|
|
121
|
+
/** Single media item rendered by the standalone Aperto component. */
|
|
90
122
|
media: ApertoMediaItem;
|
|
123
|
+
/**
|
|
124
|
+
* Overrides Aperto's plain `img` renderer for image media.
|
|
125
|
+
*
|
|
126
|
+
* Use this to render framework-specific image components such as Next.js
|
|
127
|
+
* `Image` while keeping Aperto itself framework agnostic.
|
|
128
|
+
*/
|
|
91
129
|
renderImage?: RenderImage;
|
|
92
130
|
renderVideo?: RenderVideo;
|
|
93
131
|
}
|
|
94
132
|
interface ApertoGroupProps {
|
|
95
133
|
children: ReactNode;
|
|
96
134
|
classNames?: ApertoClassNames;
|
|
97
|
-
/**
|
|
135
|
+
/**
|
|
136
|
+
* Whether dragging can dismiss the expanded media.
|
|
137
|
+
*
|
|
138
|
+
* Default `true`.
|
|
139
|
+
*/
|
|
98
140
|
dismissible?: boolean | DismissibleConfig;
|
|
141
|
+
/** Controlled active media index. Pair with `onIndexChange`. */
|
|
99
142
|
index?: number;
|
|
143
|
+
/**
|
|
144
|
+
* Initial active media index for uncontrolled groups.
|
|
145
|
+
*
|
|
146
|
+
* Default `0`.
|
|
147
|
+
*/
|
|
100
148
|
initialIndex?: number;
|
|
101
149
|
media: ApertoMediaItem[];
|
|
102
|
-
/**
|
|
150
|
+
/**
|
|
151
|
+
* Motion preset for open/close transitions, or per-part motion overrides.
|
|
152
|
+
*
|
|
153
|
+
* Default `"smooth"`.
|
|
154
|
+
*/
|
|
103
155
|
motion?: MotionPresetName | MotionVariants;
|
|
156
|
+
/**
|
|
157
|
+
* Motion preset for next/previous navigation inside expanded media.
|
|
158
|
+
*
|
|
159
|
+
* Default `"glide"`.
|
|
160
|
+
*/
|
|
104
161
|
navigationMotion?: NavigationMotionPresetName;
|
|
162
|
+
/** Called whenever grouped media navigation changes the active index. */
|
|
105
163
|
onIndexChange?: (index: number) => void;
|
|
164
|
+
/**
|
|
165
|
+
* Overrides Aperto's plain `img` renderer for image media.
|
|
166
|
+
*
|
|
167
|
+
* Use this to render framework-specific image components such as Next.js
|
|
168
|
+
* `Image` while keeping Aperto itself framework agnostic.
|
|
169
|
+
*/
|
|
106
170
|
renderImage?: RenderImage;
|
|
107
171
|
renderVideo?: RenderVideo;
|
|
108
172
|
}
|
|
109
173
|
interface ApertoThumbnailProps {
|
|
174
|
+
/** Optional custom thumbnail content; defaults to media thumbnail rendering. */
|
|
110
175
|
children?: ReactNode;
|
|
111
176
|
className?: string;
|
|
177
|
+
/** Index into the parent group's `media` array. */
|
|
112
178
|
index: number;
|
|
113
179
|
}
|
|
114
180
|
|
|
115
|
-
declare
|
|
116
|
-
|
|
117
|
-
declare function ApertoSingle({ classNames, dismissible, media, renderImage, renderVideo, }: ApertoProps): react_jsx_runtime.JSX.Element;
|
|
181
|
+
declare const ApertoGroup: ({ children, classNames, dismissible, index, initialIndex, media, motion: motionProp, navigationMotion, onIndexChange, renderImage, renderVideo, }: ApertoGroupProps) => react.JSX.Element;
|
|
118
182
|
|
|
119
|
-
declare
|
|
183
|
+
declare const ApertoThumbnail: ({ children, className, index }: ApertoThumbnailProps) => react.JSX.Element | null;
|
|
120
184
|
|
|
121
|
-
declare const ApertoClose:
|
|
185
|
+
declare const ApertoClose: {
|
|
186
|
+
({ children, ref, ...props }: ComponentPropsWithRef<typeof Dialog.Close>): react.JSX.Element;
|
|
187
|
+
displayName: string;
|
|
188
|
+
};
|
|
122
189
|
|
|
123
|
-
interface ApertoContentProps extends Omit<
|
|
190
|
+
interface ApertoContentProps extends Omit<ComponentPropsWithRef<typeof Dialog.Content>, "asChild" | "forceMount"> {
|
|
124
191
|
/** Motion preset override for this content panel, independent of the root preset. */
|
|
125
192
|
motion?: MotionPresetName;
|
|
126
193
|
/** Built-in positioning strategy. Use "none" for custom primitive compositions. */
|
|
@@ -128,24 +195,34 @@ interface ApertoContentProps extends Omit<ComponentPropsWithoutRef<typeof Dialog
|
|
|
128
195
|
/** Internal shared layout ID override for grouped media. */
|
|
129
196
|
sharedLayoutId?: string | false;
|
|
130
197
|
}
|
|
131
|
-
declare const ApertoContent:
|
|
198
|
+
declare const ApertoContent: {
|
|
199
|
+
({ children, className, motion: motionOverride, placement, ref, sharedLayoutId, style, ...props }: ApertoContentProps): react.JSX.Element;
|
|
200
|
+
displayName: string;
|
|
201
|
+
};
|
|
132
202
|
|
|
133
|
-
declare const ApertoDescription:
|
|
203
|
+
declare const ApertoDescription: {
|
|
204
|
+
({ ref, ...props }: ComponentPropsWithRef<typeof Dialog.Description>): react.JSX.Element;
|
|
205
|
+
displayName: string;
|
|
206
|
+
};
|
|
134
207
|
|
|
135
208
|
interface ApertoOverlayProps {
|
|
136
209
|
className?: string;
|
|
137
210
|
/** Internal flag used to fade the overlay during measured close transitions. */
|
|
138
211
|
fadeOut?: boolean;
|
|
139
|
-
|
|
212
|
+
ref?: Ref<HTMLDivElement>;
|
|
213
|
+
style?: CSSProperties;
|
|
140
214
|
}
|
|
141
|
-
declare const ApertoOverlay:
|
|
215
|
+
declare const ApertoOverlay: {
|
|
216
|
+
({ className, fadeOut, ref, style }: ApertoOverlayProps): react.JSX.Element;
|
|
217
|
+
displayName: string;
|
|
218
|
+
};
|
|
142
219
|
|
|
143
220
|
interface ApertoPortalProps {
|
|
144
221
|
children: ReactNode;
|
|
145
222
|
/** Container element for the portal (default: document.body) */
|
|
146
223
|
container?: HTMLElement;
|
|
147
224
|
}
|
|
148
|
-
declare
|
|
225
|
+
declare const ApertoPortal: ({ children, container }: ApertoPortalProps) => react.JSX.Element;
|
|
149
226
|
|
|
150
227
|
interface ApertoRootProps extends Omit<ComponentPropsWithoutRef<typeof Dialog.Root>, "open" | "onOpenChange"> {
|
|
151
228
|
children: ReactNode;
|
|
@@ -162,11 +239,14 @@ interface ApertoRootProps extends Omit<ComponentPropsWithoutRef<typeof Dialog.Ro
|
|
|
162
239
|
/** Force reduced motion regardless of system preference */
|
|
163
240
|
reduceMotion?: boolean;
|
|
164
241
|
}
|
|
165
|
-
declare
|
|
242
|
+
declare const ApertoRoot: ({ children, dismissible, layoutId: layoutIdProp, motion: motionProp, open: controlledOpen, onOpenChange: controlledOnOpenChange, reduceMotion: reduceMotionProp, ...dialogProps }: ApertoRootProps) => react.JSX.Element;
|
|
166
243
|
|
|
167
|
-
declare const ApertoTitle:
|
|
244
|
+
declare const ApertoTitle: {
|
|
245
|
+
({ ref, ...props }: ComponentPropsWithRef<typeof Dialog.Title>): react.JSX.Element;
|
|
246
|
+
displayName: string;
|
|
247
|
+
};
|
|
168
248
|
|
|
169
|
-
interface ApertoTriggerProps extends
|
|
249
|
+
interface ApertoTriggerProps extends ComponentPropsWithRef<typeof Dialog.Trigger> {
|
|
170
250
|
/** Internal flag used by grouped thumbnails to raise only the active trigger. */
|
|
171
251
|
active?: boolean;
|
|
172
252
|
/** Override motion preset for this trigger */
|
|
@@ -174,14 +254,17 @@ interface ApertoTriggerProps extends ComponentPropsWithoutRef<typeof Dialog.Trig
|
|
|
174
254
|
/** Internal shared layout ID override for grouped thumbnails. */
|
|
175
255
|
sharedLayoutId?: string | false;
|
|
176
256
|
}
|
|
177
|
-
declare const ApertoTrigger:
|
|
257
|
+
declare const ApertoTrigger: {
|
|
258
|
+
({ active, children, motion: motionOverride, ref, sharedLayoutId, ...props }: ApertoTriggerProps): react.JSX.Element;
|
|
259
|
+
displayName: string;
|
|
260
|
+
};
|
|
178
261
|
|
|
179
262
|
/**
|
|
180
263
|
* Motion presets — each bundles transition timing AND drag physics
|
|
181
264
|
* so "snappy" feels snappy everywhere: open, close, and drag.
|
|
182
265
|
*
|
|
183
|
-
* Curves and springs
|
|
184
|
-
*
|
|
266
|
+
* Curves and springs come from the shared @howells/motion tokens so motion
|
|
267
|
+
* feel stays consistent across the catalog.
|
|
185
268
|
*/
|
|
186
269
|
declare const PRESETS: Record<MotionPresetName, MotionPreset>;
|
|
187
270
|
type ComponentType = "trigger" | "content" | "backdrop";
|
|
@@ -193,33 +276,69 @@ type ComponentType = "trigger" | "content" | "backdrop";
|
|
|
193
276
|
*
|
|
194
277
|
* If `prefers-reduced-motion` is active, always returns "reduced".
|
|
195
278
|
*/
|
|
196
|
-
declare
|
|
279
|
+
declare const resolvePreset: (componentType: ComponentType, componentMotion: MotionPresetName | undefined, globalPreset: MotionPresetName, variants: MotionVariants | undefined, reduceMotion: boolean) => MotionPreset;
|
|
197
280
|
|
|
198
281
|
/** Lower-level compound component namespace for advanced composition. */
|
|
199
282
|
declare const ApertoPrimitive: {
|
|
200
|
-
Close:
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
283
|
+
Close: {
|
|
284
|
+
({ children, ref, ...props }: react.ComponentPropsWithRef<react.ForwardRefExoticComponent<Dialog.DialogCloseProps & react.RefAttributes<HTMLButtonElement>>>): react.JSX.Element;
|
|
285
|
+
displayName: string;
|
|
286
|
+
};
|
|
287
|
+
Content: {
|
|
288
|
+
({ children, className, motion: motionOverride, placement, ref, sharedLayoutId, style, ...props }: ApertoContentProps): react.JSX.Element;
|
|
289
|
+
displayName: string;
|
|
290
|
+
};
|
|
291
|
+
Description: {
|
|
292
|
+
({ ref, ...props }: react.ComponentPropsWithRef<react.ForwardRefExoticComponent<Dialog.DialogDescriptionProps & react.RefAttributes<HTMLParagraphElement>>>): react.JSX.Element;
|
|
293
|
+
displayName: string;
|
|
294
|
+
};
|
|
295
|
+
Overlay: {
|
|
296
|
+
({ className, fadeOut, ref, style }: ApertoOverlayProps): react.JSX.Element;
|
|
297
|
+
displayName: string;
|
|
298
|
+
};
|
|
299
|
+
Portal: ({ children, container }: ApertoPortalProps) => react.JSX.Element;
|
|
300
|
+
Root: ({ children, dismissible, layoutId: layoutIdProp, motion: motionProp, open: controlledOpen, onOpenChange: controlledOnOpenChange, reduceMotion: reduceMotionProp, ...dialogProps }: ApertoRootProps) => react.JSX.Element;
|
|
301
|
+
Title: {
|
|
302
|
+
({ ref, ...props }: react.ComponentPropsWithRef<react.ForwardRefExoticComponent<Dialog.DialogTitleProps & react.RefAttributes<HTMLHeadingElement>>>): react.JSX.Element;
|
|
303
|
+
displayName: string;
|
|
304
|
+
};
|
|
305
|
+
Trigger: {
|
|
306
|
+
({ active, children, motion: motionOverride, ref, sharedLayoutId, ...props }: ApertoTriggerProps): react.JSX.Element;
|
|
307
|
+
displayName: string;
|
|
308
|
+
};
|
|
208
309
|
};
|
|
209
310
|
/** Primary media-first component namespace. */
|
|
210
|
-
declare const Aperto:
|
|
211
|
-
Group:
|
|
311
|
+
declare const Aperto: (({ classNames, dismissible, media, renderImage, renderVideo, }: ApertoProps) => react.JSX.Element) & {
|
|
312
|
+
Group: ({ children, classNames, dismissible, index, initialIndex, media, motion: motionProp, navigationMotion, onIndexChange, renderImage, renderVideo, }: ApertoGroupProps) => react.JSX.Element;
|
|
212
313
|
Primitive: {
|
|
213
|
-
Close:
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
314
|
+
Close: {
|
|
315
|
+
({ children, ref, ...props }: react.ComponentPropsWithRef<react.ForwardRefExoticComponent<Dialog.DialogCloseProps & react.RefAttributes<HTMLButtonElement>>>): react.JSX.Element;
|
|
316
|
+
displayName: string;
|
|
317
|
+
};
|
|
318
|
+
Content: {
|
|
319
|
+
({ children, className, motion: motionOverride, placement, ref, sharedLayoutId, style, ...props }: ApertoContentProps): react.JSX.Element;
|
|
320
|
+
displayName: string;
|
|
321
|
+
};
|
|
322
|
+
Description: {
|
|
323
|
+
({ ref, ...props }: react.ComponentPropsWithRef<react.ForwardRefExoticComponent<Dialog.DialogDescriptionProps & react.RefAttributes<HTMLParagraphElement>>>): react.JSX.Element;
|
|
324
|
+
displayName: string;
|
|
325
|
+
};
|
|
326
|
+
Overlay: {
|
|
327
|
+
({ className, fadeOut, ref, style }: ApertoOverlayProps): react.JSX.Element;
|
|
328
|
+
displayName: string;
|
|
329
|
+
};
|
|
330
|
+
Portal: ({ children, container }: ApertoPortalProps) => react.JSX.Element;
|
|
331
|
+
Root: ({ children, dismissible, layoutId: layoutIdProp, motion: motionProp, open: controlledOpen, onOpenChange: controlledOnOpenChange, reduceMotion: reduceMotionProp, ...dialogProps }: ApertoRootProps) => react.JSX.Element;
|
|
332
|
+
Title: {
|
|
333
|
+
({ ref, ...props }: react.ComponentPropsWithRef<react.ForwardRefExoticComponent<Dialog.DialogTitleProps & react.RefAttributes<HTMLHeadingElement>>>): react.JSX.Element;
|
|
334
|
+
displayName: string;
|
|
335
|
+
};
|
|
336
|
+
Trigger: {
|
|
337
|
+
({ active, children, motion: motionOverride, ref, sharedLayoutId, ...props }: ApertoTriggerProps): react.JSX.Element;
|
|
338
|
+
displayName: string;
|
|
339
|
+
};
|
|
221
340
|
};
|
|
222
|
-
Thumbnail:
|
|
341
|
+
Thumbnail: ({ children, className, index }: ApertoThumbnailProps) => react.JSX.Element | null;
|
|
223
342
|
};
|
|
224
343
|
|
|
225
344
|
export { Aperto, type ApertoClassNames, ApertoClose, ApertoContent, type ApertoContentProps, ApertoDescription, ApertoGroup, type ApertoGroupProps, type ApertoImageItem, type ApertoMediaItem, ApertoOverlay, type ApertoOverlayProps, ApertoPortal, type ApertoPortalProps, ApertoPrimitive, type ApertoProps, ApertoRoot, type ApertoRootProps, ApertoThumbnail, type ApertoThumbnailProps, ApertoTitle, ApertoTrigger, type ApertoTriggerProps, type ApertoVideoItem, type DismissibleConfig, type DragSpringConfig, type MotionPreset, type MotionPresetName, type MotionProp, type MotionVariants, type NavigationMotionPresetName, PRESETS, type RenderImage, type RenderVideo, resolvePreset };
|