Skip to content

Commit

Permalink
feat: add support for setting style, update default style
Browse files Browse the repository at this point in the history
  • Loading branch information
arianrhodsandlot committed Oct 11, 2023
1 parent 6e141ab commit afca83b
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 17 deletions.
4 changes: 2 additions & 2 deletions demo/demo.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
}

canvas {
width: 800px;
height: 600px;
/* width: 800px;
height: 600px; */
}
22 changes: 22 additions & 0 deletions docs/src/content/docs/apis/launch.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,28 @@ const nostalgist = await Nostalgist.launch({
})
```

+ #### `style`

**type:** `Object`

If the canvas element is created automatically, the style will be

```js
{
position: 'fixed',
top: '0',
left: '0',
width: '100%',
height: '100%',
backgroundColor: 'black',
zIndex: '1',
}
```

otherwise it will be `undefined`.

The CSS rule name should be "camelCase" instead of "kebab-case". For example, `{ backgroundColor: 'black' }` is valid, but `{ background-color: '' }` is not.

+ #### `size`

**type:** `'auto' | { width: number, height: number }` **default:** `'auto'`
Expand Down
20 changes: 16 additions & 4 deletions src/emulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { coreFullNameMap } from './constants'
import { createEmscriptenFS, getEmscriptenModuleOverrides } from './emscripten'
import type { EmulatorOptions } from './types/emulator-options'
import type { RetroArchCommand } from './types/retroarch-command'
import { blobToBuffer } from './utils'
import { blobToBuffer, updateStyle } from './utils'

const encoder = new TextEncoder()

Expand Down Expand Up @@ -56,16 +56,23 @@ export class Emulator {
this.setupRaConfigFile()
this.setupRaCoreConfigFile()

if (this.options.waitForInteraction) {
this.options.waitForInteraction({
const { element, style, waitForInteraction } = this.options
updateStyle(element, style)
if (!element.isConnected) {
document.body.append(element)
}
const size = this.getElementSize()

if (waitForInteraction) {
waitForInteraction({
done: () => {
this.runMain()
},
})
} else {
this.runMain()
}
const { size } = this.options

if (typeof size === 'object') {
this.resize(size)
}
Expand Down Expand Up @@ -143,6 +150,11 @@ export class Emulator {
Module.setCanvasSize(width, height)
}

private getElementSize() {
const { element, size } = this.options
return !size || size === 'auto' ? { width: element.offsetWidth, height: element.offsetHeight } : size
}

private async setupFileSystem() {
const { Module, FS, PATH, ERRNO_CODES } = this.getEmscripten()

Expand Down
34 changes: 24 additions & 10 deletions src/nostalgist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,21 +331,20 @@ export class Nostalgist {
}

private async loadEmulatorOptions() {
const { waitForInteraction } = this.options
const { size = 'auto', waitForInteraction } = this.options
const element = this.getElementOption()
const size = this.getSizeOption(element)
const style = this.getStyleOption()
const retroarch = this.getRetroarchOption()
const retroarchCore = this.getRetroarchCoreOption()
const [core, rom, bios] = await Promise.all([this.getCoreOption(), this.getRomOption(), this.getBiosOption()])
const emulatorOptions = { element, size, core, rom, bios, retroarch, retroarchCore, waitForInteraction }
const emulatorOptions = { element, style, size, core, rom, bios, retroarch, retroarchCore, waitForInteraction }
this.emulatorOptions = emulatorOptions
}

private getElementOption() {
if (typeof document !== 'object') {
throw new TypeError('document must be an object')
}

let { element } = this.options
if (typeof element === 'string' && element) {
const canvas = document.body.querySelector(element)
Expand All @@ -362,19 +361,34 @@ export class Nostalgist {
}

if (element instanceof HTMLCanvasElement) {
if (!element.isConnected) {
document.body.append(element)
}
element.id = 'canvas'
return element
}

throw new TypeError('invalid element')
}

private getSizeOption(element: HTMLCanvasElement) {
const { size } = this.options
return !size || size === 'auto' ? { width: element.offsetWidth, height: element.offsetHeight } : size
private getStyleOption() {
const { element, style } = this.options
const defaultStyle: Partial<CSSStyleDeclaration> = {
position: 'fixed',
top: '0',
left: '0',
width: '100%',
height: '100%',
backgroundColor: 'black',
zIndex: '1',
}
if (!element) {
return {
...defaultStyle,
...style,
}
}
if (style) {
return style
}
return {}
}

private async getCoreOption() {
Expand Down
9 changes: 9 additions & 0 deletions src/types/emulator-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@ import type { RetroArchConfig } from './retroarch-config'

export interface EmulatorOptions {
element: HTMLCanvasElement

style: Partial<CSSStyleDeclaration>

/**
*
* The size of the canvas element.
* If it's `'auto'`, the canvas element will keep its original size, or it's width and height will be updated as specified.
*/
size?: 'auto' | { width: number; height: number }

core: {
/** the name of core */
name: string
Expand Down
28 changes: 27 additions & 1 deletion src/types/nostalgist-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,33 @@ export interface NostalgistOptions {
*/
element: string | HTMLCanvasElement

size?: 'auto' | { width: number; height: number }
/**
* The style of the canvas element.
*
* The CSS rule name should be "camelCase" instead of "kebab-case". For example, `{ backgroundColor: 'black' }` is valid, but `{ background-color: '' }` is not.
*
* If the canvas element is created automatically, the style will be
* ```js
* {
* position: 'fixed',
* top: '0',
* left: '0',
* width: '100%',
* height: '100%',
* backgroundColor: 'black',
* zIndex: '1',
* }
* ```
* otherwise it will be `undefined`.
*/
style?: Partial<CSSStyleDeclaration>

/**
*
* The size of the canvas element.
* If it's `'auto'`, the canvas element will keep its original size, or it's width and height will be updated as specified.
*/
size: 'auto' | { width: number; height: number }

core: string | NostalgistCoreDict

Expand Down
11 changes: 11 additions & 0 deletions tests/integration/nostalgist.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,15 @@ describe('nostalgist', () => {
expect(emulatorOptions.bios[1].fileName).toEqual('FinalBurn Neo (hiscore).zip')
expect(emulatorOptions.bios[1].fileContent.constructor.name).toBe('Blob')
})

test.only('Nostalgist.launch with custom style and size', async () => {
const nostalgist = await Nostalgist.launch({
size: { width: 100, height: 100 },
core: 'fceumm',
rom: 'flappybird.nes',
})

const options = nostalgist.getOptions()
expect(options.size).toEqual({ width: 100, height: 100 })
})
})

0 comments on commit afca83b

Please sign in to comment.