{"version":3,"file":"flip.mjs","names":[],"sources":["../../../../package/common/flip/flip.tsx"],"sourcesContent":["import { useEffect, useImperativeHandle, useRef, useState, type CSSProperties, type KeyboardEvent } from 'react';\nimport cx from 'classnames';\n\nimport { useComponentDefaults } from '../configProvider';\nimport type { FlipProps } from './flip.types';\nimport styles from './flip.module.pcss';\nimport { isSelfActivation } from '../utils/activationKey';\nimport { isDev } from '../utils/isDev';\n\nfunction prefersReducedMotion(): boolean {\n  return typeof window !== 'undefined' && window.matchMedia?.('(prefers-reduced-motion: reduce)').matches === true;\n}\n\nfunction Flip(props: FlipProps) {\n  const {\n    ref,\n    front,\n    back,\n    flipped,\n    defaultFlipped = false,\n    flipOnClick = false,\n    flipAxis = 'y',\n    reverse = false,\n    flipDuration = 600,\n    perspective = 800,\n    disabled = false,\n    onFlip,\n    onFlipEnd,\n    className,\n    style,\n    classNames,\n    styles: slotStyles,\n    ...rest\n  } = useComponentDefaults('Flip', props);\n\n  const isControlled = flipped !== undefined;\n  const [internalFlipped, setInternalFlipped] = useState(defaultFlipped);\n  const effectiveFlipped = isControlled ? flipped : internalFlipped;\n\n  function doFlip(nextFlipped: boolean) {\n    if (!isControlled) setInternalFlipped(nextFlipped);\n    onFlip?.(nextFlipped);\n  }\n\n  const handleClick = () => {\n    if (!flipOnClick || disabled) return;\n    doFlip(!effectiveFlipped);\n  };\n\n  const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n    if (!flipOnClick || disabled) return;\n    if (!isSelfActivation(event)) return;\n    event.preventDefault();\n    doFlip(!effectiveFlipped);\n  };\n\n  const mountedRef = useRef(false);\n  useEffect(() => {\n    if (!mountedRef.current) {\n      mountedRef.current = true;\n      return;\n    }\n    if (prefersReducedMotion()) onFlipEnd?.(effectiveFlipped);\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [effectiveFlipped]);\n\n  const handleTransitionEnd = (event: React.TransitionEvent<HTMLDivElement>) => {\n    if (event.target !== event.currentTarget || event.propertyName !== 'transform') return;\n    onFlipEnd?.(effectiveFlipped);\n  };\n\n  useImperativeHandle(ref, () => ({\n    flip() {\n      if (isControlled) {\n        if (isDev()) {\n          console.warn('Flip: flip() called on a controlled instance, update the `flipped` prop instead.');\n        }\n        return;\n      }\n      doFlip(!effectiveFlipped);\n    },\n    setFlipped(value: boolean) {\n      if (isControlled) {\n        if (isDev()) {\n          console.warn('Flip: setFlipped() called on a controlled instance, update the `flipped` prop instead.');\n        }\n        return;\n      }\n      doFlip(value);\n    },\n    reset() {\n      if (!isControlled) setInternalFlipped(false);\n    },\n  }));\n\n  // `reverse` flips the rotation sign on the same hinge axis (+180deg vs -180deg), so adjacent\n  // flips can sweep opposite ways without changing which edge they hinge on. The back face's\n  // own static rotation (below) always uses this same sign, unconditionally: two rotations of\n  // the same sign about the same axis (surface's + back's own) sum to +/-360deg, which is a full\n  // turn back to a right-reading, forward-facing back, regardless of whether `reverse` is set.\n  const turn = reverse ? -180 : 180;\n  const flipOffsetX = flipAxis === 'x' && effectiveFlipped ? turn : 0;\n  const flipOffsetY = flipAxis === 'y' && effectiveFlipped ? turn : 0;\n  const backOffsetX = flipAxis === 'x' ? turn : 0;\n  const backOffsetY = flipAxis === 'y' ? turn : 0;\n\n  return (\n    <div\n      {...rest}\n      className={cx(styles.flip, flipOnClick && styles.flipClickable, className, classNames?.root)}\n      style={{ ...style, ...slotStyles?.root }}\n      onClick={handleClick}\n      onKeyDown={flipOnClick ? handleKeyDown : undefined}\n      role={flipOnClick ? 'button' : undefined}\n      tabIndex={flipOnClick ? 0 : undefined}\n      aria-pressed={flipOnClick ? effectiveFlipped : undefined}\n    >\n      <div\n        className={cx(styles.flipPerspective, classNames?.perspective)}\n        style={{\n          perspective: perspective === 'none' ? 'none' : `${perspective}px`,\n          ...slotStyles?.perspective,\n        }}\n      >\n        <div\n          className={cx(styles.flipSurface, classNames?.surface)}\n          style={\n            {\n              transform: `rotateX(${flipOffsetX}deg) rotateY(${flipOffsetY}deg)`,\n              '--flip-duration': `${flipDuration}ms`,\n              ...slotStyles?.surface,\n            } as CSSProperties & Record<'--flip-duration', string>\n          }\n          data-flipped={effectiveFlipped}\n          onTransitionEnd={handleTransitionEnd}\n        >\n          <div className={cx(styles.flipFront, classNames?.front)} style={slotStyles?.front}>\n            {front}\n          </div>\n          <div\n            className={cx(styles.flipBack, classNames?.back)}\n            style={{\n              transform: `rotateX(${backOffsetX}deg) rotateY(${backOffsetY}deg)`,\n              ...slotStyles?.back,\n            }}\n          >\n            {back}\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default Flip;\n"],"mappings":"0YASA,SAAS,GAAgC,CACvC,OAAO,OAAO,OAAW,KAAe,OAAO,aAAa,kCAAkC,CAAC,CAAC,UAAY,EAC9G,CAEA,SAAS,EAAK,EAAkB,CAC9B,GAAM,CACJ,MACA,QACA,OACA,UACA,iBAAiB,GACjB,cAAc,GACd,WAAW,IACX,UAAU,GACV,eAAe,IACf,cAAc,IACd,WAAW,GACX,SACA,YACA,YACA,QACA,aACA,OAAQ,EACR,GAAG,GACD,EAAqB,OAAQ,CAAK,EAEhC,EAAe,IAAY,IAAA,GAC3B,CAAC,EAAiB,GAAsB,EAAS,CAAc,EAC/D,EAAmB,EAAe,EAAU,EAElD,SAAS,EAAO,EAAsB,CAC/B,GAAc,EAAmB,CAAW,EACjD,IAAS,CAAW,CACtB,CAEA,IAAM,MAAoB,CACnB,GAAe,IACpB,EAAO,CAAC,CAAgB,CAC1B,EAEM,EAAiB,GAAyC,CACzD,GAAe,IACf,EAAiB,CAAK,IAC3B,EAAM,eAAe,EACrB,EAAO,CAAC,CAAgB,EAC1B,EAEM,EAAa,EAAO,EAAK,EAC/B,MAAgB,CACd,GAAI,CAAC,EAAW,QAAS,CACvB,EAAW,QAAU,GACrB,MACF,CACI,EAAqB,GAAG,IAAY,CAAgB,CAE1D,EAAG,CAAC,CAAgB,CAAC,EAErB,IAAM,EAAuB,GAAiD,CACxE,EAAM,SAAW,EAAM,eAAiB,EAAM,eAAiB,aACnE,IAAY,CAAgB,CAC9B,EAEA,EAAoB,OAAY,CAC9B,MAAO,CACL,GAAI,EAAc,CACZ,EAAM,GACR,QAAQ,KAAK,kFAAkF,EAEjG,MACF,CACA,EAAO,CAAC,CAAgB,CAC1B,EACA,WAAW,EAAgB,CACzB,GAAI,EAAc,CACZ,EAAM,GACR,QAAQ,KAAK,wFAAwF,EAEvG,MACF,CACA,EAAO,CAAK,CACd,EACA,OAAQ,CACD,GAAc,EAAmB,EAAK,CAC7C,CACF,EAAE,EAOF,IAAM,EAAO,EAAU,KAAO,IACxB,EAAc,IAAa,KAAO,EAAmB,EAAO,EAC5D,EAAc,IAAa,KAAO,EAAmB,EAAO,EAC5D,EAAc,IAAa,IAAM,EAAO,EACxC,EAAc,IAAa,IAAM,EAAO,EAE9C,OACE,EAAC,MAAD,CACE,GAAI,EACJ,UAAW,EAAG,EAAO,KAAM,GAAe,EAAO,cAAe,EAAW,GAAY,IAAI,EAC3F,MAAO,CAAE,GAAG,EAAO,GAAG,GAAY,IAAK,EACvC,QAAS,EACT,UAAW,EAAc,EAAgB,IAAA,GACzC,KAAM,EAAc,SAAW,IAAA,GAC/B,SAAU,EAAc,EAAI,IAAA,GAC5B,eAAc,EAAc,EAAmB,IAAA,GAE/C,SAAA,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,gBAAiB,GAAY,WAAW,EAC7D,MAAO,CACL,YAAa,IAAgB,OAAS,OAAS,GAAG,EAAY,IAC9D,GAAG,GAAY,WACjB,EAEA,SAAA,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,YAAa,GAAY,OAAO,EACrD,MACE,CACE,UAAW,WAAW,EAAY,eAAe,EAAY,MAC7D,kBAAmB,GAAG,EAAa,IACnC,GAAG,GAAY,OACjB,EAEF,eAAc,EACd,gBAAiB,EAVnB,SAAA,CAYE,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,UAAW,GAAY,KAAK,EAAG,MAAO,GAAY,MACzE,SAAA,CACE,CAAA,EACL,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,SAAU,GAAY,IAAI,EAC/C,MAAO,CACL,UAAW,WAAW,EAAY,eAAe,EAAY,MAC7D,GAAG,GAAY,IACjB,EAEC,SAAA,CACE,CAAA,CACF,GACF,CAAA,CACF,CAAA,CAET"}