@patternmode/aperto 0.2.0 → 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/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
1
  import * as react from 'react';
3
2
  import { ImgHTMLAttributes, ReactNode, VideoHTMLAttributes, ComponentPropsWithRef, Ref, CSSProperties, ComponentPropsWithoutRef } from 'react';
4
3
  import * as Dialog from '@radix-ui/react-dialog';
@@ -179,12 +178,12 @@ interface ApertoThumbnailProps {
179
178
  index: number;
180
179
  }
181
180
 
182
- declare const ApertoGroup: ({ children, classNames, dismissible, index: controlledIndex, initialIndex, media, motion: motionProp, navigationMotion, onIndexChange, renderImage, renderVideo, }: ApertoGroupProps) => 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;
183
182
 
184
- declare const ApertoThumbnail: ({ children, className, index }: ApertoThumbnailProps) => react_jsx_runtime.JSX.Element | null;
183
+ declare const ApertoThumbnail: ({ children, className, index }: ApertoThumbnailProps) => react.JSX.Element | null;
185
184
 
186
185
  declare const ApertoClose: {
187
- ({ children, ref, ...props }: ComponentPropsWithRef<typeof Dialog.Close>): react_jsx_runtime.JSX.Element;
186
+ ({ children, ref, ...props }: ComponentPropsWithRef<typeof Dialog.Close>): react.JSX.Element;
188
187
  displayName: string;
189
188
  };
190
189
 
@@ -197,12 +196,12 @@ interface ApertoContentProps extends Omit<ComponentPropsWithRef<typeof Dialog.Co
197
196
  sharedLayoutId?: string | false;
198
197
  }
199
198
  declare const ApertoContent: {
200
- ({ children, className, motion: motionOverride, placement, ref, sharedLayoutId, style, ...props }: ApertoContentProps): react_jsx_runtime.JSX.Element;
199
+ ({ children, className, motion: motionOverride, placement, ref, sharedLayoutId, style, ...props }: ApertoContentProps): react.JSX.Element;
201
200
  displayName: string;
202
201
  };
203
202
 
204
203
  declare const ApertoDescription: {
205
- ({ ref, ...props }: ComponentPropsWithRef<typeof Dialog.Description>): react_jsx_runtime.JSX.Element;
204
+ ({ ref, ...props }: ComponentPropsWithRef<typeof Dialog.Description>): react.JSX.Element;
206
205
  displayName: string;
207
206
  };
208
207
 
@@ -214,7 +213,7 @@ interface ApertoOverlayProps {
214
213
  style?: CSSProperties;
215
214
  }
216
215
  declare const ApertoOverlay: {
217
- ({ className, fadeOut, ref, style }: ApertoOverlayProps): react_jsx_runtime.JSX.Element;
216
+ ({ className, fadeOut, ref, style }: ApertoOverlayProps): react.JSX.Element;
218
217
  displayName: string;
219
218
  };
220
219
 
@@ -223,7 +222,7 @@ interface ApertoPortalProps {
223
222
  /** Container element for the portal (default: document.body) */
224
223
  container?: HTMLElement;
225
224
  }
226
- declare const ApertoPortal: ({ children, container }: ApertoPortalProps) => react_jsx_runtime.JSX.Element;
225
+ declare const ApertoPortal: ({ children, container }: ApertoPortalProps) => react.JSX.Element;
227
226
 
228
227
  interface ApertoRootProps extends Omit<ComponentPropsWithoutRef<typeof Dialog.Root>, "open" | "onOpenChange"> {
229
228
  children: ReactNode;
@@ -240,10 +239,10 @@ interface ApertoRootProps extends Omit<ComponentPropsWithoutRef<typeof Dialog.Ro
240
239
  /** Force reduced motion regardless of system preference */
241
240
  reduceMotion?: boolean;
242
241
  }
243
- declare const ApertoRoot: ({ children, dismissible, layoutId: layoutIdProp, motion: motionProp, open: controlledOpen, onOpenChange: controlledOnOpenChange, reduceMotion: reduceMotionProp, ...dialogProps }: ApertoRootProps) => react_jsx_runtime.JSX.Element;
242
+ declare const ApertoRoot: ({ children, dismissible, layoutId: layoutIdProp, motion: motionProp, open: controlledOpen, onOpenChange: controlledOnOpenChange, reduceMotion: reduceMotionProp, ...dialogProps }: ApertoRootProps) => react.JSX.Element;
244
243
 
245
244
  declare const ApertoTitle: {
246
- ({ ref, ...props }: ComponentPropsWithRef<typeof Dialog.Title>): react_jsx_runtime.JSX.Element;
245
+ ({ ref, ...props }: ComponentPropsWithRef<typeof Dialog.Title>): react.JSX.Element;
247
246
  displayName: string;
248
247
  };
249
248
 
@@ -256,7 +255,7 @@ interface ApertoTriggerProps extends ComponentPropsWithRef<typeof Dialog.Trigger
256
255
  sharedLayoutId?: string | false;
257
256
  }
258
257
  declare const ApertoTrigger: {
259
- ({ active, children, motion: motionOverride, ref, sharedLayoutId, ...props }: ApertoTriggerProps): react_jsx_runtime.JSX.Element;
258
+ ({ active, children, motion: motionOverride, ref, sharedLayoutId, ...props }: ApertoTriggerProps): react.JSX.Element;
260
259
  displayName: string;
261
260
  };
262
261
 
@@ -264,8 +263,8 @@ declare const ApertoTrigger: {
264
263
  * Motion presets — each bundles transition timing AND drag physics
265
264
  * so "snappy" feels snappy everywhere: open, close, and drag.
266
265
  *
267
- * Curves and springs are local copies of the Howells motion tokens so the
268
- * published package has no private workspace runtime dependencies.
266
+ * Curves and springs come from the shared @howells/motion tokens so motion
267
+ * feel stays consistent across the catalog.
269
268
  */
270
269
  declare const PRESETS: Record<MotionPresetName, MotionPreset>;
271
270
  type ComponentType = "trigger" | "content" | "backdrop";
@@ -282,64 +281,64 @@ declare const resolvePreset: (componentType: ComponentType, componentMotion: Mot
282
281
  /** Lower-level compound component namespace for advanced composition. */
283
282
  declare const ApertoPrimitive: {
284
283
  Close: {
285
- ({ children, ref, ...props }: react.ComponentPropsWithRef<react.ForwardRefExoticComponent<Dialog.DialogCloseProps & react.RefAttributes<HTMLButtonElement>>>): react_jsx_runtime.JSX.Element;
284
+ ({ children, ref, ...props }: react.ComponentPropsWithRef<react.ForwardRefExoticComponent<Dialog.DialogCloseProps & react.RefAttributes<HTMLButtonElement>>>): react.JSX.Element;
286
285
  displayName: string;
287
286
  };
288
287
  Content: {
289
- ({ children, className, motion: motionOverride, placement, ref, sharedLayoutId, style, ...props }: ApertoContentProps): react_jsx_runtime.JSX.Element;
288
+ ({ children, className, motion: motionOverride, placement, ref, sharedLayoutId, style, ...props }: ApertoContentProps): react.JSX.Element;
290
289
  displayName: string;
291
290
  };
292
291
  Description: {
293
- ({ ref, ...props }: react.ComponentPropsWithRef<react.ForwardRefExoticComponent<Dialog.DialogDescriptionProps & react.RefAttributes<HTMLParagraphElement>>>): react_jsx_runtime.JSX.Element;
292
+ ({ ref, ...props }: react.ComponentPropsWithRef<react.ForwardRefExoticComponent<Dialog.DialogDescriptionProps & react.RefAttributes<HTMLParagraphElement>>>): react.JSX.Element;
294
293
  displayName: string;
295
294
  };
296
295
  Overlay: {
297
- ({ className, fadeOut, ref, style }: ApertoOverlayProps): react_jsx_runtime.JSX.Element;
296
+ ({ className, fadeOut, ref, style }: ApertoOverlayProps): react.JSX.Element;
298
297
  displayName: string;
299
298
  };
300
- Portal: ({ children, container }: ApertoPortalProps) => react_jsx_runtime.JSX.Element;
301
- Root: ({ children, dismissible, layoutId: layoutIdProp, motion: motionProp, open: controlledOpen, onOpenChange: controlledOnOpenChange, reduceMotion: reduceMotionProp, ...dialogProps }: ApertoRootProps) => react_jsx_runtime.JSX.Element;
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;
302
301
  Title: {
303
- ({ ref, ...props }: react.ComponentPropsWithRef<react.ForwardRefExoticComponent<Dialog.DialogTitleProps & react.RefAttributes<HTMLHeadingElement>>>): react_jsx_runtime.JSX.Element;
302
+ ({ ref, ...props }: react.ComponentPropsWithRef<react.ForwardRefExoticComponent<Dialog.DialogTitleProps & react.RefAttributes<HTMLHeadingElement>>>): react.JSX.Element;
304
303
  displayName: string;
305
304
  };
306
305
  Trigger: {
307
- ({ active, children, motion: motionOverride, ref, sharedLayoutId, ...props }: ApertoTriggerProps): react_jsx_runtime.JSX.Element;
306
+ ({ active, children, motion: motionOverride, ref, sharedLayoutId, ...props }: ApertoTriggerProps): react.JSX.Element;
308
307
  displayName: string;
309
308
  };
310
309
  };
311
310
  /** Primary media-first component namespace. */
312
- declare const Aperto: (({ classNames, dismissible, media, renderImage, renderVideo, }: ApertoProps) => react_jsx_runtime.JSX.Element) & {
313
- Group: ({ children, classNames, dismissible, index: controlledIndex, initialIndex, media, motion: motionProp, navigationMotion, onIndexChange, renderImage, renderVideo, }: ApertoGroupProps) => react_jsx_runtime.JSX.Element;
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;
314
313
  Primitive: {
315
314
  Close: {
316
- ({ children, ref, ...props }: react.ComponentPropsWithRef<react.ForwardRefExoticComponent<Dialog.DialogCloseProps & react.RefAttributes<HTMLButtonElement>>>): react_jsx_runtime.JSX.Element;
315
+ ({ children, ref, ...props }: react.ComponentPropsWithRef<react.ForwardRefExoticComponent<Dialog.DialogCloseProps & react.RefAttributes<HTMLButtonElement>>>): react.JSX.Element;
317
316
  displayName: string;
318
317
  };
319
318
  Content: {
320
- ({ children, className, motion: motionOverride, placement, ref, sharedLayoutId, style, ...props }: ApertoContentProps): react_jsx_runtime.JSX.Element;
319
+ ({ children, className, motion: motionOverride, placement, ref, sharedLayoutId, style, ...props }: ApertoContentProps): react.JSX.Element;
321
320
  displayName: string;
322
321
  };
323
322
  Description: {
324
- ({ ref, ...props }: react.ComponentPropsWithRef<react.ForwardRefExoticComponent<Dialog.DialogDescriptionProps & react.RefAttributes<HTMLParagraphElement>>>): react_jsx_runtime.JSX.Element;
323
+ ({ ref, ...props }: react.ComponentPropsWithRef<react.ForwardRefExoticComponent<Dialog.DialogDescriptionProps & react.RefAttributes<HTMLParagraphElement>>>): react.JSX.Element;
325
324
  displayName: string;
326
325
  };
327
326
  Overlay: {
328
- ({ className, fadeOut, ref, style }: ApertoOverlayProps): react_jsx_runtime.JSX.Element;
327
+ ({ className, fadeOut, ref, style }: ApertoOverlayProps): react.JSX.Element;
329
328
  displayName: string;
330
329
  };
331
- Portal: ({ children, container }: ApertoPortalProps) => react_jsx_runtime.JSX.Element;
332
- Root: ({ children, dismissible, layoutId: layoutIdProp, motion: motionProp, open: controlledOpen, onOpenChange: controlledOnOpenChange, reduceMotion: reduceMotionProp, ...dialogProps }: ApertoRootProps) => react_jsx_runtime.JSX.Element;
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;
333
332
  Title: {
334
- ({ ref, ...props }: react.ComponentPropsWithRef<react.ForwardRefExoticComponent<Dialog.DialogTitleProps & react.RefAttributes<HTMLHeadingElement>>>): react_jsx_runtime.JSX.Element;
333
+ ({ ref, ...props }: react.ComponentPropsWithRef<react.ForwardRefExoticComponent<Dialog.DialogTitleProps & react.RefAttributes<HTMLHeadingElement>>>): react.JSX.Element;
335
334
  displayName: string;
336
335
  };
337
336
  Trigger: {
338
- ({ active, children, motion: motionOverride, ref, sharedLayoutId, ...props }: ApertoTriggerProps): react_jsx_runtime.JSX.Element;
337
+ ({ active, children, motion: motionOverride, ref, sharedLayoutId, ...props }: ApertoTriggerProps): react.JSX.Element;
339
338
  displayName: string;
340
339
  };
341
340
  };
342
- Thumbnail: ({ children, className, index }: ApertoThumbnailProps) => react_jsx_runtime.JSX.Element | null;
341
+ Thumbnail: ({ children, className, index }: ApertoThumbnailProps) => react.JSX.Element | null;
343
342
  };
344
343
 
345
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 };
package/dist/index.js CHANGED
@@ -32,23 +32,8 @@ var OPACITY_OUTPUT = [1, 0.96];
32
32
  var DEFAULT_DISTANCE_THRESHOLD = 100;
33
33
  var DEFAULT_VELOCITY_THRESHOLD = 500;
34
34
 
35
- // src/motion-tokens.ts
36
- var durations = {
37
- moderate: 0.4,
38
- snappy: 0.22
39
- };
40
- var easings = {
41
- customGentle: [0.25, 0.1, 0.12, 1],
42
- snappy: [0.22, 1, 0.36, 1]
43
- };
44
- var springs = {
45
- bouncy: { damping: 12, mass: 1, stiffness: 260 },
46
- natural: { damping: 20, mass: 1, stiffness: 200 },
47
- snappy: { damping: 28, mass: 0.8, stiffness: 400 },
48
- stiff: { damping: 30, mass: 1, stiffness: 500 }
49
- };
50
-
51
35
  // src/presets.ts
36
+ import { durations, easings, springs } from "@howells/motion";
52
37
  var PRESETS = {
53
38
  bouncy: {
54
39
  drag: {
@@ -183,7 +168,7 @@ var ApertoContent = ({
183
168
  dragElastic: 0,
184
169
  dragMomentum: false,
185
170
  dragSnapToOrigin: true,
186
- layout: contentLayoutId ? true : void 0,
171
+ layout: contentLayoutId === void 0 || contentLayoutId === "" ? void 0 : true,
187
172
  layoutId: contentLayoutId,
188
173
  onDrag: isDismissible ? handleDrag : void 0,
189
174
  onDragEnd: isDismissible ? handleDragEnd : void 0,
@@ -216,10 +201,11 @@ var useApertoGroup = () => {
216
201
  // src/aperto-overlay.tsx
217
202
  import * as Dialog3 from "@radix-ui/react-dialog";
218
203
  import { m as m2 } from "motion/react";
204
+ import { easings as easings2 } from "@howells/motion";
219
205
  import { jsx as jsx3 } from "react/jsx-runtime";
220
206
  var OVERLAY_TRANSITION = {
221
207
  duration: 0.3,
222
- ease: easings.customGentle
208
+ ease: easings2.customGentle
223
209
  };
224
210
  var OVERLAY_TRANSITION_REDUCED = {
225
211
  duration: 0.01,
@@ -231,7 +217,7 @@ var ApertoOverlay = ({ className, fadeOut, ref, style }) => {
231
217
  return /* @__PURE__ */ jsx3(Dialog3.Overlay, { asChild: true, forceMount: true, children: /* @__PURE__ */ jsx3(
232
218
  m2.div,
233
219
  {
234
- animate: { opacity: fadeOut ? 0 : 1 },
220
+ animate: { opacity: fadeOut === true ? 0 : 1 },
235
221
  className,
236
222
  "data-slot": "aperto-overlay",
237
223
  exit: { opacity: 0 },
@@ -410,7 +396,7 @@ var ApertoTransitionMedia = ({
410
396
  // src/media-utils.ts
411
397
  var getMediaLabel = (item) => item.title ?? item.alt ?? "media";
412
398
  var getMediaKey = (item, index) => item.id ?? `${item.type}:${item.src}:${index}`;
413
- var getDescriptionProps = (item) => item.description ? {} : { "aria-describedby": void 0 };
399
+ var getDescriptionProps = (item) => item.description === void 0 || item.description === "" ? { "aria-describedby": void 0 } : {};
414
400
 
415
401
  // src/expanded-media-stage.tsx
416
402
  import { jsx as jsx8 } from "react/jsx-runtime";
@@ -548,13 +534,17 @@ var ApertoMediaTransitionClone = ({
548
534
  }) => {
549
535
  const ctx = useApertoContext();
550
536
  useEffect(() => {
551
- if (!transition?.to) {
552
- return;
537
+ let timer;
538
+ if (transition?.to !== void 0) {
539
+ timer = setTimeout(onComplete, transitionDurationMs(ctx.preset.transition));
553
540
  }
554
- const timer = setTimeout(onComplete, transitionDurationMs(ctx.preset.transition));
555
- return () => clearTimeout(timer);
541
+ return () => {
542
+ if (timer !== void 0) {
543
+ clearTimeout(timer);
544
+ }
545
+ };
556
546
  }, [ctx.preset.transition, onComplete, transition]);
557
- if (!transition?.to) {
547
+ if (transition?.to === void 0) {
558
548
  return null;
559
549
  }
560
550
  return /* @__PURE__ */ jsx9(
@@ -655,7 +645,7 @@ var apertoGroupReducer = (state, action) => {
655
645
 
656
646
  // src/Aperto/aperto-keyboard.ts
657
647
  var shouldIgnoreKeyboardNavigationTarget = (target) => {
658
- if (!(target instanceof Element)) {
648
+ if (!(target instanceof HTMLElement)) {
659
649
  return false;
660
650
  }
661
651
  return target.isContentEditable || Boolean(
@@ -701,67 +691,150 @@ var ApertoMediaNavigationButtons = ({
701
691
  )
702
692
  ] });
703
693
  };
704
- var ApertoGroup = ({
705
- children,
694
+ var useThumbnailMap = () => {
695
+ const thumbnailRefs = useRef(null);
696
+ thumbnailRefs.current ??= /* @__PURE__ */ new Map();
697
+ return thumbnailRefs.current;
698
+ };
699
+ var getExpandedMediaStyle = (activeMedia) => {
700
+ if (activeMedia === void 0 || activeMedia.width === void 0 || activeMedia.height === void 0) {
701
+ return void 0;
702
+ }
703
+ return {
704
+ "--aperto-expanded-aspect-ratio": `${activeMedia.width} / ${activeMedia.height}`,
705
+ "--aperto-expanded-aspect-ratio-height": activeMedia.height,
706
+ "--aperto-expanded-aspect-ratio-width": activeMedia.width
707
+ };
708
+ };
709
+ var ApertoGroupPortal = ({
710
+ activeMedia,
706
711
  classNames,
707
- dismissible,
708
- index: controlledIndex,
709
- initialIndex = 0,
712
+ expandedMediaStyle,
713
+ handleCloseAutoFocus,
714
+ handleContentKeyDown,
715
+ handleMediaTransitionComplete,
716
+ hasNavigation,
717
+ index,
718
+ mediaLength,
719
+ navigationDirection,
720
+ navigationMotion,
721
+ renderImage,
722
+ renderVideo,
723
+ setExpandedMediaNode,
724
+ startClose,
725
+ transition,
726
+ goToNext,
727
+ goToPrevious
728
+ }) => {
729
+ if (activeMedia === void 0) {
730
+ return null;
731
+ }
732
+ return /* @__PURE__ */ jsxs(ApertoPortal, { children: [
733
+ /* @__PURE__ */ jsx10(ApertoOverlay, { className: classNames?.overlay, fadeOut: transition?.phase === "closing" }),
734
+ /* @__PURE__ */ jsxs(
735
+ ApertoContent,
736
+ {
737
+ className: classNames?.content,
738
+ "data-aperto-transition": transition?.phase,
739
+ onCloseAutoFocus: handleCloseAutoFocus,
740
+ onKeyDown: handleContentKeyDown,
741
+ sharedLayoutId: false,
742
+ ...getDescriptionProps(activeMedia),
743
+ children: [
744
+ /* @__PURE__ */ jsxs("div", { "data-slot": "aperto-media", ref: setExpandedMediaNode, style: expandedMediaStyle, children: [
745
+ /* @__PURE__ */ jsx10(
746
+ ApertoExpandedMediaStage,
747
+ {
748
+ direction: navigationDirection,
749
+ index,
750
+ item: activeMedia,
751
+ navigationMotion,
752
+ renderImage,
753
+ renderVideo
754
+ }
755
+ ),
756
+ /* @__PURE__ */ jsx10(
757
+ ApertoMediaNavigationButtons,
758
+ {
759
+ classNames,
760
+ enabled: hasNavigation,
761
+ onNext: goToNext,
762
+ onPrevious: goToPrevious
763
+ }
764
+ )
765
+ ] }),
766
+ /* @__PURE__ */ jsx10(ApertoTitle, { children: activeMedia.title ?? getMediaLabel(activeMedia) }),
767
+ activeMedia.description === void 0 || activeMedia.description === "" ? null : /* @__PURE__ */ jsx10(ApertoDescription, { children: activeMedia.description }),
768
+ hasNavigation ? /* @__PURE__ */ jsxs("div", { className: classNames?.counter, "data-slot": "aperto-counter", children: [
769
+ index + 1,
770
+ " / ",
771
+ mediaLength
772
+ ] }) : null,
773
+ /* @__PURE__ */ jsx10(
774
+ "button",
775
+ {
776
+ "aria-label": "Close",
777
+ className: classNames?.closeButton,
778
+ "data-slot": "aperto-close",
779
+ onClick: startClose,
780
+ type: "button",
781
+ children: /* @__PURE__ */ jsx10(X, { "aria-hidden": "true", size: 17, strokeWidth: 2 })
782
+ }
783
+ )
784
+ ]
785
+ }
786
+ ),
787
+ /* @__PURE__ */ jsx10(
788
+ ApertoMediaTransitionClone,
789
+ {
790
+ onComplete: handleMediaTransitionComplete,
791
+ renderImage,
792
+ renderVideo,
793
+ transition
794
+ }
795
+ )
796
+ ] });
797
+ };
798
+ var useApertoMediaLifecycle = ({
799
+ activeMedia,
800
+ dispatch,
801
+ index,
710
802
  media,
711
- motion: motionProp,
712
- navigationMotion = "glide",
713
803
  onIndexChange,
714
- renderImage,
715
- renderVideo
804
+ state
716
805
  }) => {
717
- const generatedId = useId2();
718
- const [state, dispatch] = useReducer(apertoGroupReducer, initialIndex, getInitialGroupState);
719
- const isControlled = controlledIndex !== void 0;
720
- const index = isControlled ? controlledIndex : state.internalIndex;
721
- const activeMedia = media[index] ?? media[0];
722
806
  const expandedMediaRef = useRef(null);
723
- const thumbnailRefs = useRef(null);
724
- if (thumbnailRefs.current === null) {
725
- thumbnailRefs.current = /* @__PURE__ */ new Map();
726
- }
727
- const thumbnailMap = thumbnailRefs.current;
728
- const sharedLayoutIdForIndex = (nextIndex) => `aperto-group-${generatedId}-${nextIndex}-shared`;
729
- const sharedLayoutId = sharedLayoutIdForIndex(state.layoutSourceIndex);
807
+ const thumbnailMap = useThumbnailMap();
730
808
  const setExpandedMediaNode = (node) => {
731
809
  expandedMediaRef.current = node;
732
- if (node) {
733
- const targetRect = rectFromElement(node);
734
- if (targetRect) {
735
- dispatch({ rect: targetRect, type: "complete-opening-target" });
736
- }
810
+ if (node === null) {
811
+ return;
812
+ }
813
+ const targetRect = rectFromElement(node);
814
+ if (targetRect !== null) {
815
+ dispatch({ rect: targetRect, type: "complete-opening-target" });
737
816
  }
738
817
  };
739
818
  const registerThumbnail = (thumbIndex, node) => {
740
- if (node) {
819
+ if (node !== null) {
741
820
  thumbnailMap.set(thumbIndex, node);
742
821
  return;
743
822
  }
744
823
  thumbnailMap.delete(thumbIndex);
745
824
  };
746
825
  useLayoutEffect(() => {
747
- if (state.mediaTransition?.phase !== "opening" || state.mediaTransition.to || !expandedMediaRef.current) {
826
+ if (state.mediaTransition?.phase !== "opening" || state.mediaTransition.to !== void 0 || expandedMediaRef.current === null) {
748
827
  return;
749
828
  }
750
829
  const targetRect = rectFromElement(expandedMediaRef.current);
751
- if (targetRect) {
830
+ if (targetRect !== null) {
752
831
  dispatch({ rect: targetRect, type: "complete-opening-target" });
753
832
  }
754
- }, [state.mediaTransition]);
755
- const setIndex = (nextIndex) => {
756
- if (!isControlled) {
757
- dispatch({ index: nextIndex, type: "set-index" });
758
- }
759
- onIndexChange?.(nextIndex);
760
- };
833
+ }, [dispatch, state.mediaTransition]);
761
834
  const openAtIndex = (thumbIndex) => {
762
835
  const sourceRect = rectFromElement(thumbnailMap.get(thumbIndex) ?? null);
763
- const item = media[thumbIndex];
764
- const transition = sourceRect && item ? { from: sourceRect, item, phase: "opening" } : null;
836
+ const item = media[thumbIndex] ?? null;
837
+ const transition = sourceRect === null || item === null ? null : { from: sourceRect, item, phase: "opening" };
765
838
  dispatch({ index: thumbIndex, transition, type: "open-at-index" });
766
839
  onIndexChange?.(thumbIndex);
767
840
  };
@@ -771,17 +844,12 @@ var ApertoGroup = ({
771
844
  }
772
845
  const sourceRect = rectFromElement(expandedMediaRef.current);
773
846
  const targetRect = rectFromElement(thumbnailMap.get(index) ?? null);
774
- if (!activeMedia || !sourceRect || !targetRect) {
847
+ if (activeMedia === void 0 || sourceRect === null || targetRect === null) {
775
848
  dispatch({ type: "close-without-transition" });
776
849
  return;
777
850
  }
778
851
  dispatch({
779
- transition: {
780
- from: sourceRect,
781
- item: activeMedia,
782
- phase: "closing",
783
- to: targetRect
784
- },
852
+ transition: { from: sourceRect, item: activeMedia, phase: "closing", to: targetRect },
785
853
  type: "start-close"
786
854
  });
787
855
  };
@@ -789,6 +857,38 @@ var ApertoGroup = ({
789
857
  event.preventDefault();
790
858
  thumbnailMap.get(index)?.focus({ preventScroll: true });
791
859
  };
860
+ return { handleCloseAutoFocus, openAtIndex, registerThumbnail, setExpandedMediaNode, startClose };
861
+ };
862
+ var useApertoGroupController = ({
863
+ classNames,
864
+ index: controlledIndex,
865
+ initialIndex = 0,
866
+ media,
867
+ onIndexChange,
868
+ renderImage,
869
+ renderVideo
870
+ }) => {
871
+ const generatedId = useId2();
872
+ const [state, dispatch] = useReducer(apertoGroupReducer, initialIndex, getInitialGroupState);
873
+ const isControlled = controlledIndex !== void 0;
874
+ const index = isControlled ? controlledIndex : state.internalIndex;
875
+ const activeMedia = media[index] ?? media[0];
876
+ const lifecycle = useApertoMediaLifecycle({
877
+ activeMedia,
878
+ dispatch,
879
+ index,
880
+ media,
881
+ onIndexChange,
882
+ state
883
+ });
884
+ const sharedLayoutIdForIndex = (nextIndex) => `aperto-group-${generatedId}-${nextIndex}-shared`;
885
+ const sharedLayoutId = sharedLayoutIdForIndex(state.layoutSourceIndex);
886
+ const setIndex = (nextIndex) => {
887
+ if (!isControlled) {
888
+ dispatch({ index: nextIndex, type: "set-index" });
889
+ }
890
+ onIndexChange?.(nextIndex);
891
+ };
792
892
  const handleMediaTransitionComplete = () => {
793
893
  dispatch({ type: "finish-transition" });
794
894
  };
@@ -797,15 +897,15 @@ var ApertoGroup = ({
797
897
  dispatch({ open: true, type: "set-open" });
798
898
  return;
799
899
  }
800
- startClose();
900
+ lifecycle.startClose();
801
901
  };
802
902
  const value = {
803
903
  classNames,
804
904
  index,
805
905
  media,
806
906
  open: state.open,
807
- openAtIndex,
808
- registerThumbnail,
907
+ openAtIndex: lifecycle.openAtIndex,
908
+ registerThumbnail: lifecycle.registerThumbnail,
809
909
  renderImage,
810
910
  renderVideo,
811
911
  setIndex,
@@ -836,90 +936,78 @@ var ApertoGroup = ({
836
936
  goToNext();
837
937
  }
838
938
  };
839
- const expandedMediaStyle = (() => {
840
- if (!activeMedia?.width || !activeMedia.height) {
841
- return void 0;
842
- }
843
- return {
844
- "--aperto-expanded-aspect-ratio": `${activeMedia.width} / ${activeMedia.height}`,
845
- "--aperto-expanded-aspect-ratio-height": activeMedia.height,
846
- "--aperto-expanded-aspect-ratio-width": activeMedia.width
847
- };
848
- })();
849
- return /* @__PURE__ */ jsx10(ApertoGroupContext.Provider, { value, children: /* @__PURE__ */ jsxs(
939
+ const expandedMediaStyle = getExpandedMediaStyle(activeMedia);
940
+ return {
941
+ activeMedia,
942
+ expandedMediaStyle,
943
+ goToNext,
944
+ goToPrevious,
945
+ handleCloseAutoFocus: lifecycle.handleCloseAutoFocus,
946
+ handleContentKeyDown,
947
+ handleMediaTransitionComplete,
948
+ handleOpenChange,
949
+ hasNavigation,
950
+ index,
951
+ setExpandedMediaNode: lifecycle.setExpandedMediaNode,
952
+ startClose: lifecycle.startClose,
953
+ state,
954
+ value
955
+ };
956
+ };
957
+ var ApertoGroup = ({
958
+ children,
959
+ classNames,
960
+ dismissible,
961
+ index,
962
+ initialIndex,
963
+ media,
964
+ motion: motionProp,
965
+ navigationMotion = "glide",
966
+ onIndexChange,
967
+ renderImage,
968
+ renderVideo
969
+ }) => {
970
+ const controller = useApertoGroupController({
971
+ classNames,
972
+ index,
973
+ initialIndex,
974
+ media,
975
+ onIndexChange,
976
+ renderImage,
977
+ renderVideo
978
+ });
979
+ return /* @__PURE__ */ jsx10(ApertoGroupContext.Provider, { value: controller.value, children: /* @__PURE__ */ jsxs(
850
980
  ApertoRoot,
851
981
  {
852
982
  dismissible,
853
983
  motion: motionProp,
854
- onOpenChange: handleOpenChange,
855
- open: state.open,
984
+ onOpenChange: controller.handleOpenChange,
985
+ open: controller.state.open,
856
986
  children: [
857
987
  children,
858
- activeMedia ? /* @__PURE__ */ jsxs(ApertoPortal, { children: [
859
- /* @__PURE__ */ jsx10(ApertoOverlay, { className: classNames?.overlay, fadeOut: state.closing }),
860
- /* @__PURE__ */ jsxs(
861
- ApertoContent,
862
- {
863
- className: classNames?.content,
864
- "data-aperto-transition": state.mediaTransition?.phase,
865
- onCloseAutoFocus: handleCloseAutoFocus,
866
- onKeyDown: hasNavigation ? handleContentKeyDown : void 0,
867
- sharedLayoutId: false,
868
- ...getDescriptionProps(activeMedia),
869
- children: [
870
- /* @__PURE__ */ jsxs("div", { "data-slot": "aperto-media", ref: setExpandedMediaNode, style: expandedMediaStyle, children: [
871
- /* @__PURE__ */ jsx10(
872
- ApertoExpandedMediaStage,
873
- {
874
- direction: state.navigationDirection,
875
- index,
876
- item: activeMedia,
877
- navigationMotion,
878
- renderImage,
879
- renderVideo
880
- }
881
- ),
882
- /* @__PURE__ */ jsx10(
883
- ApertoMediaNavigationButtons,
884
- {
885
- classNames,
886
- enabled: hasNavigation,
887
- onNext: goToNext,
888
- onPrevious: goToPrevious
889
- }
890
- )
891
- ] }),
892
- /* @__PURE__ */ jsx10(ApertoTitle, { children: activeMedia.title ?? getMediaLabel(activeMedia) }),
893
- activeMedia.description ? /* @__PURE__ */ jsx10(ApertoDescription, { children: activeMedia.description }) : null,
894
- hasNavigation ? /* @__PURE__ */ jsxs("div", { className: classNames?.counter, "data-slot": "aperto-counter", children: [
895
- index + 1,
896
- " / ",
897
- media.length
898
- ] }) : null,
899
- /* @__PURE__ */ jsx10(
900
- "button",
901
- {
902
- "aria-label": "Close",
903
- className: classNames?.closeButton,
904
- "data-slot": "aperto-close",
905
- onClick: startClose,
906
- type: "button",
907
- children: /* @__PURE__ */ jsx10(X, { "aria-hidden": "true", size: 17, strokeWidth: 2 })
908
- }
909
- )
910
- ]
911
- }
912
- ),
913
- /* @__PURE__ */ jsx10(
914
- ApertoMediaTransitionClone,
915
- {
916
- onComplete: handleMediaTransitionComplete,
917
- renderImage,
918
- renderVideo,
919
- transition: state.mediaTransition
920
- }
921
- )
922
- ] }) : null
988
+ /* @__PURE__ */ jsx10(
989
+ ApertoGroupPortal,
990
+ {
991
+ activeMedia: controller.activeMedia,
992
+ classNames,
993
+ expandedMediaStyle: controller.expandedMediaStyle,
994
+ goToNext: controller.goToNext,
995
+ goToPrevious: controller.goToPrevious,
996
+ handleCloseAutoFocus: controller.handleCloseAutoFocus,
997
+ handleContentKeyDown: controller.hasNavigation ? controller.handleContentKeyDown : void 0,
998
+ handleMediaTransitionComplete: controller.handleMediaTransitionComplete,
999
+ hasNavigation: controller.hasNavigation,
1000
+ index: controller.index,
1001
+ mediaLength: media.length,
1002
+ navigationDirection: controller.state.navigationDirection,
1003
+ navigationMotion,
1004
+ renderImage,
1005
+ renderVideo,
1006
+ setExpandedMediaNode: controller.setExpandedMediaNode,
1007
+ startClose: controller.startClose,
1008
+ transition: controller.state.mediaTransition
1009
+ }
1010
+ )
923
1011
  ]
924
1012
  }
925
1013
  ) });
@@ -992,7 +1080,7 @@ var ApertoSingle = ({
992
1080
  /* @__PURE__ */ jsxs2(ApertoContent, { className: classNames?.content, ...getDescriptionProps(media), children: [
993
1081
  /* @__PURE__ */ jsx13(ApertoExpandedMedia, { item: media, renderImage, renderVideo }),
994
1082
  /* @__PURE__ */ jsx13(ApertoTitle, { children: title }),
995
- media.description ? /* @__PURE__ */ jsx13(ApertoDescription, { children: media.description }) : null,
1083
+ media.description === void 0 || media.description === "" ? null : /* @__PURE__ */ jsx13(ApertoDescription, { children: media.description }),
996
1084
  /* @__PURE__ */ jsx13(ApertoClose, { "aria-label": "Close", className: classNames?.closeButton, type: "button" })
997
1085
  ] })
998
1086
  ] })
@@ -1013,8 +1101,12 @@ var ApertoThumbnail = ({ children, className, index }) => {
1013
1101
  active: group.index === index,
1014
1102
  "aria-label": `Open ${getMediaLabel(media)}`,
1015
1103
  className: className ?? group.classNames?.thumbnail,
1016
- onClick: () => group.openAtIndex(index),
1017
- ref: (node) => group.registerThumbnail(index, node),
1104
+ onClick: () => {
1105
+ group.openAtIndex(index);
1106
+ },
1107
+ ref: (node) => {
1108
+ group.registerThumbnail(index, node);
1109
+ },
1018
1110
  sharedLayoutId: false,
1019
1111
  children: children ?? /* @__PURE__ */ jsx14(
1020
1112
  ApertoThumbnailMedia,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/Aperto/aperto-group.tsx","../src/aperto-content.tsx","../src/context.ts","../src/physics.ts","../src/motion-tokens.ts","../src/presets.ts","../src/aperto-description.tsx","../src/aperto-group-context.ts","../src/aperto-overlay.tsx","../src/aperto-portal.tsx","../src/aperto-root.tsx","../src/aperto-title.tsx","../src/expanded-media-stage.tsx","../src/media-rendering.tsx","../src/media-utils.ts","../src/media-transition.tsx","../src/media-transition-utils.ts","../src/Aperto/aperto-group-state.ts","../src/Aperto/aperto-keyboard.ts","../src/aperto-close.tsx","../src/aperto-trigger.tsx","../src/Aperto/aperto-single.tsx","../src/Aperto/aperto-thumbnail.tsx","../src/index.ts"],"sourcesContent":["\"use client\";\n\nimport { ChevronLeft, ChevronRight, X } from \"lucide-react\";\nimport { useId, useLayoutEffect, useReducer, useRef } from \"react\";\nimport type { CSSProperties, KeyboardEvent } from \"react\";\n\nimport { ApertoContent } from \"../aperto-content\";\nimport { ApertoDescription } from \"../aperto-description\";\nimport { ApertoGroupContext } from \"../aperto-group-context\";\nimport { ApertoOverlay } from \"../aperto-overlay\";\nimport { ApertoPortal } from \"../aperto-portal\";\nimport { ApertoRoot } from \"../aperto-root\";\nimport { ApertoTitle } from \"../aperto-title\";\nimport { ApertoExpandedMediaStage } from \"../expanded-media-stage\";\nimport type { NavigationDirection } from \"../expanded-media-stage\";\nimport { ApertoMediaTransitionClone } from \"../media-transition\";\nimport { rectFromElement } from \"../media-transition-utils\";\nimport { getDescriptionProps, getMediaLabel } from \"../media-utils\";\nimport type { ApertoClassNames } from \"../types\";\nimport { apertoGroupReducer, getInitialGroupState } from \"./aperto-group-state\";\nimport { shouldIgnoreKeyboardNavigationTarget } from \"./aperto-keyboard\";\nimport type { ApertoGroupProps } from \"./aperto-types\";\n\nconst ApertoMediaNavigationButtons = ({\n classNames,\n enabled,\n onNext,\n onPrevious,\n}: {\n classNames: ApertoClassNames | undefined;\n enabled: boolean;\n onNext: () => void;\n onPrevious: () => void;\n}) => {\n if (!enabled) {\n return null;\n }\n\n return (\n <>\n <button\n aria-label=\"Previous media\"\n className={classNames?.previousButton}\n data-slot=\"aperto-previous-button\"\n onClick={onPrevious}\n type=\"button\"\n >\n <ChevronLeft aria-hidden=\"true\" size={18} strokeWidth={2} />\n </button>\n <button\n aria-label=\"Next media\"\n className={classNames?.nextButton}\n data-slot=\"aperto-next-button\"\n onClick={onNext}\n type=\"button\"\n >\n <ChevronRight aria-hidden=\"true\" size={18} strokeWidth={2} />\n </button>\n </>\n );\n};\n\nexport const ApertoGroup = ({\n children,\n classNames,\n dismissible,\n index: controlledIndex,\n initialIndex = 0,\n media,\n motion: motionProp,\n navigationMotion = \"glide\",\n onIndexChange,\n renderImage,\n renderVideo,\n}: ApertoGroupProps) => {\n const generatedId = useId();\n const [state, dispatch] = useReducer(apertoGroupReducer, initialIndex, getInitialGroupState);\n const isControlled = controlledIndex !== undefined;\n const index = isControlled ? controlledIndex : state.internalIndex;\n const activeMedia = media[index] ?? media[0];\n const expandedMediaRef = useRef<HTMLDivElement | null>(null);\n const thumbnailRefs = useRef<Map<number, HTMLButtonElement> | null>(null);\n if (thumbnailRefs.current === null) {\n thumbnailRefs.current = new Map();\n }\n const thumbnailMap = thumbnailRefs.current;\n const sharedLayoutIdForIndex = (nextIndex: number) =>\n `aperto-group-${generatedId}-${nextIndex}-shared`;\n const sharedLayoutId = sharedLayoutIdForIndex(state.layoutSourceIndex);\n const setExpandedMediaNode = (node: HTMLDivElement | null) => {\n expandedMediaRef.current = node;\n if (node) {\n const targetRect = rectFromElement(node);\n if (targetRect) {\n dispatch({ rect: targetRect, type: \"complete-opening-target\" });\n }\n }\n };\n\n const registerThumbnail = (thumbIndex: number, node: HTMLButtonElement | null) => {\n if (node) {\n thumbnailMap.set(thumbIndex, node);\n return;\n }\n thumbnailMap.delete(thumbIndex);\n };\n\n useLayoutEffect(() => {\n if (\n state.mediaTransition?.phase !== \"opening\" ||\n state.mediaTransition.to ||\n !expandedMediaRef.current\n ) {\n return;\n }\n\n const targetRect = rectFromElement(expandedMediaRef.current);\n if (targetRect) {\n dispatch({ rect: targetRect, type: \"complete-opening-target\" });\n }\n }, [state.mediaTransition]);\n\n const setIndex = (nextIndex: number) => {\n if (!isControlled) {\n dispatch({ index: nextIndex, type: \"set-index\" });\n }\n onIndexChange?.(nextIndex);\n };\n\n const openAtIndex = (thumbIndex: number) => {\n const sourceRect = rectFromElement(thumbnailMap.get(thumbIndex) ?? null);\n const item = media[thumbIndex];\n const transition =\n sourceRect && item ? { from: sourceRect, item, phase: \"opening\" as const } : null;\n\n dispatch({ index: thumbIndex, transition, type: \"open-at-index\" });\n onIndexChange?.(thumbIndex);\n };\n\n const startClose = () => {\n if (!state.open || state.closing) {\n return;\n }\n\n const sourceRect = rectFromElement(expandedMediaRef.current);\n const targetRect = rectFromElement(thumbnailMap.get(index) ?? null);\n\n if (!activeMedia || !sourceRect || !targetRect) {\n dispatch({ type: \"close-without-transition\" });\n return;\n }\n\n dispatch({\n transition: {\n from: sourceRect,\n item: activeMedia,\n phase: \"closing\",\n to: targetRect,\n },\n type: \"start-close\",\n });\n };\n\n const handleCloseAutoFocus = (event: Event) => {\n event.preventDefault();\n thumbnailMap.get(index)?.focus({ preventScroll: true });\n };\n\n const handleMediaTransitionComplete = () => {\n dispatch({ type: \"finish-transition\" });\n };\n\n const handleOpenChange = (nextOpen: boolean) => {\n if (nextOpen) {\n dispatch({ open: true, type: \"set-open\" });\n return;\n }\n\n startClose();\n };\n\n const value = {\n classNames,\n index,\n media,\n open: state.open,\n openAtIndex,\n registerThumbnail,\n renderImage,\n renderVideo,\n setIndex,\n sharedLayoutId,\n sharedLayoutIdForIndex,\n };\n const hasNavigation = media.length > 1;\n const navigateToIndex = (nextIndex: number, direction: NavigationDirection) => {\n dispatch({ direction, index: nextIndex, type: \"navigate\" });\n onIndexChange?.(nextIndex);\n };\n const goToPrevious = () => {\n navigateToIndex((index - 1 + media.length) % media.length, -1);\n };\n const goToNext = () => {\n navigateToIndex((index + 1) % media.length, 1);\n };\n const handleContentKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (\n event.defaultPrevented ||\n event.altKey ||\n event.ctrlKey ||\n event.metaKey ||\n shouldIgnoreKeyboardNavigationTarget(event.target)\n ) {\n return;\n }\n\n if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n goToPrevious();\n }\n\n if (event.key === \"ArrowRight\") {\n event.preventDefault();\n goToNext();\n }\n };\n const expandedMediaStyle = ((): CSSProperties | undefined => {\n if (!activeMedia?.width || !activeMedia.height) {\n return undefined;\n }\n\n return {\n \"--aperto-expanded-aspect-ratio\": `${activeMedia.width} / ${activeMedia.height}`,\n \"--aperto-expanded-aspect-ratio-height\": activeMedia.height,\n \"--aperto-expanded-aspect-ratio-width\": activeMedia.width,\n } as CSSProperties;\n })();\n\n return (\n <ApertoGroupContext.Provider value={value}>\n <ApertoRoot\n dismissible={dismissible}\n motion={motionProp}\n onOpenChange={handleOpenChange}\n open={state.open}\n >\n {children}\n {activeMedia ? (\n <ApertoPortal>\n <ApertoOverlay className={classNames?.overlay} fadeOut={state.closing} />\n <ApertoContent\n className={classNames?.content}\n data-aperto-transition={state.mediaTransition?.phase}\n onCloseAutoFocus={handleCloseAutoFocus}\n onKeyDown={hasNavigation ? handleContentKeyDown : undefined}\n sharedLayoutId={false}\n {...getDescriptionProps(activeMedia)}\n >\n <div data-slot=\"aperto-media\" ref={setExpandedMediaNode} style={expandedMediaStyle}>\n <ApertoExpandedMediaStage\n direction={state.navigationDirection}\n index={index}\n item={activeMedia}\n navigationMotion={navigationMotion}\n renderImage={renderImage}\n renderVideo={renderVideo}\n />\n <ApertoMediaNavigationButtons\n classNames={classNames}\n enabled={hasNavigation}\n onNext={goToNext}\n onPrevious={goToPrevious}\n />\n </div>\n <ApertoTitle>{activeMedia.title ?? getMediaLabel(activeMedia)}</ApertoTitle>\n {activeMedia.description ? (\n <ApertoDescription>{activeMedia.description}</ApertoDescription>\n ) : null}\n {hasNavigation ? (\n <div className={classNames?.counter} data-slot=\"aperto-counter\">\n {index + 1} / {media.length}\n </div>\n ) : null}\n <button\n aria-label=\"Close\"\n className={classNames?.closeButton}\n data-slot=\"aperto-close\"\n onClick={startClose}\n type=\"button\"\n >\n <X aria-hidden=\"true\" size={17} strokeWidth={2} />\n </button>\n </ApertoContent>\n <ApertoMediaTransitionClone\n onComplete={handleMediaTransitionComplete}\n renderImage={renderImage}\n renderVideo={renderVideo}\n transition={state.mediaTransition}\n />\n </ApertoPortal>\n ) : null}\n </ApertoRoot>\n </ApertoGroupContext.Provider>\n );\n};\n","\"use client\";\n\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport { m, useMotionValue, useSpring, useTransform } from \"motion/react\";\nimport type { MotionStyle, PanInfo } from \"motion/react\";\nimport { useState } from \"react\";\nimport type { ComponentPropsWithRef } from \"react\";\n\nimport { useApertoContext } from \"./context\";\nimport {\n calculateResistance,\n DEFAULT_DISTANCE_THRESHOLD,\n DEFAULT_VELOCITY_THRESHOLD,\n OPACITY_INPUT,\n OPACITY_OUTPUT,\n SCALE_INPUT,\n SCALE_OUTPUT,\n} from \"./physics\";\nimport { getDragSpring, resolvePreset } from \"./presets\";\nimport type { DismissibleConfig, MotionPresetName } from \"./types\";\n\nexport interface ApertoContentProps extends Omit<\n ComponentPropsWithRef<typeof Dialog.Content>,\n \"asChild\" | \"forceMount\"\n> {\n /** Motion preset override for this content panel, independent of the root preset. */\n motion?: MotionPresetName;\n /** Built-in positioning strategy. Use \"none\" for custom primitive compositions. */\n placement?: \"center\" | \"none\";\n /** Internal shared layout ID override for grouped media. */\n sharedLayoutId?: string | false;\n}\n\nconst ApertoContent = ({\n children,\n className,\n motion: motionOverride,\n placement = \"center\",\n ref,\n sharedLayoutId,\n style,\n ...props\n}: ApertoContentProps) => {\n const ctx = useApertoContext();\n const [isDragging, setIsDragging] = useState(false);\n const resolved = resolvePreset(\n \"content\",\n motionOverride,\n ctx.presetName,\n ctx.variants,\n ctx.reduceMotion,\n );\n\n const contentLayoutId =\n sharedLayoutId === false ? undefined : (sharedLayoutId ?? `${ctx.layoutId}-shared`);\n\n const dragSpring = getDragSpring(resolved);\n const isDismissible = ctx.dismissible !== false;\n\n const dismissConfig: DismissibleConfig =\n typeof ctx.dismissible === \"object\" ? ctx.dismissible : {};\n const distanceThreshold = dismissConfig.threshold ?? DEFAULT_DISTANCE_THRESHOLD;\n const velocityThreshold = dismissConfig.velocity ?? DEFAULT_VELOCITY_THRESHOLD;\n\n const dragX = useMotionValue(0);\n const dragY = useMotionValue(0);\n const springX = useSpring(dragX, dragSpring);\n const springY = useSpring(dragY, dragSpring);\n\n const distance = useTransform(() => Math.hypot(springX.get(), springY.get()));\n const scaleMotion = useTransform(distance, SCALE_INPUT, SCALE_OUTPUT);\n const opacityMotion = useTransform(distance, OPACITY_INPUT, OPACITY_OUTPUT);\n const resistance = useTransform(distance, calculateResistance);\n const { onOpenChange } = ctx;\n\n const handleDrag = (_event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo) => {\n if (!isDragging) {\n setIsDragging(true);\n }\n const r = resistance.get();\n dragX.set(info.offset.x * r);\n dragY.set(info.offset.y * r);\n };\n\n const handleDragEnd = (_event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo) => {\n setIsDragging(false);\n const speed = Math.hypot(info.velocity.x, info.velocity.y);\n const dist = Math.hypot(info.offset.x, info.offset.y);\n\n if (speed > velocityThreshold || dist > distanceThreshold) {\n onOpenChange(false);\n return;\n }\n\n dragX.set(0);\n dragY.set(0);\n };\n\n const placementStyle =\n placement === \"center\"\n ? {\n left: \"50%\",\n top: \"50%\",\n translate: \"-50% -50%\",\n }\n : {};\n let cursor: MotionStyle[\"cursor\"];\n\n if (isDragging) {\n cursor = \"grabbing\";\n } else if (isDismissible) {\n cursor = \"grab\";\n }\n\n const motionStyle: MotionStyle = {\n cursor,\n opacity: opacityMotion,\n scale: scaleMotion,\n x: springX,\n y: springY,\n ...placementStyle,\n ...style,\n };\n\n return (\n <Dialog.Content asChild forceMount {...props}>\n <m.div\n className={className}\n data-slot=\"aperto-content\"\n drag={isDismissible}\n dragConstraints={{ bottom: 0, left: 0, right: 0, top: 0 }}\n dragElastic={0}\n dragMomentum={false}\n dragSnapToOrigin\n layout={contentLayoutId ? true : undefined}\n layoutId={contentLayoutId}\n onDrag={isDismissible ? handleDrag : undefined}\n onDragEnd={isDismissible ? handleDragEnd : undefined}\n ref={ref}\n style={motionStyle}\n transition={resolved.transition}\n >\n {children}\n </m.div>\n </Dialog.Content>\n );\n};\n\nApertoContent.displayName = \"ApertoContent\";\n\nexport { ApertoContent };\n","\"use client\";\n\nimport { createContext, use } from \"react\";\n\nimport type { ApertoContextValue } from \"./types\";\n\nexport const ApertoContext = createContext<ApertoContextValue | null>(null);\n\nexport const useApertoContext = (): ApertoContextValue => {\n const ctx = use(ApertoContext);\n if (!ctx) {\n throw new Error(\"Aperto components must be used within <Aperto.Root>\");\n }\n return ctx;\n};\n","/**\n * Drag physics utilities.\n *\n * The logarithmic resistance function creates a rubber-band feel:\n * initial movement is free, but gets progressively harder the further\n * you drag. Combined with spring-smoothed motion values, this produces\n * a natural, elastic gesture.\n */\n\nconst RESISTANCE_DIVISOR = 20;\nconst RESISTANCE_SCALE = 4;\nconst RESISTANCE_MIN = 0.1;\n\n/**\n * Logarithmic resistance — decelerates drag progressively.\n * Returns a multiplier between RESISTANCE_MIN and 1.0.\n *\n * At distance 0: returns 1.0 (full movement)\n * At distance 50: returns ~0.77\n * At distance 100: returns ~0.58\n * At distance 200: returns ~0.42\n */\nexport const calculateResistance = (distance: number): number =>\n Math.max(RESISTANCE_MIN, 1 - Math.log(distance / RESISTANCE_DIVISOR + 1) / RESISTANCE_SCALE);\n\n/** Scale mapping: distance → visual scale (1.0 → 0.95) */\nexport const SCALE_INPUT = [0, 50, 100];\nexport const SCALE_OUTPUT = [1, 0.98, 0.95];\n\n/** Opacity mapping: distance → visual opacity (1.0 → 0.96) */\nexport const OPACITY_INPUT = [0, 80];\nexport const OPACITY_OUTPUT = [1, 0.96];\n\n/** Default dismissal thresholds */\nexport const DEFAULT_DISTANCE_THRESHOLD = 100;\nexport const DEFAULT_VELOCITY_THRESHOLD = 500;\n","import type { Easing } from \"motion/react\";\n\nexport const durations = {\n moderate: 0.4,\n snappy: 0.22,\n} as const;\n\nexport const easings = {\n customGentle: [0.25, 0.1, 0.12, 1],\n snappy: [0.22, 1, 0.36, 1],\n} satisfies Record<string, Easing>;\n\nexport const springs = {\n bouncy: { damping: 12, mass: 1, stiffness: 260 },\n natural: { damping: 20, mass: 1, stiffness: 200 },\n snappy: { damping: 28, mass: 0.8, stiffness: 400 },\n stiff: { damping: 30, mass: 1, stiffness: 500 },\n} as const;\n","import { durations, easings, springs } from \"./motion-tokens\";\nimport type { DragSpringConfig, MotionPreset, MotionPresetName, MotionVariants } from \"./types\";\n\n/**\n * Motion presets — each bundles transition timing AND drag physics\n * so \"snappy\" feels snappy everywhere: open, close, and drag.\n *\n * Curves and springs are local copies of the Howells motion tokens so the\n * published package has no private workspace runtime dependencies.\n */\nexport const PRESETS: Record<MotionPresetName, MotionPreset> = {\n bouncy: {\n drag: {\n damping: springs.snappy.damping,\n restDelta: 0.01,\n stiffness: springs.snappy.stiffness,\n },\n transition: {\n damping: springs.bouncy.damping,\n mass: springs.bouncy.mass,\n stiffness: springs.bouncy.stiffness,\n type: \"spring\",\n },\n },\n reduced: {\n drag: { damping: 50, restDelta: 0.1, stiffness: 1000 },\n transition: { duration: 0.01, ease: \"linear\" },\n },\n smooth: {\n drag: {\n damping: springs.natural.damping,\n restDelta: 0.01,\n stiffness: springs.natural.stiffness,\n },\n transition: { duration: durations.moderate, ease: easings.customGentle },\n },\n snappy: {\n drag: {\n damping: springs.stiff.damping,\n restDelta: 0.01,\n stiffness: springs.stiff.stiffness,\n },\n transition: { duration: durations.snappy, ease: easings.snappy },\n },\n};\n\ntype ComponentType = \"trigger\" | \"content\" | \"backdrop\";\n\n/**\n * Three-level motion resolution:\n * 1. Component-level override (highest)\n * 2. Per-component variant from Root\n * 3. Global preset from Root (lowest)\n *\n * If `prefers-reduced-motion` is active, always returns \"reduced\".\n */\nexport const resolvePreset = (\n componentType: ComponentType,\n componentMotion: MotionPresetName | undefined,\n globalPreset: MotionPresetName,\n variants: MotionVariants | undefined,\n reduceMotion: boolean,\n): MotionPreset => {\n if (reduceMotion) {\n return PRESETS.reduced;\n }\n\n // 1. Component-level override\n if (componentMotion) {\n return PRESETS[componentMotion];\n }\n\n // 2. Per-component variant\n if (variants?.[componentType]) {\n return PRESETS[variants[componentType]];\n }\n\n // 3. Global preset\n return PRESETS[globalPreset];\n};\n\n/** Extract the drag spring config from a preset */\nexport const getDragSpring = (preset: MotionPreset): DragSpringConfig => preset.drag;\n","\"use client\";\n\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport type { ComponentPropsWithRef } from \"react\";\n\nconst ApertoDescription = ({ ref, ...props }: ComponentPropsWithRef<typeof Dialog.Description>) => (\n <Dialog.Description data-slot=\"aperto-description\" ref={ref} {...props} />\n);\n\nApertoDescription.displayName = \"ApertoDescription\";\n\nexport { ApertoDescription };\n","import { createContext, use } from \"react\";\n\nimport type { ApertoClassNames, ApertoMediaItem, RenderImage, RenderVideo } from \"./types\";\n\nexport interface ApertoGroupContextValue {\n classNames?: ApertoClassNames;\n index: number;\n media: ApertoMediaItem[];\n open: boolean;\n openAtIndex: (index: number) => void;\n registerThumbnail: (index: number, node: HTMLButtonElement | null) => void;\n renderImage?: RenderImage;\n renderVideo?: RenderVideo;\n setIndex: (index: number) => void;\n sharedLayoutId: string;\n sharedLayoutIdForIndex: (index: number) => string;\n}\n\nexport const ApertoGroupContext = createContext<ApertoGroupContextValue | null>(null);\n\nexport const useApertoGroup = (): ApertoGroupContextValue => {\n const ctx = use(ApertoGroupContext);\n if (!ctx) {\n throw new Error(\"Aperto.Thumbnail must be used within <Aperto.Group>\");\n }\n return ctx;\n};\n","\"use client\";\n\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport { m } from \"motion/react\";\nimport type { Transition } from \"motion/react\";\nimport type { CSSProperties, Ref } from \"react\";\n\nimport { useApertoContext } from \"./context\";\nimport { easings } from \"./motion-tokens\";\n\nexport interface ApertoOverlayProps {\n className?: string;\n /** Internal flag used to fade the overlay during measured close transitions. */\n fadeOut?: boolean;\n ref?: Ref<HTMLDivElement>;\n style?: CSSProperties;\n}\n\n/** Overlay always fades gently regardless of the content's motion preset. */\nconst OVERLAY_TRANSITION: Transition = {\n duration: 0.3,\n ease: easings.customGentle,\n};\n\nconst OVERLAY_TRANSITION_REDUCED: Transition = {\n duration: 0.01,\n ease: \"linear\",\n};\n\nconst ApertoOverlay = ({ className, fadeOut, ref, style }: ApertoOverlayProps) => {\n const ctx = useApertoContext();\n const transition = ctx.reduceMotion ? OVERLAY_TRANSITION_REDUCED : OVERLAY_TRANSITION;\n\n return (\n <Dialog.Overlay asChild forceMount>\n <m.div\n animate={{ opacity: fadeOut ? 0 : 1 }}\n className={className}\n data-slot=\"aperto-overlay\"\n exit={{ opacity: 0 }}\n initial={{ opacity: 0 }}\n ref={ref}\n style={style}\n transition={transition}\n />\n </Dialog.Overlay>\n );\n};\n\nApertoOverlay.displayName = \"ApertoOverlay\";\n\nexport { ApertoOverlay };\n","\"use client\";\n\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport { AnimatePresence } from \"motion/react\";\nimport type { ReactNode } from \"react\";\n\nimport { useApertoContext } from \"./context\";\n\nexport interface ApertoPortalProps {\n children: ReactNode;\n /** Container element for the portal (default: document.body) */\n container?: HTMLElement;\n}\n\nconst ApertoPortal = ({ children, container }: ApertoPortalProps) => {\n const { open } = useApertoContext();\n\n return (\n <AnimatePresence>\n {open && (\n <Dialog.Portal container={container} forceMount>\n {children}\n </Dialog.Portal>\n )}\n </AnimatePresence>\n );\n};\n\nexport { ApertoPortal };\n","\"use client\";\n\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport { domMax, LayoutGroup, LazyMotion, useReducedMotion } from \"motion/react\";\nimport { useId, useState } from \"react\";\nimport type { ComponentPropsWithoutRef, ReactNode } from \"react\";\n\nimport { ApertoContext } from \"./context\";\nimport { PRESETS } from \"./presets\";\nimport type { DismissibleConfig, MotionPresetName, MotionVariants } from \"./types\";\n\nexport interface ApertoRootProps extends Omit<\n ComponentPropsWithoutRef<typeof Dialog.Root>,\n \"open\" | \"onOpenChange\"\n> {\n children: ReactNode;\n /** Whether dragging can dismiss the content (default: true) */\n dismissible?: boolean | DismissibleConfig;\n /** Layout ID for shared element transition (auto-generated if omitted) */\n layoutId?: string;\n /** Motion preset or per-component variants */\n motion?: MotionPresetName | MotionVariants;\n /** Controlled open state */\n open?: boolean;\n /** Callback when open state changes */\n onOpenChange?: (open: boolean) => void;\n /** Force reduced motion regardless of system preference */\n reduceMotion?: boolean;\n}\n\nconst ApertoRoot = ({\n children,\n dismissible = true,\n layoutId: layoutIdProp,\n motion: motionProp = \"smooth\",\n open: controlledOpen,\n onOpenChange: controlledOnOpenChange,\n reduceMotion: reduceMotionProp,\n ...dialogProps\n}: ApertoRootProps) => {\n const generatedId = useId();\n const layoutId = layoutIdProp ?? `aperto-${generatedId}`;\n const systemReducedMotion = useReducedMotion() ?? false;\n const shouldReduce = reduceMotionProp ?? systemReducedMotion;\n\n // Uncontrolled state fallback\n const [internalOpen, setInternalOpen] = useState(false);\n const isControlled = controlledOpen !== undefined;\n const open = isControlled ? controlledOpen : internalOpen;\n\n const onOpenChange = (nextOpen: boolean) => {\n if (!isControlled) {\n setInternalOpen(nextOpen);\n }\n controlledOnOpenChange?.(nextOpen);\n };\n\n // Resolve global preset name\n const globalPresetName: MotionPresetName = typeof motionProp === \"string\" ? motionProp : \"smooth\";\n const variants: MotionVariants | undefined =\n typeof motionProp === \"object\" ? motionProp : undefined;\n\n const presetName: MotionPresetName = shouldReduce ? \"reduced\" : globalPresetName;\n const preset = PRESETS[presetName];\n const contextValue = {\n dismissible,\n layoutId,\n onOpenChange,\n open,\n preset,\n presetName,\n reduceMotion: shouldReduce,\n variants,\n };\n\n return (\n <ApertoContext.Provider value={contextValue}>\n <Dialog.Root onOpenChange={onOpenChange} open={open} {...dialogProps}>\n <LazyMotion features={domMax}>\n <LayoutGroup id={layoutId}>{children}</LayoutGroup>\n </LazyMotion>\n </Dialog.Root>\n </ApertoContext.Provider>\n );\n};\n\nexport { ApertoRoot };\n","\"use client\";\n\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport type { ComponentPropsWithRef } from \"react\";\n\nconst ApertoTitle = ({ ref, ...props }: ComponentPropsWithRef<typeof Dialog.Title>) => (\n <Dialog.Title data-slot=\"aperto-title\" ref={ref} {...props} />\n);\n\nApertoTitle.displayName = \"ApertoTitle\";\n\nexport { ApertoTitle };\n","import { AnimatePresence, m } from \"motion/react\";\nimport type { TargetAndTransition, Transition } from \"motion/react\";\n\nimport { useApertoContext } from \"./context\";\nimport { ApertoExpandedMedia } from \"./media-rendering\";\nimport { getMediaKey } from \"./media-utils\";\nimport type {\n ApertoMediaItem,\n NavigationMotionPresetName,\n RenderImage,\n RenderVideo,\n} from \"./types\";\n\nexport type NavigationDirection = -1 | 0 | 1;\n\ninterface NavigationMotionPreset {\n offset: number;\n scale: number;\n transition: Transition;\n}\n\ninterface NavigationAnimationCustom {\n direction: NavigationDirection;\n offset: number;\n scale: number;\n}\n\nconst NAVIGATION_MOTION_PRESETS: Record<NavigationMotionPresetName, NavigationMotionPreset> = {\n float: {\n offset: 96,\n scale: 0.97,\n transition: {\n opacity: { duration: 0.34, ease: [0.45, 0, 0.2, 1] },\n scale: { damping: 26, mass: 1.15, stiffness: 80, type: \"spring\" },\n x: { damping: 26, mass: 1.15, stiffness: 80, type: \"spring\" },\n },\n },\n glide: {\n offset: 58,\n scale: 0.984,\n transition: {\n opacity: { duration: 0.24, ease: [0.4, 0, 0.2, 1] },\n scale: { damping: 28, mass: 0.95, stiffness: 150, type: \"spring\" },\n x: { damping: 28, mass: 0.95, stiffness: 150, type: \"spring\" },\n },\n },\n snap: {\n offset: 38,\n scale: 0.996,\n transition: {\n opacity: { duration: 0.12, ease: [0.2, 0, 0, 1] },\n scale: { damping: 34, mass: 0.7, stiffness: 420, type: \"spring\" },\n x: { damping: 34, mass: 0.7, stiffness: 420, type: \"spring\" },\n },\n },\n};\n\nconst REDUCED_EXPANDED_MEDIA_TRANSITION: Transition = {\n duration: 0.12,\n ease: \"linear\",\n};\n\nconst expandedMediaVariants = {\n center: {\n opacity: 1,\n scale: 1,\n x: 0,\n },\n enter: ({ direction, offset, scale }: NavigationAnimationCustom): TargetAndTransition => ({\n opacity: 0,\n scale: direction === 0 ? 1 : scale,\n x: direction * offset,\n }),\n exit: ({ direction, offset, scale }: NavigationAnimationCustom): TargetAndTransition => ({\n opacity: 0,\n scale: direction === 0 ? 1 : scale,\n x: direction * -offset,\n }),\n};\n\nconst reducedExpandedMediaVariants = {\n center: {\n opacity: 1,\n x: 0,\n },\n enter: {\n opacity: 0,\n x: 0,\n },\n exit: {\n opacity: 0,\n x: 0,\n },\n};\n\nexport const ApertoExpandedMediaStage = ({\n direction,\n index,\n item,\n navigationMotion,\n renderImage,\n renderVideo,\n}: {\n direction: NavigationDirection;\n index: number;\n item: ApertoMediaItem;\n navigationMotion: NavigationMotionPresetName;\n renderImage?: RenderImage;\n renderVideo?: RenderVideo;\n}) => {\n const ctx = useApertoContext();\n const preset = NAVIGATION_MOTION_PRESETS[navigationMotion];\n const transition = ctx.reduceMotion ? REDUCED_EXPANDED_MEDIA_TRANSITION : preset.transition;\n const variants = ctx.reduceMotion ? reducedExpandedMediaVariants : expandedMediaVariants;\n const animationCustom: NavigationAnimationCustom = {\n direction,\n offset: preset.offset,\n scale: preset.scale,\n };\n\n return (\n <AnimatePresence custom={animationCustom} initial={false} mode=\"sync\">\n <m.div\n animate=\"center\"\n custom={animationCustom}\n data-navigation-direction={direction}\n data-navigation-motion={navigationMotion}\n data-slot=\"aperto-media-stage\"\n exit=\"exit\"\n initial=\"enter\"\n key={getMediaKey(item, index)}\n transition={transition}\n variants={variants}\n >\n <ApertoExpandedMedia item={item} renderImage={renderImage} renderVideo={renderVideo} />\n </m.div>\n </AnimatePresence>\n );\n};\n","import { createElement } from \"react\";\nimport type { ReactNode } from \"react\";\n\nimport type { ApertoMediaItem, RenderImage, RenderVideo } from \"./types\";\n\nconst renderDefaultImage = (props: Parameters<RenderImage>[0]): ReactNode => {\n const { item: _item, variant: _variant, ...imageProps } = props;\n return createElement(\"img\", { ...imageProps, alt: imageProps.alt ?? \"\" });\n};\n\nconst renderDefaultVideo = (props: Parameters<RenderVideo>[0]): ReactNode => {\n const { item: _item, variant, ...videoProps } = props;\n if (variant === \"thumbnail\") {\n return createElement(\"img\", {\n alt: videoProps[\"aria-label\"] ?? \"\",\n src: props.item.thumbnailSrc,\n });\n }\n return (\n <video {...videoProps}>\n <track kind=\"captions\" src={props.item.captionsSrc ?? \"data:text/vtt,\"} />\n </video>\n );\n};\n\nexport const ApertoThumbnailMedia = ({\n item,\n renderImage,\n renderVideo,\n}: {\n item: ApertoMediaItem;\n renderImage?: RenderImage;\n renderVideo?: RenderVideo;\n}) => {\n if (item.type === \"image\") {\n const imageProps: Parameters<RenderImage>[0] = {\n alt: \"\",\n height: item.height,\n item,\n src: item.thumbnailSrc ?? item.src,\n variant: \"thumbnail\",\n width: item.width,\n };\n return (renderImage ?? renderDefaultImage)(imageProps);\n }\n\n const videoProps: Parameters<RenderVideo>[0] = {\n \"aria-label\": item.alt ?? item.title ?? \"Video thumbnail\",\n height: item.height,\n item,\n poster: item.poster,\n src: item.thumbnailSrc,\n variant: \"thumbnail\",\n width: item.width,\n };\n return (renderVideo ?? renderDefaultVideo)(videoProps);\n};\n\nexport const ApertoExpandedMedia = ({\n item,\n renderImage,\n renderVideo,\n}: {\n item: ApertoMediaItem;\n renderImage?: RenderImage;\n renderVideo?: RenderVideo;\n}) => {\n if (item.type === \"image\") {\n const imageProps: Parameters<RenderImage>[0] = {\n alt: item.alt,\n height: item.height,\n item,\n src: item.src,\n variant: \"expanded\",\n width: item.width,\n };\n return (renderImage ?? renderDefaultImage)(imageProps);\n }\n\n const videoProps: Parameters<RenderVideo>[0] = {\n \"aria-label\": item.alt ?? item.title ?? \"Video\",\n controls: true,\n height: item.height,\n item,\n poster: item.poster,\n src: item.src,\n variant: \"expanded\",\n width: item.width,\n };\n return (renderVideo ?? renderDefaultVideo)(videoProps);\n};\n\nexport const ApertoTransitionMedia = ({\n item,\n renderImage,\n renderVideo,\n}: {\n item: ApertoMediaItem;\n renderImage?: RenderImage;\n renderVideo?: RenderVideo;\n}) => {\n if (item.type === \"image\") {\n const imageProps: Parameters<RenderImage>[0] = {\n alt: item.alt,\n height: item.height,\n item,\n src: item.src,\n variant: \"expanded\",\n width: item.width,\n };\n return (renderImage ?? renderDefaultImage)(imageProps);\n }\n\n const videoProps: Parameters<RenderVideo>[0] = {\n \"aria-label\": item.alt ?? item.title ?? \"Video\",\n height: item.height,\n item,\n poster: item.poster,\n src: item.src,\n variant: \"expanded\",\n width: item.width,\n };\n return (renderVideo ?? renderDefaultVideo)(videoProps);\n};\n","import type { ApertoMediaItem } from \"./types\";\n\nexport const getMediaLabel = (item: ApertoMediaItem): string => item.title ?? item.alt ?? \"media\";\n\nexport const getMediaKey = (item: ApertoMediaItem, index: number): string =>\n item.id ?? `${item.type}:${item.src}:${index}`;\n\nexport const getDescriptionProps = (\n item: ApertoMediaItem,\n): {\n \"aria-describedby\"?: undefined;\n} => (item.description ? {} : { \"aria-describedby\": undefined });\n","import { m } from \"motion/react\";\nimport { useEffect } from \"react\";\n\nimport { useApertoContext } from \"./context\";\nimport { ApertoTransitionMedia } from \"./media-rendering\";\nimport { rectTarget, transitionDurationMs } from \"./media-transition-utils\";\nimport type { ApertoMediaTransition } from \"./media-transition-utils\";\nimport type { RenderImage, RenderVideo } from \"./types\";\n\nexport const ApertoMediaTransitionClone = ({\n onComplete,\n renderImage,\n renderVideo,\n transition,\n}: {\n onComplete: () => void;\n renderImage?: RenderImage;\n renderVideo?: RenderVideo;\n transition: ApertoMediaTransition | null;\n}) => {\n const ctx = useApertoContext();\n\n useEffect(() => {\n if (!transition?.to) {\n return;\n }\n\n const timer = setTimeout(onComplete, transitionDurationMs(ctx.preset.transition));\n return () => clearTimeout(timer);\n }, [ctx.preset.transition, onComplete, transition]);\n\n if (!transition?.to) {\n return null;\n }\n\n return (\n <m.div\n animate={rectTarget(transition.to)}\n aria-hidden=\"true\"\n data-slot=\"aperto-transition-media\"\n initial={rectTarget(transition.from)}\n style={{\n borderRadius: \"var(--aperto-radius, 0.5rem)\",\n overflow: \"hidden\",\n pointerEvents: \"none\",\n position: \"fixed\",\n zIndex: 30,\n }}\n transition={ctx.preset.transition}\n >\n <ApertoTransitionMedia\n item={transition.item}\n renderImage={renderImage}\n renderVideo={renderVideo}\n />\n </m.div>\n );\n};\n","import type { TargetAndTransition, Transition } from \"motion/react\";\nimport type { ApertoMediaItem } from \"./types\";\n\nexport interface ApertoRect {\n height: number;\n left: number;\n top: number;\n width: number;\n}\n\nexport interface ApertoMediaTransition {\n from: ApertoRect;\n item: ApertoMediaItem;\n phase: \"opening\" | \"closing\";\n to?: ApertoRect;\n}\n\nexport const rectFromElement = (element: Element | null): ApertoRect | null => {\n if (!element) {\n return null;\n }\n\n const rect = element.getBoundingClientRect();\n return {\n height: rect.height,\n left: rect.left,\n top: rect.top,\n width: rect.width,\n };\n};\n\nexport const rectTarget = (rect: ApertoRect): TargetAndTransition => ({\n height: rect.height,\n left: rect.left,\n top: rect.top,\n width: rect.width,\n});\n\nexport const transitionDurationMs = (transition: Transition): number =>\n typeof transition.duration === \"number\" ? transition.duration * 1000 : 450;\n","import type { NavigationDirection } from \"../expanded-media-stage\";\nimport type { ApertoMediaTransition, ApertoRect } from \"../media-transition-utils\";\n\nexport interface ApertoGroupState {\n closing: boolean;\n internalIndex: number;\n layoutSourceIndex: number;\n mediaTransition: ApertoMediaTransition | null;\n navigationDirection: NavigationDirection;\n open: boolean;\n}\n\nexport type ApertoGroupAction =\n | { type: \"close-without-transition\" }\n | { type: \"complete-opening-target\"; rect: ApertoRect }\n | { type: \"finish-transition\" }\n | { type: \"navigate\"; direction: NavigationDirection; index: number }\n | {\n type: \"open-at-index\";\n index: number;\n transition: ApertoMediaTransition | null;\n }\n | { type: \"set-index\"; index: number }\n | { type: \"set-open\"; open: boolean }\n | { type: \"start-close\"; transition: ApertoMediaTransition };\n\nexport const getInitialGroupState = (initialIndex: number): ApertoGroupState => ({\n closing: false,\n internalIndex: initialIndex,\n layoutSourceIndex: initialIndex,\n mediaTransition: null,\n navigationDirection: 0,\n open: false,\n});\n\nexport const apertoGroupReducer = (\n state: ApertoGroupState,\n action: ApertoGroupAction,\n): ApertoGroupState => {\n switch (action.type) {\n case \"close-without-transition\": {\n return { ...state, closing: false, mediaTransition: null, open: false };\n }\n case \"complete-opening-target\": {\n if (state.mediaTransition?.phase !== \"opening\" || state.mediaTransition.to) {\n return state;\n }\n return {\n ...state,\n mediaTransition: { ...state.mediaTransition, to: action.rect },\n };\n }\n case \"finish-transition\": {\n return {\n ...state,\n closing: false,\n mediaTransition: null,\n open: state.mediaTransition?.phase === \"closing\" ? false : state.open,\n };\n }\n case \"navigate\": {\n return {\n ...state,\n internalIndex: action.index,\n layoutSourceIndex: action.index,\n navigationDirection: action.direction,\n };\n }\n case \"open-at-index\": {\n return {\n ...state,\n closing: false,\n internalIndex: action.index,\n layoutSourceIndex: action.index,\n mediaTransition: action.transition,\n navigationDirection: 0,\n open: true,\n };\n }\n case \"set-index\": {\n return { ...state, internalIndex: action.index };\n }\n case \"set-open\": {\n return action.open ? { ...state, closing: false, open: true } : { ...state, open: false };\n }\n case \"start-close\": {\n return {\n ...state,\n closing: true,\n mediaTransition: action.transition,\n };\n }\n default: {\n return state;\n }\n }\n};\n","export const shouldIgnoreKeyboardNavigationTarget = (target: EventTarget | null): boolean => {\n if (!(target instanceof Element)) {\n return false;\n }\n\n return (\n (target as HTMLElement).isContentEditable ||\n Boolean(\n target.closest(\n 'input, textarea, select, [contenteditable]:not([contenteditable=\"false\"]), [role=\"textbox\"], audio, video',\n ),\n )\n );\n};\n","\"use client\";\n\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport { X } from \"lucide-react\";\nimport type { ComponentPropsWithRef } from \"react\";\n\nconst ApertoClose = ({ children, ref, ...props }: ComponentPropsWithRef<typeof Dialog.Close>) => (\n <Dialog.Close data-slot=\"aperto-close\" ref={ref} {...props}>\n {children ?? <X aria-hidden=\"true\" size={17} strokeWidth={2} />}\n </Dialog.Close>\n);\n\nApertoClose.displayName = \"ApertoClose\";\n\nexport { ApertoClose };\n","\"use client\";\n\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport { m } from \"motion/react\";\nimport type { ComponentPropsWithRef } from \"react\";\n\nimport { useApertoContext } from \"./context\";\nimport { resolvePreset } from \"./presets\";\nimport type { MotionPresetName } from \"./types\";\n\nconst TRIGGER_OPEN_Z_INDEX = 1000;\n\nexport interface ApertoTriggerProps extends ComponentPropsWithRef<typeof Dialog.Trigger> {\n /** Internal flag used by grouped thumbnails to raise only the active trigger. */\n active?: boolean;\n /** Override motion preset for this trigger */\n motion?: MotionPresetName;\n /** Internal shared layout ID override for grouped thumbnails. */\n sharedLayoutId?: string | false;\n}\n\nconst ApertoTrigger = ({\n active,\n children,\n motion: motionOverride,\n ref,\n sharedLayoutId,\n ...props\n}: ApertoTriggerProps) => {\n const ctx = useApertoContext();\n const shouldRaise = ctx.open && (active ?? true);\n const zIndex = shouldRaise ? TRIGGER_OPEN_Z_INDEX : 0;\n\n const resolved = resolvePreset(\n \"trigger\",\n motionOverride,\n ctx.presetName,\n ctx.variants,\n ctx.reduceMotion,\n );\n const layoutId =\n sharedLayoutId === false ? undefined : (sharedLayoutId ?? `${ctx.layoutId}-shared`);\n\n return (\n <Dialog.Trigger asChild ref={ref} {...props}>\n <m.button\n data-aperto-active={shouldRaise ? \"\" : undefined}\n data-slot=\"aperto-trigger\"\n key={layoutId ?? \"unshared\"}\n layout\n layoutCrossfade={false}\n layoutId={layoutId}\n style={{ zIndex }}\n transition={resolved.transition}\n type=\"button\"\n >\n {children}\n </m.button>\n </Dialog.Trigger>\n );\n};\n\nApertoTrigger.displayName = \"ApertoTrigger\";\n\nexport { ApertoTrigger };\n","\"use client\";\n\nimport { ApertoClose } from \"../aperto-close\";\nimport { ApertoContent } from \"../aperto-content\";\nimport { ApertoDescription } from \"../aperto-description\";\nimport { ApertoOverlay } from \"../aperto-overlay\";\nimport { ApertoPortal } from \"../aperto-portal\";\nimport { ApertoRoot } from \"../aperto-root\";\nimport { ApertoTitle } from \"../aperto-title\";\nimport { ApertoTrigger } from \"../aperto-trigger\";\nimport { ApertoExpandedMedia, ApertoThumbnailMedia } from \"../media-rendering\";\nimport { getDescriptionProps, getMediaLabel } from \"../media-utils\";\nimport type { ApertoProps } from \"./aperto-types\";\n\nexport const ApertoSingle = ({\n classNames,\n dismissible,\n media,\n renderImage,\n renderVideo,\n}: ApertoProps) => {\n const label = getMediaLabel(media);\n const title = media.title ?? label;\n\n return (\n <ApertoRoot dismissible={dismissible}>\n <ApertoTrigger aria-label={`Open ${label}`} className={classNames?.thumbnail}>\n <ApertoThumbnailMedia item={media} renderImage={renderImage} renderVideo={renderVideo} />\n </ApertoTrigger>\n <ApertoPortal>\n <ApertoOverlay className={classNames?.overlay} />\n <ApertoContent className={classNames?.content} {...getDescriptionProps(media)}>\n <ApertoExpandedMedia item={media} renderImage={renderImage} renderVideo={renderVideo} />\n <ApertoTitle>{title}</ApertoTitle>\n {media.description ? <ApertoDescription>{media.description}</ApertoDescription> : null}\n <ApertoClose aria-label=\"Close\" className={classNames?.closeButton} type=\"button\" />\n </ApertoContent>\n </ApertoPortal>\n </ApertoRoot>\n );\n};\n","\"use client\";\n\nimport { useApertoGroup } from \"../aperto-group-context\";\nimport { ApertoTrigger } from \"../aperto-trigger\";\nimport { ApertoThumbnailMedia } from \"../media-rendering\";\nimport { getMediaLabel } from \"../media-utils\";\nimport type { ApertoThumbnailProps } from \"./aperto-types\";\n\nexport const ApertoThumbnail = ({ children, className, index }: ApertoThumbnailProps) => {\n const group = useApertoGroup();\n const media = group.media[index];\n\n if (!media) {\n return null;\n }\n\n return (\n <ApertoTrigger\n active={group.index === index}\n aria-label={`Open ${getMediaLabel(media)}`}\n className={className ?? group.classNames?.thumbnail}\n onClick={() => group.openAtIndex(index)}\n ref={(node) => group.registerThumbnail(index, node)}\n sharedLayoutId={false}\n >\n {children ?? (\n <ApertoThumbnailMedia\n item={media}\n renderImage={group.renderImage}\n renderVideo={group.renderVideo}\n />\n )}\n </ApertoTrigger>\n );\n};\n","\"use client\";\n\n/**\n * Package: @patternmode/aperto\n *\n * Opinionated thumbnail-to-expanded media transitions.\n * Built on Radix Dialog + Motion.\n *\n * Inspired by Cambio (https://github.com/raphaelsalaja/cambio)\n * by Raphael Salaja.\n *\n * @example\n * ```tsx\n * import { Aperto } from \"@patternmode/aperto\";\n *\n * import { Aperto } from \"@patternmode/aperto\";\n * import \"@patternmode/aperto/styles.css\";\n *\n * <Aperto.Group media={media}>\n * {media.map((item, index) => (\n * <Aperto.Thumbnail key={item.id ?? item.src} index={index} />\n * ))}\n * </Aperto.Group>\n * ```\n */\n\nimport { ApertoGroup, ApertoSingle, ApertoThumbnail } from \"./aperto\";\nimport type { ApertoGroupProps, ApertoProps, ApertoThumbnailProps } from \"./aperto\";\nimport { ApertoClose } from \"./aperto-close\";\nimport { ApertoContent } from \"./aperto-content\";\nimport type { ApertoContentProps } from \"./aperto-content\";\nimport { ApertoDescription } from \"./aperto-description\";\nimport { ApertoOverlay } from \"./aperto-overlay\";\nimport type { ApertoOverlayProps } from \"./aperto-overlay\";\nimport { ApertoPortal } from \"./aperto-portal\";\nimport type { ApertoPortalProps } from \"./aperto-portal\";\nimport { ApertoRoot } from \"./aperto-root\";\nimport type { ApertoRootProps } from \"./aperto-root\";\nimport { ApertoTitle } from \"./aperto-title\";\nimport { ApertoTrigger } from \"./aperto-trigger\";\nimport type { ApertoTriggerProps } from \"./aperto-trigger\";\n\n/** Lower-level compound component namespace for advanced composition. */\nconst ApertoPrimitive = {\n Close: ApertoClose,\n Content: ApertoContent,\n Description: ApertoDescription,\n Overlay: ApertoOverlay,\n Portal: ApertoPortal,\n Root: ApertoRoot,\n Title: ApertoTitle,\n Trigger: ApertoTrigger,\n};\n\n/** Primary media-first component namespace. */\nconst Aperto = Object.assign(ApertoSingle, {\n Group: ApertoGroup,\n Primitive: ApertoPrimitive,\n Thumbnail: ApertoThumbnail,\n});\n\n// Preset system\nexport { PRESETS, resolvePreset } from \"./presets\";\n// Types\nexport type {\n ApertoClassNames,\n ApertoImageItem,\n ApertoMediaItem,\n ApertoVideoItem,\n DismissibleConfig,\n DragSpringConfig,\n MotionPreset,\n MotionPresetName,\n MotionProp,\n MotionVariants,\n NavigationMotionPresetName,\n RenderImage,\n RenderVideo,\n} from \"./types\";\n// Named exports for tree-shaking\nexport {\n Aperto,\n ApertoClose,\n ApertoContent,\n type ApertoContentProps,\n ApertoDescription,\n ApertoGroup,\n type ApertoGroupProps,\n ApertoOverlay,\n type ApertoOverlayProps,\n ApertoPortal,\n type ApertoPortalProps,\n ApertoPrimitive,\n type ApertoProps,\n ApertoRoot,\n type ApertoRootProps,\n ApertoThumbnail,\n type ApertoThumbnailProps,\n ApertoTitle,\n ApertoTrigger,\n type ApertoTriggerProps,\n};\n"],"mappings":"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","names":["useId","Dialog","jsx","createContext","use","Dialog","m","jsx","m","Dialog","jsx","Dialog","useState","jsx","useState","Dialog","jsx","AnimatePresence","m","jsx","jsx","AnimatePresence","m","m","jsx","m","jsx","useId","Dialog","X","jsx","Dialog","m","jsx","m","jsx","jsxs","jsx"]}
1
+ {"version":3,"sources":["../src/Aperto/aperto-group.tsx","../src/aperto-content.tsx","../src/context.ts","../src/physics.ts","../src/presets.ts","../src/aperto-description.tsx","../src/aperto-group-context.ts","../src/aperto-overlay.tsx","../src/aperto-portal.tsx","../src/aperto-root.tsx","../src/aperto-title.tsx","../src/expanded-media-stage.tsx","../src/media-rendering.tsx","../src/media-utils.ts","../src/media-transition.tsx","../src/media-transition-utils.ts","../src/Aperto/aperto-group-state.ts","../src/Aperto/aperto-keyboard.ts","../src/aperto-close.tsx","../src/aperto-trigger.tsx","../src/Aperto/aperto-single.tsx","../src/Aperto/aperto-thumbnail.tsx","../src/index.ts"],"sourcesContent":["\"use client\";\n\nimport { ChevronLeft, ChevronRight, X } from \"lucide-react\";\nimport { useId, useLayoutEffect, useReducer, useRef } from \"react\";\nimport type { CSSProperties, Dispatch, KeyboardEvent } from \"react\";\n\nimport { ApertoContent } from \"../aperto-content\";\nimport { ApertoDescription } from \"../aperto-description\";\nimport { ApertoGroupContext } from \"../aperto-group-context\";\nimport { ApertoOverlay } from \"../aperto-overlay\";\nimport { ApertoPortal } from \"../aperto-portal\";\nimport { ApertoRoot } from \"../aperto-root\";\nimport { ApertoTitle } from \"../aperto-title\";\nimport { ApertoExpandedMediaStage } from \"../expanded-media-stage\";\nimport type { NavigationDirection } from \"../expanded-media-stage\";\nimport { ApertoMediaTransitionClone } from \"../media-transition\";\nimport { rectFromElement } from \"../media-transition-utils\";\nimport type { ApertoMediaTransition } from \"../media-transition-utils\";\nimport { getDescriptionProps, getMediaLabel } from \"../media-utils\";\nimport type {\n ApertoClassNames,\n ApertoMediaItem,\n NavigationMotionPresetName,\n RenderImage,\n RenderVideo,\n} from \"../types\";\nimport { apertoGroupReducer, getInitialGroupState } from \"./aperto-group-state\";\nimport type { ApertoGroupAction, ApertoGroupState } from \"./aperto-group-state\";\nimport { shouldIgnoreKeyboardNavigationTarget } from \"./aperto-keyboard\";\nimport type { ApertoGroupProps } from \"./aperto-types\";\n\ntype ApertoExpandedMediaStyle = CSSProperties & {\n \"--aperto-expanded-aspect-ratio\"?: string;\n \"--aperto-expanded-aspect-ratio-height\"?: number;\n \"--aperto-expanded-aspect-ratio-width\"?: number;\n};\ntype ApertoGroupDispatch = Dispatch<ApertoGroupAction>;\n\nconst ApertoMediaNavigationButtons = ({\n classNames,\n enabled,\n onNext,\n onPrevious,\n}: {\n classNames: ApertoClassNames | undefined;\n enabled: boolean;\n onNext: () => void;\n onPrevious: () => void;\n}) => {\n if (!enabled) {\n return null;\n }\n\n return (\n <>\n <button\n aria-label=\"Previous media\"\n className={classNames?.previousButton}\n data-slot=\"aperto-previous-button\"\n onClick={onPrevious}\n type=\"button\"\n >\n <ChevronLeft aria-hidden=\"true\" size={18} strokeWidth={2} />\n </button>\n <button\n aria-label=\"Next media\"\n className={classNames?.nextButton}\n data-slot=\"aperto-next-button\"\n onClick={onNext}\n type=\"button\"\n >\n <ChevronRight aria-hidden=\"true\" size={18} strokeWidth={2} />\n </button>\n </>\n );\n};\n\nconst useThumbnailMap = () => {\n const thumbnailRefs = useRef<Map<number, HTMLButtonElement> | null>(null);\n thumbnailRefs.current ??= new Map();\n return thumbnailRefs.current;\n};\n\nconst getExpandedMediaStyle = (\n activeMedia: ApertoMediaItem | undefined,\n): ApertoExpandedMediaStyle | undefined => {\n if (\n activeMedia === undefined ||\n activeMedia.width === undefined ||\n activeMedia.height === undefined\n ) {\n return undefined;\n }\n\n return {\n \"--aperto-expanded-aspect-ratio\": `${activeMedia.width} / ${activeMedia.height}`,\n \"--aperto-expanded-aspect-ratio-height\": activeMedia.height,\n \"--aperto-expanded-aspect-ratio-width\": activeMedia.width,\n };\n};\n\nconst ApertoGroupPortal = ({\n activeMedia,\n classNames,\n expandedMediaStyle,\n handleCloseAutoFocus,\n handleContentKeyDown,\n handleMediaTransitionComplete,\n hasNavigation,\n index,\n mediaLength,\n navigationDirection,\n navigationMotion,\n renderImage,\n renderVideo,\n setExpandedMediaNode,\n startClose,\n transition,\n goToNext,\n goToPrevious,\n}: {\n activeMedia: ApertoMediaItem | undefined;\n classNames: ApertoClassNames | undefined;\n expandedMediaStyle: ApertoExpandedMediaStyle | undefined;\n goToNext: () => void;\n goToPrevious: () => void;\n handleCloseAutoFocus: (event: Event) => void;\n handleContentKeyDown: ((event: KeyboardEvent<HTMLDivElement>) => void) | undefined;\n handleMediaTransitionComplete: () => void;\n hasNavigation: boolean;\n index: number;\n mediaLength: number;\n navigationDirection: NavigationDirection;\n navigationMotion: NavigationMotionPresetName;\n renderImage: RenderImage | undefined;\n renderVideo: RenderVideo | undefined;\n setExpandedMediaNode: (node: HTMLDivElement | null) => void;\n startClose: () => void;\n transition: ApertoMediaTransition | null;\n}) => {\n if (activeMedia === undefined) {\n return null;\n }\n\n return (\n <ApertoPortal>\n <ApertoOverlay className={classNames?.overlay} fadeOut={transition?.phase === \"closing\"} />\n <ApertoContent\n className={classNames?.content}\n data-aperto-transition={transition?.phase}\n onCloseAutoFocus={handleCloseAutoFocus}\n onKeyDown={handleContentKeyDown}\n sharedLayoutId={false}\n {...getDescriptionProps(activeMedia)}\n >\n <div data-slot=\"aperto-media\" ref={setExpandedMediaNode} style={expandedMediaStyle}>\n <ApertoExpandedMediaStage\n direction={navigationDirection}\n index={index}\n item={activeMedia}\n navigationMotion={navigationMotion}\n renderImage={renderImage}\n renderVideo={renderVideo}\n />\n <ApertoMediaNavigationButtons\n classNames={classNames}\n enabled={hasNavigation}\n onNext={goToNext}\n onPrevious={goToPrevious}\n />\n </div>\n <ApertoTitle>{activeMedia.title ?? getMediaLabel(activeMedia)}</ApertoTitle>\n {activeMedia.description === undefined || activeMedia.description === \"\" ? null : (\n <ApertoDescription>{activeMedia.description}</ApertoDescription>\n )}\n {hasNavigation ? (\n <div className={classNames?.counter} data-slot=\"aperto-counter\">\n {index + 1} / {mediaLength}\n </div>\n ) : null}\n <button\n aria-label=\"Close\"\n className={classNames?.closeButton}\n data-slot=\"aperto-close\"\n onClick={startClose}\n type=\"button\"\n >\n <X aria-hidden=\"true\" size={17} strokeWidth={2} />\n </button>\n </ApertoContent>\n <ApertoMediaTransitionClone\n onComplete={handleMediaTransitionComplete}\n renderImage={renderImage}\n renderVideo={renderVideo}\n transition={transition}\n />\n </ApertoPortal>\n );\n};\n\nconst useApertoMediaLifecycle = ({\n activeMedia,\n dispatch,\n index,\n media,\n onIndexChange,\n state,\n}: {\n activeMedia: ApertoMediaItem | undefined;\n dispatch: ApertoGroupDispatch;\n index: number;\n media: ApertoMediaItem[];\n onIndexChange: ApertoGroupProps[\"onIndexChange\"];\n state: ApertoGroupState;\n}) => {\n const expandedMediaRef = useRef<HTMLDivElement | null>(null);\n const thumbnailMap = useThumbnailMap();\n\n const setExpandedMediaNode = (node: HTMLDivElement | null) => {\n expandedMediaRef.current = node;\n if (node === null) {\n return;\n }\n const targetRect = rectFromElement(node);\n if (targetRect !== null) {\n dispatch({ rect: targetRect, type: \"complete-opening-target\" });\n }\n };\n\n const registerThumbnail = (thumbIndex: number, node: HTMLButtonElement | null) => {\n if (node !== null) {\n thumbnailMap.set(thumbIndex, node);\n return;\n }\n thumbnailMap.delete(thumbIndex);\n };\n\n useLayoutEffect(() => {\n if (\n state.mediaTransition?.phase !== \"opening\" ||\n state.mediaTransition.to !== undefined ||\n expandedMediaRef.current === null\n ) {\n return;\n }\n\n const targetRect = rectFromElement(expandedMediaRef.current);\n if (targetRect !== null) {\n dispatch({ rect: targetRect, type: \"complete-opening-target\" });\n }\n }, [dispatch, state.mediaTransition]);\n\n const openAtIndex = (thumbIndex: number) => {\n const sourceRect = rectFromElement(thumbnailMap.get(thumbIndex) ?? null);\n const item = media[thumbIndex] ?? null;\n const transition =\n sourceRect === null || item === null\n ? null\n : { from: sourceRect, item, phase: \"opening\" as const };\n\n dispatch({ index: thumbIndex, transition, type: \"open-at-index\" });\n onIndexChange?.(thumbIndex);\n };\n\n const startClose = () => {\n if (!state.open || state.closing) {\n return;\n }\n\n const sourceRect = rectFromElement(expandedMediaRef.current);\n const targetRect = rectFromElement(thumbnailMap.get(index) ?? null);\n if (activeMedia === undefined || sourceRect === null || targetRect === null) {\n dispatch({ type: \"close-without-transition\" });\n return;\n }\n\n dispatch({\n transition: { from: sourceRect, item: activeMedia, phase: \"closing\", to: targetRect },\n type: \"start-close\",\n });\n };\n\n const handleCloseAutoFocus = (event: Event) => {\n event.preventDefault();\n thumbnailMap.get(index)?.focus({ preventScroll: true });\n };\n\n return { handleCloseAutoFocus, openAtIndex, registerThumbnail, setExpandedMediaNode, startClose };\n};\n\nconst useApertoGroupController = ({\n classNames,\n index: controlledIndex,\n initialIndex = 0,\n media,\n onIndexChange,\n renderImage,\n renderVideo,\n}: Omit<ApertoGroupProps, \"children\" | \"dismissible\" | \"motion\" | \"navigationMotion\">) => {\n const generatedId = useId();\n const [state, dispatch] = useReducer(apertoGroupReducer, initialIndex, getInitialGroupState);\n const isControlled = controlledIndex !== undefined;\n const index = isControlled ? controlledIndex : state.internalIndex;\n const activeMedia = media[index] ?? media[0];\n const lifecycle = useApertoMediaLifecycle({\n activeMedia,\n dispatch,\n index,\n media,\n onIndexChange,\n state,\n });\n const sharedLayoutIdForIndex = (nextIndex: number) =>\n `aperto-group-${generatedId}-${nextIndex}-shared`;\n const sharedLayoutId = sharedLayoutIdForIndex(state.layoutSourceIndex);\n\n const setIndex = (nextIndex: number) => {\n if (!isControlled) {\n dispatch({ index: nextIndex, type: \"set-index\" });\n }\n onIndexChange?.(nextIndex);\n };\n\n const handleMediaTransitionComplete = () => {\n dispatch({ type: \"finish-transition\" });\n };\n\n const handleOpenChange = (nextOpen: boolean) => {\n if (nextOpen) {\n dispatch({ open: true, type: \"set-open\" });\n return;\n }\n\n lifecycle.startClose();\n };\n\n const value = {\n classNames,\n index,\n media,\n open: state.open,\n openAtIndex: lifecycle.openAtIndex,\n registerThumbnail: lifecycle.registerThumbnail,\n renderImage,\n renderVideo,\n setIndex,\n sharedLayoutId,\n sharedLayoutIdForIndex,\n };\n const hasNavigation = media.length > 1;\n const navigateToIndex = (nextIndex: number, direction: NavigationDirection) => {\n dispatch({ direction, index: nextIndex, type: \"navigate\" });\n onIndexChange?.(nextIndex);\n };\n const goToPrevious = () => {\n navigateToIndex((index - 1 + media.length) % media.length, -1);\n };\n const goToNext = () => {\n navigateToIndex((index + 1) % media.length, 1);\n };\n const handleContentKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (\n event.defaultPrevented ||\n event.altKey ||\n event.ctrlKey ||\n event.metaKey ||\n shouldIgnoreKeyboardNavigationTarget(event.target)\n ) {\n return;\n }\n\n if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n goToPrevious();\n }\n\n if (event.key === \"ArrowRight\") {\n event.preventDefault();\n goToNext();\n }\n };\n const expandedMediaStyle = getExpandedMediaStyle(activeMedia);\n\n return {\n activeMedia,\n expandedMediaStyle,\n goToNext,\n goToPrevious,\n handleCloseAutoFocus: lifecycle.handleCloseAutoFocus,\n handleContentKeyDown,\n handleMediaTransitionComplete,\n handleOpenChange,\n hasNavigation,\n index,\n setExpandedMediaNode: lifecycle.setExpandedMediaNode,\n startClose: lifecycle.startClose,\n state,\n value,\n };\n};\n\nexport const ApertoGroup = ({\n children,\n classNames,\n dismissible,\n index,\n initialIndex,\n media,\n motion: motionProp,\n navigationMotion = \"glide\",\n onIndexChange,\n renderImage,\n renderVideo,\n}: ApertoGroupProps) => {\n const controller = useApertoGroupController({\n classNames,\n index,\n initialIndex,\n media,\n onIndexChange,\n renderImage,\n renderVideo,\n });\n\n return (\n <ApertoGroupContext.Provider value={controller.value}>\n <ApertoRoot\n dismissible={dismissible}\n motion={motionProp}\n onOpenChange={controller.handleOpenChange}\n open={controller.state.open}\n >\n {children}\n <ApertoGroupPortal\n activeMedia={controller.activeMedia}\n classNames={classNames}\n expandedMediaStyle={controller.expandedMediaStyle}\n goToNext={controller.goToNext}\n goToPrevious={controller.goToPrevious}\n handleCloseAutoFocus={controller.handleCloseAutoFocus}\n handleContentKeyDown={\n controller.hasNavigation ? controller.handleContentKeyDown : undefined\n }\n handleMediaTransitionComplete={controller.handleMediaTransitionComplete}\n hasNavigation={controller.hasNavigation}\n index={controller.index}\n mediaLength={media.length}\n navigationDirection={controller.state.navigationDirection}\n navigationMotion={navigationMotion}\n renderImage={renderImage}\n renderVideo={renderVideo}\n setExpandedMediaNode={controller.setExpandedMediaNode}\n startClose={controller.startClose}\n transition={controller.state.mediaTransition}\n />\n </ApertoRoot>\n </ApertoGroupContext.Provider>\n );\n};\n","\"use client\";\n\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport { m, useMotionValue, useSpring, useTransform } from \"motion/react\";\nimport type { MotionStyle, PanInfo } from \"motion/react\";\nimport { useState } from \"react\";\nimport type { ComponentPropsWithRef } from \"react\";\n\nimport { useApertoContext } from \"./context\";\nimport {\n calculateResistance,\n DEFAULT_DISTANCE_THRESHOLD,\n DEFAULT_VELOCITY_THRESHOLD,\n OPACITY_INPUT,\n OPACITY_OUTPUT,\n SCALE_INPUT,\n SCALE_OUTPUT,\n} from \"./physics\";\nimport { getDragSpring, resolvePreset } from \"./presets\";\nimport type { DismissibleConfig, MotionPresetName } from \"./types\";\n\nexport interface ApertoContentProps extends Omit<\n ComponentPropsWithRef<typeof Dialog.Content>,\n \"asChild\" | \"forceMount\"\n> {\n /** Motion preset override for this content panel, independent of the root preset. */\n motion?: MotionPresetName;\n /** Built-in positioning strategy. Use \"none\" for custom primitive compositions. */\n placement?: \"center\" | \"none\";\n /** Internal shared layout ID override for grouped media. */\n sharedLayoutId?: string | false;\n}\n\nconst ApertoContent = ({\n children,\n className,\n motion: motionOverride,\n placement = \"center\",\n ref,\n sharedLayoutId,\n style,\n ...props\n}: ApertoContentProps) => {\n const ctx = useApertoContext();\n const [isDragging, setIsDragging] = useState(false);\n const resolved = resolvePreset(\n \"content\",\n motionOverride,\n ctx.presetName,\n ctx.variants,\n ctx.reduceMotion,\n );\n\n const contentLayoutId =\n sharedLayoutId === false ? undefined : (sharedLayoutId ?? `${ctx.layoutId}-shared`);\n\n const dragSpring = getDragSpring(resolved);\n const isDismissible = ctx.dismissible !== false;\n\n const dismissConfig: DismissibleConfig =\n typeof ctx.dismissible === \"object\" ? ctx.dismissible : {};\n const distanceThreshold = dismissConfig.threshold ?? DEFAULT_DISTANCE_THRESHOLD;\n const velocityThreshold = dismissConfig.velocity ?? DEFAULT_VELOCITY_THRESHOLD;\n\n const dragX = useMotionValue(0);\n const dragY = useMotionValue(0);\n const springX = useSpring(dragX, dragSpring);\n const springY = useSpring(dragY, dragSpring);\n\n const distance = useTransform(() => Math.hypot(springX.get(), springY.get()));\n const scaleMotion = useTransform(distance, SCALE_INPUT, SCALE_OUTPUT);\n const opacityMotion = useTransform(distance, OPACITY_INPUT, OPACITY_OUTPUT);\n const resistance = useTransform(distance, calculateResistance);\n const { onOpenChange } = ctx;\n\n const handleDrag = (_event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo) => {\n if (!isDragging) {\n setIsDragging(true);\n }\n const r = resistance.get();\n dragX.set(info.offset.x * r);\n dragY.set(info.offset.y * r);\n };\n\n const handleDragEnd = (_event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo) => {\n setIsDragging(false);\n const speed = Math.hypot(info.velocity.x, info.velocity.y);\n const dist = Math.hypot(info.offset.x, info.offset.y);\n\n if (speed > velocityThreshold || dist > distanceThreshold) {\n onOpenChange(false);\n return;\n }\n\n dragX.set(0);\n dragY.set(0);\n };\n\n const placementStyle =\n placement === \"center\"\n ? {\n left: \"50%\",\n top: \"50%\",\n translate: \"-50% -50%\",\n }\n : {};\n let cursor: MotionStyle[\"cursor\"];\n\n if (isDragging) {\n cursor = \"grabbing\";\n } else if (isDismissible) {\n cursor = \"grab\";\n }\n\n const motionStyle: MotionStyle = {\n cursor,\n opacity: opacityMotion,\n scale: scaleMotion,\n x: springX,\n y: springY,\n ...placementStyle,\n ...style,\n };\n\n return (\n <Dialog.Content asChild forceMount {...props}>\n <m.div\n className={className}\n data-slot=\"aperto-content\"\n drag={isDismissible}\n dragConstraints={{ bottom: 0, left: 0, right: 0, top: 0 }}\n dragElastic={0}\n dragMomentum={false}\n dragSnapToOrigin\n layout={contentLayoutId === undefined || contentLayoutId === \"\" ? undefined : true}\n layoutId={contentLayoutId}\n onDrag={isDismissible ? handleDrag : undefined}\n onDragEnd={isDismissible ? handleDragEnd : undefined}\n ref={ref}\n style={motionStyle}\n transition={resolved.transition}\n >\n {children}\n </m.div>\n </Dialog.Content>\n );\n};\n\nApertoContent.displayName = \"ApertoContent\";\n\nexport { ApertoContent };\n","\"use client\";\n\nimport { createContext, use } from \"react\";\n\nimport type { ApertoContextValue } from \"./types\";\n\nexport const ApertoContext = createContext<ApertoContextValue | null>(null);\n\nexport const useApertoContext = (): ApertoContextValue => {\n const ctx = use(ApertoContext);\n if (!ctx) {\n throw new Error(\"Aperto components must be used within <Aperto.Root>\");\n }\n return ctx;\n};\n","/**\n * Drag physics utilities.\n *\n * The logarithmic resistance function creates a rubber-band feel:\n * initial movement is free, but gets progressively harder the further\n * you drag. Combined with spring-smoothed motion values, this produces\n * a natural, elastic gesture.\n */\n\nconst RESISTANCE_DIVISOR = 20;\nconst RESISTANCE_SCALE = 4;\nconst RESISTANCE_MIN = 0.1;\n\n/**\n * Logarithmic resistance — decelerates drag progressively.\n * Returns a multiplier between RESISTANCE_MIN and 1.0.\n *\n * At distance 0: returns 1.0 (full movement)\n * At distance 50: returns ~0.77\n * At distance 100: returns ~0.58\n * At distance 200: returns ~0.42\n */\nexport const calculateResistance = (distance: number): number =>\n Math.max(RESISTANCE_MIN, 1 - Math.log(distance / RESISTANCE_DIVISOR + 1) / RESISTANCE_SCALE);\n\n/** Scale mapping: distance → visual scale (1.0 → 0.95) */\nexport const SCALE_INPUT = [0, 50, 100];\nexport const SCALE_OUTPUT = [1, 0.98, 0.95];\n\n/** Opacity mapping: distance → visual opacity (1.0 → 0.96) */\nexport const OPACITY_INPUT = [0, 80];\nexport const OPACITY_OUTPUT = [1, 0.96];\n\n/** Default dismissal thresholds */\nexport const DEFAULT_DISTANCE_THRESHOLD = 100;\nexport const DEFAULT_VELOCITY_THRESHOLD = 500;\n","import { durations, easings, springs } from \"@howells/motion\";\nimport type { DragSpringConfig, MotionPreset, MotionPresetName, MotionVariants } from \"./types\";\n\n/**\n * Motion presets — each bundles transition timing AND drag physics\n * so \"snappy\" feels snappy everywhere: open, close, and drag.\n *\n * Curves and springs come from the shared @howells/motion tokens so motion\n * feel stays consistent across the catalog.\n */\nexport const PRESETS: Record<MotionPresetName, MotionPreset> = {\n bouncy: {\n drag: {\n damping: springs.snappy.damping,\n restDelta: 0.01,\n stiffness: springs.snappy.stiffness,\n },\n transition: {\n damping: springs.bouncy.damping,\n mass: springs.bouncy.mass,\n stiffness: springs.bouncy.stiffness,\n type: \"spring\",\n },\n },\n reduced: {\n drag: { damping: 50, restDelta: 0.1, stiffness: 1000 },\n transition: { duration: 0.01, ease: \"linear\" },\n },\n smooth: {\n drag: {\n damping: springs.natural.damping,\n restDelta: 0.01,\n stiffness: springs.natural.stiffness,\n },\n transition: { duration: durations.moderate, ease: easings.customGentle },\n },\n snappy: {\n drag: {\n damping: springs.stiff.damping,\n restDelta: 0.01,\n stiffness: springs.stiff.stiffness,\n },\n transition: { duration: durations.snappy, ease: easings.snappy },\n },\n};\n\ntype ComponentType = \"trigger\" | \"content\" | \"backdrop\";\n\n/**\n * Three-level motion resolution:\n * 1. Component-level override (highest)\n * 2. Per-component variant from Root\n * 3. Global preset from Root (lowest)\n *\n * If `prefers-reduced-motion` is active, always returns \"reduced\".\n */\nexport const resolvePreset = (\n componentType: ComponentType,\n componentMotion: MotionPresetName | undefined,\n globalPreset: MotionPresetName,\n variants: MotionVariants | undefined,\n reduceMotion: boolean,\n): MotionPreset => {\n if (reduceMotion) {\n return PRESETS.reduced;\n }\n\n // 1. Component-level override\n if (componentMotion) {\n return PRESETS[componentMotion];\n }\n\n // 2. Per-component variant\n if (variants?.[componentType]) {\n return PRESETS[variants[componentType]];\n }\n\n // 3. Global preset\n return PRESETS[globalPreset];\n};\n\n/** Extract the drag spring config from a preset */\nexport const getDragSpring = (preset: MotionPreset): DragSpringConfig => preset.drag;\n","\"use client\";\n\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport type { ComponentPropsWithRef } from \"react\";\n\nconst ApertoDescription = ({ ref, ...props }: ComponentPropsWithRef<typeof Dialog.Description>) => (\n <Dialog.Description data-slot=\"aperto-description\" ref={ref} {...props} />\n);\n\nApertoDescription.displayName = \"ApertoDescription\";\n\nexport { ApertoDescription };\n","import { createContext, use } from \"react\";\n\nimport type { ApertoClassNames, ApertoMediaItem, RenderImage, RenderVideo } from \"./types\";\n\nexport interface ApertoGroupContextValue {\n classNames?: ApertoClassNames;\n index: number;\n media: ApertoMediaItem[];\n open: boolean;\n openAtIndex: (index: number) => void;\n registerThumbnail: (index: number, node: HTMLButtonElement | null) => void;\n renderImage?: RenderImage;\n renderVideo?: RenderVideo;\n setIndex: (index: number) => void;\n sharedLayoutId: string;\n sharedLayoutIdForIndex: (index: number) => string;\n}\n\nexport const ApertoGroupContext = createContext<ApertoGroupContextValue | null>(null);\n\nexport const useApertoGroup = (): ApertoGroupContextValue => {\n const ctx = use(ApertoGroupContext);\n if (!ctx) {\n throw new Error(\"Aperto.Thumbnail must be used within <Aperto.Group>\");\n }\n return ctx;\n};\n","\"use client\";\n\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport { m } from \"motion/react\";\nimport type { Transition } from \"motion/react\";\nimport type { CSSProperties, Ref } from \"react\";\n\nimport { useApertoContext } from \"./context\";\nimport { easings } from \"@howells/motion\";\n\nexport interface ApertoOverlayProps {\n className?: string;\n /** Internal flag used to fade the overlay during measured close transitions. */\n fadeOut?: boolean;\n ref?: Ref<HTMLDivElement>;\n style?: CSSProperties;\n}\n\n/** Overlay always fades gently regardless of the content's motion preset. */\nconst OVERLAY_TRANSITION: Transition = {\n duration: 0.3,\n ease: easings.customGentle,\n};\n\nconst OVERLAY_TRANSITION_REDUCED: Transition = {\n duration: 0.01,\n ease: \"linear\",\n};\n\nconst ApertoOverlay = ({ className, fadeOut, ref, style }: ApertoOverlayProps) => {\n const ctx = useApertoContext();\n const transition = ctx.reduceMotion ? OVERLAY_TRANSITION_REDUCED : OVERLAY_TRANSITION;\n\n return (\n <Dialog.Overlay asChild forceMount>\n <m.div\n animate={{ opacity: fadeOut === true ? 0 : 1 }}\n className={className}\n data-slot=\"aperto-overlay\"\n exit={{ opacity: 0 }}\n initial={{ opacity: 0 }}\n ref={ref}\n style={style}\n transition={transition}\n />\n </Dialog.Overlay>\n );\n};\n\nApertoOverlay.displayName = \"ApertoOverlay\";\n\nexport { ApertoOverlay };\n","\"use client\";\n\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport { AnimatePresence } from \"motion/react\";\nimport type { ReactNode } from \"react\";\n\nimport { useApertoContext } from \"./context\";\n\nexport interface ApertoPortalProps {\n children: ReactNode;\n /** Container element for the portal (default: document.body) */\n container?: HTMLElement;\n}\n\nconst ApertoPortal = ({ children, container }: ApertoPortalProps) => {\n const { open } = useApertoContext();\n\n return (\n <AnimatePresence>\n {open && (\n <Dialog.Portal container={container} forceMount>\n {children}\n </Dialog.Portal>\n )}\n </AnimatePresence>\n );\n};\n\nexport { ApertoPortal };\n","\"use client\";\n\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport { domMax, LayoutGroup, LazyMotion, useReducedMotion } from \"motion/react\";\nimport { useId, useState } from \"react\";\nimport type { ComponentPropsWithoutRef, ReactNode } from \"react\";\n\nimport { ApertoContext } from \"./context\";\nimport { PRESETS } from \"./presets\";\nimport type { DismissibleConfig, MotionPresetName, MotionVariants } from \"./types\";\n\nexport interface ApertoRootProps extends Omit<\n ComponentPropsWithoutRef<typeof Dialog.Root>,\n \"open\" | \"onOpenChange\"\n> {\n children: ReactNode;\n /** Whether dragging can dismiss the content (default: true) */\n dismissible?: boolean | DismissibleConfig;\n /** Layout ID for shared element transition (auto-generated if omitted) */\n layoutId?: string;\n /** Motion preset or per-component variants */\n motion?: MotionPresetName | MotionVariants;\n /** Controlled open state */\n open?: boolean;\n /** Callback when open state changes */\n onOpenChange?: (open: boolean) => void;\n /** Force reduced motion regardless of system preference */\n reduceMotion?: boolean;\n}\n\nconst ApertoRoot = ({\n children,\n dismissible = true,\n layoutId: layoutIdProp,\n motion: motionProp = \"smooth\",\n open: controlledOpen,\n onOpenChange: controlledOnOpenChange,\n reduceMotion: reduceMotionProp,\n ...dialogProps\n}: ApertoRootProps) => {\n const generatedId = useId();\n const layoutId = layoutIdProp ?? `aperto-${generatedId}`;\n const systemReducedMotion = useReducedMotion() ?? false;\n const shouldReduce = reduceMotionProp ?? systemReducedMotion;\n\n // Uncontrolled state fallback\n const [internalOpen, setInternalOpen] = useState(false);\n const isControlled = controlledOpen !== undefined;\n const open = isControlled ? controlledOpen : internalOpen;\n\n const onOpenChange = (nextOpen: boolean) => {\n if (!isControlled) {\n setInternalOpen(nextOpen);\n }\n controlledOnOpenChange?.(nextOpen);\n };\n\n // Resolve global preset name\n const globalPresetName: MotionPresetName = typeof motionProp === \"string\" ? motionProp : \"smooth\";\n const variants: MotionVariants | undefined =\n typeof motionProp === \"object\" ? motionProp : undefined;\n\n const presetName: MotionPresetName = shouldReduce ? \"reduced\" : globalPresetName;\n const preset = PRESETS[presetName];\n const contextValue = {\n dismissible,\n layoutId,\n onOpenChange,\n open,\n preset,\n presetName,\n reduceMotion: shouldReduce,\n variants,\n };\n\n return (\n <ApertoContext.Provider value={contextValue}>\n <Dialog.Root onOpenChange={onOpenChange} open={open} {...dialogProps}>\n <LazyMotion features={domMax}>\n <LayoutGroup id={layoutId}>{children}</LayoutGroup>\n </LazyMotion>\n </Dialog.Root>\n </ApertoContext.Provider>\n );\n};\n\nexport { ApertoRoot };\n","\"use client\";\n\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport type { ComponentPropsWithRef } from \"react\";\n\nconst ApertoTitle = ({ ref, ...props }: ComponentPropsWithRef<typeof Dialog.Title>) => (\n <Dialog.Title data-slot=\"aperto-title\" ref={ref} {...props} />\n);\n\nApertoTitle.displayName = \"ApertoTitle\";\n\nexport { ApertoTitle };\n","import { AnimatePresence, m } from \"motion/react\";\nimport type { TargetAndTransition, Transition } from \"motion/react\";\n\nimport { useApertoContext } from \"./context\";\nimport { ApertoExpandedMedia } from \"./media-rendering\";\nimport { getMediaKey } from \"./media-utils\";\nimport type {\n ApertoMediaItem,\n NavigationMotionPresetName,\n RenderImage,\n RenderVideo,\n} from \"./types\";\n\nexport type NavigationDirection = -1 | 0 | 1;\n\ninterface NavigationMotionPreset {\n offset: number;\n scale: number;\n transition: Transition;\n}\n\ninterface NavigationAnimationCustom {\n direction: NavigationDirection;\n offset: number;\n scale: number;\n}\n\nconst NAVIGATION_MOTION_PRESETS: Record<NavigationMotionPresetName, NavigationMotionPreset> = {\n float: {\n offset: 96,\n scale: 0.97,\n transition: {\n opacity: { duration: 0.34, ease: [0.45, 0, 0.2, 1] },\n scale: { damping: 26, mass: 1.15, stiffness: 80, type: \"spring\" },\n x: { damping: 26, mass: 1.15, stiffness: 80, type: \"spring\" },\n },\n },\n glide: {\n offset: 58,\n scale: 0.984,\n transition: {\n opacity: { duration: 0.24, ease: [0.4, 0, 0.2, 1] },\n scale: { damping: 28, mass: 0.95, stiffness: 150, type: \"spring\" },\n x: { damping: 28, mass: 0.95, stiffness: 150, type: \"spring\" },\n },\n },\n snap: {\n offset: 38,\n scale: 0.996,\n transition: {\n opacity: { duration: 0.12, ease: [0.2, 0, 0, 1] },\n scale: { damping: 34, mass: 0.7, stiffness: 420, type: \"spring\" },\n x: { damping: 34, mass: 0.7, stiffness: 420, type: \"spring\" },\n },\n },\n};\n\nconst REDUCED_EXPANDED_MEDIA_TRANSITION: Transition = {\n duration: 0.12,\n ease: \"linear\",\n};\n\nconst expandedMediaVariants = {\n center: {\n opacity: 1,\n scale: 1,\n x: 0,\n },\n enter: ({ direction, offset, scale }: NavigationAnimationCustom): TargetAndTransition => ({\n opacity: 0,\n scale: direction === 0 ? 1 : scale,\n x: direction * offset,\n }),\n exit: ({ direction, offset, scale }: NavigationAnimationCustom): TargetAndTransition => ({\n opacity: 0,\n scale: direction === 0 ? 1 : scale,\n x: direction * -offset,\n }),\n};\n\nconst reducedExpandedMediaVariants = {\n center: {\n opacity: 1,\n x: 0,\n },\n enter: {\n opacity: 0,\n x: 0,\n },\n exit: {\n opacity: 0,\n x: 0,\n },\n};\n\nexport const ApertoExpandedMediaStage = ({\n direction,\n index,\n item,\n navigationMotion,\n renderImage,\n renderVideo,\n}: {\n direction: NavigationDirection;\n index: number;\n item: ApertoMediaItem;\n navigationMotion: NavigationMotionPresetName;\n renderImage?: RenderImage;\n renderVideo?: RenderVideo;\n}) => {\n const ctx = useApertoContext();\n const preset = NAVIGATION_MOTION_PRESETS[navigationMotion];\n const transition = ctx.reduceMotion ? REDUCED_EXPANDED_MEDIA_TRANSITION : preset.transition;\n const variants = ctx.reduceMotion ? reducedExpandedMediaVariants : expandedMediaVariants;\n const animationCustom: NavigationAnimationCustom = {\n direction,\n offset: preset.offset,\n scale: preset.scale,\n };\n\n return (\n <AnimatePresence custom={animationCustom} initial={false} mode=\"sync\">\n <m.div\n animate=\"center\"\n custom={animationCustom}\n data-navigation-direction={direction}\n data-navigation-motion={navigationMotion}\n data-slot=\"aperto-media-stage\"\n exit=\"exit\"\n initial=\"enter\"\n key={getMediaKey(item, index)}\n transition={transition}\n variants={variants}\n >\n <ApertoExpandedMedia item={item} renderImage={renderImage} renderVideo={renderVideo} />\n </m.div>\n </AnimatePresence>\n );\n};\n","import { createElement } from \"react\";\nimport type { ReactNode } from \"react\";\n\nimport type { ApertoMediaItem, RenderImage, RenderVideo } from \"./types\";\n\nconst renderDefaultImage = (props: Parameters<RenderImage>[0]): ReactNode => {\n const { item: _item, variant: _variant, ...imageProps } = props;\n return createElement(\"img\", { ...imageProps, alt: imageProps.alt ?? \"\" });\n};\n\nconst renderDefaultVideo = (props: Parameters<RenderVideo>[0]): ReactNode => {\n const { item: _item, variant, ...videoProps } = props;\n if (variant === \"thumbnail\") {\n return createElement(\"img\", {\n alt: videoProps[\"aria-label\"] ?? \"\",\n src: props.item.thumbnailSrc,\n });\n }\n return (\n <video {...videoProps}>\n <track kind=\"captions\" src={props.item.captionsSrc ?? \"data:text/vtt,\"} />\n </video>\n );\n};\n\nexport const ApertoThumbnailMedia = ({\n item,\n renderImage,\n renderVideo,\n}: {\n item: ApertoMediaItem;\n renderImage?: RenderImage;\n renderVideo?: RenderVideo;\n}): ReactNode => {\n if (item.type === \"image\") {\n const imageProps: Parameters<RenderImage>[0] = {\n alt: \"\",\n height: item.height,\n item,\n src: item.thumbnailSrc ?? item.src,\n variant: \"thumbnail\",\n width: item.width,\n };\n return (renderImage ?? renderDefaultImage)(imageProps);\n }\n\n const videoProps: Parameters<RenderVideo>[0] = {\n \"aria-label\": item.alt ?? item.title ?? \"Video thumbnail\",\n height: item.height,\n item,\n poster: item.poster,\n src: item.thumbnailSrc,\n variant: \"thumbnail\",\n width: item.width,\n };\n return (renderVideo ?? renderDefaultVideo)(videoProps);\n};\n\nexport const ApertoExpandedMedia = ({\n item,\n renderImage,\n renderVideo,\n}: {\n item: ApertoMediaItem;\n renderImage?: RenderImage;\n renderVideo?: RenderVideo;\n}): ReactNode => {\n if (item.type === \"image\") {\n const imageProps: Parameters<RenderImage>[0] = {\n alt: item.alt,\n height: item.height,\n item,\n src: item.src,\n variant: \"expanded\",\n width: item.width,\n };\n return (renderImage ?? renderDefaultImage)(imageProps);\n }\n\n const videoProps: Parameters<RenderVideo>[0] = {\n \"aria-label\": item.alt ?? item.title ?? \"Video\",\n controls: true,\n height: item.height,\n item,\n poster: item.poster,\n src: item.src,\n variant: \"expanded\",\n width: item.width,\n };\n return (renderVideo ?? renderDefaultVideo)(videoProps);\n};\n\nexport const ApertoTransitionMedia = ({\n item,\n renderImage,\n renderVideo,\n}: {\n item: ApertoMediaItem;\n renderImage?: RenderImage;\n renderVideo?: RenderVideo;\n}): ReactNode => {\n if (item.type === \"image\") {\n const imageProps: Parameters<RenderImage>[0] = {\n alt: item.alt,\n height: item.height,\n item,\n src: item.src,\n variant: \"expanded\",\n width: item.width,\n };\n return (renderImage ?? renderDefaultImage)(imageProps);\n }\n\n const videoProps: Parameters<RenderVideo>[0] = {\n \"aria-label\": item.alt ?? item.title ?? \"Video\",\n height: item.height,\n item,\n poster: item.poster,\n src: item.src,\n variant: \"expanded\",\n width: item.width,\n };\n return (renderVideo ?? renderDefaultVideo)(videoProps);\n};\n","import type { ApertoMediaItem } from \"./types\";\n\nexport const getMediaLabel = (item: ApertoMediaItem): string => item.title ?? item.alt ?? \"media\";\n\nexport const getMediaKey = (item: ApertoMediaItem, index: number): string =>\n item.id ?? `${item.type}:${item.src}:${index}`;\n\nexport const getDescriptionProps = (\n item: ApertoMediaItem,\n): {\n \"aria-describedby\"?: undefined;\n} =>\n item.description === undefined || item.description === \"\"\n ? { \"aria-describedby\": undefined }\n : {};\n","import { m } from \"motion/react\";\nimport { useEffect } from \"react\";\n\nimport { useApertoContext } from \"./context\";\nimport { ApertoTransitionMedia } from \"./media-rendering\";\nimport { rectTarget, transitionDurationMs } from \"./media-transition-utils\";\nimport type { ApertoMediaTransition } from \"./media-transition-utils\";\nimport type { RenderImage, RenderVideo } from \"./types\";\n\nexport const ApertoMediaTransitionClone = ({\n onComplete,\n renderImage,\n renderVideo,\n transition,\n}: {\n onComplete: () => void;\n renderImage?: RenderImage;\n renderVideo?: RenderVideo;\n transition: ApertoMediaTransition | null;\n}) => {\n const ctx = useApertoContext();\n\n useEffect(() => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n if (transition?.to !== undefined) {\n timer = setTimeout(onComplete, transitionDurationMs(ctx.preset.transition));\n }\n\n return () => {\n if (timer !== undefined) {\n clearTimeout(timer);\n }\n };\n }, [ctx.preset.transition, onComplete, transition]);\n\n if (transition?.to === undefined) {\n return null;\n }\n\n return (\n <m.div\n animate={rectTarget(transition.to)}\n aria-hidden=\"true\"\n data-slot=\"aperto-transition-media\"\n initial={rectTarget(transition.from)}\n style={{\n borderRadius: \"var(--aperto-radius, 0.5rem)\",\n overflow: \"hidden\",\n pointerEvents: \"none\",\n position: \"fixed\",\n zIndex: 30,\n }}\n transition={ctx.preset.transition}\n >\n <ApertoTransitionMedia\n item={transition.item}\n renderImage={renderImage}\n renderVideo={renderVideo}\n />\n </m.div>\n );\n};\n","import type { TargetAndTransition, Transition } from \"motion/react\";\nimport type { ApertoMediaItem } from \"./types\";\n\nexport interface ApertoRect {\n height: number;\n left: number;\n top: number;\n width: number;\n}\n\nexport interface ApertoMediaTransition {\n from: ApertoRect;\n item: ApertoMediaItem;\n phase: \"opening\" | \"closing\";\n to?: ApertoRect;\n}\n\nexport const rectFromElement = (element: Element | null): ApertoRect | null => {\n if (!element) {\n return null;\n }\n\n const rect = element.getBoundingClientRect();\n return {\n height: rect.height,\n left: rect.left,\n top: rect.top,\n width: rect.width,\n };\n};\n\nexport const rectTarget = (rect: ApertoRect): TargetAndTransition => ({\n height: rect.height,\n left: rect.left,\n top: rect.top,\n width: rect.width,\n});\n\nexport const transitionDurationMs = (transition: Transition): number =>\n typeof transition.duration === \"number\" ? transition.duration * 1000 : 450;\n","import type { NavigationDirection } from \"../expanded-media-stage\";\nimport type { ApertoMediaTransition, ApertoRect } from \"../media-transition-utils\";\n\nexport interface ApertoGroupState {\n closing: boolean;\n internalIndex: number;\n layoutSourceIndex: number;\n mediaTransition: ApertoMediaTransition | null;\n navigationDirection: NavigationDirection;\n open: boolean;\n}\n\nexport type ApertoGroupAction =\n | { type: \"close-without-transition\" }\n | { type: \"complete-opening-target\"; rect: ApertoRect }\n | { type: \"finish-transition\" }\n | { type: \"navigate\"; direction: NavigationDirection; index: number }\n | {\n type: \"open-at-index\";\n index: number;\n transition: ApertoMediaTransition | null;\n }\n | { type: \"set-index\"; index: number }\n | { type: \"set-open\"; open: boolean }\n | { type: \"start-close\"; transition: ApertoMediaTransition };\n\nexport const getInitialGroupState = (initialIndex: number): ApertoGroupState => ({\n closing: false,\n internalIndex: initialIndex,\n layoutSourceIndex: initialIndex,\n mediaTransition: null,\n navigationDirection: 0,\n open: false,\n});\n\nexport const apertoGroupReducer = (\n state: ApertoGroupState,\n action: ApertoGroupAction,\n): ApertoGroupState => {\n switch (action.type) {\n case \"close-without-transition\": {\n return { ...state, closing: false, mediaTransition: null, open: false };\n }\n case \"complete-opening-target\": {\n if (state.mediaTransition?.phase !== \"opening\" || state.mediaTransition.to) {\n return state;\n }\n return {\n ...state,\n mediaTransition: { ...state.mediaTransition, to: action.rect },\n };\n }\n case \"finish-transition\": {\n return {\n ...state,\n closing: false,\n mediaTransition: null,\n open: state.mediaTransition?.phase === \"closing\" ? false : state.open,\n };\n }\n case \"navigate\": {\n return {\n ...state,\n internalIndex: action.index,\n layoutSourceIndex: action.index,\n navigationDirection: action.direction,\n };\n }\n case \"open-at-index\": {\n return {\n ...state,\n closing: false,\n internalIndex: action.index,\n layoutSourceIndex: action.index,\n mediaTransition: action.transition,\n navigationDirection: 0,\n open: true,\n };\n }\n case \"set-index\": {\n return { ...state, internalIndex: action.index };\n }\n case \"set-open\": {\n return action.open ? { ...state, closing: false, open: true } : { ...state, open: false };\n }\n case \"start-close\": {\n return {\n ...state,\n closing: true,\n mediaTransition: action.transition,\n };\n }\n default: {\n return state;\n }\n }\n};\n","export const shouldIgnoreKeyboardNavigationTarget = (target: EventTarget | null): boolean => {\n if (!(target instanceof HTMLElement)) {\n return false;\n }\n\n return (\n target.isContentEditable ||\n Boolean(\n target.closest(\n 'input, textarea, select, [contenteditable]:not([contenteditable=\"false\"]), [role=\"textbox\"], audio, video',\n ),\n )\n );\n};\n","\"use client\";\n\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport { X } from \"lucide-react\";\nimport type { ComponentPropsWithRef } from \"react\";\n\nconst ApertoClose = ({ children, ref, ...props }: ComponentPropsWithRef<typeof Dialog.Close>) => (\n <Dialog.Close data-slot=\"aperto-close\" ref={ref} {...props}>\n {children ?? <X aria-hidden=\"true\" size={17} strokeWidth={2} />}\n </Dialog.Close>\n);\n\nApertoClose.displayName = \"ApertoClose\";\n\nexport { ApertoClose };\n","\"use client\";\n\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport { m } from \"motion/react\";\nimport type { ComponentPropsWithRef } from \"react\";\n\nimport { useApertoContext } from \"./context\";\nimport { resolvePreset } from \"./presets\";\nimport type { MotionPresetName } from \"./types\";\n\nconst TRIGGER_OPEN_Z_INDEX = 1000;\n\nexport interface ApertoTriggerProps extends ComponentPropsWithRef<typeof Dialog.Trigger> {\n /** Internal flag used by grouped thumbnails to raise only the active trigger. */\n active?: boolean;\n /** Override motion preset for this trigger */\n motion?: MotionPresetName;\n /** Internal shared layout ID override for grouped thumbnails. */\n sharedLayoutId?: string | false;\n}\n\nconst ApertoTrigger = ({\n active,\n children,\n motion: motionOverride,\n ref,\n sharedLayoutId,\n ...props\n}: ApertoTriggerProps) => {\n const ctx = useApertoContext();\n const shouldRaise = ctx.open && (active ?? true);\n const zIndex = shouldRaise ? TRIGGER_OPEN_Z_INDEX : 0;\n\n const resolved = resolvePreset(\n \"trigger\",\n motionOverride,\n ctx.presetName,\n ctx.variants,\n ctx.reduceMotion,\n );\n const layoutId =\n sharedLayoutId === false ? undefined : (sharedLayoutId ?? `${ctx.layoutId}-shared`);\n\n return (\n <Dialog.Trigger asChild ref={ref} {...props}>\n <m.button\n data-aperto-active={shouldRaise ? \"\" : undefined}\n data-slot=\"aperto-trigger\"\n key={layoutId ?? \"unshared\"}\n layout\n layoutCrossfade={false}\n layoutId={layoutId}\n style={{ zIndex }}\n transition={resolved.transition}\n type=\"button\"\n >\n {children}\n </m.button>\n </Dialog.Trigger>\n );\n};\n\nApertoTrigger.displayName = \"ApertoTrigger\";\n\nexport { ApertoTrigger };\n","\"use client\";\n\nimport { ApertoClose } from \"../aperto-close\";\nimport { ApertoContent } from \"../aperto-content\";\nimport { ApertoDescription } from \"../aperto-description\";\nimport { ApertoOverlay } from \"../aperto-overlay\";\nimport { ApertoPortal } from \"../aperto-portal\";\nimport { ApertoRoot } from \"../aperto-root\";\nimport { ApertoTitle } from \"../aperto-title\";\nimport { ApertoTrigger } from \"../aperto-trigger\";\nimport { ApertoExpandedMedia, ApertoThumbnailMedia } from \"../media-rendering\";\nimport { getDescriptionProps, getMediaLabel } from \"../media-utils\";\nimport type { ApertoProps } from \"./aperto-types\";\n\nexport const ApertoSingle = ({\n classNames,\n dismissible,\n media,\n renderImage,\n renderVideo,\n}: ApertoProps) => {\n const label = getMediaLabel(media);\n const title = media.title ?? label;\n\n return (\n <ApertoRoot dismissible={dismissible}>\n <ApertoTrigger aria-label={`Open ${label}`} className={classNames?.thumbnail}>\n <ApertoThumbnailMedia item={media} renderImage={renderImage} renderVideo={renderVideo} />\n </ApertoTrigger>\n <ApertoPortal>\n <ApertoOverlay className={classNames?.overlay} />\n <ApertoContent className={classNames?.content} {...getDescriptionProps(media)}>\n <ApertoExpandedMedia item={media} renderImage={renderImage} renderVideo={renderVideo} />\n <ApertoTitle>{title}</ApertoTitle>\n {media.description === undefined || media.description === \"\" ? null : (\n <ApertoDescription>{media.description}</ApertoDescription>\n )}\n <ApertoClose aria-label=\"Close\" className={classNames?.closeButton} type=\"button\" />\n </ApertoContent>\n </ApertoPortal>\n </ApertoRoot>\n );\n};\n","\"use client\";\n\nimport { useApertoGroup } from \"../aperto-group-context\";\nimport { ApertoTrigger } from \"../aperto-trigger\";\nimport { ApertoThumbnailMedia } from \"../media-rendering\";\nimport { getMediaLabel } from \"../media-utils\";\nimport type { ApertoThumbnailProps } from \"./aperto-types\";\n\nexport const ApertoThumbnail = ({ children, className, index }: ApertoThumbnailProps) => {\n const group = useApertoGroup();\n const media = group.media[index];\n\n if (!media) {\n return null;\n }\n\n return (\n <ApertoTrigger\n active={group.index === index}\n aria-label={`Open ${getMediaLabel(media)}`}\n className={className ?? group.classNames?.thumbnail}\n onClick={() => {\n group.openAtIndex(index);\n }}\n ref={(node) => {\n group.registerThumbnail(index, node);\n }}\n sharedLayoutId={false}\n >\n {children ?? (\n <ApertoThumbnailMedia\n item={media}\n renderImage={group.renderImage}\n renderVideo={group.renderVideo}\n />\n )}\n </ApertoTrigger>\n );\n};\n","\"use client\";\n\n/**\n * Package: @patternmode/aperto\n *\n * Opinionated thumbnail-to-expanded media transitions.\n * Built on Radix Dialog + Motion.\n *\n * Inspired by Cambio (https://github.com/raphaelsalaja/cambio)\n * by Raphael Salaja.\n *\n * @example\n * ```tsx\n * import { Aperto } from \"@patternmode/aperto\";\n *\n * import { Aperto } from \"@patternmode/aperto\";\n * import \"@patternmode/aperto/styles.css\";\n *\n * <Aperto.Group media={media}>\n * {media.map((item, index) => (\n * <Aperto.Thumbnail key={item.id ?? item.src} index={index} />\n * ))}\n * </Aperto.Group>\n * ```\n */\n\nimport { ApertoGroup, ApertoSingle, ApertoThumbnail } from \"./aperto\";\nimport type { ApertoGroupProps, ApertoProps, ApertoThumbnailProps } from \"./aperto\";\nimport { ApertoClose } from \"./aperto-close\";\nimport { ApertoContent } from \"./aperto-content\";\nimport type { ApertoContentProps } from \"./aperto-content\";\nimport { ApertoDescription } from \"./aperto-description\";\nimport { ApertoOverlay } from \"./aperto-overlay\";\nimport type { ApertoOverlayProps } from \"./aperto-overlay\";\nimport { ApertoPortal } from \"./aperto-portal\";\nimport type { ApertoPortalProps } from \"./aperto-portal\";\nimport { ApertoRoot } from \"./aperto-root\";\nimport type { ApertoRootProps } from \"./aperto-root\";\nimport { ApertoTitle } from \"./aperto-title\";\nimport { ApertoTrigger } from \"./aperto-trigger\";\nimport type { ApertoTriggerProps } from \"./aperto-trigger\";\n\n/** Lower-level compound component namespace for advanced composition. */\nconst ApertoPrimitive = {\n Close: ApertoClose,\n Content: ApertoContent,\n Description: ApertoDescription,\n Overlay: ApertoOverlay,\n Portal: ApertoPortal,\n Root: ApertoRoot,\n Title: ApertoTitle,\n Trigger: ApertoTrigger,\n};\n\n/** Primary media-first component namespace. */\nconst Aperto = Object.assign(ApertoSingle, {\n Group: ApertoGroup,\n Primitive: ApertoPrimitive,\n Thumbnail: ApertoThumbnail,\n});\n\n// Preset system\nexport { PRESETS, resolvePreset } from \"./presets\";\n// Types\nexport type {\n ApertoClassNames,\n ApertoImageItem,\n ApertoMediaItem,\n ApertoVideoItem,\n DismissibleConfig,\n DragSpringConfig,\n MotionPreset,\n MotionPresetName,\n MotionProp,\n MotionVariants,\n NavigationMotionPresetName,\n RenderImage,\n RenderVideo,\n} from \"./types\";\n// Named exports for tree-shaking\nexport {\n Aperto,\n ApertoClose,\n ApertoContent,\n type ApertoContentProps,\n ApertoDescription,\n ApertoGroup,\n type ApertoGroupProps,\n ApertoOverlay,\n type ApertoOverlayProps,\n ApertoPortal,\n type ApertoPortalProps,\n ApertoPrimitive,\n type ApertoProps,\n ApertoRoot,\n type ApertoRootProps,\n ApertoThumbnail,\n type ApertoThumbnailProps,\n ApertoTitle,\n ApertoTrigger,\n type ApertoTriggerProps,\n};\n"],"mappings":"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","names":["useId","Dialog","jsx","createContext","use","Dialog","m","easings","jsx","m","Dialog","jsx","Dialog","useState","jsx","useState","Dialog","jsx","AnimatePresence","m","jsx","jsx","AnimatePresence","m","m","jsx","m","jsx","useId","Dialog","X","jsx","Dialog","m","jsx","m","jsx","jsxs","jsx"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patternmode/aperto",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Opinionated, styled thumbnail-to-expanded media transitions for React.",
5
5
  "homepage": "https://github.com/howells/patternmode/tree/main/packages/aperto#readme",
6
6
  "bugs": {
@@ -34,26 +34,27 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@radix-ui/react-dialog": "^1.1.15",
37
- "lucide-react": "^1.16.0",
38
- "motion": "^12.38.0"
37
+ "lucide-react": "^1.17.0",
38
+ "motion": "^12.40.0",
39
+ "@howells/motion": "0.1.0"
39
40
  },
40
41
  "devDependencies": {
41
- "@howells/lint": "^0.2.1",
42
- "@howells/typescript-config": "^0.1.2",
42
+ "@howells/lint": "^0.5.0",
43
+ "@howells/typescript-config": "^0.1.6",
43
44
  "@tailwindcss/cli": "^4.3.0",
44
45
  "@testing-library/jest-dom": "^6.9.1",
45
46
  "@testing-library/react": "^16.3.2",
46
47
  "@testing-library/user-event": "^14.6.1",
47
- "@types/react": "^19.2.14",
48
+ "@types/react": "^19.2.17",
48
49
  "@types/react-dom": "^19.2.3",
49
50
  "concurrently": "^9.2.1",
50
51
  "jsdom": "^29.1.1",
51
- "react": "^19.2.3",
52
- "react-dom": "^19.2.3",
52
+ "react": "^19.2.7",
53
+ "react-dom": "^19.2.7",
53
54
  "tailwindcss": "^4.3.0",
54
55
  "tsup": "^8.5.1",
55
56
  "typescript": "^6.0.3",
56
- "vitest": "^4.1.6"
57
+ "vitest": "^4.1.8"
57
58
  },
58
59
  "peerDependencies": {
59
60
  "react": "^19.0.0",
@@ -65,8 +66,8 @@
65
66
  "dev": "concurrently \"pnpm dev:js\" \"pnpm dev:styles\"",
66
67
  "dev:js": "tsup --watch",
67
68
  "dev:styles": "tailwindcss -i styles.css -o dist/styles.css --watch",
68
- "lint": "howells-ox-check .",
69
- "lint:fix": "howells-ox-fix .",
69
+ "lint": "howells-check .",
70
+ "lint:fix": "howells-fix .",
70
71
  "test": "vitest run --passWithNoTests",
71
72
  "typecheck": "tsc --noEmit"
72
73
  }