{"version":3,"file":"OverlayController.mjs","names":[],"sources":["../../../../../../../../src/lib/controller/overlay/OverlayController.ts"],"sourcesContent":["import {\n  OverlayState,\n  type AnyOverlayOpenStateHandler,\n  type DisposerFn,\n  type OverlayCloseHandler,\n  type OverlayCloseOptions,\n  type OverlayOpenHandler,\n  type OverlayOpenStateHandler,\n} from \"@mittwald/flow-components-base\";\nimport useSelector from \"@/lib/mobx/useSelector\";\nimport { useStatic } from \"@/lib/hooks/useStatic\";\nimport { useEffect, useRef, type DependencyList } from \"react\";\nimport { useCloseOverlayConfirmationController } from \"@/lib/controller/overlay/useCloseOverlayConfirmationController\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\n\nexport type {\n  OverlayCloseHandler,\n  OverlayOpenHandler,\n  OverlayOpenStateHandler,\n} from \"@mittwald/flow-components-base\";\n\nexport interface CloseOverlayOptions extends OverlayCloseOptions {\n  /**\n   * The overlay to close. Omitted, the nearest enclosing overlay is closed –\n   * the same thing `closeOverlay={true}` means.\n   */\n  overlay?: FlowComponentName | OverlayController;\n}\n\nexport interface OnOverlayClosedOptions {\n  dependencies?: DependencyList;\n}\n\nexport type CloseModalOptions = Omit<CloseOverlayOptions, \"overlay\">;\n\n/**\n * Every way an action can point at an overlay: by the Flow component name it\n * registers under, by controller, by options, or with `true` – the nearest\n * enclosing overlay, whatever its name.\n */\nexport type OverlayReference =\n  FlowComponentName | OverlayController | CloseOverlayOptions | true;\n\ntype CloseOptions = CloseOverlayOptions | CloseModalOptions;\n\nexport interface OverlayControllerOptions {\n  isDefaultOpen?: boolean;\n  onOpen?: OverlayOpenHandler;\n  onClose?: OverlayCloseHandler;\n  onOpenChange?: OverlayOpenStateHandler;\n  /**\n   * Whether closing the overlay must be confirmed. `undefined` means \"no\n   * opinion\": the value is not contributed at all, so other sources (e.g. a\n   * `Modal`'s `confirmOnClose` prop or a dirty `Form`) still decide.\n   */\n  confirmOnClose?: boolean;\n}\n\n/**\n * The state is `OverlayState` from `@mittwald/flow-components-base`, shared\n * with every remote binding; this adds the hooks.\n */\nexport class OverlayController extends OverlayState<CloseOptions> {\n  public useUpdateOptions(options: OverlayControllerOptions = {}): void {\n    const { onOpen, onClose, onOpenChange, confirmOnClose } = options;\n\n    this.useOnHandler(onOpen, (h) => this.addOnOpen(h));\n    this.useOnHandler(onClose, (h) => this.addOnClose(h));\n    this.useOnHandler(onOpenChange, (h) => this.addOnOpenChange(h));\n\n    this.useConfirmOnCloseSource(confirmOnClose);\n  }\n\n  /**\n   * Registers the calling component as a close confirmation source for as long\n   * as it is mounted. `undefined` contributes nothing at all.\n   */\n  private useConfirmOnCloseSource(confirmOnClose: boolean | undefined): void {\n    const source = useStatic((): object => ({}));\n\n    useEffect(() => {\n      if (confirmOnClose === undefined) {\n        this.removeConfirmOnCloseSource(source);\n        return;\n      }\n      this.setConfirmOnCloseSource(source, confirmOnClose);\n      return () => this.removeConfirmOnCloseSource(source);\n    }, [this, source, confirmOnClose]);\n  }\n\n  /**\n   * Can be used to execute a callback when the Overlay has unmounted – means\n   * after any closing animation.\n   *\n   * NOTICE: This hook only works inside the corresponding Overlay!\n   */\n  public useOnClosed(\n    callback: () => unknown,\n    options: OnOverlayClosedOptions = {},\n  ) {\n    const { dependencies = [] } = options;\n    const isOpen = this.useIsOpen();\n    const wasOpen = useRef(this.isOpen);\n\n    this.useUpdateOptions({\n      onOpen: () => {\n        wasOpen.current = true;\n      },\n    });\n\n    useEffect(() => {\n      return () => {\n        if (!isOpen && wasOpen.current) {\n          wasOpen.current = false;\n          callback();\n        }\n      };\n    }, [isOpen, ...dependencies]);\n  }\n\n  public static useNew(\n    options: OverlayControllerOptions = {},\n  ): OverlayController {\n    const controller = useStatic(() => new OverlayController(options));\n    controller.useUpdateOptions(options);\n    return controller;\n  }\n\n  private useOnHandler<T extends AnyOverlayOpenStateHandler>(\n    handler: T | undefined,\n    addHandlerFn: (handler: T) => DisposerFn,\n  ) {\n    useEffect(\n      () => (handler ? addHandlerFn(handler) : undefined),\n      [handler, this],\n    );\n  }\n\n  public useIsOpen() {\n    return useSelector(() => this.isOpen);\n  }\n\n  public useIsContentSuspended() {\n    return useSelector(() => this.isContentSuspended);\n  }\n\n  public useShowConfirmationModal() {\n    return useSelector(() => this.showConfirmationModal);\n  }\n\n  public useConfirmOnCloseEnabled() {\n    return useSelector(() => this.confirmOnCloseEnabled);\n  }\n\n  public useConfirmationController() {\n    return useCloseOverlayConfirmationController(this);\n  }\n}\n"],"mappings":";;;;;;;;;;;;;AA8DA,IAAa,oBAAb,MAAa,0BAA0B,aAA2B;CAChE,iBAAwB,UAAoC,CAAC,GAAS;EACpE,MAAM,EAAE,QAAQ,SAAS,cAAc,mBAAmB;EAE1D,KAAK,aAAa,SAAS,MAAM,KAAK,UAAU,CAAC,CAAC;EAClD,KAAK,aAAa,UAAU,MAAM,KAAK,WAAW,CAAC,CAAC;EACpD,KAAK,aAAa,eAAe,MAAM,KAAK,gBAAgB,CAAC,CAAC;EAE9D,KAAK,wBAAwB,cAAc;CAC7C;;;;;CAMA,wBAAgC,gBAA2C;EACzE,MAAM,SAAS,iBAAyB,CAAC,EAAE;EAE3C,gBAAgB;GACd,IAAI,mBAAmB,KAAA,GAAW;IAChC,KAAK,2BAA2B,MAAM;IACtC;GACF;GACA,KAAK,wBAAwB,QAAQ,cAAc;GACnD,aAAa,KAAK,2BAA2B,MAAM;EACrD,GAAG;GAAC;GAAM;GAAQ;EAAc,CAAC;CACnC;;;;;;;CAQA,YACE,UACA,UAAkC,CAAC,GACnC;EACA,MAAM,EAAE,eAAe,CAAC,MAAM;EAC9B,MAAM,SAAS,KAAK,UAAU;EAC9B,MAAM,UAAU,OAAO,KAAK,MAAM;EAElC,KAAK,iBAAiB,EACpB,cAAc;GACZ,QAAQ,UAAU;EACpB,EACF,CAAC;EAED,gBAAgB;GACd,aAAa;IACX,IAAI,CAAC,UAAU,QAAQ,SAAS;KAC9B,QAAQ,UAAU;KAClB,SAAS;IACX;GACF;EACF,GAAG,CAAC,QAAQ,GAAG,YAAY,CAAC;CAC9B;CAEA,OAAc,OACZ,UAAoC,CAAC,GAClB;EACnB,MAAM,aAAa,gBAAgB,IAAI,kBAAkB,OAAO,CAAC;EACjE,WAAW,iBAAiB,OAAO;EACnC,OAAO;CACT;CAEA,aACE,SACA,cACA;EACA,gBACS,UAAU,aAAa,OAAO,IAAI,KAAA,GACzC,CAAC,SAAS,IAAI,CAChB;CACF;CAEA,YAAmB;EACjB,OAAO,kBAAkB,KAAK,MAAM;CACtC;CAEA,wBAA+B;EAC7B,OAAO,kBAAkB,KAAK,kBAAkB;CAClD;CAEA,2BAAkC;EAChC,OAAO,kBAAkB,KAAK,qBAAqB;CACrD;CAEA,2BAAkC;EAChC,OAAO,kBAAkB,KAAK,qBAAqB;CACrD;CAEA,4BAAmC;EACjC,OAAO,sCAAsC,IAAI;CACnD;AACF"}