@phreshos/react-ui 0.1.10 → 0.1.12
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 +23 -5
- package/dist/appearance-provider.js +3 -2
- package/dist/document-scrollbars.d.ts +6 -0
- package/dist/document-scrollbars.js +164 -0
- package/dist/main.d.ts +1 -1
- package/dist/surface-material.js +13 -3
- package/dist/surface.d.ts +2 -9
- package/dist/surface.js +4 -24
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -27,14 +27,30 @@ collapses Appearance into a second retained object.
|
|
|
27
27
|
An application using the Client SDK composes the packages explicitly:
|
|
28
28
|
|
|
29
29
|
```tsx
|
|
30
|
+
import { useDesktopPreferences, useSystemAppearance } from "@phreshos/react"
|
|
31
|
+
|
|
30
32
|
const appearance = useSystemAppearance()
|
|
31
|
-
const theme =
|
|
33
|
+
const { theme } = useDesktopPreferences()
|
|
32
34
|
|
|
33
35
|
return <AppearanceProvider appearance={appearance} theme={theme}>
|
|
34
36
|
{children}
|
|
35
37
|
</AppearanceProvider>
|
|
36
38
|
```
|
|
37
39
|
|
|
40
|
+
Document color-scheme negotiation belongs to the System iframe and the Client
|
|
41
|
+
HTML document, not to a visual component or React hook.
|
|
42
|
+
|
|
43
|
+
`AppearanceProvider` also owns the native scrollbars in its document. It adds
|
|
44
|
+
no rendered container: one document stylesheet styles a six-pixel rounded
|
|
45
|
+
thumb from Appearance foreground and radius, leaves the track transparent, and
|
|
46
|
+
gives its container five pixels of transparent padding. With a precise
|
|
47
|
+
pointer, the thumb is transparent outside its scrollable area, uses foreground
|
|
48
|
+
at 10% inside it, and rises to 20% directly under the pointer. Touch documents
|
|
49
|
+
retain the 10% thumb. The standardized scrollbar API has no thumb-hover state,
|
|
50
|
+
so its fallback stops at 10%. Standard and WebKit rules are mutually exclusive
|
|
51
|
+
so the standard thin width cannot override the padded geometry. WebKit hover
|
|
52
|
+
also invalidates the scrollbar style to ensure Safari repaints each state.
|
|
53
|
+
|
|
38
54
|
## Levels
|
|
39
55
|
|
|
40
56
|
`useScale(value)` and `useColor(value)` derive semantic UI levels from one
|
|
@@ -49,14 +65,16 @@ radii require Appearance because their concrete source is `spacing` or
|
|
|
49
65
|
## Surface
|
|
50
66
|
|
|
51
67
|
`Surface` is the shared visual material. It accepts native `div` properties
|
|
52
|
-
plus local overrides for
|
|
68
|
+
plus local overrides for grain, grain amount, backdrop blur, opacity,
|
|
53
69
|
distortion, waves, ripples, saturation, and brightness. Omitted controls derive
|
|
54
70
|
from the resolved Appearance. A zero-valued optional effect is omitted from the
|
|
55
71
|
rendered material so disabled work costs nothing.
|
|
56
72
|
|
|
57
|
-
Each Surface
|
|
58
|
-
|
|
59
|
-
|
|
73
|
+
Each Surface returns one plain geometry and content container. Its existing SVG
|
|
74
|
+
material paints both the fill and its material-derived border; no separate
|
|
75
|
+
border element is rendered. Backdrop refraction and frost remain separate
|
|
76
|
+
compositor layers. Radius and foreground resolve from Appearance; elevation
|
|
77
|
+
stays with the surrounding layout.
|
|
60
78
|
|
|
61
79
|
## Components
|
|
62
80
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { createContext, useContext } from "react";
|
|
3
|
+
import DocumentScrollbars from "./document-scrollbars.js";
|
|
3
4
|
const missing = Symbol("AppearanceProvider");
|
|
4
5
|
const AppearanceContext = createContext(missing);
|
|
5
6
|
const ThemeContext = createContext(missing);
|
|
6
7
|
/** Provides unresolved Appearance and one effective Theme to a React subtree. */
|
|
7
8
|
export function AppearanceProvider({ appearance, children, theme }) {
|
|
8
|
-
return _jsx(AppearanceContext.Provider, { value: appearance, children:
|
|
9
|
+
return _jsx(AppearanceContext.Provider, { value: appearance, children: _jsxs(ThemeContext.Provider, { value: theme, children: [_jsx(DocumentScrollbars, { appearance: appearance, theme: theme }), children] }) });
|
|
9
10
|
}
|
|
10
11
|
/** Returns the complete unresolved Appearance supplied by the nearest provider. */
|
|
11
12
|
export function useAppearance() {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Appearance, Theme } from "@phreshos/core";
|
|
2
|
+
/** Applies one Appearance to the complete owning document without rendering. */
|
|
3
|
+
export default function DocumentScrollbars({ appearance, theme }: Readonly<{
|
|
4
|
+
appearance: Appearance;
|
|
5
|
+
theme: Theme;
|
|
6
|
+
}>): null;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { useInsertionEffect, useRef } from "react";
|
|
2
|
+
import { colorOpacity } from "./color.js";
|
|
3
|
+
const properties = {
|
|
4
|
+
thumb: "--phreshos-scrollbar-thumb",
|
|
5
|
+
thumbHover: "--phreshos-scrollbar-thumb-hover",
|
|
6
|
+
size: "--phreshos-scrollbar-size",
|
|
7
|
+
padding: "--phreshos-scrollbar-padding",
|
|
8
|
+
radius: "--phreshos-scrollbar-radius"
|
|
9
|
+
};
|
|
10
|
+
const stylesheet = `
|
|
11
|
+
@supports not selector(::-webkit-scrollbar) {
|
|
12
|
+
* {
|
|
13
|
+
scrollbar-color: var(${properties.thumb}) transparent;
|
|
14
|
+
scrollbar-width: thin;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@media (hover: hover) and (pointer: fine) {
|
|
18
|
+
* {
|
|
19
|
+
scrollbar-color: transparent transparent;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
*:hover {
|
|
23
|
+
scrollbar-color: var(${properties.thumb}) transparent;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@media (forced-colors: active) {
|
|
28
|
+
*,
|
|
29
|
+
*:hover {
|
|
30
|
+
scrollbar-color: auto;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@supports selector(::-webkit-scrollbar) {
|
|
36
|
+
*::-webkit-scrollbar {
|
|
37
|
+
width: var(${properties.size});
|
|
38
|
+
height: var(${properties.size});
|
|
39
|
+
background: transparent;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
*::-webkit-scrollbar-track,
|
|
43
|
+
*::-webkit-scrollbar-corner {
|
|
44
|
+
background: transparent;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
*::-webkit-scrollbar-button {
|
|
48
|
+
display: none;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
*::-webkit-scrollbar-thumb {
|
|
52
|
+
border: var(${properties.padding}) solid transparent;
|
|
53
|
+
border-radius: var(${properties.radius});
|
|
54
|
+
background-color: var(${properties.thumb});
|
|
55
|
+
background-clip: padding-box;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@media (hover: hover) and (pointer: fine) {
|
|
59
|
+
*:hover {
|
|
60
|
+
--phreshos-scrollbar-repaint: ;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
*::-webkit-scrollbar-thumb {
|
|
64
|
+
background-color: transparent;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
*:hover::-webkit-scrollbar-thumb {
|
|
68
|
+
background-color: var(${properties.thumb});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
*::-webkit-scrollbar-thumb:hover {
|
|
72
|
+
background-color: var(${properties.thumbHover});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@media (forced-colors: active) {
|
|
77
|
+
*::-webkit-scrollbar-thumb,
|
|
78
|
+
*:hover::-webkit-scrollbar-thumb,
|
|
79
|
+
*::-webkit-scrollbar-thumb:hover {
|
|
80
|
+
background-color: ButtonText;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
`;
|
|
85
|
+
const documents = new WeakMap();
|
|
86
|
+
/** Applies one Appearance to the complete owning document without rendering. */
|
|
87
|
+
export default function DocumentScrollbars({ appearance, theme }) {
|
|
88
|
+
const identity = useRef(Symbol("AppearanceProvider")).current;
|
|
89
|
+
const foreground = theme === "dark" ? appearance.foreground.dark : appearance.foreground.light;
|
|
90
|
+
const padding = 5;
|
|
91
|
+
const thumbSize = 6;
|
|
92
|
+
const size = thumbSize + padding * 2;
|
|
93
|
+
const values = {
|
|
94
|
+
thumb: colorOpacity(foreground, 0.1),
|
|
95
|
+
thumbHover: colorOpacity(foreground, 0.2),
|
|
96
|
+
size: `${size}px`,
|
|
97
|
+
padding: `${padding}px`,
|
|
98
|
+
radius: `${Math.min(appearance.radius.light, padding + thumbSize / 2)}px`
|
|
99
|
+
};
|
|
100
|
+
useInsertionEffect(function () {
|
|
101
|
+
if (typeof document === "undefined")
|
|
102
|
+
return;
|
|
103
|
+
return register(document, identity, values);
|
|
104
|
+
}, []);
|
|
105
|
+
useInsertionEffect(function () {
|
|
106
|
+
if (typeof document !== "undefined")
|
|
107
|
+
update(document, identity, values);
|
|
108
|
+
}, [values.thumb, values.thumbHover, values.size, values.padding, values.radius]);
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
function register(owner, identity, values) {
|
|
112
|
+
const state = documents.get(owner) ?? create(owner);
|
|
113
|
+
state.providers.set(identity, values);
|
|
114
|
+
apply(state);
|
|
115
|
+
return function () {
|
|
116
|
+
state.providers.delete(identity);
|
|
117
|
+
if (state.providers.size) {
|
|
118
|
+
apply(state);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
state.style.remove();
|
|
122
|
+
restore(state);
|
|
123
|
+
documents.delete(owner);
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function update(owner, identity, values) {
|
|
127
|
+
const state = documents.get(owner);
|
|
128
|
+
if (!state?.providers.has(identity))
|
|
129
|
+
return;
|
|
130
|
+
state.providers.set(identity, values);
|
|
131
|
+
apply(state);
|
|
132
|
+
}
|
|
133
|
+
function create(owner) {
|
|
134
|
+
const root = owner.documentElement;
|
|
135
|
+
const style = owner.createElement("style");
|
|
136
|
+
const original = new Map(Object.values(properties).map(property => [property, {
|
|
137
|
+
value: root.style.getPropertyValue(property),
|
|
138
|
+
priority: root.style.getPropertyPriority(property)
|
|
139
|
+
}]));
|
|
140
|
+
style.dataset.phreshosScrollbars = "";
|
|
141
|
+
style.textContent = stylesheet;
|
|
142
|
+
owner.head.append(style);
|
|
143
|
+
const state = { root, style, original, providers: new Map() };
|
|
144
|
+
documents.set(owner, state);
|
|
145
|
+
return state;
|
|
146
|
+
}
|
|
147
|
+
function apply(state) {
|
|
148
|
+
const values = [...state.providers.values()].at(-1);
|
|
149
|
+
if (!values)
|
|
150
|
+
return;
|
|
151
|
+
state.root.style.setProperty(properties.thumb, values.thumb);
|
|
152
|
+
state.root.style.setProperty(properties.thumbHover, values.thumbHover);
|
|
153
|
+
state.root.style.setProperty(properties.size, values.size);
|
|
154
|
+
state.root.style.setProperty(properties.padding, values.padding);
|
|
155
|
+
state.root.style.setProperty(properties.radius, values.radius);
|
|
156
|
+
}
|
|
157
|
+
function restore(state) {
|
|
158
|
+
for (const [property, original] of state.original) {
|
|
159
|
+
if (original.value)
|
|
160
|
+
state.root.style.setProperty(property, original.value, original.priority);
|
|
161
|
+
else
|
|
162
|
+
state.root.style.removeProperty(property);
|
|
163
|
+
}
|
|
164
|
+
}
|
package/dist/main.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
export { AppearanceProvider, useAppearance, useResolveTheme, useTheme, type AppearanceProviderProps } from "./appearance-provider.js";
|
|
8
8
|
export { Flex, type FlexProps } from "./flex.js";
|
|
9
9
|
export { Grid, type GridProps } from "./grid.js";
|
|
10
|
-
export { Surface, type
|
|
10
|
+
export { Surface, type SurfaceProps } from "./surface.js";
|
|
11
11
|
export { Button, type ButtonProps } from "./button.js";
|
|
12
12
|
export type { LayoutAlignment, LayoutGap, LayoutJustification } from "./layout.js";
|
|
13
13
|
export { resolveRadius, type Radius, type RadiusProps } from "./radius.js";
|
package/dist/surface-material.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Fragment, useMemo } from "react";
|
|
3
|
+
import { scale } from "./scale.js";
|
|
3
4
|
/** The locally owned SVG paint layer inside one Surface. */
|
|
4
5
|
export function SurfaceMaterial({ color, distortion, grain, grainAmount, identity, opacity, ripples, waves }) {
|
|
5
6
|
const seed = useMemo(() => seedFrom(identity), [identity]);
|
|
@@ -9,7 +10,7 @@ export function SurfaceMaterial({ color, distortion, grain, grainAmount, identit
|
|
|
9
10
|
const initial = useMemo(() => hasGrain ? grainPaths(seed, grainAmount) : [], [grainAmount, hasGrain, seed]);
|
|
10
11
|
if (!hasPaint && !hasDistortion)
|
|
11
12
|
return null;
|
|
12
|
-
return _jsxs("svg", { "data-surface-material": "", "aria-hidden": "true", focusable: "false", style: {
|
|
13
|
+
return _jsxs("svg", { "data-surface-material": "", "data-surface-border": hasPaint ? "" : undefined, "aria-hidden": "true", focusable: "false", style: {
|
|
13
14
|
position: "absolute",
|
|
14
15
|
zIndex: -1,
|
|
15
16
|
inset: 0,
|
|
@@ -18,10 +19,19 @@ export function SurfaceMaterial({ color, distortion, grain, grainAmount, identit
|
|
|
18
19
|
height: "100%",
|
|
19
20
|
overflow: "hidden",
|
|
20
21
|
borderRadius: "inherit",
|
|
22
|
+
borderColor: edgeColor(color, opacity),
|
|
23
|
+
borderStyle: hasPaint ? "solid" : "none",
|
|
24
|
+
borderWidth: hasPaint ? 1 : 0,
|
|
21
25
|
boxSizing: "border-box",
|
|
22
|
-
opacity,
|
|
23
26
|
pointerEvents: "none"
|
|
24
|
-
}, children: [(hasGrain || hasDistortion) && _jsxs("defs", { children: [hasDistortion && _jsx(DistortionFilter, { distortion: distortion, identity: identity, ripples: ripples, seed: seed, waves: waves }), hasGrain && _jsx("pattern", { id: `${identity}-grain`, width: patternSize, height: patternSize, patternUnits: "userSpaceOnUse", children: initial.map((path, tone) => _jsx("path", { "data-surface-grain-tone": tone, d: path, fill: grainTone(color, tone, grain), shapeRendering: "crispEdges" }, tone)) })] }), hasPaint && _jsx("rect", { "data-surface-base": "", width: "100%", height: "100%", fill: color }), hasGrain && _jsx("rect", { "data-surface-grain": "", width: "100%", height: "100%", fill: `url(#${identity}-grain)`, shapeRendering: "crispEdges" })] });
|
|
27
|
+
}, children: [(hasGrain || hasDistortion) && _jsxs("defs", { children: [hasDistortion && _jsx(DistortionFilter, { distortion: distortion, identity: identity, ripples: ripples, seed: seed, waves: waves }), hasGrain && _jsx("pattern", { id: `${identity}-grain`, width: patternSize, height: patternSize, patternUnits: "userSpaceOnUse", children: initial.map((path, tone) => _jsx("path", { "data-surface-grain-tone": tone, d: path, fill: grainTone(color, tone, grain), shapeRendering: "crispEdges" }, tone)) })] }), hasPaint && _jsxs("g", { "data-surface-paint": "", opacity: opacity, children: [_jsx("rect", { "data-surface-base": "", width: "100%", height: "100%", fill: color }), hasGrain && _jsx("rect", { "data-surface-grain": "", width: "100%", height: "100%", fill: `url(#${identity}-grain)`, shapeRendering: "crispEdges" })] })] });
|
|
28
|
+
}
|
|
29
|
+
function edgeColor(color, opacity) {
|
|
30
|
+
const edge = `color-mix(in oklch, ${color} 94%, black)`;
|
|
31
|
+
const edgeOpacity = Math.min(1, scale(opacity, "large"));
|
|
32
|
+
if (edgeOpacity === 1)
|
|
33
|
+
return edge;
|
|
34
|
+
return `color-mix(in srgb, ${edge} ${Math.round(edgeOpacity * 10_000) / 100}%, transparent)`;
|
|
25
35
|
}
|
|
26
36
|
function DistortionFilter({ distortion, identity, ripples, seed, waves }) {
|
|
27
37
|
const fields = [
|
package/dist/surface.d.ts
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import type { ComponentPropsWithoutRef } from "react";
|
|
2
|
-
import { type ColorLevel } from "./color.js";
|
|
3
2
|
import { type ScaleLevel } from "./scale.js";
|
|
4
|
-
/** An Appearance-derived treatment or direct CSS color. */
|
|
5
|
-
export type SurfaceColor = ColorLevel | (string & {});
|
|
6
3
|
/** Native div properties plus controls for the locally owned material. */
|
|
7
|
-
export type SurfaceProps = Omit<ComponentPropsWithoutRef<"div">, "
|
|
8
|
-
/** Appearance-derived treatment or direct CSS material color. */
|
|
9
|
-
color?: SurfaceColor;
|
|
4
|
+
export type SurfaceProps = Omit<ComponentPropsWithoutRef<"div">, "opacity"> & Readonly<{
|
|
10
5
|
/** Appearance-derived level or direct grain intensity from zero to one. */
|
|
11
6
|
grain?: ScaleLevel | number;
|
|
12
7
|
/** Appearance-derived level or direct retained grain amount from zero to one. */
|
|
@@ -27,9 +22,7 @@ export type SurfaceProps = Omit<ComponentPropsWithoutRef<"div">, "color" | "opac
|
|
|
27
22
|
brightness?: ScaleLevel | number;
|
|
28
23
|
}>;
|
|
29
24
|
/** Contains content above locally owned Surface material layers. */
|
|
30
|
-
export declare const Surface: import("react").ForwardRefExoticComponent<Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "opacity"
|
|
31
|
-
/** Appearance-derived treatment or direct CSS material color. */
|
|
32
|
-
color?: SurfaceColor;
|
|
25
|
+
export declare const Surface: import("react").ForwardRefExoticComponent<Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "opacity"> & Readonly<{
|
|
33
26
|
/** Appearance-derived level or direct grain intensity from zero to one. */
|
|
34
27
|
grain?: ScaleLevel | number;
|
|
35
28
|
/** Appearance-derived level or direct retained grain amount from zero to one. */
|
package/dist/surface.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef, useCallback, useId, useLayoutEffect, useRef } from "react";
|
|
3
3
|
import { appearanceLimits } from "@phreshos/core";
|
|
4
|
-
import { color as deriveColor } from "./color.js";
|
|
5
4
|
import { isScaleLevel, scale, scaleMultiplier } from "./scale.js";
|
|
6
5
|
import { SurfaceMaterial } from "./surface-material.js";
|
|
7
6
|
import { useAppearance, useResolveTheme } from "./appearance-provider.js";
|
|
@@ -12,7 +11,7 @@ const layerStyle = {
|
|
|
12
11
|
pointerEvents: "none"
|
|
13
12
|
};
|
|
14
13
|
/** Contains content above locally owned Surface material layers. */
|
|
15
|
-
export const Surface = forwardRef(function Surface({ backdrop, brightness, children,
|
|
14
|
+
export const Surface = forwardRef(function Surface({ backdrop, brightness, children, distortion, grain, grainAmount, opacity, ripples, saturation, style, waves, ...properties }, forwardedRef) {
|
|
16
15
|
const appearance = useAppearance();
|
|
17
16
|
const background = useResolveTheme(appearance.background);
|
|
18
17
|
const foreground = useResolveTheme(appearance.foreground);
|
|
@@ -27,7 +26,7 @@ export const Surface = forwardRef(function Surface({ backdrop, brightness, child
|
|
|
27
26
|
else if (forwardedRef)
|
|
28
27
|
forwardedRef.current = node;
|
|
29
28
|
}, [forwardedRef]);
|
|
30
|
-
const resolved = resolveSurface({ backdrop, brightness,
|
|
29
|
+
const resolved = resolveSurface({ backdrop, brightness, distortion, grain, grainAmount, opacity, ripples, saturation, waves }, background, surface);
|
|
31
30
|
useLayoutEffect(() => {
|
|
32
31
|
const surface = element.current;
|
|
33
32
|
if (surface)
|
|
@@ -37,19 +36,8 @@ export const Surface = forwardRef(function Surface({ backdrop, brightness, child
|
|
|
37
36
|
borderRadius: radius,
|
|
38
37
|
color: foreground,
|
|
39
38
|
...style
|
|
40
|
-
}, children: [resolved.refracts && _jsx(BackdropLayer, { name: "refraction", filter: `url("#${identity}-distortion")`, zIndex: -3 }), resolved.frost && _jsx(BackdropLayer, { name: "frost", filter: resolved.frost, zIndex: -2 }), _jsx(
|
|
39
|
+
}, children: [resolved.refracts && _jsx(BackdropLayer, { name: "refraction", filter: `url("#${identity}-distortion")`, zIndex: -3 }), resolved.frost && _jsx(BackdropLayer, { name: "frost", filter: resolved.frost, zIndex: -2 }), _jsx(SurfaceMaterial, { identity: identity, ...resolved.material }), children] });
|
|
41
40
|
});
|
|
42
|
-
/** Draws one uniform inset edge from the same color as the Surface material. */
|
|
43
|
-
function SurfaceBorder({ color, opacity }) {
|
|
44
|
-
const edge = `color-mix(in oklch, ${color} 94%, black)`;
|
|
45
|
-
return _jsx("div", { "data-surface-border": "", "aria-hidden": "true", style: {
|
|
46
|
-
...layerStyle,
|
|
47
|
-
zIndex: 0,
|
|
48
|
-
boxSizing: "border-box",
|
|
49
|
-
boxShadow: `inset 0 0 0 1px ${edge}`,
|
|
50
|
-
opacity
|
|
51
|
-
} });
|
|
52
|
-
}
|
|
53
41
|
/** Keeps refraction and native frost in independent compositor passes. */
|
|
54
42
|
function BackdropLayer({ filter, name, zIndex }) {
|
|
55
43
|
return _jsx("div", { "data-surface-backdrop": name, "aria-hidden": "true", style: {
|
|
@@ -61,7 +49,7 @@ function BackdropLayer({ filter, name, zIndex }) {
|
|
|
61
49
|
}
|
|
62
50
|
function resolveSurface(values, background, surface) {
|
|
63
51
|
const material = {
|
|
64
|
-
color:
|
|
52
|
+
color: background,
|
|
65
53
|
distortion: resolveScale(values.distortion, surface.distortion, appearanceLimits.surface.distortion),
|
|
66
54
|
grain: resolveScale(values.grain, surface.grain, appearanceLimits.surface.grain),
|
|
67
55
|
grainAmount: resolveScale(values.grainAmount, surface.grainAmount, appearanceLimits.surface.grainAmount),
|
|
@@ -83,14 +71,6 @@ function resolveSurface(values, background, surface) {
|
|
|
83
71
|
refracts: material.distortion > 0 || material.waves > 0 || material.ripples > 0
|
|
84
72
|
};
|
|
85
73
|
}
|
|
86
|
-
function resolveColor(value, base) {
|
|
87
|
-
if (value === undefined)
|
|
88
|
-
return base;
|
|
89
|
-
return isColorLevel(value) ? deriveColor(base)[value] : value;
|
|
90
|
-
}
|
|
91
|
-
function isColorLevel(value) {
|
|
92
|
-
return value === "subtle" || value === "soft" || value === "base" || value === "strong" || value === "intense";
|
|
93
|
-
}
|
|
94
74
|
function resolveScale(value, base, range) {
|
|
95
75
|
const resolved = isScaleLevel(value) ? scale(base, value) : value ?? base;
|
|
96
76
|
const finite = Number.isFinite(resolved) ? resolved : base;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phreshos/react-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "React components for coherent PhreshOS Program interfaces.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"prepack": "node --run test && node --run build"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
|
-
"@phreshos/core": "^0.1.
|
|
55
|
+
"@phreshos/core": "^0.1.22",
|
|
56
56
|
"react": "^19.2.0",
|
|
57
57
|
"react-dom": "^19.2.0"
|
|
58
58
|
},
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@base-ui/react": "^1.7.0",
|
|
64
|
-
"@phreshos/core": "^0.1.
|
|
64
|
+
"@phreshos/core": "^0.1.22",
|
|
65
65
|
"@testing-library/dom": "^10.4.1",
|
|
66
66
|
"@testing-library/react": "^16.3.0",
|
|
67
67
|
"@testing-library/user-event": "^14.6.1",
|