diff --git a/docs/README.md b/docs/README.md index 01663cc01776..02d5d1331ca2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -113,6 +113,7 @@ These individual tutorials expand on topics discussed in the guide above. * [dialog](api/dialog.md) * [globalShortcut](api/global-shortcut.md) * [inAppPurchase](api/in-app-purchase.md) +* [ImageView](api/image-view.md) * [ipcMain](api/ipc-main.md) * [Menu](api/menu.md) * [MenuItem](api/menu-item.md) diff --git a/docs/api/image-view.md b/docs/api/image-view.md new file mode 100644 index 000000000000..854de3054601 --- /dev/null +++ b/docs/api/image-view.md @@ -0,0 +1,61 @@ +# ImageView + +> A View that displays an image. + +Process: [Main](../glossary.md#main-process) + +This module cannot be used until the `ready` event of the `app` +module is emitted. + +Useful for showing splash screens that will be swapped for `WebContentsView`s +when the content finishes loading. + +Note that `ImageView` is experimental and may be changed or removed in the future. + +```js +const { BaseWindow, ImageView, nativeImage, WebContentsView } = require('electron') +const path = require('node:path') + +const win = new BaseWindow({ width: 800, height: 600 }) + +// Create a "splash screen" image to display while the WebContentsView loads +const splashView = new ImageView() +const splashImage = nativeImage.createFromPath(path.join(__dirname, 'loading.png')) +splashView.setImage(splashImage) +win.setContentView(splashView) + +const webContentsView = new WebContentsView() +webContentsView.webContents.once('did-finish-load', () => { + // Now that the WebContentsView has loaded, swap out the "splash screen" ImageView + win.setContentView(webContentsView) +}) +webContentsView.webContents.loadURL('https://electronjs.org') +``` + +## Class: ImageView extends `View` + +> A View that displays an image. + +Process: [Main](../glossary.md#main-process) + +`ImageView` inherits from [`View`](view.md). + +`ImageView` is an [EventEmitter][event-emitter]. + +### `new ImageView()` _Experimental_ + +Creates an ImageView. + +### Instance Methods + +The following methods are available on instances of the `ImageView` class, in +addition to those inherited from [View](view.md): + +#### `image.setImage(image)` _Experimental_ + +* `image` NativeImage + +Sets the image for this `ImageView`. Note that only image formats supported by +`NativeImage` can be used with an `ImageView`. + +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter diff --git a/filenames.auto.gni b/filenames.auto.gni index df963e2c831b..ecdc659fd06a 100644 --- a/filenames.auto.gni +++ b/filenames.auto.gni @@ -25,6 +25,7 @@ auto_filenames = { "docs/api/extensions-api.md", "docs/api/extensions.md", "docs/api/global-shortcut.md", + "docs/api/image-view.md", "docs/api/in-app-purchase.md", "docs/api/incoming-message.md", "docs/api/ipc-main-service-worker.md", diff --git a/spec/api-image-view-spec.ts b/spec/api-image-view-spec.ts new file mode 100644 index 000000000000..45f7bfdb96c2 --- /dev/null +++ b/spec/api-image-view-spec.ts @@ -0,0 +1,86 @@ +import { nativeImage } from 'electron/common'; +import { BaseWindow, BrowserWindow, ImageView } from 'electron/main'; + +import { expect } from 'chai'; + +import * as path from 'node:path'; + +import { closeAllWindows } from './lib/window-helpers'; + +describe('ImageView', () => { + afterEach(async () => { + await closeAllWindows(); + }); + + it('can be instantiated with no arguments', () => { + // eslint-disable-next-line no-new + new ImageView(); + }); + + it('can set an empty NativeImage', () => { + const view = new ImageView(); + const image = nativeImage.createEmpty(); + view.setImage(image); + }); + + it('can set a NativeImage', () => { + const view = new ImageView(); + const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')); + view.setImage(image); + }); + + it('can change its NativeImage', () => { + const view = new ImageView(); + const image1 = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')); + const image2 = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'capybara.png')); + view.setImage(image1); + view.setImage(image2); + }); + + it('can be embedded in a BaseWindow', () => { + const w = new BaseWindow({ show: false }); + const view = new ImageView(); + const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'capybara.png')); + view.setImage(image); + w.setContentView(view); + w.setContentSize(image.getSize().width, image.getSize().height); + view.setBounds({ + x: 0, + y: 0, + width: image.getSize().width, + height: image.getSize().height + }); + }); + + it('can be embedded in a BrowserWindow', () => { + const w = new BrowserWindow({ show: false }); + const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')); + const view = new ImageView(); + view.setImage(image); + w.contentView.addChildView(view); + w.setContentSize(image.getSize().width, image.getSize().height); + view.setBounds({ + x: 0, + y: 0, + width: image.getSize().width, + height: image.getSize().height + }); + + expect(w.contentView.children).to.include(view); + }); + + it('can be removed from a BrowserWindow', async () => { + const w = new BrowserWindow({ show: false }); + const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')); + const view = new ImageView(); + view.setImage(image); + + w.contentView.addChildView(view); + expect(w.contentView.children).to.include(view); + + await w.loadFile(path.join(__dirname, 'fixtures', 'api', 'blank.html')); + + w.contentView.removeChildView(view); + expect(w.contentView.children).to.not.include(view); + }); +});