@pathscale/ui 2.6.6 → 2.7.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/dist/components/_shared/material.css +155 -4
- package/dist/components/card/Card.css +88 -28
- package/dist/components/card/Card.generated.js +3 -0
- package/dist/components/dialog/Dialog.generated.js +3 -0
- package/dist/components/drawer/Drawer.generated.js +3 -0
- package/dist/components/menu/Menu.generated.js +3 -0
- package/dist/components/navbar/Navbar.generated.js +3 -0
- package/dist/components/popover/Popover.generated.js +3 -0
- package/dist/layouts.manifest.json +1 -1
- package/dist/styles/glass.d.ts +15 -0
- package/dist/styles/glass.js +13 -3
- package/package.json +1 -1
|
@@ -24,7 +24,68 @@
|
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
@layer components {
|
|
27
|
-
|
|
27
|
+
/*
|
|
28
|
+
* Glass is one flip, not one flip per component.
|
|
29
|
+
*
|
|
30
|
+
* Every component here emits `data-material="solid"` when its prop is unset,
|
|
31
|
+
* so glass used to mean visiting each call site and passing `material="glass"`
|
|
32
|
+
* by hand. That is backwards: an app choosing glass is choosing a material for
|
|
33
|
+
* its whole surface vocabulary, not for one card. Put `glass` on the root
|
|
34
|
+
* element and every unset component becomes glass; take it off and they are
|
|
35
|
+
* all solid again. Nothing else changes and no call site is touched.
|
|
36
|
+
*
|
|
37
|
+
* `data-material` still wins where it is given explicitly, because "this one
|
|
38
|
+
* stays solid" is a real requirement inside a glassed app. The distinction is
|
|
39
|
+
* between a component that was never told and one that was, which is what
|
|
40
|
+
* `data-material-explicit` records.
|
|
41
|
+
*
|
|
42
|
+
* A root class rather than a style query on a token, which is the more
|
|
43
|
+
* natural expression and cannot be used. Verified by rendering rather than
|
|
44
|
+
* assumed: the engine's own `container_style_query.rs` shows the query never
|
|
45
|
+
* matching, so that form would have been dead CSS and the flip would have
|
|
46
|
+
* looked broken rather than unsupported.
|
|
47
|
+
*/
|
|
48
|
+
:root.glass [data-material="solid"]:not([data-material-explicit]) {
|
|
49
|
+
background-color: color-mix(
|
|
50
|
+
in oklab,
|
|
51
|
+
var(--glass-background-color, white),
|
|
52
|
+
transparent calc(100% - var(--glass-background-opacity, 55%))
|
|
53
|
+
);
|
|
54
|
+
border-color: color-mix(
|
|
55
|
+
in oklab,
|
|
56
|
+
var(--glass-border-color, white),
|
|
57
|
+
transparent calc(100% - var(--glass-border-opacity, 12%))
|
|
58
|
+
);
|
|
59
|
+
-webkit-backdrop-filter: blur(var(--glass-blur, 9px))
|
|
60
|
+
saturate(var(--glass-saturation, 1.2))
|
|
61
|
+
brightness(var(--glass-brightness, 1));
|
|
62
|
+
backdrop-filter: blur(var(--glass-blur, 9px))
|
|
63
|
+
saturate(var(--glass-saturation, 1.2))
|
|
64
|
+
brightness(var(--glass-brightness, 1));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
:root.glass [data-material="solid"]:not([data-material-explicit])::before {
|
|
68
|
+
content: "";
|
|
69
|
+
position: absolute;
|
|
70
|
+
inset: 0;
|
|
71
|
+
border-radius: inherit;
|
|
72
|
+
pointer-events: none;
|
|
73
|
+
box-shadow: inset 0 var(--border, 1px) 0 0
|
|
74
|
+
color-mix(
|
|
75
|
+
in oklab,
|
|
76
|
+
var(--glass-highlight-color, white),
|
|
77
|
+
transparent calc(100% - var(--glass-highlight-opacity, 18%))
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/*
|
|
82
|
+
* Solid, either because the app never flipped glass on or because this
|
|
83
|
+
* component was told to stay solid inside one that did. The `:not()` keeps
|
|
84
|
+
* this from overriding the flip above, which sits earlier in the file and
|
|
85
|
+
* would otherwise lose to it on source order alone.
|
|
86
|
+
*/
|
|
87
|
+
:root:not(.glass) [data-material="solid"],
|
|
88
|
+
[data-material="solid"][data-material-explicit] {
|
|
28
89
|
-webkit-backdrop-filter: none;
|
|
29
90
|
backdrop-filter: none;
|
|
30
91
|
}
|
|
@@ -40,9 +101,11 @@
|
|
|
40
101
|
var(--glass-border-color, white),
|
|
41
102
|
transparent calc(100% - var(--glass-border-opacity, 12%))
|
|
42
103
|
);
|
|
43
|
-
-webkit-backdrop-filter: blur(var(--glass-blur,
|
|
104
|
+
-webkit-backdrop-filter: blur(var(--glass-blur, 9px))
|
|
105
|
+
saturate(var(--glass-saturation, 1.2))
|
|
44
106
|
brightness(var(--glass-brightness, 1));
|
|
45
|
-
backdrop-filter: blur(var(--glass-blur,
|
|
107
|
+
backdrop-filter: blur(var(--glass-blur, 9px))
|
|
108
|
+
saturate(var(--glass-saturation, 1.2))
|
|
46
109
|
brightness(var(--glass-brightness, 1));
|
|
47
110
|
}
|
|
48
111
|
|
|
@@ -74,12 +137,97 @@
|
|
|
74
137
|
* A backdrop filter reads the pixels behind it, so nesting one inside another
|
|
75
138
|
* blurs already-blurred output. That is muddy rather than deeper, and it
|
|
76
139
|
* costs a second render pass to get there.
|
|
140
|
+
*
|
|
141
|
+
* The fill has to go with the filter, and dropping only the filter was a bug.
|
|
142
|
+
* Alpha stacks multiplicatively: two surfaces at 55% composite to 1 - 0.45²,
|
|
143
|
+
* which is 79.75%, and a pane that opaque reads as a flat slab rather than as
|
|
144
|
+
* glass. Turning the opacity axis down does not rescue it, because the inner
|
|
145
|
+
* fill keeps its own share of whatever the axis says. The inner surface
|
|
146
|
+
* therefore contributes nothing: the outer pane already painted the film they
|
|
147
|
+
* are both meant to share.
|
|
148
|
+
*
|
|
149
|
+
* The highlight goes too. It is the lit top edge of *a pane*, and an inner
|
|
150
|
+
* surface that is not its own pane drawing one puts a stray line across the
|
|
151
|
+
* middle of the outer one.
|
|
77
152
|
*/
|
|
78
153
|
[data-material="glass"] [data-material="glass"] {
|
|
154
|
+
background-color: transparent;
|
|
79
155
|
-webkit-backdrop-filter: none;
|
|
80
156
|
backdrop-filter: none;
|
|
81
157
|
}
|
|
82
158
|
|
|
159
|
+
[data-material="glass"] [data-material="glass"]::before {
|
|
160
|
+
box-shadow: none;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/*
|
|
164
|
+
* Controls, when the surface around them is glass.
|
|
165
|
+
*
|
|
166
|
+
* Not scoped under `[data-material="glass"]`, and that is the point rather
|
|
167
|
+
* than an oversight. An app does not have to glass its panels with this
|
|
168
|
+
* library's attribute to have glass panels: the application that drove this
|
|
169
|
+
* work glasses its own surfaces with its own class, so an ancestor selector
|
|
170
|
+
* would have matched nothing there and every control would have kept the
|
|
171
|
+
* fill this block exists to change. The token is the contract instead. One
|
|
172
|
+
* value in one file decides it, which is what makes glass a setting rather
|
|
173
|
+
* than a migration.
|
|
174
|
+
*
|
|
175
|
+
* `--glass-control-opacity` defaults to 100%, so a theme that never sets it
|
|
176
|
+
* gets exactly what it renders today. Flipping glass on therefore cannot
|
|
177
|
+
* make a control unreadable, which is what lets the flip be safe to throw.
|
|
178
|
+
*
|
|
179
|
+
* The bug this fixes is the other side of it: in a light palette `base-100`
|
|
180
|
+
* is white, so a control taking it raw paints a bright slab on a dark glass
|
|
181
|
+
* panel. Five separate screenshots of "some elements are not getting glass"
|
|
182
|
+
* were all this one rule.
|
|
183
|
+
*
|
|
184
|
+
* A surface and a control cannot share one opacity token. Audited in that
|
|
185
|
+
* same application: of 38 uses of its inset colour, 30 were surfaces and 8
|
|
186
|
+
* were controls. Surfaces want the alpha. A control does not, because a
|
|
187
|
+
* translucent switch track, checkbox box or select trigger reads as disabled
|
|
188
|
+
* and its label stops being legible against whatever the glass admits from
|
|
189
|
+
* behind. Chrome stays solid to say it is live.
|
|
190
|
+
*/
|
|
191
|
+
:is(
|
|
192
|
+
.checkbox__control,
|
|
193
|
+
.radio__control,
|
|
194
|
+
.input-control,
|
|
195
|
+
.ui-select__trigger,
|
|
196
|
+
.language-switcher__trigger,
|
|
197
|
+
.dropdown__trigger,
|
|
198
|
+
.toggle__track,
|
|
199
|
+
[data-control-material="solid"]
|
|
200
|
+
):not([data-control-material="glass"]) {
|
|
201
|
+
background-color: rgb(
|
|
202
|
+
from var(--color-base-100) r g b /
|
|
203
|
+
var(--glass-control-opacity, 100%)
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/*
|
|
208
|
+
* The exception: a control that *displays* a value rather than framing one.
|
|
209
|
+
*
|
|
210
|
+
* A colour wheel, a swatch or a gradient stop is showing you the thing it is
|
|
211
|
+
* filled with, so an opaque fill is a lie about the value rather than a cue
|
|
212
|
+
* that the control is live. Held solid, a light theme's colour wheel paints
|
|
213
|
+
* a white disc and the swatches on it stop being readable as swatches.
|
|
214
|
+
*
|
|
215
|
+
* Opted into per component, because which controls belong in this set is a
|
|
216
|
+
* judgement that can reasonably go either way, and a data attribute keeps it
|
|
217
|
+
* a token flip rather than a rewrite.
|
|
218
|
+
*/
|
|
219
|
+
[data-control-material="glass"] {
|
|
220
|
+
background-color: color-mix(
|
|
221
|
+
in oklab,
|
|
222
|
+
var(--glass-background-color, white),
|
|
223
|
+
transparent
|
|
224
|
+
calc(
|
|
225
|
+
100% -
|
|
226
|
+
var(--glass-control-opacity, var(--glass-background-opacity, 55%))
|
|
227
|
+
)
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
83
231
|
/*
|
|
84
232
|
* No backdrop support, or a reader who asked for less transparency.
|
|
85
233
|
*
|
|
@@ -87,7 +235,10 @@
|
|
|
87
235
|
* happens to be behind it, because the tint alone is unreadable. The
|
|
88
236
|
* highlight goes too: it reads as a stray line without the material.
|
|
89
237
|
*/
|
|
90
|
-
@supports not (
|
|
238
|
+
@supports not (
|
|
239
|
+
(backdrop-filter: blur(1px)) or
|
|
240
|
+
(-webkit-backdrop-filter: blur(1px))
|
|
241
|
+
) {
|
|
91
242
|
[data-material="glass"] {
|
|
92
243
|
background-color: color-mix(
|
|
93
244
|
in oklab,
|
|
@@ -72,7 +72,11 @@
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
.card--soft {
|
|
75
|
-
--card-bg: color-mix(
|
|
75
|
+
--card-bg: color-mix(
|
|
76
|
+
in oklab,
|
|
77
|
+
var(--card-accent),
|
|
78
|
+
var(--color-base-100) 86%
|
|
79
|
+
);
|
|
76
80
|
--card-border: transparent;
|
|
77
81
|
}
|
|
78
82
|
|
|
@@ -120,10 +124,14 @@
|
|
|
120
124
|
var(--glass-border-color, white),
|
|
121
125
|
transparent calc(100% - var(--glass-border-opacity, 12%))
|
|
122
126
|
);
|
|
123
|
-
-webkit-backdrop-filter: blur(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
saturate(var(--glass-saturation, 1.2))
|
|
127
|
+
-webkit-backdrop-filter: blur(
|
|
128
|
+
var(--card-glass-blur, var(--glass-blur, 9px))
|
|
129
|
+
)
|
|
130
|
+
saturate(var(--glass-saturation, 1.2))
|
|
131
|
+
brightness(var(--glass-brightness, 1));
|
|
132
|
+
backdrop-filter: blur(var(--card-glass-blur, var(--glass-blur, 9px)))
|
|
133
|
+
saturate(var(--glass-saturation, 1.2))
|
|
134
|
+
brightness(var(--glass-brightness, 1));
|
|
127
135
|
}
|
|
128
136
|
|
|
129
137
|
.card--material-glass::before {
|
|
@@ -145,42 +153,88 @@
|
|
|
145
153
|
--card-shadow: none;
|
|
146
154
|
}
|
|
147
155
|
.card--elevation-sm {
|
|
148
|
-
--card-shadow: var(
|
|
156
|
+
--card-shadow: var(
|
|
157
|
+
--shadow-sm,
|
|
158
|
+
0 1px 2px rgb(var(--shadow-color, 0 0 0) / 5%),
|
|
159
|
+
0 1px 3px rgb(var(--shadow-color, 0 0 0) / 10%)
|
|
160
|
+
);
|
|
149
161
|
}
|
|
150
162
|
.card--elevation-md {
|
|
151
|
-
--card-shadow: var(
|
|
163
|
+
--card-shadow: var(
|
|
164
|
+
--shadow-md,
|
|
165
|
+
0 4px 6px -1px rgb(var(--shadow-color, 0 0 0) / 10%),
|
|
166
|
+
0 2px 4px -2px rgb(var(--shadow-color, 0 0 0) / 10%)
|
|
167
|
+
);
|
|
152
168
|
}
|
|
153
169
|
.card--elevation-lg {
|
|
154
|
-
--card-shadow: var(
|
|
170
|
+
--card-shadow: var(
|
|
171
|
+
--shadow-lg,
|
|
172
|
+
0 10px 15px -3px rgb(var(--shadow-color, 0 0 0) / 10%),
|
|
173
|
+
0 4px 6px -4px rgb(var(--shadow-color, 0 0 0) / 10%)
|
|
174
|
+
);
|
|
155
175
|
}
|
|
156
176
|
|
|
157
177
|
/* -------------------------------------------------------------- Padding */
|
|
158
|
-
.card--padding-none .card__body {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
.card--padding-
|
|
162
|
-
|
|
163
|
-
|
|
178
|
+
.card--padding-none .card__body {
|
|
179
|
+
padding: 0;
|
|
180
|
+
}
|
|
181
|
+
.card--padding-xs .card__body {
|
|
182
|
+
padding: 0.5rem;
|
|
183
|
+
}
|
|
184
|
+
.card--padding-sm .card__body {
|
|
185
|
+
padding: 0.75rem;
|
|
186
|
+
}
|
|
187
|
+
.card--padding-md .card__body {
|
|
188
|
+
padding: 1rem;
|
|
189
|
+
}
|
|
190
|
+
.card--padding-lg .card__body {
|
|
191
|
+
padding: 1.5rem;
|
|
192
|
+
}
|
|
193
|
+
.card--padding-xl .card__body {
|
|
194
|
+
padding: 2rem;
|
|
195
|
+
}
|
|
164
196
|
|
|
165
197
|
.card--padding-none .card__header,
|
|
166
|
-
.card--padding-none .card__footer {
|
|
198
|
+
.card--padding-none .card__footer {
|
|
199
|
+
padding: 0;
|
|
200
|
+
}
|
|
167
201
|
.card--padding-xs .card__header,
|
|
168
|
-
.card--padding-xs .card__footer {
|
|
202
|
+
.card--padding-xs .card__footer {
|
|
203
|
+
padding: 0.5rem;
|
|
204
|
+
}
|
|
169
205
|
.card--padding-sm .card__header,
|
|
170
|
-
.card--padding-sm .card__footer {
|
|
206
|
+
.card--padding-sm .card__footer {
|
|
207
|
+
padding: 0.75rem;
|
|
208
|
+
}
|
|
171
209
|
.card--padding-md .card__header,
|
|
172
|
-
.card--padding-md .card__footer {
|
|
210
|
+
.card--padding-md .card__footer {
|
|
211
|
+
padding: 1rem;
|
|
212
|
+
}
|
|
173
213
|
.card--padding-lg .card__header,
|
|
174
|
-
.card--padding-lg .card__footer {
|
|
214
|
+
.card--padding-lg .card__footer {
|
|
215
|
+
padding: 1.5rem;
|
|
216
|
+
}
|
|
175
217
|
.card--padding-xl .card__header,
|
|
176
|
-
.card--padding-xl .card__footer {
|
|
218
|
+
.card--padding-xl .card__footer {
|
|
219
|
+
padding: 2rem;
|
|
220
|
+
}
|
|
177
221
|
|
|
178
222
|
/* --------------------------------------------------------------- Radius */
|
|
179
|
-
.card--radius-none {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
.card--radius-
|
|
183
|
-
|
|
223
|
+
.card--radius-none {
|
|
224
|
+
border-radius: 0;
|
|
225
|
+
}
|
|
226
|
+
.card--radius-sm {
|
|
227
|
+
border-radius: 0.25rem;
|
|
228
|
+
}
|
|
229
|
+
.card--radius-md {
|
|
230
|
+
border-radius: 0.5rem;
|
|
231
|
+
}
|
|
232
|
+
.card--radius-lg {
|
|
233
|
+
border-radius: var(--radius-box, 1rem);
|
|
234
|
+
}
|
|
235
|
+
.card--radius-full {
|
|
236
|
+
border-radius: var(--radius-pill, 9999px);
|
|
237
|
+
}
|
|
184
238
|
|
|
185
239
|
/* ---------------------------------------------------------- Interactive */
|
|
186
240
|
.card--interactive {
|
|
@@ -188,7 +242,11 @@
|
|
|
188
242
|
}
|
|
189
243
|
|
|
190
244
|
.card--interactive:hover {
|
|
191
|
-
--card-shadow: var(
|
|
245
|
+
--card-shadow: var(
|
|
246
|
+
--shadow-lg,
|
|
247
|
+
0 10px 15px -3px rgb(var(--shadow-color, 0 0 0) / 10%),
|
|
248
|
+
0 4px 6px -4px rgb(var(--shadow-color, 0 0 0) / 10%)
|
|
249
|
+
);
|
|
192
250
|
transform: translateY(-1px);
|
|
193
251
|
}
|
|
194
252
|
|
|
@@ -207,7 +265,8 @@
|
|
|
207
265
|
align-items: center;
|
|
208
266
|
justify-content: space-between;
|
|
209
267
|
gap: 0.75rem;
|
|
210
|
-
border-block-end: var(--border, 1px) solid
|
|
268
|
+
border-block-end: var(--border, 1px) solid
|
|
269
|
+
color-mix(in oklab, var(--color-base-300), transparent 40%);
|
|
211
270
|
}
|
|
212
271
|
|
|
213
272
|
.card__body {
|
|
@@ -221,6 +280,7 @@
|
|
|
221
280
|
display: flex;
|
|
222
281
|
align-items: center;
|
|
223
282
|
gap: 0.5rem;
|
|
224
|
-
border-block-start: var(--border, 1px) solid
|
|
283
|
+
border-block-start: var(--border, 1px) solid
|
|
284
|
+
color-mix(in oklab, var(--color-base-300), transparent 40%);
|
|
225
285
|
}
|
|
226
286
|
}
|
|
@@ -351,6 +351,9 @@ const __solidLayoutDialogContent = (_stable, p)=>{
|
|
|
351
351
|
get ["data-material"] () {
|
|
352
352
|
return p.material ?? "solid";
|
|
353
353
|
},
|
|
354
|
+
get ["data-material-explicit"] () {
|
|
355
|
+
return p.material ? "" : void 0;
|
|
356
|
+
},
|
|
354
357
|
get ["data-placement"] () {
|
|
355
358
|
return placement();
|
|
356
359
|
},
|
|
@@ -235,6 +235,9 @@ const __solidLayoutDrawerContent = (_stable, p)=>{
|
|
|
235
235
|
get ["data-material"] () {
|
|
236
236
|
return p.material ?? "solid";
|
|
237
237
|
},
|
|
238
|
+
get ["data-material-explicit"] () {
|
|
239
|
+
return p.material ? "" : void 0;
|
|
240
|
+
},
|
|
238
241
|
get ["data-placement"] () {
|
|
239
242
|
return placement();
|
|
240
243
|
},
|
|
@@ -175,6 +175,9 @@ const __solidLayoutMenuRoot = (_stable, p)=>{
|
|
|
175
175
|
get ["data-material"] () {
|
|
176
176
|
return p.material ?? "solid";
|
|
177
177
|
},
|
|
178
|
+
get ["data-material-explicit"] () {
|
|
179
|
+
return p.material ? "" : void 0;
|
|
180
|
+
},
|
|
178
181
|
get ["data-theme"] () {
|
|
179
182
|
return p.dataTheme;
|
|
180
183
|
},
|
|
@@ -210,6 +210,9 @@ const __solidLayoutPopoverContent = (_stable, p)=>{
|
|
|
210
210
|
get ["data-material"] () {
|
|
211
211
|
return p.material ?? "solid";
|
|
212
212
|
},
|
|
213
|
+
get ["data-material-explicit"] () {
|
|
214
|
+
return p.material ? "" : void 0;
|
|
215
|
+
},
|
|
213
216
|
get ["data-open"] () {
|
|
214
217
|
return ctx.isOpen() ? "true" : "false";
|
|
215
218
|
},
|
package/dist/styles/glass.d.ts
CHANGED
|
@@ -38,6 +38,17 @@ export type GlassTuning = {
|
|
|
38
38
|
refraction: number;
|
|
39
39
|
/** How far off the page it sits, 0 to 30. Drives glows, sheen and shadow. */
|
|
40
40
|
depth: number;
|
|
41
|
+
/**
|
|
42
|
+
* How much of the glass film a *control* takes, 0 to 1. Defaults to 0.
|
|
43
|
+
*
|
|
44
|
+
* Separate from `refraction` on purpose. Surfaces and controls cannot share
|
|
45
|
+
* one opacity: a translucent switch track or checkbox reads as disabled and
|
|
46
|
+
* its label stops being legible against whatever the glass admits. So glass
|
|
47
|
+
* cascades to surfaces only, and this is the deliberate opt-in for apps that
|
|
48
|
+
* want their chrome to pick some of it up. At 0 controls stay fully opaque,
|
|
49
|
+
* which is why turning glass on cannot make anything unreadable.
|
|
50
|
+
*/
|
|
51
|
+
controlTint?: number;
|
|
41
52
|
};
|
|
42
53
|
export declare const GLASS_LIMITS: {
|
|
43
54
|
readonly blur: {
|
|
@@ -52,6 +63,10 @@ export declare const GLASS_LIMITS: {
|
|
|
52
63
|
readonly min: 0;
|
|
53
64
|
readonly max: 30;
|
|
54
65
|
};
|
|
66
|
+
readonly controlTint: {
|
|
67
|
+
readonly min: 0;
|
|
68
|
+
readonly max: 1;
|
|
69
|
+
};
|
|
55
70
|
};
|
|
56
71
|
/** What the shipped themes use. Both land on the same numbers. */
|
|
57
72
|
export declare const GLASS_DEFAULTS: Record<GlassMode, GlassTuning>;
|
package/dist/styles/glass.js
CHANGED
|
@@ -10,18 +10,24 @@ const GLASS_LIMITS = {
|
|
|
10
10
|
depth: {
|
|
11
11
|
min: 0,
|
|
12
12
|
max: 30
|
|
13
|
+
},
|
|
14
|
+
controlTint: {
|
|
15
|
+
min: 0,
|
|
16
|
+
max: 1
|
|
13
17
|
}
|
|
14
18
|
};
|
|
15
19
|
const GLASS_DEFAULTS = {
|
|
16
20
|
light: {
|
|
17
21
|
blur: 9,
|
|
18
22
|
refraction: 0.31,
|
|
19
|
-
depth: 24
|
|
23
|
+
depth: 24,
|
|
24
|
+
controlTint: 0
|
|
20
25
|
},
|
|
21
26
|
dark: {
|
|
22
27
|
blur: 9,
|
|
23
28
|
refraction: 0.31,
|
|
24
|
-
depth: 24
|
|
29
|
+
depth: 24,
|
|
30
|
+
controlTint: 0
|
|
25
31
|
}
|
|
26
32
|
};
|
|
27
33
|
const clamp = (value, min, max, fallback)=>{
|
|
@@ -36,10 +42,12 @@ function normalise(tuning, mode) {
|
|
|
36
42
|
const blur = clamp(tuning.blur, GLASS_LIMITS.blur.min, GLASS_LIMITS.blur.max, base.blur);
|
|
37
43
|
const refraction = clamp(tuning.refraction, GLASS_LIMITS.refraction.min, GLASS_LIMITS.refraction.max, base.refraction);
|
|
38
44
|
const depth = clamp(tuning.depth, GLASS_LIMITS.depth.min, GLASS_LIMITS.depth.max, base.depth);
|
|
45
|
+
const controlTint = clamp(tuning.controlTint, GLASS_LIMITS.controlTint.min, GLASS_LIMITS.controlTint.max, base.controlTint ?? 0);
|
|
39
46
|
const r = refraction / GLASS_LIMITS.refraction.max;
|
|
40
47
|
const d = depth / GLASS_LIMITS.depth.max;
|
|
41
48
|
return {
|
|
42
49
|
blur,
|
|
50
|
+
controlTint,
|
|
43
51
|
light: "light" === mode,
|
|
44
52
|
rs: 0 === r ? 0 : r ** 0.82,
|
|
45
53
|
rv: 0 === r ? 0 : r ** 0.95,
|
|
@@ -52,6 +60,7 @@ function resolveGlassTokens(tuning, mode) {
|
|
|
52
60
|
const v = normalise(tuning, mode);
|
|
53
61
|
const { rs, rv, ds, light } = v;
|
|
54
62
|
const zero = 0 === v.r;
|
|
63
|
+
const controlTint = v.controlTint;
|
|
55
64
|
const background = light ? zero ? 0 : 18 + 30 * rv : 7 * rv;
|
|
56
65
|
const border = light ? zero ? 0 : 18 + 18 * rs : 26 * rs;
|
|
57
66
|
const highlight = light ? zero ? 0 : 22 + 26 * rs : 24 * rs;
|
|
@@ -89,7 +98,8 @@ function resolveGlassTokens(tuning, mode) {
|
|
|
89
98
|
"--glass-liquid-edge-size": px(1 + 2 * rs),
|
|
90
99
|
"--glass-liquid-inner-blur": px(6 + 12 * rs),
|
|
91
100
|
"--glass-shadow-depth": shadow,
|
|
92
|
-
"--glass-fallback-background-opacity": pct(fallbackBackground)
|
|
101
|
+
"--glass-fallback-background-opacity": pct(fallbackBackground),
|
|
102
|
+
"--glass-control-opacity": pct(100 - controlTint * (100 - background))
|
|
93
103
|
};
|
|
94
104
|
}
|
|
95
105
|
function applyGlassTokens(tuning, mode, target) {
|