Skip to content

Commit

Permalink
fixes/improvements/docs (#157)
Browse files Browse the repository at this point in the history
  • Loading branch information
huntabyte authored Dec 2, 2024
1 parent 520ecb2 commit 86a00b8
Show file tree
Hide file tree
Showing 30 changed files with 271 additions and 104 deletions.
5 changes: 5 additions & 0 deletions .changeset/clean-foxes-refuse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"runed": patch
---

widen the type of element getter args to `HTMLElement | undefined | null`
5 changes: 5 additions & 0 deletions .changeset/dull-moons-melt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"runed": patch
---

ensure explicit return types for utilities
5 changes: 5 additions & 0 deletions .changeset/tricky-buttons-perform.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"runed": patch
---

fix: `isIdle.current` should be readonly
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class AnimationFrames {
});
}

#loop = (timestamp: DOMHighResTimeStamp) => {
#loop = (timestamp: DOMHighResTimeStamp): void => {
if (!this.#running) return;

if (this.#previousTimestamp === null) {
Expand All @@ -76,28 +76,28 @@ export class AnimationFrames {
this.#frame = requestAnimationFrame(this.#loop);
};

start = () => {
start = (): void => {
this.#running = true;
this.#previousTimestamp = 0;
this.#frame = requestAnimationFrame(this.#loop);
};

stop = () => {
stop = (): void => {
if (!this.#frame) return;
this.#running = false;
cancelAnimationFrame(this.#frame);
this.#frame = null;
};

toggle = () => {
toggle = (): void => {
this.#running ? this.stop() : this.start();
};

get fps() {
get fps(): number {
return !this.#running ? 0 : this.#fps;
}

get running() {
get running(): boolean {
return this.#running;
}
}
10 changes: 5 additions & 5 deletions packages/runed/src/lib/utilities/Debounced/Debounced.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { noop } from "$lib/internal/utils/function.js";
/**
* A wrapper over {@link useDebounce} that creates a debounced state.
* It takes a "getter" function which returns the state you want to debounce.
* Everytime this state changes a timer (re)starts, the length of which is
* Every time this state changes a timer (re)starts, the length of which is
* configurable with the `wait` arg. When the timer ends the `current` value
* is updated.
*
Expand Down Expand Up @@ -56,15 +56,15 @@ export class Debounced<T> {
/**
* Cancel the latest timer.
*/
cancel() {
cancel = (): void => {
this.#debounceFn.cancel();
}
};

/**
* Set the `current` value without waiting.
*/
setImmediately(v: T) {
setImmediately = (v: T): void => {
this.cancel();
this.#current = v;
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export class ElementRect {
left: 0,
});

constructor(node: MaybeGetter<HTMLElement | undefined>, options: ElementRectOptions = {}) {
constructor(node: MaybeGetter<HTMLElement | undefined | null>, options: ElementRectOptions = {}) {
this.#rect = {
width: options.initialRect?.width ?? 0,
height: options.initialRect?.height ?? 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class ElementSize {
});

constructor(
node: MaybeGetter<HTMLElement | undefined>,
node: MaybeGetter<HTMLElement | undefined | null>,
options: ElementSizeOptions = { box: "border-box" }
) {
this.#size = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export type Transition<StatesT extends string, EventsT extends string> = {
* @see {@link https://runed.dev/docs/utilities/finite-state-machine}
*/
export class FiniteStateMachine<StatesT extends string, EventsT extends string> {
#current = $state() as StatesT;
#current: StatesT = $state()!;
readonly states: Transition<StatesT, EventsT>;
#timeout: Partial<Record<EventsT, NodeJS.Timeout>> = {};

Expand Down Expand Up @@ -93,16 +93,16 @@ export class FiniteStateMachine<StatesT extends string, EventsT extends string>
}

/** Triggers a new event and returns the new state. */
send(event: EventsT, ...args: unknown[]) {
send = (event: EventsT, ...args: unknown[]): StatesT => {
const newState = this.#dispatch(event, ...args);
if (newState && newState !== this.#current) {
this.#transition(newState as StatesT, event, args);
}
return this.#current;
}
};

/** Debounces the triggering of an event. */
async debounce(wait: number = 500, event: EventsT, ...args: unknown[]): Promise<StatesT> {
debounce = async (wait: number = 500, event: EventsT, ...args: unknown[]): Promise<StatesT> => {
if (this.#timeout[event]) {
clearTimeout(this.#timeout[event]);
}
Expand All @@ -112,10 +112,10 @@ export class FiniteStateMachine<StatesT extends string, EventsT extends string>
resolve(this.send(event, ...args));
}, wait);
});
}
};

/** The current state. */
get current() {
get current(): StatesT {
return this.#current;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import type { MaybeGetter } from "$lib/internal/types.js";
* @see {@link https://runed.dev/docs/utilities/is-focus-within}
*/
export class IsFocusWithin {
#node: MaybeGetter<HTMLElement | undefined>;
#node: MaybeGetter<HTMLElement | undefined | null>;
#target = $derived.by(() => extract(this.#node));

constructor(node: MaybeGetter<HTMLElement | undefined>) {
constructor(node: MaybeGetter<HTMLElement | undefined | null>) {
this.#node = node;
}

Expand Down
12 changes: 8 additions & 4 deletions packages/runed/src/lib/utilities/IsIdle/IsIdle.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const DEFAULT_OPTIONS = {
* @see {@link https://runed.dev/docs/utilities/is-idle}
*/
export class IsIdle {
current = $state(false);
#current: boolean = $state(false);
#lastActive = $state(Date.now());

constructor(_options?: IsIdleOptions) {
Expand All @@ -63,19 +63,19 @@ export class IsIdle {
const timeout = $derived(extract(options.timeout));
const events = $derived(extract(options.events));
const detectVisibilityChanges = $derived(extract(options.detectVisibilityChanges));
this.current = options.initialState;
this.#current = options.initialState;

const debouncedReset = useDebounce(
() => {
this.current = true;
this.#current = true;
},
() => timeout
);

debouncedReset();

const handleActivity = () => {
this.current = false;
this.#current = false;
this.#lastActive = Date.now();
debouncedReset();
};
Expand All @@ -101,4 +101,8 @@ export class IsIdle {
get lastActive(): number {
return this.#lastActive;
}

get current(): boolean {
return this.#current;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,11 @@ function getValueFromStorage<T>({
storage: Storage | null;
serializer: Serializer<T>;
}): GetValueFromStorageResult<T> {
if (!storage) {
return { found: false, value: null };
}
if (!storage) return { found: false, value: null };

const value = storage.getItem(key);
if (value === null) {
return { found: false, value: null };
}

if (value === null) return { found: false, value: null };

try {
return {
Expand All @@ -57,9 +54,7 @@ function setValueToStorage<T>({
storage: Storage | null;
serializer: Serializer<T>;
}) {
if (!storage) {
return;
}
if (!storage) return;

try {
storage.setItem(key, serializer.serialize(value));
Expand All @@ -71,9 +66,7 @@ function setValueToStorage<T>({
type StorageType = "local" | "session";

function getStorage(storageType: StorageType): Storage | null {
if (typeof window === "undefined") {
return null;
}
if (typeof window === "undefined") return null;

const storageByStorageType = {
local: localStorage,
Expand Down Expand Up @@ -101,7 +94,7 @@ type PersistedStateOptions<T> = {
* @see {@link https://runed.dev/docs/utilities/persisted-state}
*/
export class PersistedState<T> {
#current = $state() as T;
#current: T = $state()!;
#key: string;
#storage: Storage | null;
#serializer: Serializer<T>;
Expand Down Expand Up @@ -135,18 +128,13 @@ export class PersistedState<T> {
});

$effect(() => {
if (!syncTabs) {
return;
}

if (!syncTabs) return;
return addEventListener(window, "storage", this.#handleStorageEvent.bind(this));
});
}

#handleStorageEvent(event: StorageEvent) {
if (event.key !== this.#key || !this.#storage) {
return;
}
if (event.key !== this.#key || !this.#storage) return;

const valueFromStorage = getValueFromStorage({
key: this.#key,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { addEventListener } from "$lib/internal/utils/event.js";
* @see {@link https://runed.dev/docs/utilities/pressed-keys}
*/
export class PressedKeys {
#pressedKeys: string[] = $state([]);
#pressedKeys = $state<string[]>([]);

constructor() {
$effect(() => {
Expand All @@ -32,10 +32,10 @@ export class PressedKeys {
});
}

has(...keys: string[]): boolean {
has = (...keys: string[]): boolean => {
const normalizedKeys = keys.map((key) => key.toLowerCase());
return normalizedKeys.every((key) => this.#pressedKeys.includes(key));
}
};

get all(): string[] {
return this.#pressedKeys;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { Getter } from "$lib/internal/types.js";
* @see {@link https://runed.dev/docs/utilities/previous}
*/
export class Previous<T> {
#previous: T | undefined = $state();
#previous: T | undefined = $state(undefined);
#curr?: T;

constructor(getter: Getter<T>) {
Expand Down
2 changes: 1 addition & 1 deletion packages/runed/src/lib/utilities/Store/Store.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ function isWritable(t: Readable<unknown>): t is Writable<unknown> {
}

export class Store<T extends Readable<unknown>> {
#current = $state() as ReadableValue<T>;
#current: ReadableValue<T> = $state()!;
#store: T;

constructor(store: T) {
Expand Down
18 changes: 17 additions & 1 deletion sites/docs/src/content/utilities/active-element.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
---
title: activeElement
description: An object holding the currently active element.
description: Track and access the currently focused DOM element
category: Elements
---

<script>
import Demo from '$lib/components/demos/active-element.svelte';
</script>

`activeElement` provides reactive access to the currently focused DOM element in your application,
similar to `document.activeElement` but with reactive updates.

- Updates synchronously with DOM focus changes
- Returns `null` when no element is focused
- Safe to use with SSR (Server-Side Rendering)
- Lightweight alternative to manual focus tracking

## Demo

<Demo />
Expand All @@ -24,3 +32,11 @@ import Demo from '$lib/components/demos/active-element.svelte';
{activeElement.current?.localName ?? "No active element found"}
</p>
```

## Type Definition

```ts
interface ActiveElement {
readonly current: Element | null;
}
```
21 changes: 5 additions & 16 deletions sites/docs/src/content/utilities/animation-frames.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,21 @@
---
title: AnimationFrames
description:
A wrapper over `requestAnimationFrame`, with controls for limiting FPS, and information about the
current frame.
description: A wrapper for requestAnimationFrame with FPS control and frame metrics
category: Browser
---

<script>
import Demo from '$lib/components/demos/animation-frames.svelte';
</script>

`AnimationFrames` provides a declarative API over the browser's
[`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame),
offering FPS limiting capabilities and frame metrics while handling cleanup automatically.

## Demo

<Demo />

## Description

`AnimationFrames` wraps over
[`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame).
While it is not necessary to use it to use `requestAnimationFrame`, it removes some of the
boilerplate, and adds common utilities for it.

- Automatically interrupts the requestAnimationFrame loop once the component is unmounted
- Lets you set an FPS limit
- Lets you get information about the current frame, such as its current timestamp, and the
difference in ms between the last frame and the current one
- Returns information about current FPS

## Usage

```svelte
Expand Down
Loading

0 comments on commit 86a00b8

Please sign in to comment.