@uniflowed/stylex 0.8.0 → 0.10.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/index.js CHANGED
@@ -153,10 +153,13 @@ export function create<T extends { readonly [string]: mixed }>(
153
153
 
154
154
  /**
155
155
  * Declare design tokens, and hand back the `var(--…)` references to them.
156
+ * Every compiled value is a string, including a token with a numeric default.
156
157
  *
157
158
  * Compile-time, for the same reason as `create`.
158
159
  */
159
- export function defineVars<T extends { readonly [string]: ThemeValue }>(tokens: T): T {
160
+ export function defineVars<T extends { readonly [string]: ThemeValue }>(
161
+ tokens: T,
162
+ ): { readonly [Key in keyof T]: string } {
160
163
  return nativeRuntimeRequired(MODULE, "stylex.defineVars");
161
164
  }
162
165
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniflowed/stylex",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "Flow declarations for @uniflowed/stylex, part of the Unified Toolchain for Flow.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -23,7 +23,7 @@
23
23
  "!*.test.js"
24
24
  ],
25
25
  "dependencies": {
26
- "@uniflowed/core": "0.8.0"
26
+ "@uniflowed/core": "0.10.0"
27
27
  },
28
28
  "peerDependencies": {
29
29
  "react-native": ">=0.86.0"
package/preset.js CHANGED
@@ -234,36 +234,55 @@ const fields = stylex.create({
234
234
 
235
235
  const overlays = stylex.create({
236
236
  // Enter: the wash fades in over `durationSlow`, the same time as the panel
237
- // in front of it. A fade is what reduced motion keeps, so it keeps this.
237
+ // in front of it. Exit: it clears with the panel, in `durationBase` on the
238
+ // accelerating curve, while `@uniflowed/ui` keeps it on the page with
239
+ // `data-state="closed"` and `inert`. A fade is what reduced motion keeps,
240
+ // so it keeps both.
238
241
  backdrop: {
239
242
  position: "fixed",
240
243
  inset: 0,
241
244
  backgroundColor: ufTokens.scrim,
242
- opacity: { default: 1, "@starting-style": 0 },
245
+ opacity: { default: 1, "@starting-style": 0, ":is([data-state=closed])": 0 },
243
246
  transitionProperty: "opacity",
244
- transitionDuration: ufTokens.durationSlow,
245
- transitionTimingFunction: ufTokens.easingEnter,
247
+ transitionDuration: {
248
+ default: ufTokens.durationSlow,
249
+ ":is([data-state=closed])": ufTokens.durationBase,
250
+ },
251
+ transitionTimingFunction: {
252
+ default: ufTokens.easingEnter,
253
+ ":is([data-state=closed])": ufTokens.easingExit,
254
+ },
246
255
  },
247
256
  // Enter: the panel fades in and grows from 96% of its size where it rests,
248
257
  // on the decelerating curve, so it is legible almost at once and is seen
249
258
  // settling rather than popping. The centring translate is part of both
250
- // values, or the panel would start in the corner. Under reduced motion it
251
- // only fades.
259
+ // values, or the panel would start in the corner. Exit: back to 96% as it
260
+ // fades, in `durationBase` on the accelerating curve. Under reduced motion
261
+ // both only fade: `--uf-exit-travel` is 0 there, so the scale does not jump.
252
262
  dialog: {
253
263
  position: "fixed",
254
264
  top: "50%",
255
265
  left: "50%",
256
- opacity: { default: 1, "@starting-style": 0 },
266
+ "--uf-exit-travel": { default: "1", "@media (prefers-reduced-motion: reduce)": "0" },
267
+ opacity: { default: 1, "@starting-style": 0, ":is([data-state=closed])": 0 },
257
268
  transform: {
258
269
  default: "translate(-50%, -50%)",
259
270
  "@starting-style": "translate(-50%, -50%) scale(0.96)",
271
+ ":is([data-state=closed])":
272
+ "translate(-50%, -50%) scale(calc(1 - 0.04 * var(--uf-exit-travel)))",
260
273
  },
261
274
  transitionProperty: {
262
275
  default: "opacity, transform",
263
276
  "@media (prefers-reduced-motion: reduce)": "opacity",
264
277
  },
265
- transitionDuration: ufTokens.durationSlow,
266
- transitionTimingFunction: ufTokens.easingEnter,
278
+ transitionDuration: {
279
+ default: ufTokens.durationSlow,
280
+ ":is([data-state=closed])": ufTokens.durationBase,
281
+ },
282
+ transitionTimingFunction: {
283
+ default: ufTokens.easingEnter,
284
+ ":is([data-state=closed])": ufTokens.easingExit,
285
+ },
267
286
  width: "calc(100% - 32px)",
268
287
  maxWidth: "32rem",
269
288
  backgroundColor: ufTokens.surface,
@@ -280,7 +299,8 @@ const overlays = stylex.create({
280
299
  const menus = stylex.create({
281
300
  // Enter: it fades in while travelling 4px out of its trigger, from the side
282
301
  // `@uniflowed/ui` put it on (`data-side`), the way `registry/ui/menu.js`
283
- // does. Under reduced motion it only fades.
302
+ // does. Exit: back towards the trigger in `durationFast` on the
303
+ // accelerating curve. Under reduced motion both only fade.
284
304
  menu: {
285
305
  "--uf-enter-x": {
286
306
  default: "0px",
@@ -292,17 +312,26 @@ const menus = stylex.create({
292
312
  ":is([data-side=top])": "4px",
293
313
  ":is([data-side=bottom])": "-4px",
294
314
  },
295
- opacity: { default: 1, "@starting-style": 0 },
315
+ "--uf-exit-travel": { default: "1", "@media (prefers-reduced-motion: reduce)": "0" },
316
+ opacity: { default: 1, "@starting-style": 0, ":is([data-state=closed])": 0 },
296
317
  transform: {
297
318
  default: "none",
298
319
  "@starting-style": "translate(var(--uf-enter-x), var(--uf-enter-y))",
320
+ ":is([data-state=closed])":
321
+ "translate(calc(var(--uf-enter-x) * var(--uf-exit-travel)), calc(var(--uf-enter-y) * var(--uf-exit-travel)))",
299
322
  },
300
323
  transitionProperty: {
301
324
  default: "opacity, transform",
302
325
  "@media (prefers-reduced-motion: reduce)": "opacity",
303
326
  },
304
- transitionDuration: ufTokens.durationBase,
305
- transitionTimingFunction: ufTokens.easingEnter,
327
+ transitionDuration: {
328
+ default: ufTokens.durationBase,
329
+ ":is([data-state=closed])": ufTokens.durationFast,
330
+ },
331
+ transitionTimingFunction: {
332
+ default: ufTokens.easingEnter,
333
+ ":is([data-state=closed])": ufTokens.easingExit,
334
+ },
306
335
  minWidth: "12rem",
307
336
  margin: 0,
308
337
  padding: ufTokens.space1,
package/theme.js CHANGED
@@ -51,7 +51,7 @@
51
51
  // actually pairs, and `crates/uf_stylex/src/tests/preset.rs` computes those
52
52
  // ratios from the compiled stylesheet.
53
53
 
54
- import { stylex } from "@uniflowed/stylex";
54
+ import { stylex, type CompiledStyle } from "@uniflowed/stylex";
55
55
 
56
56
  import { ufTokens } from "./tokens.stylex.js";
57
57
 
@@ -61,7 +61,7 @@ import { ufTokens } from "./tokens.stylex.js";
61
61
  * Every entry is conditional, so this theme is inert in light mode and costs
62
62
  * exactly one `@media (prefers-color-scheme: dark)` block.
63
63
  */
64
- export const ufAutoTheme = stylex.createTheme(ufTokens, {
64
+ export const ufAutoTheme: CompiledStyle = stylex.createTheme(ufTokens, {
65
65
  canvas: { "@media (prefers-color-scheme: dark)": "#141413" },
66
66
  sunken: { "@media (prefers-color-scheme: dark)": "#0f0f0e" },
67
67
  surface: { "@media (prefers-color-scheme: dark)": "#1c1c1a" },
@@ -87,7 +87,7 @@ export const ufAutoTheme = stylex.createTheme(ufTokens, {
87
87
  * For a subtree that is dark whatever the system says, and for the stored
88
88
  * preference a reader chose.
89
89
  */
90
- export const ufDarkTheme = stylex.createTheme(ufTokens, {
90
+ export const ufDarkTheme: CompiledStyle = stylex.createTheme(ufTokens, {
91
91
  canvas: "#141413",
92
92
  sunken: "#0f0f0e",
93
93
  surface: "#1c1c1a",
package/tokens.stylex.js CHANGED
@@ -59,10 +59,59 @@
59
59
 
60
60
  import { stylex } from "@uniflowed/stylex";
61
61
 
62
- // Deliberately unannotated: `defineVars` hands back exactly what it was given,
63
- // so the inferred type is the token set itself — which is what makes
64
- // `ThemeOverrides<typeof ufTokens>` reject a token this module does not declare.
65
- export const ufTokens = stylex.defineVars({
62
+ // The explicit key set is also the module interface downstream themes read.
63
+ export type UFTokens = {|
64
+ readonly canvas: string,
65
+ readonly sunken: string,
66
+ readonly surface: string,
67
+ readonly surfaceHover: string,
68
+ readonly border: string,
69
+ readonly ink: string,
70
+ readonly muted: string,
71
+ readonly accent: string,
72
+ readonly accentHover: string,
73
+ readonly accentInk: string,
74
+ readonly accentSoft: string,
75
+ readonly danger: string,
76
+ readonly dangerHover: string,
77
+ readonly dangerInk: string,
78
+ readonly dangerSoft: string,
79
+ readonly focus: string,
80
+ readonly scrim: string,
81
+ readonly fontSans: string,
82
+ readonly fontMono: string,
83
+ readonly textXs: string,
84
+ readonly textSm: string,
85
+ readonly textMd: string,
86
+ readonly textLg: string,
87
+ readonly textXl: string,
88
+ readonly text2Xl: string,
89
+ readonly leadingTight: string,
90
+ readonly leadingBase: string,
91
+ readonly weightRegular: string,
92
+ readonly weightMedium: string,
93
+ readonly weightBold: string,
94
+ readonly space1: string,
95
+ readonly space2: string,
96
+ readonly space3: string,
97
+ readonly space4: string,
98
+ readonly space6: string,
99
+ readonly space8: string,
100
+ readonly space12: string,
101
+ readonly radiusSm: string,
102
+ readonly radiusMd: string,
103
+ readonly radiusLg: string,
104
+ readonly radiusPill: string,
105
+ readonly sizeControl: string,
106
+ readonly durationFast: string,
107
+ readonly durationBase: string,
108
+ readonly durationSlow: string,
109
+ readonly easing: string,
110
+ readonly easingEnter: string,
111
+ readonly easingExit: string,
112
+ |};
113
+
114
+ export const ufTokens: UFTokens = stylex.defineVars({
66
115
  // Surfaces, from furthest back to nearest front.
67
116
  canvas: "#f6f6f4",
68
117
  sunken: "#eeeeeb",