@phreshos/react-ui 0.1.16 → 0.1.17

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.
Files changed (52) hide show
  1. package/README.md +164 -8
  2. package/dist/appearance-provider.d.ts +6 -8
  3. package/dist/appearance-provider.js +34 -19
  4. package/dist/button.d.ts +11 -5
  5. package/dist/button.js +28 -36
  6. package/dist/checkbox.d.ts +11 -0
  7. package/dist/checkbox.js +10 -0
  8. package/dist/color.d.ts +33 -0
  9. package/dist/color.js +84 -5
  10. package/dist/control-material.d.ts +20 -0
  11. package/dist/control-material.js +14 -0
  12. package/dist/control.d.ts +55 -0
  13. package/dist/control.js +87 -0
  14. package/dist/document-scrollbars.js +1 -1
  15. package/dist/field-style.d.ts +3 -0
  16. package/dist/field-style.js +11 -0
  17. package/dist/flex.js +2 -2
  18. package/dist/grid.js +2 -2
  19. package/dist/input.d.ts +4 -0
  20. package/dist/input.js +11 -0
  21. package/dist/main.d.ts +13 -2
  22. package/dist/main.js +10 -0
  23. package/dist/material-options.d.ts +20 -0
  24. package/dist/material-options.js +22 -0
  25. package/dist/material-paint.d.ts +11 -0
  26. package/dist/material-paint.js +76 -0
  27. package/dist/material.d.ts +27 -0
  28. package/dist/material.js +45 -0
  29. package/dist/motion-style.d.ts +21 -0
  30. package/dist/motion-style.js +45 -0
  31. package/dist/panel.d.ts +1 -1
  32. package/dist/radio.d.ts +14 -0
  33. package/dist/radio.js +17 -0
  34. package/dist/select.d.ts +17 -0
  35. package/dist/select.js +28 -0
  36. package/dist/slider.d.ts +7 -0
  37. package/dist/slider.js +36 -0
  38. package/dist/surface-edge.d.ts +7 -0
  39. package/dist/surface-edge.js +59 -0
  40. package/dist/surface.d.ts +7 -44
  41. package/dist/surface.js +18 -98
  42. package/dist/switch.d.ts +10 -0
  43. package/dist/switch.js +10 -0
  44. package/dist/text-control.d.ts +9 -0
  45. package/dist/text-control.js +0 -0
  46. package/dist/textarea.d.ts +6 -0
  47. package/dist/textarea.js +17 -0
  48. package/dist/toggle-indicator.d.ts +16 -0
  49. package/dist/toggle-indicator.js +51 -0
  50. package/package.json +3 -3
  51. package/dist/surface-material.d.ts +0 -14
  52. package/dist/surface-material.js +0 -128
@@ -1,128 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Fragment, useLayoutEffect, useMemo, useRef, useState } from "react";
3
- import { colorLightness, colorOpacity, orderColors } from "./color.js";
4
- import { scale } from "./scale.js";
5
- /** The locally owned fill, refraction definition, and glass rim inside one Surface. */
6
- export function SurfaceMaterial({ color, distortion, foreground, grain, grainAmount, identity, opacity, ripples, waves }) {
7
- const element = useRef(null);
8
- const [colors, setColors] = useState(null);
9
- const seed = useMemo(() => seedFrom(identity), [identity]);
10
- const hasPaint = opacity > 0;
11
- const hasGrain = hasPaint && grain > 0 && grainAmount > 0;
12
- const hasDistortion = distortion > 0 || waves > 0 || ripples > 0;
13
- const initial = useMemo(() => hasGrain ? grainPaths(seed, grainAmount) : [], [grainAmount, hasGrain, seed]);
14
- // Resolve variables, currentColor, and CSS expressions in this Surface's
15
- // own scope before comparing colors. Layout effects settle before paint.
16
- useLayoutEffect(() => {
17
- const material = element.current;
18
- const view = material?.ownerDocument.defaultView;
19
- if (!material || !view || !hasPaint)
20
- return;
21
- const computed = view.getComputedStyle(material);
22
- const background = computed.fill;
23
- const foreground = computed.color;
24
- if (colors?.background === background && colors.foreground === foreground)
25
- return;
26
- setColors({ ...orderColors(background, foreground), background, foreground, lightness: Math.max(0, Math.min(1, colorLightness(background))) });
27
- });
28
- if (!hasPaint && !hasDistortion)
29
- return null;
30
- return _jsxs(Fragment, { children: [_jsxs("svg", { "data-surface-material": "", "aria-hidden": "true", focusable: "false", style: {
31
- position: "absolute",
32
- zIndex: -1,
33
- inset: 0,
34
- display: "block",
35
- width: "100%",
36
- height: "100%",
37
- overflow: "hidden",
38
- borderRadius: "inherit",
39
- boxShadow: hasPaint && colors ? `inset 0 1px 2px ${colorOpacity(colors.lighter, 0.28)}, 0 8px 24px ${colorOpacity(colors.darker, 0.04)}` : undefined,
40
- pointerEvents: "none"
41
- }, 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", { ref: element, "data-surface-base": "", width: "100%", height: "100%", style: { fill: color, color: foreground } }), hasGrain && _jsx("rect", { "data-surface-grain": "", width: "100%", height: "100%", fill: `url(#${identity}-grain)`, shapeRendering: "crispEdges" })] })] }), hasPaint && _jsx("div", { "data-surface-border": "", "aria-hidden": "true", style: {
42
- position: "absolute",
43
- // The material belongs behind content; its rim belongs above it.
44
- // Opaque children must not erase the Surface's rounded edge.
45
- zIndex: 1,
46
- inset: 0,
47
- padding: 1,
48
- borderRadius: "inherit",
49
- pointerEvents: "none",
50
- opacity: Math.min(1, scale(opacity, "xlarge")) * (colors?.lightness ?? 0),
51
- background: colors ? glassRim(colors.lighter, colors.darker) : undefined,
52
- WebkitMask: "linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0)",
53
- WebkitMaskComposite: "xor",
54
- mask: "linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0)",
55
- maskComposite: "exclude"
56
- } })] });
57
- }
58
- function glassRim(light, dark) {
59
- const edge = `color-mix(in oklch, ${dark} 20%, ${light})`;
60
- return `linear-gradient(145deg, ${colorOpacity(light, 0.92)}, ${colorOpacity(light, 0.4)} 35%, ${colorOpacity(edge, 0.18)} 55%, ${colorOpacity(light, 0.6)} 85%, ${colorOpacity(light, 0.3)})`;
61
- }
62
- function DistortionFilter({ distortion, identity, ripples, seed, waves }) {
63
- const fields = [
64
- distortion > 0 && { name: "organic", strength: distortion, x: "R" },
65
- waves > 0 && { name: "waves", strength: waves, x: "R" },
66
- ripples > 0 && { name: "ripples", strength: ripples, x: "B" }
67
- ].filter((field) => Boolean(field));
68
- const scale = fields.reduce((total, field) => total + field.strength, 0);
69
- const weighted = fields.map(field => `${identity}-${field.name}-weighted`);
70
- const map = `${identity}-distortion-map`;
71
- return _jsxs("filter", { id: `${identity}-distortion`, "data-surface-distortion": "", x: "-20%", y: "-20%", width: "140%", height: "140%", colorInterpolationFilters: "sRGB", children: [distortion > 0 && _jsxs(Fragment, { children: [_jsx("feTurbulence", { "data-surface-distortion-noise": "", "data-surface-distortion-field": "organic", type: "fractalNoise", baseFrequency: "0.008 0.008", numOctaves: 2, seed: 92, result: `${identity}-organic-noise` }), _jsx("feGaussianBlur", { in: `${identity}-organic-noise`, stdDeviation: 2, result: `${identity}-organic-noise-blurred` })] }), waves > 0 && _jsx(Fragment, { children: _jsx("feTurbulence", { "data-surface-distortion-field": "waves", type: "turbulence", baseFrequency: "0.006 0.045", numOctaves: 1, seed: seed + 17, result: `${identity}-waves-noise` }) }), ripples > 0 && _jsx(Fragment, { children: _jsx("feTurbulence", { "data-surface-distortion-field": "ripples", type: "turbulence", baseFrequency: "0.055", numOctaves: 2, seed: seed + 31, result: `${identity}-ripples-noise` }) }), fields.map(field => _jsx("feColorMatrix", { "data-surface-distortion-weight": field.name, in: `${identity}-${field.name}-noise${field.name === "organic" ? "-blurred" : ""}`, type: "matrix", values: weightMatrix(field.x, field.strength / scale), result: `${identity}-${field.name}-weighted` }, field.name)), weighted.slice(1).map((field, index) => _jsx("feComposite", { "data-surface-distortion-combine": "", in: index === 0 ? weighted[0] : `${identity}-distortion-sum-${index}`, in2: field, operator: "arithmetic", k2: 1, k3: 1, result: index === weighted.length - 2 ? map : `${identity}-distortion-sum-${index + 1}` }, field)), _jsx("feDisplacementMap", { "data-surface-distortion-stage": "combined", in: "SourceGraphic", in2: weighted.length === 1 ? weighted[0] : map, scale: scale, xChannelSelector: "R", yChannelSelector: "G" })] });
72
- }
73
- function weightMatrix(x, weight) {
74
- const red = x === "R" ? `${weight} 0 0 0 0` : `0 0 ${weight} 0 0`;
75
- return `${red}
76
- 0 ${weight} 0 0 0
77
- 0 0 0 0 0
78
- 0 0 0 1 0`;
79
- }
80
- function grainTone(color, tone, intensity) {
81
- const channel = Math.round(tone / (toneCount - 1) * 255);
82
- const percentage = Math.round(intensity * 10_000) / 100;
83
- return `color-mix(in srgb, ${color} ${100 - percentage}%, rgb(${channel} ${channel} ${channel}) ${percentage}%)`;
84
- }
85
- function grainPaths(seed, amount) {
86
- const tones = Array.from({ length: toneCount }, () => []);
87
- for (let y = 0; y < patternSize; y += 1) {
88
- for (let x = 0; x < patternSize; x += 1) {
89
- const pointX = x + seed * 41;
90
- const pointY = y + seed * 17;
91
- const presence = shaderHash(pointX + 71.9, pointY + 13.7);
92
- if (presence > amount)
93
- continue;
94
- const fine = shaderHash(Math.floor(pointX * 1.18), Math.floor(pointY * 1.18));
95
- const clustered = shaderHash(Math.floor(pointX * 0.47) + 31.7, Math.floor(pointY * 0.47) + 31.7);
96
- const value = clamp(fine * 0.8 + clustered * 0.2, 0, 1);
97
- const tone = Math.min(toneCount - 1, Math.floor(value * toneCount));
98
- tones[tone]?.push(`M${x} ${y}h1v1h-1z`);
99
- }
100
- }
101
- return tones.map(tone => tone.join(""));
102
- }
103
- function shaderHash(x, y) {
104
- let red = fract(x * 0.1031);
105
- let green = fract(y * 0.1031);
106
- let blue = fract(x * 0.1031);
107
- const product = red * (green + 33.33) + green * (blue + 33.33) + blue * (red + 33.33);
108
- red += product;
109
- green += product;
110
- blue += product;
111
- return fract((red + green) * blue);
112
- }
113
- function seedFrom(value) {
114
- let seed = 2166136261;
115
- for (const character of value) {
116
- seed ^= character.codePointAt(0) ?? 0;
117
- seed = Math.imul(seed, 16777619);
118
- }
119
- return (seed >>> 0) % 997 + 1;
120
- }
121
- function fract(value) {
122
- return value - Math.floor(value);
123
- }
124
- function clamp(value, minimum, maximum) {
125
- return Math.min(maximum, Math.max(minimum, value));
126
- }
127
- const patternSize = 64;
128
- const toneCount = 16;