UNPKG

@lobehub/ui

Version:

Lobe UI is an open-source UI component library for building AIGC web apps

1 lines 3.86 kB
{"version":3,"file":"registry.mjs","names":[],"sources":["../../../src/Image/viewer/registry.ts"],"sourcesContent":["import { type RefObject, useCallback, useSyncExternalStore } from 'react';\n\nimport type { ImagePreviewOptions } from '../type';\nimport type { ZoomPolicy } from './geometry';\n\nexport interface ResolvedPreviewOptions extends Omit<\n ImagePreviewOptions,\n 'autoZoomThreshold' | 'defaultZoom' | 'maxScale'\n> {\n autoZoomThreshold: number;\n defaultZoom: ZoomPolicy;\n maxScale: number;\n}\n\nexport interface PreviewEntry {\n element: HTMLImageElement;\n options: ResolvedPreviewOptions;\n previewSrc?: string;\n src: string;\n}\n\nexport interface PreviewSession {\n entries: PreviewEntry[];\n index: number;\n openerFocusElement: HTMLElement | null;\n token: number;\n}\n\ninterface HostState extends PreviewSession {\n closing: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\nlet state: HostState | null = null;\nlet nextToken = 0;\n\nconst listeners = new Set<() => void>();\n\nconst emit = () => {\n for (const listener of listeners) listener();\n};\n\nconst flushClosed = () => {\n if (!state || state.closing) return;\n state.closing = true;\n state.onOpenChange?.(false);\n};\n\n// openerFocusElement must be captured by the caller at pointerdown, not read here:\n// clicking a non-focusable thumbnail already blurs to document.body before its\n// click handler (and therefore this call) runs.\nexport const openPreview = (\n entry: PreviewEntry,\n entries?: PreviewEntry[],\n index = 0,\n openerFocusElement: HTMLElement | null = null,\n): void => {\n flushClosed();\n nextToken += 1;\n const resolvedEntries = entries && entries.length > 0 ? entries : [entry];\n const resolvedIndex =\n entries && entries.length > 0 ? Math.min(Math.max(index, 0), entries.length - 1) : 0;\n state = {\n closing: false,\n entries: resolvedEntries,\n index: resolvedIndex,\n onOpenChange: entry.options.onOpenChange,\n openerFocusElement,\n token: nextToken,\n };\n emit();\n entry.options.onOpenChange?.(true);\n};\n\nexport const beginClosePreview = (token: number): void => {\n if (state?.token !== token) return;\n flushClosed();\n};\n\nexport const endClosePreview = (token: number): void => {\n if (state?.token !== token) return;\n flushClosed();\n state = null;\n emit();\n};\n\nconst subscribe = (listener: () => void) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n};\n\nconst getServerSnapshot = (): PreviewSession | null => null;\n\nexport const usePreviewSession = (\n elementRef: RefObject<HTMLImageElement | null>,\n): PreviewSession | null => {\n const getSnapshot = useCallback(\n () => (state && state.entries[state.index]?.element === elementRef.current ? state : null),\n [elementRef],\n );\n\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n};\n"],"mappings":";;AAiCA,IAAI,QAA0B;AAC9B,IAAI,YAAY;AAEhB,MAAM,4BAAY,IAAI,IAAgB;AAEtC,MAAM,aAAa;CACjB,KAAK,MAAM,YAAY,WAAW,SAAS;AAC7C;AAEA,MAAM,oBAAoB;CACxB,IAAI,CAAC,SAAS,MAAM,SAAS;CAC7B,MAAM,UAAU;CAChB,MAAM,eAAe,KAAK;AAC5B;AAKA,MAAa,eACX,OACA,SACA,QAAQ,GACR,qBAAyC,SAChC;CACT,YAAY;CACZ,aAAa;CAIb,QAAQ;EACN,SAAS;EACT,SALsB,WAAW,QAAQ,SAAS,IAAI,UAAU,CAAC,KAAK;EAMtE,OAJA,WAAW,QAAQ,SAAS,IAAI,KAAK,IAAI,KAAK,IAAI,OAAO,CAAC,GAAG,QAAQ,SAAS,CAAC,IAAI;EAKnF,cAAc,MAAM,QAAQ;EAC5B;EACA,OAAO;CACT;CACA,KAAK;CACL,MAAM,QAAQ,eAAe,IAAI;AACnC;AAEA,MAAa,qBAAqB,UAAwB;CACxD,IAAI,OAAO,UAAU,OAAO;CAC5B,YAAY;AACd;AAEA,MAAa,mBAAmB,UAAwB;CACtD,IAAI,OAAO,UAAU,OAAO;CAC5B,YAAY;CACZ,QAAQ;CACR,KAAK;AACP;AAEA,MAAM,aAAa,aAAyB;CAC1C,UAAU,IAAI,QAAQ;CACtB,aAAa;EACX,UAAU,OAAO,QAAQ;CAC3B;AACF;AAEA,MAAM,0BAAiD;AAEvD,MAAa,qBACX,eAC0B;CAC1B,MAAM,cAAc,kBACX,SAAS,MAAM,QAAQ,MAAM,MAAM,EAAE,YAAY,WAAW,UAAU,QAAQ,MACrF,CAAC,UAAU,CACb;CAEA,OAAO,qBAAqB,WAAW,aAAa,iBAAiB;AACvE"}