@phreshos/react-ui 0.1.50 → 0.1.51

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/README.md CHANGED
@@ -231,7 +231,7 @@ component-owned.
231
231
  Text fields, Select, ComboBox, and the date fields recess the `background` by
232
232
  default. Checkbox, Switch, and RadioGroup indicators are recessed beds that rise
233
233
  in their color when selected. Slider and ProgressBar fill a recessed rail with
234
- their color. Motion follows `appearance.transaction`; Preferences with
234
+ their color. Motion is derived from what moves, how far, and `appearance.tempo` (`timing`, `useTiming`); Preferences with
235
235
  animations disabled make every change immediate without changing Appearance.
236
236
 
237
237
  | Component | Value contract | Purpose |
@@ -61,5 +61,5 @@ export declare function controlMetrics(visual: Visual, size: ScaleLevel, radius:
61
61
  * Appearance radius itself.
62
62
  */
63
63
  export declare function proportionalRadius(visual: Visual, height: number, level?: ScaleLevel): number;
64
- /** A CSS transition for the given properties using the Appearance transaction. */
64
+ /** A CSS transition for the given properties moving as a change in place. */
65
65
  export declare function transition(visual: Visual, properties: string, factor?: number): CSSProperties;
@@ -69,7 +69,7 @@ export function proportionalRadius(visual, height, level = "medium") {
69
69
  const medium = controlHeight(visual.spacing);
70
70
  return Math.round(scale(visual.radius, level) * height / medium * 100) / 100;
71
71
  }
72
- /** A CSS transition for the given properties using the Appearance transaction. */
72
+ /** A CSS transition for the given properties moving as a change in place. */
73
73
  export function transition(visual, properties, factor = 1) {
74
74
  return {
75
75
  transitionProperty: properties,
package/dist/drawer.d.ts CHANGED
@@ -14,7 +14,7 @@ export interface DrawerProps {
14
14
  * A narrow layout's sidebar, over its content from the start side, such as the navigation a narrow
15
15
  * window gives up to its content. It is placed in its nearest positioned container. A press
16
16
  * outside or Escape closes it. It slides in and back out along the same path, timed by the
17
- * Appearance transaction, the way out its own animation so its end is seen; without motion it
17
+ * motion of a change in place, the way out its own animation so its end is seen; without motion it
18
18
  * simply shows and goes. Only its position moves:
19
19
  * fading it would switch off the blur it draws of what is behind it.
20
20
  */
package/dist/drawer.js CHANGED
@@ -9,7 +9,7 @@ import { Surface } from "./surface/surface.js";
9
9
  * A narrow layout's sidebar, over its content from the start side, such as the navigation a narrow
10
10
  * window gives up to its content. It is placed in its nearest positioned container. A press
11
11
  * outside or Escape closes it. It slides in and back out along the same path, timed by the
12
- * Appearance transaction, the way out its own animation so its end is seen; without motion it
12
+ * motion of a change in place, the way out its own animation so its end is seen; without motion it
13
13
  * simply shows and goes. Only its position moves:
14
14
  * fading it would switch off the blur it draws of what is behind it.
15
15
  */
@@ -1,7 +1,7 @@
1
- import { type Appearance as SystemAppearance, type AppearanceColors, type AppearanceMaterial, type AppearanceShadow, type AppearanceTransaction } from "@phreshos/core";
2
- export type { AppearanceColor, AppearanceColors, AppearanceMaterial, AppearanceRange, AppearanceShadow, AppearanceTransaction, Easing, ThemedValue } from "@phreshos/core";
1
+ import { type Appearance as SystemAppearance, type AppearanceColors, type AppearanceMaterial, type AppearanceShadow } from "@phreshos/core";
2
+ export type { AppearanceColor, AppearanceColors, AppearanceMaterial, AppearanceRange, AppearanceShadow, Transaction, Easing, ThemedValue } from "@phreshos/core";
3
3
  /** The System Appearance fields consumed by React UI. */
4
- export type Appearance = Pick<SystemAppearance, "colors" | "spacing" | "radius" | "shadow" | "material" | "transaction">;
4
+ export type Appearance = Pick<SystemAppearance, "colors" | "spacing" | "radius" | "shadow" | "material" | "tempo">;
5
5
  type Themed<Value> = Readonly<{
6
6
  light?: Readonly<Partial<Value>>;
7
7
  dark?: Readonly<Partial<Value>>;
@@ -12,7 +12,7 @@ type AppearanceUpdateFields = Readonly<{
12
12
  radius?: number;
13
13
  shadow?: Themed<AppearanceShadow>;
14
14
  material?: Themed<AppearanceMaterial>;
15
- transaction?: Readonly<Partial<AppearanceTransaction>>;
15
+ tempo?: number;
16
16
  }>;
17
17
  /** At least one partial visual field merged recursively with the nearest UIProvider. */
18
18
  export type AppearanceUpdate = {
@@ -76,6 +76,10 @@ export declare const appearanceLimits: Readonly<{
76
76
  maximum: 2.6;
77
77
  }>;
78
78
  }>;
79
+ tempo: Readonly<{
80
+ minimum: number;
81
+ maximum: 4;
82
+ }>;
79
83
  }>;
80
84
  /** The visual portion of the System's default Appearance. */
81
85
  export declare const defaultAppearance: Appearance;
@@ -4,7 +4,8 @@ export const appearanceLimits = Object.freeze({
4
4
  spacing: coreAppearanceLimits.spacing,
5
5
  radius: coreAppearanceLimits.radius,
6
6
  shadow: coreAppearanceLimits.shadow,
7
- material: coreAppearanceLimits.material
7
+ material: coreAppearanceLimits.material,
8
+ tempo: coreAppearanceLimits.tempo
8
9
  });
9
10
  /** The visual portion of the System's default Appearance. */
10
11
  export const defaultAppearance = Object.freeze({
@@ -13,7 +14,7 @@ export const defaultAppearance = Object.freeze({
13
14
  radius: systemDefaultAppearance.radius,
14
15
  shadow: systemDefaultAppearance.shadow,
15
16
  material: systemDefaultAppearance.material,
16
- transaction: systemDefaultAppearance.transaction
17
+ tempo: systemDefaultAppearance.tempo
17
18
  });
18
19
  /** Applies one partial update; omitted leaves continue to inherit. */
19
20
  export function mergeAppearance(appearance, update) {
@@ -23,9 +24,7 @@ export function mergeAppearance(appearance, update) {
23
24
  radius: update.radius ?? appearance.radius,
24
25
  shadow: mergeThemed(appearance.shadow, update.shadow),
25
26
  material: mergeThemed(appearance.material, update.material),
26
- transaction: update.transaction === undefined
27
- ? appearance.transaction
28
- : Object.freeze({ ...appearance.transaction, ...update.transaction })
27
+ tempo: update.tempo ?? appearance.tempo
29
28
  });
30
29
  }
31
30
  function mergeThemed(current, update) {
@@ -4,7 +4,7 @@ import type { Visual } from "./visual.js";
4
4
  export declare function overlayTransition(visual: Visual): CSSProperties;
5
5
  /**
6
6
  * How long one pass of a repeating motion takes, such as an indeterminate
7
- * progress sweep or a skeleton pulse: eight Appearance transactions, and never
7
+ * progress sweep or a skeleton pulse: eight changes in place, and never
8
8
  * quicker than a calm breath.
9
9
  */
10
10
  export declare function loopDuration(visual: Visual): number;
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { timing } from "./timing.js";
2
3
  /** Per-overlay variables consumed by the shared entrance keyframes. */
3
4
  export function overlayTransition(visual) {
4
5
  return {
@@ -8,11 +9,11 @@ export function overlayTransition(visual) {
8
9
  }
9
10
  /**
10
11
  * How long one pass of a repeating motion takes, such as an indeterminate
11
- * progress sweep or a skeleton pulse: eight Appearance transactions, and never
12
+ * progress sweep or a skeleton pulse: eight changes in place, and never
12
13
  * quicker than a calm breath.
13
14
  */
14
15
  export function loopDuration(visual) {
15
- return Math.max(900, visual.appearance.transaction.duration * 8);
16
+ return Math.max(900, timing("change", { tempo: visual.appearance.tempo }).duration * 8);
16
17
  }
17
18
  /** The stacking layer of content above an interface: dialogs and notifications. */
18
19
  export const overlayLayer = 1_000;
@@ -0,0 +1,30 @@
1
+ import type { Transaction } from "@phreshos/core";
2
+ /**
3
+ * What moves, which decides how it moves:
4
+ *
5
+ * - `change`: something changing in its place, such as a color, a control's state, or an overlay
6
+ * appearing. It is short, and the same whatever the size of what changes.
7
+ * - `window`: a box carried across a distance, such as a Window moving or resizing. A light body
8
+ * answering a hand: it sets off at once and settles softly.
9
+ * - `view`: a whole scene carried across a distance, such as the view over the plane. It moves as
10
+ * a body on a spring: it arrives without passing its place, and a move taken on the way carries
11
+ * on at the speed it already has.
12
+ */
13
+ export type MotionKind = "change" | "window" | "view";
14
+ export type TimingOptions = Readonly<{
15
+ /** How far it goes, in pixels; nothing for a change in place. */
16
+ distance?: number;
17
+ /** Whether it leaves the person's sight: then it sets off softly, or it is gone in the first frames. */
18
+ leaving?: boolean;
19
+ /** The Appearance tempo, or a tempo made from it; 1 by default. */
20
+ tempo?: number;
21
+ }>;
22
+ /**
23
+ * The motion of one change: how long it takes and how it moves, from what moves, how far, and the
24
+ * tempo. The shape of every motion is the System's own; the tempo only stretches or shortens time,
25
+ * so every motion keeps its shape and its length beside every other.
26
+ *
27
+ * Across a distance, the time grows with the distance, gently, as the square root, within bounds:
28
+ * a fixed short time would cross a far distance so fast that frames show as jumps.
29
+ */
30
+ export declare function timing(kind: MotionKind, options?: TimingOptions): Transaction;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * The motion of one change: how long it takes and how it moves, from what moves, how far, and the
3
+ * tempo. The shape of every motion is the System's own; the tempo only stretches or shortens time,
4
+ * so every motion keeps its shape and its length beside every other.
5
+ *
6
+ * Across a distance, the time grows with the distance, gently, as the square root, within bounds:
7
+ * a fixed short time would cross a far distance so fast that frames show as jumps.
8
+ */
9
+ export function timing(kind, options = {}) {
10
+ const tempo = options.tempo ?? 1;
11
+ // A change in place is the same for one tempo, so it is one value that effects can depend on. Only
12
+ // the few tempos in use are kept: a tempo dragged across its range leaves none of its steps behind.
13
+ if (kind === "change") {
14
+ let cached = changes.get(tempo);
15
+ if (!cached) {
16
+ if (changes.size >= 8)
17
+ changes.delete(changes.keys().next().value);
18
+ changes.set(tempo, cached = Object.freeze({ duration: Math.round(change.duration * tempo), easing: change.easing }));
19
+ }
20
+ return cached;
21
+ }
22
+ const pace = paces[kind];
23
+ const distance = options.distance ?? 0;
24
+ // Near, the time grows as the square root; a long crossing adds a little more for each pixel
25
+ // past a first stretch, so a far journey is not crossed at a rush.
26
+ const designed = Math.min(pace.maximum, Math.max(pace.minimum, pace.base + pace.growth * Math.sqrt(distance) + pace.far * Math.max(0, distance - 1000)));
27
+ return Object.freeze({ duration: Math.round(designed * tempo), easing: options.leaving ? departure : pace.easing });
28
+ }
29
+ const change = Object.freeze({ duration: 102, easing: "ease-out" });
30
+ const changes = new Map();
31
+ /** The curve of something leaving the view: soft to start, gathering speed as it goes. */
32
+ const departure = Object.freeze([0.65, 0, 0.35, 1]);
33
+ const paces = {
34
+ view: { base: 187, growth: 8.5, far: 0, minimum: 255, maximum: 850, easing: Object.freeze({ spring: Object.freeze({ bounce: 0 }) }) },
35
+ window: { base: 72, growth: 3.4, far: 0.0425, minimum: 110, maximum: 553, easing: Object.freeze([0.22, 1, 0.36, 1]) }
36
+ };
@@ -1,4 +1,6 @@
1
- import { type Appearance, type AppearanceColors, type AppearanceMaterial, type AppearanceShadow, type Easing, type ThemedValue } from "./appearance.js";
1
+ import { type Transaction } from "@phreshos/core";
2
+ import { type MotionKind, type TimingOptions } from "./timing.js";
3
+ import { type Appearance, type AppearanceColors, type AppearanceMaterial, type AppearanceShadow, type ThemedValue } from "./appearance.js";
2
4
  import type { Preferences } from "./preferences.js";
3
5
  /**
4
6
  * One Appearance resolved for one set of Preferences. Every component reads
@@ -13,9 +15,9 @@ export interface Visual {
13
15
  readonly shadow: AppearanceShadow;
14
16
  readonly spacing: number;
15
17
  readonly radius: number;
16
- /** Duration in milliseconds, already zero when animations are disabled. */
18
+ /** Duration in milliseconds of a change in place, already zero when animations are disabled. */
17
19
  readonly duration: number;
18
- /** CSS timing function for the Appearance transaction. */
20
+ /** CSS timing function of a change in place. */
19
21
  readonly easing: string;
20
22
  }
21
23
  /** Resolves and memoizes one Visual per Appearance, Theme, and animation preference. */
@@ -32,11 +34,15 @@ export declare function useAppearance(): Appearance;
32
34
  export declare function usePreferences(): Preferences;
33
35
  /** Returns the shared resolved Visual for the nearest Appearance and Preferences. */
34
36
  export declare function useVisual(): Visual;
37
+ /**
38
+ * Derives the motion of a change from the nearest Appearance's tempo: what moves, how far, and
39
+ * whether it leaves sight. With animations off, every motion takes no time.
40
+ */
41
+ export declare function useTiming(): (kind: MotionKind, options?: Omit<TimingOptions, "tempo">) => Transaction;
35
42
  /** Selects the active branch of one themed value. */
36
43
  export declare function useThemedValue<Value>(value: ThemedValue<Value>): Value;
37
44
  /** Reactively reads the browser's complete visual preferences. */
38
45
  export declare function useBrowserPreferences(): Preferences;
39
46
  /** Creates a stable source for one explicitly supplied Preferences value. */
40
47
  export declare function fixedPreferencesSource(preferences: Preferences): PreferencesSource;
41
- export declare function cssEasing(easing: Easing): string;
42
48
  export declare const PreferencesContext: import("react").Context<PreferencesSource>;
@@ -1,4 +1,6 @@
1
- import { createContext, useContext, useSyncExternalStore } from "react";
1
+ import { createContext, useCallback, useContext, useSyncExternalStore } from "react";
2
+ import { cssEasing } from "@phreshos/core";
3
+ import { timing } from "./timing.js";
2
4
  import { defaultAppearance } from "./appearance.js";
3
5
  const visuals = new WeakMap();
4
6
  /** Resolves and memoizes one Visual per Appearance, Theme, and animation preference. */
@@ -10,7 +12,8 @@ export function resolveVisual(appearance, preferences) {
10
12
  const cached = resolved.get(key);
11
13
  if (cached !== undefined)
12
14
  return cached;
13
- const duration = preferences.animations ? appearance.transaction.duration : 0;
15
+ const change = timing("change", { tempo: appearance.tempo });
16
+ const duration = preferences.animations ? change.duration : 0;
14
17
  const visual = Object.freeze({
15
18
  appearance,
16
19
  preferences,
@@ -20,7 +23,7 @@ export function resolveVisual(appearance, preferences) {
20
23
  spacing: appearance.spacing,
21
24
  radius: appearance.radius,
22
25
  duration,
23
- easing: cssEasing(appearance.transaction.easing)
26
+ easing: cssEasing(change.easing)
24
27
  });
25
28
  resolved.set(key, visual);
26
29
  return visual;
@@ -39,6 +42,18 @@ export function usePreferences() {
39
42
  export function useVisual() {
40
43
  return resolveVisual(useAppearance(), usePreferences());
41
44
  }
45
+ /**
46
+ * Derives the motion of a change from the nearest Appearance's tempo: what moves, how far, and
47
+ * whether it leaves sight. With animations off, every motion takes no time.
48
+ */
49
+ export function useTiming() {
50
+ const visual = useVisual();
51
+ return useCallback(function (kind, options = {}) {
52
+ if (!visual.preferences.animations)
53
+ return still;
54
+ return timing(kind, { ...options, tempo: visual.appearance.tempo });
55
+ }, [visual]);
56
+ }
42
57
  /** Selects the active branch of one themed value. */
43
58
  export function useThemedValue(value) {
44
59
  return value[usePreferences().theme];
@@ -55,9 +70,8 @@ export function fixedPreferencesSource(preferences) {
55
70
  subscribe: () => () => undefined
56
71
  };
57
72
  }
58
- export function cssEasing(easing) {
59
- return typeof easing === "string" ? easing : `cubic-bezier(${easing.join(", ")})`;
60
- }
73
+ // Every motion with animations off: it takes no time, so its curve never shows.
74
+ const still = Object.freeze({ duration: 0, easing: "linear" });
61
75
  const defaultPreferences = Object.freeze({ theme: "light", animations: true });
62
76
  const subscribers = new Set();
63
77
  let darkPreference;
@@ -8,6 +8,8 @@ type GridListRootBaseProps<T extends object> = Omit<AriaGridListProps<T>, "class
8
8
  className?: string;
9
9
  /** Color laid beneath selected Items. */
10
10
  color?: Color;
11
+ /** Color of Items that are not selected: `default` unless given. */
12
+ restColor?: Color;
11
13
  /** The narrowest an Item may be; the grid fits as many columns as that allows. Sixteen times the spacing by default. */
12
14
  itemWidth?: CSSProperties["width"];
13
15
  size?: ScaleLevel;
@@ -29,6 +31,8 @@ export interface GridListItemProps<T = object> extends Omit<AriaGridListItemProp
29
31
  readonly className?: string;
30
32
  /** Color laid beneath this Item when it is selected. */
31
33
  readonly color?: Color;
34
+ /** Color of this Item while it is not selected; the GridList's unless given. */
35
+ readonly restColor?: Color;
32
36
  readonly disabled?: boolean;
33
37
  readonly style?: CSSProperties;
34
38
  }
package/dist/grid-list.js CHANGED
@@ -10,12 +10,12 @@ import { resolveDirection, useDirection } from "./foundation/direction.js";
10
10
  import { collectionHeaderStyle } from "./list-box.js";
11
11
  const GridListStyleContext = createContext(null);
12
12
  const GridListRootImplementation = forwardRef(function GridList(properties, ref) {
13
- const { className, color = "primary", defaultValue: _defaultValue, itemWidth, onChange: _onChange, radius, selectionMode: _selectionMode, size, style, value: _value, ...native } = properties;
13
+ const { className, color = "primary", restColor = "default", defaultValue: _defaultValue, itemWidth, onChange: _onChange, radius, selectionMode: _selectionMode, size, style, value: _value, ...native } = properties;
14
14
  const metrics = useControlMetrics(size, radius);
15
15
  const width = itemWidth ?? metrics.visual.spacing * 16;
16
16
  // As many columns as fit, each at least the Item width; a Section repeats the same columns.
17
17
  const columns = `repeat(auto-fill, minmax(min(${typeof width === "number" ? `${width}px` : width}, 100%), 1fr))`;
18
- const context = useMemo(() => ({ color, metrics, columns }), [color, metrics, columns]);
18
+ const context = useMemo(() => ({ color, restColor, metrics, columns }), [color, restColor, metrics, columns]);
19
19
  const direction = resolveDirection(native.dir, useDirection());
20
20
  return _jsx(GridListStyleContext.Provider, { value: context, children: _jsx(AriaDirectionBoundary, { direction: direction, children: _jsx(AriaGridList, { ...native, ...ariaSelection(properties, "single"), ref: ref, dir: direction, layout: "grid", className: className, style: state => ({
21
21
  display: "grid",
@@ -33,7 +33,7 @@ const GridListRootImplementation = forwardRef(function GridList(properties, ref)
33
33
  }) }) }) });
34
34
  });
35
35
  /** One card. It holds whatever it is given, and shows a check in its corner when selected. */
36
- const GridListItemImplementation = forwardRef(function GridListItem({ children, className, color, disabled = false, style, textValue, ...properties }, ref) {
36
+ const GridListItemImplementation = forwardRef(function GridListItem({ children, className, color, restColor, disabled = false, style, textValue, ...properties }, ref) {
37
37
  const inherited = useGridListStyle();
38
38
  const itemColor = color ?? inherited.color;
39
39
  const { metrics } = inherited;
@@ -46,9 +46,9 @@ const GridListItemImplementation = forwardRef(function GridListItem({ children,
46
46
  focusVisible: state.isFocusVisible,
47
47
  disabled: state.isDisabled
48
48
  }, metrics.radius),
49
- // Unlike a list row, a card is a whole Surface: flat, in the default color at rest, in its
50
- // selection color once selected, with the default material in both.
51
- ...(state.isSelected || state.isDropTarget === true ? {} : { color: "default" }),
49
+ // Unlike a list row, a card is a whole Surface: flat, in its rest color, in its selection
50
+ // color once selected, with the default material in both.
51
+ ...(state.isSelected || state.isDropTarget === true ? {} : { color: restColor ?? inherited.restColor }),
52
52
  material: undefined
53
53
  })), style: {
54
54
  position: "relative",
package/dist/loading.d.ts CHANGED
@@ -17,7 +17,7 @@ export interface LoadingProps extends Pick<ReadinessProps, "children" | "delay">
17
17
  * requirements are waited for without being shown.
18
18
  *
19
19
  * The loading fills the nearest positioned ancestor. It appears at once; when
20
- * everything is ready it fades out with the Appearance transaction and the
20
+ * everything is ready it fades out as a change in place and the
21
21
  * interface appears whole at once.
22
22
  */
23
23
  export declare function Loading({ children, delay, steps, className, style }: LoadingProps): import("react").JSX.Element;
package/dist/loading.js CHANGED
@@ -15,7 +15,7 @@ import { Text } from "./typography.js";
15
15
  * requirements are waited for without being shown.
16
16
  *
17
17
  * The loading fills the nearest positioned ancestor. It appears at once; when
18
- * everything is ready it fades out with the Appearance transaction and the
18
+ * everything is ready it fades out as a change in place and the
19
19
  * interface appears whole at once.
20
20
  */
21
21
  export function Loading({ children, delay, steps = false, className, style }) {
package/dist/main.d.ts CHANGED
@@ -4,10 +4,11 @@
4
4
  * Components enter this surface only after their implementation-independent
5
5
  * behavior contract has been established by the package's tests.
6
6
  */
7
- export { appearanceLimits, defaultAppearance, type Appearance, type AppearanceColor, type AppearanceColors, type AppearanceMaterial, type AppearanceRange, type AppearanceShadow, type AppearanceTransaction, type AppearanceUpdate, type Easing, type ThemedValue } from "./foundation/appearance.js";
7
+ export { appearanceLimits, defaultAppearance, type Appearance, type AppearanceColor, type AppearanceColors, type AppearanceMaterial, type AppearanceRange, type AppearanceShadow, type Transaction, type AppearanceUpdate, type Easing, type ThemedValue } from "./foundation/appearance.js";
8
8
  export { UIProvider, type UIProviderProps } from "./foundation/provider.js";
9
9
  export { DocumentTheme } from "./document-theme.js";
10
- export { useAppearance, useBrowserPreferences, usePreferences, useThemedValue } from "./foundation/visual.js";
10
+ export { useAppearance, useBrowserPreferences, usePreferences, useThemedValue, useTiming } from "./foundation/visual.js";
11
+ export { timing, type MotionKind, type TimingOptions } from "./foundation/timing.js";
11
12
  export { useDirection, useDocumentDirection, type Direction } from "./foundation/direction.js";
12
13
  export type { Preferences, PreferencesUpdate, Theme } from "./foundation/preferences.js";
13
14
  export { Flex, type FlexProps } from "./flex.js";
package/dist/main.js CHANGED
@@ -7,7 +7,8 @@
7
7
  export { appearanceLimits, defaultAppearance } from "./foundation/appearance.js";
8
8
  export { UIProvider } from "./foundation/provider.js";
9
9
  export { DocumentTheme } from "./document-theme.js";
10
- export { useAppearance, useBrowserPreferences, usePreferences, useThemedValue } from "./foundation/visual.js";
10
+ export { useAppearance, useBrowserPreferences, usePreferences, useThemedValue, useTiming } from "./foundation/visual.js";
11
+ export { timing } from "./foundation/timing.js";
11
12
  export { useDirection, useDocumentDirection } from "./foundation/direction.js";
12
13
  export { Flex } from "./flex.js";
13
14
  export { Grid } from "./grid.js";
package/dist/tooltip.d.ts CHANGED
@@ -5,7 +5,7 @@ import { type AriaOverlayInternals, type OverlayRootProps } from "./control/open
5
5
  import { type Direction } from "./foundation/direction.js";
6
6
  import { type SurfaceOwnProps } from "./surface/surface.js";
7
7
  export type TooltipRootProps = OverlayRootProps & Readonly<Pick<AriaTooltipTriggerProps, "closeDelay" | "trigger">> & Readonly<{
8
- /** Milliseconds the pointer rests on the trigger before the Tooltip opens: four Appearance transactions by default. */
8
+ /** Milliseconds the pointer rests on the trigger before the Tooltip opens: four changes in place by default. */
9
9
  delay?: number;
10
10
  /** Whether the Tooltip is prevented from opening. */
11
11
  disabled?: boolean;
package/dist/tooltip.js CHANGED
@@ -9,11 +9,12 @@ import MotionStyle, { overlayMotionClass, overlayTransition } from "./foundation
9
9
  import { resolveDirectionalPlacement } from "./foundation/overlay-placement.js";
10
10
  import { scale } from "./foundation/scale.js";
11
11
  import { useVisual } from "./foundation/visual.js";
12
+ import { timing } from "./foundation/timing.js";
12
13
  import { floatingShadow } from "./surface/shadow-options.js";
13
14
  import { Surface } from "./surface/surface.js";
14
15
  export function TooltipRoot({ children, delay, closeDelay, trigger, disabled, closeOnPress, ...state }) {
15
- // A pointer resting on a trigger for four Appearance transactions is asking what it is.
16
- const rest = useVisual().appearance.transaction.duration * 4;
16
+ // A pointer resting on a trigger for four changes in place is asking what it is.
17
+ const rest = timing("change", { tempo: useVisual().appearance.tempo }).duration * 4;
17
18
  return _jsx(AriaTooltipTrigger, { ...ariaOpenState(state), delay: delay ?? rest, closeDelay: closeDelay, trigger: trigger, isDisabled: disabled, shouldCloseOnPress: closeOnPress, children: children });
18
19
  }
19
20
  export const TooltipTrigger = forwardRef(function TooltipTrigger(properties, ref) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phreshos/react-ui",
3
- "version": "0.1.50",
3
+ "version": "0.1.51",
4
4
  "description": "React components for coherent PhreshOS Program interfaces.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -57,7 +57,7 @@
57
57
  "dependencies": {
58
58
  "@base-ui/react": "^1.7.0",
59
59
  "@internationalized/date": "^3.12.3",
60
- "@phreshos/core": "^0.1.67",
60
+ "@phreshos/core": "^0.1.69",
61
61
  "colorjs.io": "^0.7.1",
62
62
  "lucide-react": "^1.48.0",
63
63
  "react-aria": "^3.51.0",