@dloizides/ui-motion 1.0.2 → 1.2.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/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.0
4
+
5
+ ### Added
6
+ - `@dloizides/ui-motion/hairline`: `HairlineFigure` (web: vanilla `@lucasmarkes/hairline@0.3.0` on the host DOM node; native: inlined bundle in `react-native-webview`, optional peer), `HairlineFigureName`, `hairlineVars` token mapping (HAIRLINE-1 "Adopt hairline isometric line figures").
7
+
8
+ ## 1.1.0
9
+
10
+ ### Added
11
+
12
+ - **`computeFlipDeltas(prev, next, { staggerMs, cap })`** — the pure FLIP invert step: for each
13
+ item that moved, the offset it must start from, staggered in new reading order (y, then x).
14
+ New and unmoved items are omitted; past `cap` the rest snap.
15
+ - **`<Reorder itemKeys spring staggerMs? cap? testID?>{(key) => node}</Reorder>`** — plays that
16
+ step on a keyed list when its order changes. Web reads slots synchronously from the DOM and
17
+ inverts in a layout effect (before paint; RN-web `onLayout` misses position-only moves); native
18
+ uses `onLayout`. Mid-flight items start from where they are drawn; moved items past `cap` snap.
19
+ Items get `${testID}-item-${key}`. No animation under reduced motion.
20
+ - **`useFocusLift(focused, spring, { scale?, lift? })`** + pure **`focusLiftTarget`** — a focused
21
+ tile lifts 8px and scales 1.06 on a retargetable spring; stays put under reduced motion.
22
+
3
23
  ## 1.0.2
4
24
 
5
25
  ### Fixed
package/README.md CHANGED
@@ -50,6 +50,12 @@ if (!mounted) return null;
50
50
  return <Animated.View style={style}>{children}</Animated.View>;
51
51
  ```
52
52
 
53
+ ### `useFocusLift(focused, spring, { scale?, lift? })`
54
+
55
+ Springs a tile to `scale` (default 1.06) and `-lift` px (default 8) while `focused`, back to rest
56
+ otherwise. A focus change retargets the running spring. Reduced motion: no movement (signal focus
57
+ with a ring/shadow instead). Spread `style` onto an `Animated.View`. Pure target: `focusLiftTarget`.
58
+
53
59
  ## Components
54
60
 
55
61
  ### `<FadeIn duration? delay? translateY? style? testID>`
@@ -91,6 +97,12 @@ loading signal than the opacity pulse in `ui-feedback`'s PageSkeleton.
91
97
  <Skeleton width="60%" height={20} borderRadius={6} />
92
98
  ```
93
99
 
100
+ ### `<Reorder itemKeys spring staggerMs? cap? testID>{(key) => node}</Reorder>`
101
+
102
+ FLIP re-rank for a keyed list: when `itemKeys` changes order, moved items spring from their old
103
+ slot to the new one, staggered (default 18ms), at most `cap` (default 8) animated. Under reduced
104
+ motion items jump. The invert maths is the pure `computeFlipDeltas`.
105
+
94
106
  ## Reduced motion
95
107
 
96
108
  Every primitive honours the OS "reduce motion" setting: `FadeIn` shows content at rest,
@@ -106,3 +118,11 @@ verified in the app E2E suites.
106
118
  ## License
107
119
 
108
120
  MIT © dloizides
121
+
122
+ ## HairlineFigure (`@dloizides/ui-motion/hairline`)
123
+
124
+ Wraps `@lucasmarkes/hairline@0.3.0` (exact pin) so apps never import it directly. Props: `figure` (`HairlineFigureName`), `colors` (a `ModeColors` from `@dloizides/design-tokens`, mapped onto `--hairline-*` by `hairlineVars`), `intensity` (0-1), `label` (translated), `testID`.
125
+
126
+ - Web (RN-web, `browser` condition): mounts the vanilla API on the View's DOM node; destroyed on unmount.
127
+ - Native (`react-native` condition): renders the upstream bundle inlined as HTML in `react-native-webview` (optional peer; install it to use this subpath on iOS/Android). One figure per screen.
128
+ - A figure is decoration: never put information a user needs in it. On touch-first screens prefer horizontal/area figures (`terrain`, `riffle`, `keyboard`, `router`, `rail`, `dish`, `turntable`, `plot`).
@@ -0,0 +1,54 @@
1
+ import { ModeColors } from '@dloizides/design-tokens';
2
+
3
+ declare const enum HairlineFigureName {
4
+ Basket = "basket",
5
+ Branches = "branches",
6
+ Cabinet = "cabinet",
7
+ Dish = "dish",
8
+ Drawer = "drawer",
9
+ Elevator = "elevator",
10
+ Exploded = "exploded",
11
+ Keyboard = "keyboard",
12
+ Laptop = "laptop",
13
+ Lockers = "lockers",
14
+ Loupe = "loupe",
15
+ Padlock = "padlock",
16
+ Patch = "patch",
17
+ Phone = "phone",
18
+ Phosphor = "phosphor",
19
+ Plot = "plot",
20
+ Plug = "plug",
21
+ Query = "query",
22
+ Rail = "rail",
23
+ Riffle = "riffle",
24
+ Router = "router",
25
+ Sieve = "sieve",
26
+ Slow = "slow",
27
+ Terminal = "terminal",
28
+ Terrain = "terrain",
29
+ Turntable = "turntable",
30
+ Vault = "vault"
31
+ }
32
+
33
+ interface HairlineFigureProps {
34
+ /** Which upstream figure to draw. */
35
+ figure: HairlineFigureName;
36
+ /** Mode colours of the current theme; mapped onto the `--hairline-*` vars. */
37
+ colors: ModeColors;
38
+ /** Pointer response strength, 0 (subtle) to 1 (strong). */
39
+ intensity?: number;
40
+ /** Accessible name of the figure (pass a translated string). */
41
+ label?: string;
42
+ testID?: string;
43
+ }
44
+ type HairlineVarName = '--hairline-plate' | '--hairline-hi' | '--hairline-edge' | '--hairline-mid' | '--hairline-lo';
45
+ type HairlineVars = Record<HairlineVarName, string>;
46
+
47
+ /** Maps one theme mode's colour tokens onto the hairline palette vars (stroke width stays upstream). */
48
+ declare const hairlineVars: (colors: ModeColors) => HairlineVars;
49
+
50
+ declare const HAIRLINE_TEST_ID = "motion-hairline-figure";
51
+ declare const HAIRLINE_ASPECT_RATIO: number;
52
+ declare const DEFAULT_HAIRLINE_INTENSITY = 0.5;
53
+
54
+ export { DEFAULT_HAIRLINE_INTENSITY as D, type HairlineFigureProps as H, HAIRLINE_ASPECT_RATIO as a, HAIRLINE_TEST_ID as b, HairlineFigureName as c, type HairlineVarName as d, type HairlineVars as e, hairlineVars as h };
@@ -0,0 +1,54 @@
1
+ import { ModeColors } from '@dloizides/design-tokens';
2
+
3
+ declare const enum HairlineFigureName {
4
+ Basket = "basket",
5
+ Branches = "branches",
6
+ Cabinet = "cabinet",
7
+ Dish = "dish",
8
+ Drawer = "drawer",
9
+ Elevator = "elevator",
10
+ Exploded = "exploded",
11
+ Keyboard = "keyboard",
12
+ Laptop = "laptop",
13
+ Lockers = "lockers",
14
+ Loupe = "loupe",
15
+ Padlock = "padlock",
16
+ Patch = "patch",
17
+ Phone = "phone",
18
+ Phosphor = "phosphor",
19
+ Plot = "plot",
20
+ Plug = "plug",
21
+ Query = "query",
22
+ Rail = "rail",
23
+ Riffle = "riffle",
24
+ Router = "router",
25
+ Sieve = "sieve",
26
+ Slow = "slow",
27
+ Terminal = "terminal",
28
+ Terrain = "terrain",
29
+ Turntable = "turntable",
30
+ Vault = "vault"
31
+ }
32
+
33
+ interface HairlineFigureProps {
34
+ /** Which upstream figure to draw. */
35
+ figure: HairlineFigureName;
36
+ /** Mode colours of the current theme; mapped onto the `--hairline-*` vars. */
37
+ colors: ModeColors;
38
+ /** Pointer response strength, 0 (subtle) to 1 (strong). */
39
+ intensity?: number;
40
+ /** Accessible name of the figure (pass a translated string). */
41
+ label?: string;
42
+ testID?: string;
43
+ }
44
+ type HairlineVarName = '--hairline-plate' | '--hairline-hi' | '--hairline-edge' | '--hairline-mid' | '--hairline-lo';
45
+ type HairlineVars = Record<HairlineVarName, string>;
46
+
47
+ /** Maps one theme mode's colour tokens onto the hairline palette vars (stroke width stays upstream). */
48
+ declare const hairlineVars: (colors: ModeColors) => HairlineVars;
49
+
50
+ declare const HAIRLINE_TEST_ID = "motion-hairline-figure";
51
+ declare const HAIRLINE_ASPECT_RATIO: number;
52
+ declare const DEFAULT_HAIRLINE_INTENSITY = 0.5;
53
+
54
+ export { DEFAULT_HAIRLINE_INTENSITY as D, type HairlineFigureProps as H, HAIRLINE_ASPECT_RATIO as a, HAIRLINE_TEST_ID as b, HairlineFigureName as c, type HairlineVarName as d, type HairlineVars as e, hairlineVars as h };
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import { H as HairlineFigureProps } from '../constants-BrJ7VJYu.mjs';
3
+ export { D as DEFAULT_HAIRLINE_INTENSITY, a as HAIRLINE_ASPECT_RATIO, b as HAIRLINE_TEST_ID, c as HairlineFigureName, d as HairlineVarName, e as HairlineVars, h as hairlineVars } from '../constants-BrJ7VJYu.mjs';
4
+ import '@dloizides/design-tokens';
5
+
6
+ /** Renders a hairline figure in a WebView with the upstream bundle inlined (iOS/Android). */
7
+ declare const HairlineFigure: ({ figure, colors, intensity, label, testID, }: HairlineFigureProps) => React.ReactElement;
8
+
9
+ export { HairlineFigure, HairlineFigureProps };
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import { H as HairlineFigureProps } from '../constants-BrJ7VJYu.js';
3
+ export { D as DEFAULT_HAIRLINE_INTENSITY, a as HAIRLINE_ASPECT_RATIO, b as HAIRLINE_TEST_ID, c as HairlineFigureName, d as HairlineVarName, e as HairlineVars, h as hairlineVars } from '../constants-BrJ7VJYu.js';
4
+ import '@dloizides/design-tokens';
5
+
6
+ /** Renders a hairline figure in a WebView with the upstream bundle inlined (iOS/Android). */
7
+ declare const HairlineFigure: ({ figure, colors, intensity, label, testID, }: HairlineFigureProps) => React.ReactElement;
8
+
9
+ export { HairlineFigure, HairlineFigureProps };