diff --git a/package-lock.json b/package-lock.json index 55866e19f..f99db67af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "5.2.6", "license": "GPL-3.0", "dependencies": { + "@angular/core": "^18.2.2", "@babel/runtime": "^7.25.4", "@iframe-resizer/child": "file:./packages/child/", "@iframe-resizer/core": "file:./packages/core/", @@ -121,6 +122,22 @@ "node": ">=6.0.0" } }, + "node_modules/@angular/core": { + "version": "18.2.2", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.2.tgz", + "integrity": "sha512-Rx6XajL0Ydj9hXUSPDvL2Q/kMzWtbiE3VxZFJnkE+fLQiWvr0GncB+NTb/nQ6QlPQ0ly60DvuI3KLcGDuFtGVA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.14.10" + } + }, "node_modules/@babel/code-frame": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", @@ -17833,6 +17850,16 @@ "integrity": "sha512-u5qvfulb7NXoY/+OE28920WEgFi6aiDjf5iF9rA2f9tBXejLgTLd0WxkclvIQWjFFHfNJlb7pSTsrjgiDh+Uug==", "dev": true }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/safe-array-concat": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", @@ -19168,8 +19195,7 @@ "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -20553,6 +20579,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zone.js": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.10.tgz", + "integrity": "sha512-YGAhaO7J5ywOXW6InXNlLmfU194F8lVgu7bRntUF3TiG8Y3nBK0x1UJJuHUP/e8IyihkjCYqhCScpSwnlaSRkQ==", + "license": "MIT", + "peer": true + }, "packages/child": {}, "packages/core": {}, "packages/parent": {}, diff --git a/package.json b/package.json index cc1c6a3c9..cca615788 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "url": "https://iframe-resizer.com/pricing/" }, "dependencies": { + "@angular/core": "^18.2.2", "@babel/runtime": "^7.25.4", "@iframe-resizer/child": "file:./packages/child/", "@iframe-resizer/core": "file:./packages/core/", diff --git a/packages/angular/directive.ts b/packages/angular/directive.ts new file mode 100644 index 000000000..b0399e1d0 --- /dev/null +++ b/packages/angular/directive.ts @@ -0,0 +1,161 @@ +/** + * Angular directive for iframe-resizer by Bjørn Håkon (https://github.com/bjornoss) + */ + + +import { + Directive, + EventEmitter, + Input, + Output, + ElementRef, +} from '@angular/core' + +import connectResizer from '@iframe-resizer/core' + +export type iframeResizerObject = { + moveToAnchor: (anchor: string) => void + resize: () => void + sendMessage: (message: string, targetOrigin?: string) => void +} + +type iframeResizerObjectPrivateMethods = { + disconnect: () => void +} +type iframeResizerObjectPrivate = iframeResizerObject & + iframeResizerObjectPrivateMethods + +export interface iframeResizerElement extends HTMLIFrameElement { + iFrameResizer: iframeResizerObject +} + +export type iframeResizerOptions = { + bodyBackground?: string | null + bodyMargin?: string | number | null + bodyPadding?: string | number | null + checkOrigin?: boolean | string[] + direction?: 'vertical' | 'horizontal' | 'none' + inPageLinks?: boolean + license: string + offsetSize?: number + scrolling?: boolean | 'omit' + tolerance?: number + warningTimeout?: number +} + +@Directive({ + selector: '[iframe-resizer]', + standalone: true, +}) +export class IframeResizerDirective { + private resizer?: iframeResizerObjectPrivate + + @Output() onReady = new EventEmitter() + @Output() onClose = new EventEmitter() + @Output() onMessage = new EventEmitter<{ + iframe: iframeResizerElement + message: string + }>() + @Output() onMouseEnter = new EventEmitter<{ + iframe: iframeResizerElement + height: number + width: number + type: string + }>() + @Output() onMouseLeave = new EventEmitter<{ + iframe: iframeResizerElement + height: number + width: number + type: string + }>() + @Output() onResized = new EventEmitter<{ + iframe: iframeResizerElement + height: number + width: number + type: string + }>() + @Output() onScroll = new EventEmitter<{ + iframe: iframeResizerElement + top: number + left: number + }>() + + get iframeResizer(): iframeResizerObject | undefined { + return this.resizer + } + + @Input() options: iframeResizerOptions = { + license: '', + } + + @Input() debug: boolean = false + + constructor(private elementRef: ElementRef) { + if (this.debug) console.debug('[IframeResizerDirective].constructor') + } + + ngOnInit() {} + + ngAfterViewInit(): void { + this.resizer = connectResizer({ + ...this.options, + waitForLoad: true, + + onClose: (iframeID: any) => { + console.warn( + `[iframe-resizer/angular][${this.elementRef.nativeElement?.id}] Close event ignored, to remove the iframe update your Angular component.`, + ) + return false + }, + + onMessage: (event: { iframe: iframeResizerElement; message: string }) => + this.onMessage.next(event), + + onMouseEnter: (event: { + iframe: iframeResizerElement + height: number + width: number + type: string + }) => this.onMouseEnter.next(event), + + onMouseLeave: (event: { + iframe: iframeResizerElement + height: number + width: number + type: string + }) => this.onMouseLeave.next(event), + + onReady: (iframe: iframeResizerElement) => this.onReady.next(iframe), + + onResized: (event: { + iframe: iframeResizerElement + height: number + width: number + type: string + }) => this.onResized.next(event), + + onScroll: (event: { + iframe: iframeResizerElement + top: number + left: number + }) => this.onScroll.next(event), + })(this.elementRef.nativeElement) + } + + ngOnDestroy() { + if (this.debug) console.debug('ngOnDestroy') + this.resizer?.disconnect() + } + + // parent methods + public resize() { + this.resizer?.resize() + } + public moveToAnchor(anchor: string) { + this.resizer?.moveToAnchor(anchor) + } + + public sendMessage(message: string, targetOrigin?: string) { + this.resizer?.sendMessage(message, targetOrigin) + } +} diff --git a/packages/angular/index.d.ts b/packages/angular/index.d.ts new file mode 100644 index 000000000..6026cce34 --- /dev/null +++ b/packages/angular/index.d.ts @@ -0,0 +1,5 @@ +/** + * @fileoverview Declare module @iframe-resizer/core for use in Angular + */ + +declare module '@iframe-resizer/core'