@phreshos/react-ui 0.2.0 → 0.2.1
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.
|
@@ -54,6 +54,13 @@ export declare function canvasDarkness(colors: AppearanceColors): number;
|
|
|
54
54
|
* Depth therefore reads the same on a light, mid-tone, or dark canvas.
|
|
55
55
|
*/
|
|
56
56
|
export declare function recessColor(base: string): string;
|
|
57
|
+
/**
|
|
58
|
+
* A paint moved just far enough from the paint it sits on to be told apart: at least `minimum`
|
|
59
|
+
* perceived difference (OKLab), stepping lighter, or darker only when lighter has no room. Raised
|
|
60
|
+
* and level things stand out the same way everywhere, whatever happens to be beneath them. A paint
|
|
61
|
+
* already far enough stays as it is.
|
|
62
|
+
*/
|
|
63
|
+
export declare function separateColor(paint: string, surroundings: string, minimum: number): string;
|
|
57
64
|
/** The lighter Appearance content candidate: the paint of anything lit from above, such as a thumb. */
|
|
58
65
|
export declare function lightColor(colors: AppearanceColors): string;
|
|
59
66
|
export declare function isColorLevel(value: string): value is ColorLevel;
|
package/dist/foundation/color.js
CHANGED
|
@@ -252,6 +252,31 @@ export function recessColor(base) {
|
|
|
252
252
|
}
|
|
253
253
|
/** The constant difference between a recess and the paint it sinks into. */
|
|
254
254
|
const recessContrast = 1.15;
|
|
255
|
+
const separateCache = new Map();
|
|
256
|
+
/**
|
|
257
|
+
* A paint moved just far enough from the paint it sits on to be told apart: at least `minimum`
|
|
258
|
+
* perceived difference (OKLab), stepping lighter, or darker only when lighter has no room. Raised
|
|
259
|
+
* and level things stand out the same way everywhere, whatever happens to be beneath them. A paint
|
|
260
|
+
* already far enough stays as it is.
|
|
261
|
+
*/
|
|
262
|
+
export function separateColor(paint, surroundings, minimum) {
|
|
263
|
+
const key = `${paint}|${surroundings}|${minimum}`;
|
|
264
|
+
const cached = separateCache.get(key);
|
|
265
|
+
if (cached !== undefined)
|
|
266
|
+
return cached;
|
|
267
|
+
const distance = perceivedDistance(paint, surroundings);
|
|
268
|
+
if (distance === null || distance >= minimum)
|
|
269
|
+
return remember(separateCache, key, paint);
|
|
270
|
+
const directions = ["#ffffff", "#000000"];
|
|
271
|
+
for (const toward of directions) {
|
|
272
|
+
for (let amount = 0.01; amount <= 0.6; amount += 0.01) {
|
|
273
|
+
const result = mixColor(paint, toward, Math.round(amount * 1_000) / 1_000);
|
|
274
|
+
if ((perceivedDistance(result, surroundings) ?? 0) >= minimum)
|
|
275
|
+
return remember(separateCache, key, result);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return remember(separateCache, key, paint);
|
|
279
|
+
}
|
|
255
280
|
/** The lighter Appearance content candidate: the paint of anything lit from above, such as a thumb. */
|
|
256
281
|
export function lightColor(colors) {
|
|
257
282
|
return darkCanvas(colors) ? colors.foreground : colors.default;
|
|
@@ -47,6 +47,11 @@ export interface SurfaceInteraction {
|
|
|
47
47
|
/** Marks a value-holding Surface whose current value is rejected. */
|
|
48
48
|
readonly invalid?: boolean;
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* How far a nested Surface keeps from the one it sits on: farther on a dark canvas, where
|
|
52
|
+
* differences read smaller.
|
|
53
|
+
*/
|
|
54
|
+
export declare function nestingDistance(darkness: number): number;
|
|
50
55
|
/**
|
|
51
56
|
* The single visual primitive. Components express what they are through
|
|
52
57
|
* color, depth, and interaction; paint, grain, frost, edge, shadow, focus,
|
|
@@ -81,8 +86,10 @@ export declare function surfaceColor(color: Color, depth: SurfaceDepth, colors:
|
|
|
81
86
|
/** The color a Surface of this color and depth is painted with at rest, in the active Appearance. */
|
|
82
87
|
export declare function useSurfaceColor(color?: Color, depth?: SurfaceDepth): string;
|
|
83
88
|
/** Resolves every visual value of one Surface. Pure over its inputs. */
|
|
84
|
-
export declare function surfacePaint(visual: Visual, color: Color, depth: SurfaceDepth, options: MaterialMode | MaterialOptions | undefined, shadowOptions: ShadowOverrides["shadow"], interaction: SurfaceInteraction | undefined): {
|
|
89
|
+
export declare function surfacePaint(visual: Visual, color: Color, depth: SurfaceDepth, options: MaterialMode | MaterialOptions | undefined, shadowOptions: ShadowOverrides["shadow"], interaction: SurfaceInteraction | undefined, surroundings?: string | null): {
|
|
85
90
|
fill: string;
|
|
91
|
+
/** The paint at rest, or `null` for a clear Surface. */
|
|
92
|
+
rest: string | null;
|
|
86
93
|
text: string;
|
|
87
94
|
ring: string;
|
|
88
95
|
shadow: string;
|
package/dist/surface/surface.js
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { createElement, forwardRef, useId, useInsertionEffect } from "react";
|
|
3
|
-
import { canvasDarkness, colorOpacity, contrast, mixColor, readableColor, recessColor, resolveColor } from "../foundation/color.js";
|
|
2
|
+
import { createContext, createElement, forwardRef, useContext, useId, useInsertionEffect } from "react";
|
|
3
|
+
import { canvasDarkness, colorOpacity, contrast, mixColor, readableColor, recessColor, resolveColor, separateColor } from "../foundation/color.js";
|
|
4
4
|
import { resolveRadius } from "../foundation/radius.js";
|
|
5
5
|
import { useVisual } from "../foundation/visual.js";
|
|
6
6
|
import { grainSeed, grainSize, grainTexture } from "./grain.js";
|
|
7
7
|
import { flushPaintRules, paintClass, usePaintClasses } from "./paint-class.js";
|
|
8
8
|
import { resolveMaterialOptions } from "./material-options.js";
|
|
9
9
|
import { resolveShadowOptions, shadowStyle } from "./shadow-options.js";
|
|
10
|
+
/** The resting paint of the nearest painted Surface around, which a nested Surface keeps apart from. */
|
|
11
|
+
const SurroundingPaint = createContext(null);
|
|
12
|
+
/**
|
|
13
|
+
* How far a nested Surface keeps from the one it sits on: farther on a dark canvas, where
|
|
14
|
+
* differences read smaller.
|
|
15
|
+
*/
|
|
16
|
+
export function nestingDistance(darkness) {
|
|
17
|
+
return 0.04 + 0.03 * darkness;
|
|
18
|
+
}
|
|
10
19
|
/**
|
|
11
20
|
* The single visual primitive. Components express what they are through
|
|
12
21
|
* color, depth, and interaction; paint, grain, frost, edge, shadow, focus,
|
|
@@ -15,7 +24,8 @@ import { resolveShadowOptions, shadowStyle } from "./shadow-options.js";
|
|
|
15
24
|
export const SurfaceView = forwardRef(function Surface({ as: Element = "div", color = "background", depth = "raised", material, shadow, radius, interaction, className, children, style, ...properties }, ref) {
|
|
16
25
|
const visual = useVisual();
|
|
17
26
|
const identity = useId();
|
|
18
|
-
const
|
|
27
|
+
const surroundings = useContext(SurroundingPaint);
|
|
28
|
+
const paint = surfacePaint(visual, color, depth, material, shadow, interaction, surroundings);
|
|
19
29
|
const borderRadius = radius === undefined && style?.borderRadius !== undefined
|
|
20
30
|
? style.borderRadius
|
|
21
31
|
: resolveRadius(radius ?? "medium", visual.radius);
|
|
@@ -38,7 +48,9 @@ export const SurfaceView = forwardRef(function Surface({ as: Element = "div", co
|
|
|
38
48
|
className: [surfaceClass, paint.grain?.name, painted, dimmedClass(interaction?.disabled ?? false), className].filter(Boolean).join(" "),
|
|
39
49
|
// Without a document (server rendering), the same declarations travel inline.
|
|
40
50
|
style: painted === undefined ? { ...inlineDeclarations(declarations), ...style } : style
|
|
41
|
-
}, _jsx(SurfaceStyle, {}), paint.grain && _jsx(GrainStyle, { grain: paint.grain }), paint.distortion > 0 && _jsx(Refraction, { identity: identity, distortion: paint.distortion }),
|
|
51
|
+
}, _jsx(SurfaceStyle, {}), paint.grain && _jsx(GrainStyle, { grain: paint.grain }), paint.distortion > 0 && _jsx(Refraction, { identity: identity, distortion: paint.distortion }),
|
|
52
|
+
// A clear Surface paints nothing, so what is inside it sits on what is around it.
|
|
53
|
+
paint.rest === null ? children : _jsx(SurroundingPaint.Provider, { value: paint.rest, children: children }));
|
|
42
54
|
});
|
|
43
55
|
function inlineDeclarations(declarations) {
|
|
44
56
|
const result = {};
|
|
@@ -85,7 +97,7 @@ export function useSurfaceColor(color = "background", depth = "raised") {
|
|
|
85
97
|
return surfaceColor(color, depth, colors);
|
|
86
98
|
}
|
|
87
99
|
/** Resolves every visual value of one Surface. Pure over its inputs. */
|
|
88
|
-
export function surfacePaint(visual, color, depth, options, shadowOptions, interaction) {
|
|
100
|
+
export function surfacePaint(visual, color, depth, options, shadowOptions, interaction, surroundings = null) {
|
|
89
101
|
const { colors } = visual;
|
|
90
102
|
const base = resolveColor(color, colors);
|
|
91
103
|
const active = interaction !== undefined && !interaction.disabled;
|
|
@@ -95,12 +107,15 @@ export function surfacePaint(visual, color, depth, options, shadowOptions, inter
|
|
|
95
107
|
const darkness = canvasDarkness(colors);
|
|
96
108
|
// A recess moves away from its surroundings toward whichever extreme has
|
|
97
109
|
// room, by one constant perceptual difference on any canvas.
|
|
98
|
-
const
|
|
110
|
+
const own = depth === "recessed" ? surfaceColor(color, depth, colors) : base;
|
|
99
111
|
// A clear Surface, with no depth or a transparent color, has no substance of
|
|
100
112
|
// its own: it paints nothing at rest, takes the content color of whatever it
|
|
101
113
|
// sits on, and only reveals interaction as a veil. With no depth, a color
|
|
102
114
|
// other than the neutral one colors its content instead of a fill.
|
|
103
115
|
const clear = depth === "none" || base === "transparent";
|
|
116
|
+
// A raised or level Surface nested in another keeps apart from it, however deep the nesting goes.
|
|
117
|
+
// A recess keeps its own constant depth below its color, so a well reads the same wherever it is.
|
|
118
|
+
const rest = clear || depth === "recessed" || surroundings === null ? own : separateColor(own, surroundings, nestingDistance(darkness));
|
|
104
119
|
const tinted = depth === "none" && base !== "transparent" && base !== colors.default;
|
|
105
120
|
const fill = clear
|
|
106
121
|
? shift > 0 ? colorOpacity(colors.foreground, shift * clearVeil) : "transparent"
|
|
@@ -149,6 +164,8 @@ export function surfacePaint(visual, color, depth, options, shadowOptions, inter
|
|
|
149
164
|
: shadowStyle(resolveShadowOptions(typeof shadowOptions === "object" ? shadowOptions : {}, shadow));
|
|
150
165
|
return {
|
|
151
166
|
fill,
|
|
167
|
+
/** The paint at rest, or `null` for a clear Surface. */
|
|
168
|
+
rest: clear ? null : rest,
|
|
152
169
|
// The label is chosen once for the resting paint: interaction shades stay
|
|
153
170
|
// close to it, and re-deciding per state would flip text on near-ties.
|
|
154
171
|
text: tinted ? base : clear ? "inherit" : readableColor(rest, colors),
|