@labpics/colors 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +248 -242
- package/adapt-theme.d.ts +67 -67
- package/adapt-theme.js +431 -431
- package/apply-theme.d.ts +16 -16
- package/apply-theme.js +44 -44
- package/effective-bg.d.ts +48 -48
- package/effective-bg.js +255 -255
- package/index.d.ts +36 -36
- package/index.js +21 -21
- package/package.json +65 -65
- package/pkg/labcolors.js +5 -5
- package/pkg/labcolors_bg.wasm +0 -0
- package/watch-theme.d.ts +57 -57
- package/watch-theme.js +144 -144
package/apply-theme.d.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import type { ResolvedTheme } from "./pkg/labcolors.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Apply a resolved theme's CSS variables to an element.
|
|
5
|
-
*
|
|
6
|
-
* Writes every reachable role from `result.vars` onto `element.style` via
|
|
7
|
-
* `setProperty`. Unreachable and zero-token roles are absent from `vars` and
|
|
8
|
-
* are not written, so the caller's CSS fallbacks stay in effect for them.
|
|
9
|
-
*
|
|
10
|
-
* @param element The target element (e.g. `document.documentElement`).
|
|
11
|
-
* @param result A `LabColors.resolveTheme(...)` result.
|
|
12
|
-
*/
|
|
13
|
-
export declare function applyTheme(
|
|
14
|
-
element: HTMLElement,
|
|
15
|
-
result: Pick<ResolvedTheme, "vars">,
|
|
16
|
-
): void;
|
|
1
|
+
import type { ResolvedTheme } from "./pkg/labcolors.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Apply a resolved theme's CSS variables to an element.
|
|
5
|
+
*
|
|
6
|
+
* Writes every reachable role from `result.vars` onto `element.style` via
|
|
7
|
+
* `setProperty`. Unreachable and zero-token roles are absent from `vars` and
|
|
8
|
+
* are not written, so the caller's CSS fallbacks stay in effect for them.
|
|
9
|
+
*
|
|
10
|
+
* @param element The target element (e.g. `document.documentElement`).
|
|
11
|
+
* @param result A `LabColors.resolveTheme(...)` result.
|
|
12
|
+
*/
|
|
13
|
+
export declare function applyTheme(
|
|
14
|
+
element: HTMLElement,
|
|
15
|
+
result: Pick<ResolvedTheme, "vars">,
|
|
16
|
+
): void;
|
package/apply-theme.js
CHANGED
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
// Vanilla DOM helper — zero dependencies.
|
|
2
|
-
//
|
|
3
|
-
// The WASM core returns data and never touches the DOM (that separation is
|
|
4
|
-
// deliberate; full reactive injection is the css-injection-runtime chapter).
|
|
5
|
-
// This helper is the minimal, framework-free bridge: write a resolved theme's
|
|
6
|
-
// reachable colours onto an element as `--lab-*` custom properties.
|
|
7
|
-
|
|
8
|
-
const LAB_VAR_PREFIX = "--lab-";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Apply a resolved theme's CSS variables to an element.
|
|
12
|
-
*
|
|
13
|
-
* First clears every inline `--lab-*` custom property a previous call set on
|
|
14
|
-
* this element, then writes every reachable role from `result.vars` via
|
|
15
|
-
* `setProperty`. Unreachable and zero-token (`none`) roles carry no colour, so
|
|
16
|
-
* they are absent from `vars` and are not written — the caller's CSS fallbacks
|
|
17
|
-
* stay in effect for those, including across theme re-application (a role
|
|
18
|
-
* reachable in the previous theme but not in the new one does not linger).
|
|
19
|
-
*
|
|
20
|
-
* @param {HTMLElement} element - The target element (e.g. `document.documentElement`).
|
|
21
|
-
* @param {{ vars: Record<string, string> }} result - A `resolveTheme(...)` result.
|
|
22
|
-
* @returns {void}
|
|
23
|
-
*/
|
|
24
|
-
export function applyTheme(element, result) {
|
|
25
|
-
if (!element || typeof element.style?.setProperty !== "function") {
|
|
26
|
-
throw new TypeError("applyTheme: first argument must be an element with a style");
|
|
27
|
-
}
|
|
28
|
-
if (!result || typeof result.vars !== "object" || result.vars === null) {
|
|
29
|
-
throw new TypeError("applyTheme: second argument must be a resolveTheme result");
|
|
30
|
-
}
|
|
31
|
-
// Inline style is a live list; collect names first, then remove, so the
|
|
32
|
-
// iteration is not invalidated mid-walk.
|
|
33
|
-
const stale = [];
|
|
34
|
-
for (let i = 0; i < element.style.length; i++) {
|
|
35
|
-
const name = element.style.item(i);
|
|
36
|
-
if (name.startsWith(LAB_VAR_PREFIX)) stale.push(name);
|
|
37
|
-
}
|
|
38
|
-
for (const name of stale) {
|
|
39
|
-
element.style.removeProperty(name);
|
|
40
|
-
}
|
|
41
|
-
for (const [name, value] of Object.entries(result.vars)) {
|
|
42
|
-
element.style.setProperty(name, value);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
1
|
+
// Vanilla DOM helper — zero dependencies.
|
|
2
|
+
//
|
|
3
|
+
// The WASM core returns data and never touches the DOM (that separation is
|
|
4
|
+
// deliberate; full reactive injection is the css-injection-runtime chapter).
|
|
5
|
+
// This helper is the minimal, framework-free bridge: write a resolved theme's
|
|
6
|
+
// reachable colours onto an element as `--lab-*` custom properties.
|
|
7
|
+
|
|
8
|
+
const LAB_VAR_PREFIX = "--lab-";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Apply a resolved theme's CSS variables to an element.
|
|
12
|
+
*
|
|
13
|
+
* First clears every inline `--lab-*` custom property a previous call set on
|
|
14
|
+
* this element, then writes every reachable role from `result.vars` via
|
|
15
|
+
* `setProperty`. Unreachable and zero-token (`none`) roles carry no colour, so
|
|
16
|
+
* they are absent from `vars` and are not written — the caller's CSS fallbacks
|
|
17
|
+
* stay in effect for those, including across theme re-application (a role
|
|
18
|
+
* reachable in the previous theme but not in the new one does not linger).
|
|
19
|
+
*
|
|
20
|
+
* @param {HTMLElement} element - The target element (e.g. `document.documentElement`).
|
|
21
|
+
* @param {{ vars: Record<string, string> }} result - A `resolveTheme(...)` result.
|
|
22
|
+
* @returns {void}
|
|
23
|
+
*/
|
|
24
|
+
export function applyTheme(element, result) {
|
|
25
|
+
if (!element || typeof element.style?.setProperty !== "function") {
|
|
26
|
+
throw new TypeError("applyTheme: first argument must be an element with a style");
|
|
27
|
+
}
|
|
28
|
+
if (!result || typeof result.vars !== "object" || result.vars === null) {
|
|
29
|
+
throw new TypeError("applyTheme: second argument must be a resolveTheme result");
|
|
30
|
+
}
|
|
31
|
+
// Inline style is a live list; collect names first, then remove, so the
|
|
32
|
+
// iteration is not invalidated mid-walk.
|
|
33
|
+
const stale = [];
|
|
34
|
+
for (let i = 0; i < element.style.length; i++) {
|
|
35
|
+
const name = element.style.item(i);
|
|
36
|
+
if (name.startsWith(LAB_VAR_PREFIX)) stale.push(name);
|
|
37
|
+
}
|
|
38
|
+
for (const name of stale) {
|
|
39
|
+
element.style.removeProperty(name);
|
|
40
|
+
}
|
|
41
|
+
for (const [name, value] of Object.entries(result.vars)) {
|
|
42
|
+
element.style.setProperty(name, value);
|
|
43
|
+
}
|
|
44
|
+
}
|
package/effective-bg.d.ts
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
// Public types for the effective-background resolver.
|
|
2
|
-
|
|
3
|
-
/** `[r, g, b, a]` — r,g,b in 0..255, a in 0..1. */
|
|
4
|
-
export type Rgba = [number, number, number, number];
|
|
5
|
-
|
|
6
|
-
/** A computed-style-like accessor: only `getPropertyValue` is used. */
|
|
7
|
-
export interface StyleLike {
|
|
8
|
-
getPropertyValue(property: string): string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface EffectiveBackgroundOptions {
|
|
12
|
-
/** Base colour when the ancestor chain never reaches an opaque layer. Default `"#FFFFFF"`. */
|
|
13
|
-
fallback?: string;
|
|
14
|
-
/** Injection seam for the computed style of an element. Defaults to `getComputedStyle`. */
|
|
15
|
-
getStyle?: (element: unknown) => StyleLike;
|
|
16
|
-
/** Injection seam for an element's parent. Defaults to `el.parentElement`. */
|
|
17
|
-
parentOf?: (element: unknown) => unknown;
|
|
18
|
-
/** Guard against detached/cyclic chains. Default `64`. */
|
|
19
|
-
maxDepth?: number;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** Parse a CSS colour string into `[r,g,b,a]`, or `null` if unrecognised. */
|
|
23
|
-
export declare function parseCssColor(css: string): Rgba | null;
|
|
24
|
-
|
|
25
|
-
/** Porter-Duff source-over composite of `top` onto `bottom`. */
|
|
26
|
-
export declare function compositeOver(top: Rgba, bottom: Rgba): Rgba;
|
|
27
|
-
|
|
28
|
-
/** `[r,g,b]` (0..255) → `#RRGGBB`. */
|
|
29
|
-
export declare function toHex(rgb: Rgba | [number, number, number]): string;
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Interpolate two `#RRGGBB` colours in Oklab at `t ∈ [0,1]` → `#RRGGBB`.
|
|
33
|
-
* Perceptually uniform (even crossfade timing, non-muddy chroma path); endpoints
|
|
34
|
-
* are exact and out-of-gamut intermediates are clamped per channel.
|
|
35
|
-
*/
|
|
36
|
-
export declare function oklabLerp(fromHex: string, toHex_: string, t: number): string;
|
|
37
|
-
|
|
38
|
-
/** Composite an ordered front-to-back layer stack over an opaque base → `#RRGGBB`. */
|
|
39
|
-
export declare function compositeStackToHex(layersFrontToBack: Rgba[], opaqueBase: Rgba): string;
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* The opaque effective background `#RRGGBB` visible behind `element`'s content,
|
|
43
|
-
* by walking ancestors and alpha-compositing their `background-color`s.
|
|
44
|
-
*/
|
|
45
|
-
export declare function effectiveBackground(
|
|
46
|
-
element: unknown,
|
|
47
|
-
opts?: EffectiveBackgroundOptions,
|
|
48
|
-
): string;
|
|
1
|
+
// Public types for the effective-background resolver.
|
|
2
|
+
|
|
3
|
+
/** `[r, g, b, a]` — r,g,b in 0..255, a in 0..1. */
|
|
4
|
+
export type Rgba = [number, number, number, number];
|
|
5
|
+
|
|
6
|
+
/** A computed-style-like accessor: only `getPropertyValue` is used. */
|
|
7
|
+
export interface StyleLike {
|
|
8
|
+
getPropertyValue(property: string): string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface EffectiveBackgroundOptions {
|
|
12
|
+
/** Base colour when the ancestor chain never reaches an opaque layer. Default `"#FFFFFF"`. */
|
|
13
|
+
fallback?: string;
|
|
14
|
+
/** Injection seam for the computed style of an element. Defaults to `getComputedStyle`. */
|
|
15
|
+
getStyle?: (element: unknown) => StyleLike;
|
|
16
|
+
/** Injection seam for an element's parent. Defaults to `el.parentElement`. */
|
|
17
|
+
parentOf?: (element: unknown) => unknown;
|
|
18
|
+
/** Guard against detached/cyclic chains. Default `64`. */
|
|
19
|
+
maxDepth?: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Parse a CSS colour string into `[r,g,b,a]`, or `null` if unrecognised. */
|
|
23
|
+
export declare function parseCssColor(css: string): Rgba | null;
|
|
24
|
+
|
|
25
|
+
/** Porter-Duff source-over composite of `top` onto `bottom`. */
|
|
26
|
+
export declare function compositeOver(top: Rgba, bottom: Rgba): Rgba;
|
|
27
|
+
|
|
28
|
+
/** `[r,g,b]` (0..255) → `#RRGGBB`. */
|
|
29
|
+
export declare function toHex(rgb: Rgba | [number, number, number]): string;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Interpolate two `#RRGGBB` colours in Oklab at `t ∈ [0,1]` → `#RRGGBB`.
|
|
33
|
+
* Perceptually uniform (even crossfade timing, non-muddy chroma path); endpoints
|
|
34
|
+
* are exact and out-of-gamut intermediates are clamped per channel.
|
|
35
|
+
*/
|
|
36
|
+
export declare function oklabLerp(fromHex: string, toHex_: string, t: number): string;
|
|
37
|
+
|
|
38
|
+
/** Composite an ordered front-to-back layer stack over an opaque base → `#RRGGBB`. */
|
|
39
|
+
export declare function compositeStackToHex(layersFrontToBack: Rgba[], opaqueBase: Rgba): string;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The opaque effective background `#RRGGBB` visible behind `element`'s content,
|
|
43
|
+
* by walking ancestors and alpha-compositing their `background-color`s.
|
|
44
|
+
*/
|
|
45
|
+
export declare function effectiveBackground(
|
|
46
|
+
element: unknown,
|
|
47
|
+
opts?: EffectiveBackgroundOptions,
|
|
48
|
+
): string;
|