From f6ef899f93bd1e2294f98495291a29b741cc3a37 Mon Sep 17 00:00:00 2001 From: Mateus Lage Date: Mon, 22 Dec 2025 17:25:47 -0300 Subject: [PATCH 1/8] feat(UseFullscreen): add utility export --- packages/runed/src/lib/utilities/index.ts | 1 + .../src/lib/utilities/use-fullscreen/index.ts | 1 + .../use-fullscreen/use-fullscreen.svelte.ts | 41 +++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 packages/runed/src/lib/utilities/use-fullscreen/index.ts create mode 100644 packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.svelte.ts diff --git a/packages/runed/src/lib/utilities/index.ts b/packages/runed/src/lib/utilities/index.ts index 55f528b8..317c36d9 100644 --- a/packages/runed/src/lib/utilities/index.ts +++ b/packages/runed/src/lib/utilities/index.ts @@ -22,6 +22,7 @@ export * from "./textarea-autosize/index.js"; export * from "./throttled/index.js"; export * from "./use-debounce/index.js"; export * from "./use-event-listener/index.js"; +export * from "./use-fullscreen/index.js"; export * from "./use-geolocation/index.js"; export * from "./use-intersection-observer/index.js"; export * from "./use-mutation-observer/index.js"; diff --git a/packages/runed/src/lib/utilities/use-fullscreen/index.ts b/packages/runed/src/lib/utilities/use-fullscreen/index.ts new file mode 100644 index 00000000..ea102457 --- /dev/null +++ b/packages/runed/src/lib/utilities/use-fullscreen/index.ts @@ -0,0 +1 @@ +export * from "./use-fullscreen.svelte"; diff --git a/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.svelte.ts b/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.svelte.ts new file mode 100644 index 00000000..9bd3f1a9 --- /dev/null +++ b/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.svelte.ts @@ -0,0 +1,41 @@ +export interface UseFullscreenReturn { + readonly isFullscreen: boolean; + enter: () => Promise; + exit: () => Promise; + toggle: () => Promise; +} + +export function useFullscreen(el: () => HTMLElement | undefined): UseFullscreenReturn { + let isFullscreen = $state(false); + async function exit() { + await document.exitFullscreen(); + } + async function enter() { + await el()?.requestFullscreen(); + } + async function toggle() { + if (!el()) return; + if (isFullscreen) { + await exit(); + } else { + await enter(); + } + } + function updateFullscreenState() { + isFullscreen = !!document.fullscreenElement; + } + $effect(() => { + document.addEventListener("fullscreenchange", updateFullscreenState); + return () => { + document.removeEventListener("fullscreenchange", updateFullscreenState); + }; + }); + return { + get isFullscreen() { + return isFullscreen; + }, + enter, + exit, + toggle, + }; +} From 191211227a3556d79c791ba517630b9b3d0cc70b Mon Sep 17 00:00:00 2001 From: Mateus Lage Date: Mon, 22 Dec 2025 19:56:55 -0300 Subject: [PATCH 2/8] feat(useFullscreen): align implementation to VueUse --- .../use-fullscreen/use-fullscreen.svelte.ts | 162 ++++++++++++++++-- 1 file changed, 148 insertions(+), 14 deletions(-) diff --git a/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.svelte.ts b/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.svelte.ts index 9bd3f1a9..5ed0d436 100644 --- a/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.svelte.ts +++ b/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.svelte.ts @@ -1,36 +1,170 @@ +import { type ConfigurableDocument, defaultDocument } from "../../internal/configurable-globals.js"; +import type { MaybeElementGetter } from "../../internal/types.js"; +import { extract } from "../extract/extract.svelte.js"; +import { useEventListener } from "../use-event-listener/index.js"; + +export interface UseFullscreenOptions extends ConfigurableDocument { + /** + * Automatically exit fullscreen when component is unmounted + * + * @default false + */ + autoExit?: boolean; +} + export interface UseFullscreenReturn { + readonly isSupported: boolean; readonly isFullscreen: boolean; enter: () => Promise; exit: () => Promise; toggle: () => Promise; } -export function useFullscreen(el: () => HTMLElement | undefined): UseFullscreenReturn { +const eventHandlers = [ + "fullscreenchange", + "webkitfullscreenchange", + "webkitendfullscreen", + "mozfullscreenchange", + "MSFullscreenChange", +] as any as "fullscreenchange"[]; + +export function useFullscreen( + target?: MaybeElementGetter, + options: UseFullscreenOptions = {} +): UseFullscreenReturn { + const { document = defaultDocument, autoExit = false } = options; + + let targetRef = $derived(extract(target) ?? document?.documentElement) as T | null | undefined; let isFullscreen = $state(false); + + const requestMethod = $derived.by<"requestFullscreen" | undefined>(() => { + return [ + "requestFullscreen", + "webkitRequestFullscreen", + "webkitEnterFullscreen", + "webkitEnterFullScreen", + "webkitRequestFullScreen", + "mozRequestFullScreen", + "msRequestFullscreen", + ].find((m) => (document && m in document) || (targetRef && m in targetRef)) as + | "requestFullscreen" + | undefined; + }); + + const exitMethod = $derived.by<"exitFullscreen" | undefined>(() => { + return [ + "exitFullscreen", + "webkitExitFullscreen", + "webkitExitFullScreen", + "webkitCancelFullScreen", + "mozCancelFullScreen", + "msExitFullscreen", + ].find((m) => (document && m in document) || (targetRef && m in targetRef)) as + | "exitFullscreen" + | undefined; + }); + + const fullscreenEnabled = $derived.by<"fullscreenEnabled" | undefined>(() => { + return [ + "fullScreen", + "webkitIsFullScreen", + "webkitDisplayingFullscreen", + "mozFullScreen", + "msFullscreenElement", + ].find((m) => (document && m in document) || (targetRef && m in targetRef)) as + | "fullscreenEnabled" + | undefined; + }); + + const fullscreenElementMethod = [ + "fullscreenElement", + "webkitFullscreenElement", + "mozFullScreenElement", + "msFullscreenElement", + ].find((m) => document && m in document) as "fullscreenElement" | undefined; + + const isSupported = $derived( + !!(targetRef && document && requestMethod && exitMethod && fullscreenEnabled) + ); + + const isCurrentElementFullScreen = (): boolean => { + if (fullscreenElementMethod) return document?.[fullscreenElementMethod] === targetRef; + return false; + }; + + const isElementFullScreen = (): boolean => { + if (fullscreenEnabled) { + if (document && document[fullscreenEnabled] != null) { + return document[fullscreenEnabled]; + } else { + const target = targetRef; + // @ts-expect-error - Fallback for WebKit and iOS Safari browsers + if (target?.[fullscreenEnabled] != null) { + // @ts-expect-error - Fallback for WebKit and iOS Safari browsers + return Boolean(target[fullscreenEnabled]); + } + } + } + return false; + }; + async function exit() { - await document.exitFullscreen(); + if (!isSupported || !isFullscreen) return; + if (exitMethod) { + if (document?.[exitMethod] != null) { + await document[exitMethod](); + } else { + const target = targetRef; + // @ts-expect-error - Fallback for Safari iOS + if (target?.[exitMethod] != null) + // @ts-expect-error - Fallback for Safari iOS + await target[exitMethod](); + } + } + + isFullscreen = false; } + async function enter() { - await el()?.requestFullscreen(); - } - async function toggle() { - if (!el()) return; - if (isFullscreen) { - await exit(); - } else { - await enter(); + if (!isSupported || isFullscreen) return; + + if (isElementFullScreen()) await exit(); + + const target = targetRef; + if (requestMethod && target?.[requestMethod] != null) { + await target[requestMethod](); + isFullscreen = true; } } - function updateFullscreenState() { - isFullscreen = !!document.fullscreenElement; + + async function toggle() { + await (isFullscreen ? exit() : enter()); } + + const handlerCallback = () => { + const isElementFullScreenValue = isElementFullScreen(); + if (!isElementFullScreenValue || (isElementFullScreenValue && isCurrentElementFullScreen())) + isFullscreen = isElementFullScreenValue; + }; + + const listenerOptions = { capture: false, passive: true }; + useEventListener(document, eventHandlers, handlerCallback, listenerOptions); + useEventListener(() => targetRef, eventHandlers, handlerCallback, listenerOptions); + $effect(() => { - document.addEventListener("fullscreenchange", updateFullscreenState); + handlerCallback(); + return () => { - document.removeEventListener("fullscreenchange", updateFullscreenState); + if (autoExit) { + exit(); + } }; }); + return { + get isSupported() { + return isSupported; + }, get isFullscreen() { return isFullscreen; }, From b06a035b75b5bba09f721c93f4c64d171de3628e Mon Sep 17 00:00:00 2001 From: Mateus Lage Date: Mon, 22 Dec 2025 19:59:17 -0300 Subject: [PATCH 3/8] add docs --- .../src/content/utilities/use-fullscreen.md | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 sites/docs/src/content/utilities/use-fullscreen.md diff --git a/sites/docs/src/content/utilities/use-fullscreen.md b/sites/docs/src/content/utilities/use-fullscreen.md new file mode 100644 index 00000000..c6fc8b72 --- /dev/null +++ b/sites/docs/src/content/utilities/use-fullscreen.md @@ -0,0 +1,82 @@ +--- +title: useFullscreen +description: Reactive access to the browser's Fullscreen API. +category: Browser +--- + + + +`useFullscreen` is a reactive wrapper around the browser's +[Fullscreen API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API). + +## Demo + + + +## Usage + +```svelte + + +
Is Supported: {fullscreen.isSupported}
+
Is Fullscreen: {fullscreen.isFullscreen}
+ + + +``` + +With a specific target element: + +```svelte + + + + + + +``` + +## Type Definitions + +```ts +type UseFullscreenOptions = { + /** + * Automatically exit fullscreen when component is unmounted + * + * @default false + */ + autoExit?: boolean; + /** + * Custom document instance + * + * @default defaultDocument + */ + document?: Document; +}; + +type UseFullscreenReturn = { + readonly isSupported: boolean; + readonly isFullscreen: boolean; + enter: () => Promise; + exit: () => Promise; + toggle: () => Promise; +}; +``` From 0f1f64f1408a77e2b995abaaad8b37c168793091 Mon Sep 17 00:00:00 2001 From: Mateus Lage Date: Mon, 22 Dec 2025 20:07:45 -0300 Subject: [PATCH 4/8] add demo --- .../components/demos/use-fullscreen.svelte | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 sites/docs/src/lib/components/demos/use-fullscreen.svelte diff --git a/sites/docs/src/lib/components/demos/use-fullscreen.svelte b/sites/docs/src/lib/components/demos/use-fullscreen.svelte new file mode 100644 index 00000000..5a23dbf6 --- /dev/null +++ b/sites/docs/src/lib/components/demos/use-fullscreen.svelte @@ -0,0 +1,26 @@ + + + +
Is Supported: {fullscreen.isSupported}
+
Is Fullscreen: {fullscreen.isFullscreen}
+
+ + + +
+
From 20cb6dde6dc6d2e93735ff499d65049cf414bd7f Mon Sep 17 00:00:00 2001 From: Mateus Lage Date: Mon, 22 Dec 2025 20:16:44 -0300 Subject: [PATCH 5/8] improve var naming --- .../use-fullscreen/use-fullscreen.svelte.ts | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.svelte.ts b/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.svelte.ts index 5ed0d436..b5309a58 100644 --- a/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.svelte.ts +++ b/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.svelte.ts @@ -29,12 +29,12 @@ const eventHandlers = [ ] as any as "fullscreenchange"[]; export function useFullscreen( - target?: MaybeElementGetter, + targetGetter?: MaybeElementGetter, options: UseFullscreenOptions = {} ): UseFullscreenReturn { const { document = defaultDocument, autoExit = false } = options; - let targetRef = $derived(extract(target) ?? document?.documentElement) as T | null | undefined; + let target = $derived(extract(targetGetter) ?? document?.documentElement) as T | null | undefined; let isFullscreen = $state(false); const requestMethod = $derived.by<"requestFullscreen" | undefined>(() => { @@ -46,7 +46,7 @@ export function useFullscreen( "webkitRequestFullScreen", "mozRequestFullScreen", "msRequestFullscreen", - ].find((m) => (document && m in document) || (targetRef && m in targetRef)) as + ].find((m) => (document && m in document) || (target && m in target)) as | "requestFullscreen" | undefined; }); @@ -59,7 +59,7 @@ export function useFullscreen( "webkitCancelFullScreen", "mozCancelFullScreen", "msExitFullscreen", - ].find((m) => (document && m in document) || (targetRef && m in targetRef)) as + ].find((m) => (document && m in document) || (target && m in target)) as | "exitFullscreen" | undefined; }); @@ -71,7 +71,7 @@ export function useFullscreen( "webkitDisplayingFullscreen", "mozFullScreen", "msFullscreenElement", - ].find((m) => (document && m in document) || (targetRef && m in targetRef)) as + ].find((m) => (document && m in document) || (target && m in target)) as | "fullscreenEnabled" | undefined; }); @@ -84,11 +84,11 @@ export function useFullscreen( ].find((m) => document && m in document) as "fullscreenElement" | undefined; const isSupported = $derived( - !!(targetRef && document && requestMethod && exitMethod && fullscreenEnabled) + !!(target && document && requestMethod && exitMethod && fullscreenEnabled) ); const isCurrentElementFullScreen = (): boolean => { - if (fullscreenElementMethod) return document?.[fullscreenElementMethod] === targetRef; + if (fullscreenElementMethod) return document?.[fullscreenElementMethod] === target; return false; }; @@ -97,7 +97,6 @@ export function useFullscreen( if (document && document[fullscreenEnabled] != null) { return document[fullscreenEnabled]; } else { - const target = targetRef; // @ts-expect-error - Fallback for WebKit and iOS Safari browsers if (target?.[fullscreenEnabled] != null) { // @ts-expect-error - Fallback for WebKit and iOS Safari browsers @@ -114,7 +113,6 @@ export function useFullscreen( if (document?.[exitMethod] != null) { await document[exitMethod](); } else { - const target = targetRef; // @ts-expect-error - Fallback for Safari iOS if (target?.[exitMethod] != null) // @ts-expect-error - Fallback for Safari iOS @@ -130,7 +128,6 @@ export function useFullscreen( if (isElementFullScreen()) await exit(); - const target = targetRef; if (requestMethod && target?.[requestMethod] != null) { await target[requestMethod](); isFullscreen = true; @@ -149,7 +146,7 @@ export function useFullscreen( const listenerOptions = { capture: false, passive: true }; useEventListener(document, eventHandlers, handlerCallback, listenerOptions); - useEventListener(() => targetRef, eventHandlers, handlerCallback, listenerOptions); + useEventListener(() => target, eventHandlers, handlerCallback, listenerOptions); $effect(() => { handlerCallback(); From cd02a00dfbf0114266a2656dbf4f33f22c6d334b Mon Sep 17 00:00:00 2001 From: Mateus Lage Date: Mon, 22 Dec 2025 20:19:45 -0300 Subject: [PATCH 6/8] docs --- .../lib/utilities/use-fullscreen/use-fullscreen.svelte.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.svelte.ts b/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.svelte.ts index b5309a58..295c2b4b 100644 --- a/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.svelte.ts +++ b/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.svelte.ts @@ -28,6 +28,13 @@ const eventHandlers = [ "MSFullscreenChange", ] as any as "fullscreenchange"[]; +/** + * Reactive Fullscreen API. + * + * @see https://runed.dev/docs/utilities/use-fullscreen + * @param targetGetter + * @param options + */ export function useFullscreen( targetGetter?: MaybeElementGetter, options: UseFullscreenOptions = {} From a8d4605074f381044d7290f14e9182f74774e4c5 Mon Sep 17 00:00:00 2001 From: Mateus Lage Date: Tue, 23 Dec 2025 15:29:58 -0300 Subject: [PATCH 7/8] add test --- .../use-fullscreen.test.svelte.ts | 243 ++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.test.svelte.ts diff --git a/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.test.svelte.ts b/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.test.svelte.ts new file mode 100644 index 00000000..60254f14 --- /dev/null +++ b/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.test.svelte.ts @@ -0,0 +1,243 @@ +import { describe, expect, beforeEach, afterEach, vi } from "vitest"; +import { flushSync } from "svelte"; +import { useFullscreen } from "./use-fullscreen.svelte.js"; +import { testWithEffect } from "$lib/test/util.svelte.js"; + +describe("useFullscreen", () => { + let mockElement: HTMLElement; + let mockDocument: Document; + + beforeEach(() => { + mockElement = document.createElement("div"); + document.body.appendChild(mockElement); + + // Create a proper mock document with all required fullscreen properties + mockDocument = { + ...document, + fullscreenElement: null, + // The code checks for 'fullScreen' not 'fullscreenEnabled' + fullScreen: false, + requestFullscreen: vi.fn().mockResolvedValue(undefined), + exitFullscreen: vi.fn().mockResolvedValue(undefined), + webkitRequestFullscreen: vi.fn().mockResolvedValue(undefined), + webkitExitFullscreen: vi.fn().mockResolvedValue(undefined), + mozRequestFullScreen: vi.fn().mockResolvedValue(undefined), + mozCancelFullScreen: vi.fn().mockResolvedValue(undefined), + msRequestFullscreen: vi.fn().mockResolvedValue(undefined), + msExitFullscreen: vi.fn().mockResolvedValue(undefined), + webkitFullscreenElement: null, + webkitIsFullScreen: false, + webkitDisplayingFullscreen: false, + mozFullScreen: false, + mozFullScreenElement: null, + msFullscreenElement: null, + // Ensure event listener methods are available + addEventListener: document.addEventListener.bind(document), + removeEventListener: document.removeEventListener.bind(document), + dispatchEvent: document.dispatchEvent.bind(document), + }; + + // Add fullscreen methods to the element + Object.defineProperty(mockElement, "requestFullscreen", { + value: vi.fn().mockResolvedValue(undefined), + writable: true, + }); + Object.defineProperty(mockElement, "webkitRequestFullscreen", { + value: vi.fn().mockResolvedValue(undefined), + writable: true, + }); + }); + + afterEach(() => { + mockElement.remove(); + }); + + testWithEffect("initializes with correct default state", () => { + const fullscreen = useFullscreen(() => mockElement, { document: mockDocument }); + flushSync(); + + expect(fullscreen.isSupported).toBe(true); + expect(fullscreen.isFullscreen).toBe(false); + }); + + testWithEffect("detects support when fullscreen API is available", () => { + const fullscreen = useFullscreen(() => mockElement, { document: mockDocument }); + flushSync(); + + expect(fullscreen.isSupported).toBe(true); + }); + + testWithEffect("detects lack of support when fullscreen API is unavailable", () => { + const unsupportedElement = document.createElement("div"); + // Create a minimal mock without any fullscreen support + const unsupportedDoc = { + fullscreenElement: null, + fullScreen: false, + webkitIsFullScreen: false, + webkitDisplayingFullscreen: false, + mozFullScreen: false, + msFullscreenElement: null, + documentElement: unsupportedElement, + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + } as unknown as Document; + + const fullscreen = useFullscreen(() => unsupportedElement, { + document: unsupportedDoc, + }); + flushSync(); + + expect(fullscreen.isSupported).toBe(false); + }); + + testWithEffect("enter() calls requestFullscreen on target element", async () => { + const fullscreen = useFullscreen(() => mockElement, { document: mockDocument }); + flushSync(); + + await fullscreen.enter(); + + expect(mockElement.requestFullscreen).toHaveBeenCalledTimes(1); + }); + + testWithEffect("exit() calls exitFullscreen on document", async () => { + const fullscreen = useFullscreen(() => mockElement, { document: mockDocument }); + flushSync(); + + // First enter fullscreen + await fullscreen.enter(); + // Simulate fullscreen state + (mockDocument as any).fullscreenElement = mockElement; + (mockDocument as any).fullScreen = true; + mockDocument.dispatchEvent(new Event("fullscreenchange")); + flushSync(); + + await fullscreen.exit(); + + expect(mockDocument.exitFullscreen).toHaveBeenCalledTimes(1); + }); + + testWithEffect("toggle() switches between fullscreen states", async () => { + const fullscreen = useFullscreen(() => mockElement, { document: mockDocument }); + flushSync(); + + expect(fullscreen.isFullscreen).toBe(false); + + await fullscreen.toggle(); + // Simulate fullscreen state change + (mockDocument as any).fullscreenElement = mockElement; + (mockDocument as any).fullScreen = true; + mockDocument.dispatchEvent(new Event("fullscreenchange")); + flushSync(); + expect(fullscreen.isFullscreen).toBe(true); + + await fullscreen.toggle(); + // Simulate exit fullscreen + (mockDocument as any).fullscreenElement = null; + (mockDocument as any).fullScreen = false; + mockDocument.dispatchEvent(new Event("fullscreenchange")); + flushSync(); + expect(fullscreen.isFullscreen).toBe(false); + }); + + testWithEffect("does not enter fullscreen if already in fullscreen", async () => { + const fullscreen = useFullscreen(() => mockElement, { document: mockDocument }); + flushSync(); + + await fullscreen.enter(); + const firstCallCount = (mockElement.requestFullscreen as any).mock.calls.length; + + await fullscreen.enter(); + const secondCallCount = (mockElement.requestFullscreen as any).mock.calls.length; + + expect(secondCallCount).toBe(firstCallCount); + }); + + testWithEffect("does not exit fullscreen if not in fullscreen", async () => { + const fullscreen = useFullscreen(() => mockElement, { document: mockDocument }); + flushSync(); + + await fullscreen.exit(); + + expect(mockDocument.exitFullscreen).not.toHaveBeenCalled(); + }); + + testWithEffect("responds to fullscreenchange events", () => { + const fullscreen = useFullscreen(() => mockElement, { document: mockDocument }); + flushSync(); + + expect(fullscreen.isFullscreen).toBe(false); + + // Simulate entering fullscreen + (mockDocument as any).fullscreenElement = mockElement; + (mockDocument as any).fullScreen = true; + mockDocument.dispatchEvent(new Event("fullscreenchange")); + flushSync(); + + expect(fullscreen.isFullscreen).toBe(true); + }); + + testWithEffect("autoExit option exits fullscreen on cleanup", async () => { + const fullscreen = useFullscreen(() => mockElement, { + document: mockDocument, + autoExit: true, + }); + flushSync(); + + // Just verify the utility initializes correctly with autoExit + expect(fullscreen.isSupported).toBe(true); + expect(fullscreen.isFullscreen).toBe(false); + }); + + testWithEffect("works with document element as default target", () => { + // When no target is provided, it should default to document.documentElement + // Ensure mockDocument.documentElement has requestFullscreen + Object.defineProperty(mockDocument, "documentElement", { + value: mockElement, + writable: true, + }); + + const fullscreen = useFullscreen(() => undefined, { document: mockDocument }); + flushSync(); + + expect(fullscreen.isSupported).toBe(true); + }); + + testWithEffect("handles custom document option", () => { + const customDoc = { + ...mockDocument, + documentElement: mockElement, + } as unknown as Document; + + const fullscreen = useFullscreen(() => mockElement, { document: customDoc }); + flushSync(); + + expect(fullscreen.isSupported).toBe(true); + }); + + testWithEffect("handles vendor-prefixed fullscreen methods", async () => { + const vendorElement = document.createElement("div"); + document.body.appendChild(vendorElement); + + // Remove standard method and add vendor prefix + Object.defineProperty(vendorElement, "requestFullscreen", { + value: undefined, + writable: true, + }); + Object.defineProperty(vendorElement, "webkitRequestFullscreen", { + value: vi.fn().mockResolvedValue(undefined), + writable: true, + }); + + // Use the real document but with vendor element + const fullscreen = useFullscreen(() => vendorElement); + flushSync(); + + // Since the real document has requestFullscreen, we need to mock the detection + // This test is limited by the mocking capabilities in the test environment + // We can only verify that the method exists on the element + expect((vendorElement as any).webkitRequestFullscreen).toBeDefined(); + + vendorElement.remove(); + }); +}); From b8aaa5b245dc59ebf59a1029a7416b14ffab5f51 Mon Sep 17 00:00:00 2001 From: Mateus Lage Date: Tue, 23 Dec 2025 15:34:23 -0300 Subject: [PATCH 8/8] test(useFullscreen): add ts-ignore comment for fullScreen property --- .../lib/utilities/use-fullscreen/use-fullscreen.test.svelte.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.test.svelte.ts b/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.test.svelte.ts index 60254f14..a424ea19 100644 --- a/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.test.svelte.ts +++ b/packages/runed/src/lib/utilities/use-fullscreen/use-fullscreen.test.svelte.ts @@ -15,7 +15,7 @@ describe("useFullscreen", () => { mockDocument = { ...document, fullscreenElement: null, - // The code checks for 'fullScreen' not 'fullscreenEnabled' + // @ts-ignore - The code checks for 'fullScreen' not 'fullscreenEnabled' fullScreen: false, requestFullscreen: vi.fn().mockResolvedValue(undefined), exitFullscreen: vi.fn().mockResolvedValue(undefined),