@uniflowed/stylex 0.2.0 → 0.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.
package/index.js CHANGED
@@ -132,13 +132,22 @@ export type ThemeOverrides<Tokens extends { readonly [string]: ThemeValue }> = P
132
132
  /**
133
133
  * Declare a set of style namespaces.
134
134
  *
135
+ * Typed as what the compiler hands back, not what was written: every key of
136
+ * `styles` becomes a {@link CompiledStyle}, a map of property to class name
137
+ * marked with `$$css`. Typing the result as the input (`T`) said a namespace
138
+ * held `{ color: "black" }` when at run time it holds `{ $$css: true, color:
139
+ * "x1e2nbdu" }`, so code reading the compiled marker, and `props`'s own
140
+ * tests, were type errors against the truth.
141
+ *
135
142
  * Never runs. `uf transform` replaces the whole call with the object it
136
143
  * computed, so reaching this means the module was loaded without going through
137
144
  * uf — a bundler configured by hand, a plain `node` invocation — and the styles
138
145
  * it declares are in no stylesheet. Throwing says so; returning the input would
139
146
  * render an application with no styles and no explanation.
140
147
  */
141
- export function create<T extends { readonly [string]: mixed }>(styles: T): T {
148
+ export function create<T extends { readonly [string]: mixed }>(
149
+ styles: T,
150
+ ): { readonly [Key in keyof T]: CompiledStyle } {
142
151
  return nativeRuntimeRequired(MODULE, "stylex.create");
143
152
  }
144
153
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniflowed/stylex",
3
- "version": "0.2.0",
3
+ "version": "0.4.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.2.0"
26
+ "@uniflowed/core": "0.4.0"
27
27
  },
28
28
  "peerDependencies": {
29
29
  "react-native": ">=0.86.0"
package/preset.js CHANGED
@@ -132,11 +132,21 @@ const buttons = stylex.create({
132
132
  borderStyle: "solid",
133
133
  borderColor: "transparent",
134
134
  cursor: "pointer",
135
- transitionProperty: "background-color, border-color, color",
136
- transitionDuration: {
137
- default: ufTokens.durationFast,
138
- "@media (prefers-reduced-motion: reduce)": "0s",
135
+ // Press: the button gives a little under the pointer, to 97% of its size
136
+ // in `durationFast`, and comes back on release without passing 1. Under
137
+ // reduced motion it does not move; only the colours still change.
138
+ transform: {
139
+ default: "none",
140
+ ":active": "scale(0.97)",
141
+ "@media (prefers-reduced-motion: reduce)": "none",
139
142
  },
143
+ // The focus ring draws itself outward from the edge (`outline-width`
144
+ // 0 → 2px) rather than blinking on, in `durationFast`.
145
+ transitionProperty: {
146
+ default: "background-color, border-color, color, outline-width, transform",
147
+ "@media (prefers-reduced-motion: reduce)": "background-color, border-color, color",
148
+ },
149
+ transitionDuration: ufTokens.durationFast,
140
150
  transitionTimingFunction: ufTokens.easing,
141
151
  // The ring is drawn only for a keyboard focus, which is the whole reason
142
152
  // `:focus-visible` exists: a mouse click should not light the control up.
@@ -319,11 +329,13 @@ const controls = stylex.create({
319
329
  backgroundColor: ufTokens.surface,
320
330
  color: ufTokens.accentInk,
321
331
  cursor: "pointer",
322
- transitionProperty: "background-color, border-color",
323
- transitionDuration: {
324
- default: ufTokens.durationFast,
325
- "@media (prefers-reduced-motion: reduce)": "0s",
332
+ // Colours, and the focus ring drawing outward; only the colours stay
333
+ // under reduced motion.
334
+ transitionProperty: {
335
+ default: "background-color, border-color, outline-width",
336
+ "@media (prefers-reduced-motion: reduce)": "background-color, border-color",
326
337
  },
338
+ transitionDuration: ufTokens.durationFast,
327
339
  transitionTimingFunction: ufTokens.easing,
328
340
  outlineWidth: { default: "0", ":focus-visible": "2px" },
329
341
  outlineStyle: "solid",
package/tokens.stylex.js CHANGED
@@ -127,17 +127,64 @@ export const ufTokens = stylex.defineVars({
127
127
  // The size of a control a finger or a pointer aims at.
128
128
  sizeControl: "18px",
129
129
 
130
- // Motion. Two short durations and one easing: `durationFast` for a colour
131
- // or a chevron, `durationBase` for something that travels, such as a
132
- // switch's thumb or a drawer. The easing decelerates and never overshoots,
133
- // so nothing bounces. A transition names the properties it moves, never
134
- // `all`, and is `0s` under `prefers-reduced-motion: reduce`;
135
- // `crates/uf_stylex/src/tests/defaults.rs` holds every default style to
136
- // that.
130
+ // There is no elevation: a surface in front of another is told apart by a
131
+ // 1px `border` and its own background, never by a shadow.
132
+
133
+ // # Motion
134
+ //
135
+ // Three durations and three easings, and every default transition is one of
136
+ // each. `docs/ui-visual-language.md` has the table of what moves how; the
137
+ // values are argued here, where a theme that wants to change them will look.
138
+ //
139
+ // **Durations, by how far the eye has to follow.**
140
+ //
141
+ // * `durationFast`, 120ms: a change *in place* — a colour, a pressed
142
+ // button giving way, a focus ring drawing itself, a chevron turning.
143
+ // Nothing travels, so anything longer reads as lag between the press
144
+ // and the answer; anything under ~100ms is not seen at all, which is
145
+ // how #1414's defaults came to look like they had no motion.
146
+ // * `durationBase`, 200ms: something small *arriving* or *travelling* — a
147
+ // popover, menu or listbox leaving its trigger, a switch's thumb, a
148
+ // check being drawn. Long enough to see where it came from, short enough
149
+ // that a reader who opens a menu to act in it is never waiting for it.
150
+ // * `durationSlow`, 280ms: something *large* — a dialog, a sheet, a
151
+ // drawer, a toast, a progress bar's fill. A surface that covers a third
152
+ // of the screen and moves as fast as a menu looks thrown. It stops short
153
+ // of the ~300ms where an interface starts to feel like it is performing.
154
+ //
155
+ // **Easings, by where the motion starts and ends.** All three are
156
+ // cubic-béziers with both y values inside 0..1, so nothing overshoots its
157
+ // destination and nothing bounces; `defaults.rs` holds them to that.
158
+ //
159
+ // * `easing`, `cubic-bezier(0.2, 0, 0, 1)`: the standard curve, for
160
+ // something moving between two places it rests at — a switch's thumb, a
161
+ // progress fill, a drawer between snap points, a colour. It eases out of
162
+ // rest a little and settles for a long time, so it never stops abruptly.
163
+ // * `easingEnter`, `cubic-bezier(0, 0, 0.2, 1)`: a decelerate, for
164
+ // something *arriving*. It leaves at full speed and spends its second
165
+ // half settling: half the distance is covered by a fifth of the time,
166
+ // so the content is legible almost at once, while the settle is long
167
+ // enough to be seen. A stronger curve (Material's emphasised
168
+ // `0.05, 0.7, 0.1, 1`) was tried and rejected: it is 78% there by a
169
+ // fifth of the time, which on a 200ms popover is the "almost no motion"
170
+ // this replaces.
171
+ // * `easingExit`, `cubic-bezier(0.4, 0, 1, 1)`: an accelerate, for
172
+ // something *leaving*. It starts slowly, so the eye registers that it is
173
+ // going, then gets out of the way at full speed. Exits pair it with a
174
+ // shorter duration than the matching enter, because nobody watches a
175
+ // thing leave. (Exit transitions need the behaviour layer to keep a
176
+ // closing part mounted until they finish; until it does, this token is
177
+ // declared and not yet read — see `docs/ui-visual-language.md`.)
137
178
  //
138
- // There is no elevation either: a surface in front of another is told
139
- // apart by a 1px `border` and its own background, never by a shadow.
179
+ // A transition names the properties it moves, never `all`. Under
180
+ // `prefers-reduced-motion: reduce` nothing travels, grows or is drawn:
181
+ // either the duration is `0s`, or only opacity and colour still transition,
182
+ // so an overlay still fades rather than cutting. `defaults.rs` checks every
183
+ // default style for each of these.
140
184
  durationFast: "120ms",
141
- durationBase: "160ms",
185
+ durationBase: "200ms",
186
+ durationSlow: "280ms",
142
187
  easing: "cubic-bezier(0.2, 0, 0, 1)",
188
+ easingEnter: "cubic-bezier(0, 0, 0.2, 1)",
189
+ easingExit: "cubic-bezier(0.4, 0, 1, 1)",
143
190
  });