@pathscale/ui 2.3.2 → 2.4.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.
@@ -98,16 +98,26 @@
98
98
  backdrop-filter: none;
99
99
  }
100
100
 
101
- /* Absorbs GlassPanel. The highlight ring was its `highlight` flag. */
101
+ /* Absorbs GlassPanel. The highlight ring was its `highlight` flag.
102
+
103
+ Every `--glass-*` read below carries a fallback, and that is load-bearing
104
+ rather than tidy. An undefined custom property does not fall back to its
105
+ initial value: CSS drops the whole declaration. Three of these were read
106
+ bare, so a theme that defined twenty-eight of the thirty-one glass tokens
107
+ got a card with no background at all rather than a plainer one, and the
108
+ only themes that defined all thirty-one were the two shipped here. Both
109
+ use `white` for the three colours, so that is what the fallbacks say.
110
+
111
+ `src/styles/glass.ts` derives the other twenty-five from three numbers. */
102
112
  .card--material-glass {
103
113
  --card-bg: color-mix(
104
114
  in oklab,
105
- var(--glass-background-color),
115
+ var(--glass-background-color, white),
106
116
  transparent calc(100% - var(--glass-background-opacity, 55%))
107
117
  );
108
118
  --card-border: color-mix(
109
119
  in oklab,
110
- var(--glass-border-color),
120
+ var(--glass-border-color, white),
111
121
  transparent calc(100% - var(--glass-border-opacity, 12%))
112
122
  );
113
123
  backdrop-filter: blur(var(--card-glass-blur, var(--glass-blur, 50px)))
@@ -125,7 +135,7 @@
125
135
  box-shadow: inset 0 var(--border, 1px) 0 0
126
136
  color-mix(
127
137
  in oklab,
128
- var(--glass-highlight-color),
138
+ var(--glass-highlight-color, white),
129
139
  transparent calc(100% - var(--glass-highlight-opacity, 18%))
130
140
  );
131
141
  }
package/dist/index.d.ts CHANGED
@@ -130,3 +130,5 @@ export type { ColorSwatchProps, ColorSwatchShape, ColorSwatchSize, } from "./com
130
130
  export { default as ChatBubble } from "./components/chatbubble";
131
131
  export { summarizeStatus, diffStatus } from "./components/status";
132
132
  export type { Health, Quality, StatusItem, StatusSummary, StatusTransition } from "./components/status";
133
+ export { GLASS_DEFAULTS, GLASS_LIMITS, applyGlassTokens, glassTokensToCss, resolveGlassTokens, } from "./styles/glass";
134
+ export type { GlassMode, GlassTuning } from "./styles/glass";
package/dist/index.js CHANGED
@@ -73,4 +73,5 @@ export { ListBoxItem, ListBoxItemIndicator, ListBoxSection, default as ListBox }
73
73
  export { default as ColorSwatch } from "./components/color-swatch/index.js";
74
74
  export { default as ChatBubble } from "./components/chatbubble/index.js";
75
75
  export { diffStatus, summarizeStatus } from "./components/status/index.js";
76
+ export { GLASS_DEFAULTS, GLASS_LIMITS, applyGlassTokens, glassTokensToCss, resolveGlassTokens } from "./styles/glass.js";
76
77
  export { DEFAULT_GAP as DEFAULT_TOAST_GAP, DEFAULT_MAX_VISIBLE_TOAST, DEFAULT_SCALE_FACTOR as DEFAULT_TOAST_SCALE_FACTOR, DEFAULT_TOAST_TIMEOUT, DEFAULT_TOAST_WIDTH, ToastActionButton, ToastCloseButton, ToastContent, ToastDescription, ToastIndicator, ToastProvider, ToastQueue, ToastTitle, index_js_toast as Toast, index_js_toast as toast, toastQueue };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "format": "solid-layouts-library-v2",
3
3
  "package": "@pathscale/ui",
4
- "version": "2.3.2",
4
+ "version": "2.4.0",
5
5
  "components": {
6
6
  "Accordion": {
7
7
  "kind": "embedded"
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Glass, as three numbers instead of thirty-one.
3
+ *
4
+ * `material="glass"` is styled by a family of `--glass-*` custom properties.
5
+ * Both shipped themes declare all of them by hand, which made glass a thing you
6
+ * inherited rather than a thing you could add: a new theme had to copy
7
+ * thirty-one values, and three of them are read without a fallback, so a theme
8
+ * that copied twenty-eight got a card with no background at all rather than a
9
+ * plainer one. An undefined custom property does not fall back to its initial
10
+ * value; CSS drops the whole declaration.
11
+ *
12
+ * So the set splits in two. Six are colours and stay with the theme, because
13
+ * only the theme knows what its glass is tinted with. The other twenty-five are
14
+ * opacities, sizes and blurs, and every one of them is a function of three
15
+ * numbers:
16
+ *
17
+ * blur how far the backdrop is smeared, in pixels
18
+ * refraction how much the surface asserts itself: tint, border, highlights
19
+ * depth how far off the page it sits: glows, sheen, shadow
20
+ *
21
+ * Adding glass to a theme is now those three numbers and, if it wants them, the
22
+ * six colours. The curves are lifted from the tuning surface that consulting.parcle.ai
23
+ * arrived at by eye against this same token vocabulary, so the shipped themes
24
+ * keep the appearance they already had.
25
+ */
26
+ export type GlassMode = "light" | "dark";
27
+ /** What a theme sets. Everything else is derived. */
28
+ export type GlassTuning = {
29
+ /** Backdrop blur radius in pixels. 0 turns glass into a plain translucent fill. */
30
+ blur: number;
31
+ /**
32
+ * How much the surface asserts itself, 0 to 0.4.
33
+ *
34
+ * Drives tint, border, highlights and rim together, because they are one
35
+ * physical property and tuning them separately is how the thirty-one-value
36
+ * version became unmaintainable.
37
+ */
38
+ refraction: number;
39
+ /** How far off the page it sits, 0 to 30. Drives glows, sheen and shadow. */
40
+ depth: number;
41
+ };
42
+ export declare const GLASS_LIMITS: {
43
+ readonly blur: {
44
+ readonly min: 0;
45
+ readonly max: 50;
46
+ };
47
+ readonly refraction: {
48
+ readonly min: 0;
49
+ readonly max: 0.4;
50
+ };
51
+ readonly depth: {
52
+ readonly min: 0;
53
+ readonly max: 30;
54
+ };
55
+ };
56
+ /** What the shipped themes use. Both land on the same numbers. */
57
+ export declare const GLASS_DEFAULTS: Record<GlassMode, GlassTuning>;
58
+ /**
59
+ * The `--glass-*` custom properties three numbers imply.
60
+ *
61
+ * Returns only what is derived. The six colours - background, border,
62
+ * highlight, the two rim stops and the inner glow - are the theme's, and a
63
+ * theme that sets none of them still renders because the component CSS carries
64
+ * fallbacks for all six.
65
+ */
66
+ export declare function resolveGlassTokens(tuning: Partial<GlassTuning>, mode: GlassMode): Record<string, string>;
67
+ /**
68
+ * Writes the derived tokens onto an element, `:root` by default.
69
+ *
70
+ * Inline styles rather than a stylesheet, because this is the layer above the
71
+ * theme: a theme sets its glass in CSS, and this is for changing it at runtime
72
+ * without a rebuild - a settings panel, a per-route override, a preview.
73
+ *
74
+ * A no-op without a DOM, so it is safe to call during server rendering.
75
+ */
76
+ export declare function applyGlassTokens(tuning: Partial<GlassTuning>, mode: GlassMode, target?: {
77
+ style: {
78
+ setProperty(name: string, value: string): void;
79
+ };
80
+ }): void;
81
+ /**
82
+ * The derived tokens as a CSS declaration block, for a theme that wants them
83
+ * baked in rather than applied at runtime.
84
+ *
85
+ * The intended use is a build step or a scratch buffer: paste the output into a
86
+ * theme file beside its six colours and glass is part of that theme, with no
87
+ * JavaScript involved.
88
+ */
89
+ export declare function glassTokensToCss(tuning: Partial<GlassTuning>, mode: GlassMode): string;
@@ -0,0 +1,103 @@
1
+ const GLASS_LIMITS = {
2
+ blur: {
3
+ min: 0,
4
+ max: 50
5
+ },
6
+ refraction: {
7
+ min: 0,
8
+ max: 0.4
9
+ },
10
+ depth: {
11
+ min: 0,
12
+ max: 30
13
+ }
14
+ };
15
+ const GLASS_DEFAULTS = {
16
+ light: {
17
+ blur: 9,
18
+ refraction: 0.31,
19
+ depth: 24
20
+ },
21
+ dark: {
22
+ blur: 9,
23
+ refraction: 0.31,
24
+ depth: 24
25
+ }
26
+ };
27
+ const clamp = (value, min, max, fallback)=>{
28
+ const n = Number(value);
29
+ return Number.isFinite(n) ? Math.min(max, Math.max(min, n)) : fallback;
30
+ };
31
+ const round = (v, places = 2)=>String(Math.round((v + Number.EPSILON) * 10 ** places) / 10 ** places);
32
+ const pct = (v, places = 2)=>`${round(v, places)}%`;
33
+ const px = (v, places = 2)=>`${round(v, places)}px`;
34
+ function normalise(tuning, mode) {
35
+ const base = GLASS_DEFAULTS[mode];
36
+ const blur = clamp(tuning.blur, GLASS_LIMITS.blur.min, GLASS_LIMITS.blur.max, base.blur);
37
+ const refraction = clamp(tuning.refraction, GLASS_LIMITS.refraction.min, GLASS_LIMITS.refraction.max, base.refraction);
38
+ const depth = clamp(tuning.depth, GLASS_LIMITS.depth.min, GLASS_LIMITS.depth.max, base.depth);
39
+ const r = refraction / GLASS_LIMITS.refraction.max;
40
+ const d = depth / GLASS_LIMITS.depth.max;
41
+ return {
42
+ blur,
43
+ light: "light" === mode,
44
+ rs: 0 === r ? 0 : r ** 0.82,
45
+ rv: 0 === r ? 0 : r ** 0.95,
46
+ ds: 0 === d ? 0 : d ** 0.85,
47
+ r,
48
+ d
49
+ };
50
+ }
51
+ function resolveGlassTokens(tuning, mode) {
52
+ const v = normalise(tuning, mode);
53
+ const { rs, rv, ds, light } = v;
54
+ const zero = 0 === v.r;
55
+ const background = light ? zero ? 0 : 18 + 30 * rv : 7 * rv;
56
+ const border = light ? zero ? 0 : 18 + 18 * rs : 26 * rs;
57
+ const highlight = light ? zero ? 0 : 22 + 26 * rs : 24 * rs;
58
+ const bottomHighlight = light ? zero ? 0 : 10 + 14 * rs + 5 * ds : 3.5 * rs + 3 * rs * ds;
59
+ const edgeHighlight = light ? zero ? 0 : 20 + 22 * rs + 4 * ds : 18 * rs + 4 * ds;
60
+ const rimStart = light ? zero ? 0 : 14 + 18 * rs + 4 * ds : 17 * rs + 3 * ds;
61
+ const rimEnd = light ? zero ? 0 : 18 + 22 * rs + 4 * ds : 23 * rs + 5 * ds;
62
+ const innerGlow = light ? 0.035 * rs + 0.045 * rs * ds + 0.012 * ds : 0.055 * rs * ds + 0.018 * ds;
63
+ const topGlow = light ? 8 * ds * (0.4 + 0.6 * rs) : 6 * ds * (0.35 + 0.65 * rs);
64
+ const bottomGlow = light ? 9 * ds * (0.25 + 0.65 * rs) : 5 * ds * (0.2 + 0.55 * rs);
65
+ const sheen = light ? 14 * ds * (0.25 + 0.75 * rs) : 10 * ds * (0.25 + 0.75 * rs);
66
+ const fallbackBackground = Math.min(70, light ? background + 10 * rs : 8 * background + 12 * rs);
67
+ const shadow = ds > 0 ? `0 ${px(light ? 5 + 10 * ds : 4 + 10 * ds)} ${px(light ? 20 + 28 * ds : 18 + 26 * ds)} rgb(0 0 0 / ${pct(light ? 2 + 5 * ds : 3 + 7 * ds)})` : "0 0 0 rgb(0 0 0 / 0%)";
68
+ return {
69
+ "--glass-blur": px(v.blur, 0),
70
+ "--glass-saturation": round(1 + 0.18 * rs),
71
+ "--glass-brightness": "1",
72
+ "--glass-background-opacity": pct(background),
73
+ "--glass-border-opacity": pct(border),
74
+ "--glass-highlight-opacity": pct(highlight),
75
+ "--glass-bottom-highlight-opacity": pct(bottomHighlight),
76
+ "--glass-edge-highlight-opacity": pct(edgeHighlight),
77
+ "--glass-rim-start-opacity": pct(rimStart),
78
+ "--glass-rim-end-opacity": pct(rimEnd),
79
+ "--glass-inner-glow-alpha": round(innerGlow, 3),
80
+ "--glass-inner-glow-blur": px(ds > 0 ? 1 + 3 * ds : 0),
81
+ "--glass-inner-glow-spread": "0px",
82
+ "--glass-depth-top-glow-opacity": pct(topGlow),
83
+ "--glass-depth-bottom-glow-opacity": pct(bottomGlow),
84
+ "--glass-depth-sheen-opacity": pct(sheen),
85
+ "--glass-depth-sheen-size": pct(82 - 16 * ds),
86
+ "--glass-depth-surface-opacity": "0%",
87
+ "--glass-depth-surface-size": pct(82),
88
+ "--glass-glow-ring-opacity": pct(light ? 6 * rs : 10 * rs),
89
+ "--glass-liquid-edge-size": px(1 + 2 * rs),
90
+ "--glass-liquid-inner-blur": px(6 + 12 * rs),
91
+ "--glass-shadow-depth": shadow,
92
+ "--glass-fallback-background-opacity": pct(fallbackBackground)
93
+ };
94
+ }
95
+ function applyGlassTokens(tuning, mode, target) {
96
+ const element = target ?? ("u" < typeof document ? void 0 : document.documentElement);
97
+ if (!element) return;
98
+ for (const [name, value] of Object.entries(resolveGlassTokens(tuning, mode)))element.style.setProperty(name, value);
99
+ }
100
+ function glassTokensToCss(tuning, mode) {
101
+ return Object.entries(resolveGlassTokens(tuning, mode)).map(([name, value])=>` ${name}: ${value};`).join("\n");
102
+ }
103
+ export { GLASS_DEFAULTS, GLASS_LIMITS, applyGlassTokens, glassTokensToCss, resolveGlassTokens };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pathscale/ui",
3
- "version": "2.3.2",
3
+ "version": "2.4.0",
4
4
  "author": "pathscale",
5
5
  "repository": {
6
6
  "type": "git",